2018 Day 22 Complete

This commit is contained in:
2019-11-07 11:53:26 -06:00
parent 7a00e2f9cc
commit 7c9742fb73
4 changed files with 225 additions and 123 deletions

View File

@@ -2,141 +2,74 @@ package main
import (
"bufio"
"container/heap"
"fmt"
"log"
"os"
"regexp"
"strconv"
"strings"
)
var depth int
var target *Pos
const bailFactor = 8
func main() {
input := stdinToStringSlice()
reg, err := regexp.Compile("[^0-9]+")
if err != nil {
log.Fatal(err)
}
depth = Atoi(reg.ReplaceAllString(input[0], ""))
tgt := strings.Trim(input[1], "target: ")
tgtPts := strings.Split(tgt, ",")
target = NewPos(Atoi(tgtPts[0]), Atoi(tgtPts[1]), depth)
inp := StdinToStringSlice()
fmt.Printf("# Part 1\nRisk level: %d\n", RiskLevel(inp))
fmt.Printf("# Part 2\nRescue minutes: %d\n", Rescue(inp))
}
func part1() {
c := BuildCave(target)
var risk int
for y := 0; y <= target.y; y++ {
for x := 0; x <= target.x; x++ {
risk += c.risk(x, y, depth)
func RiskLevel(input []string) int {
m := NewMap(input)
sum := 0
for y := 0; y <= m.target.y; y++ {
for x := 0; x <= m.target.x; x++ {
sum += m.Type(x, y)
}
}
fmt.Println("= Part 1 =")
fmt.Println(risk)
return sum
}
func part2() {
// Find shortest path form 0,0 to target
// taking into account cost of changing gear
// when necessary
}
type Cave struct {
positions map[string]*Pos
}
func BuildCave(target *Pos) *Cave {
c := &Cave{
positions: make(map[string]*Pos),
func Rescue(input []string) int {
m := NewMap(input)
queue := PriorityQueue{
&Item{pos: coord{0, 0}, time: 0, equip: ToolTorch},
}
c.addPos(target)
return c
}
heap.Init(&queue)
func (c *Cave) addPos(p *Pos) {
c.positions[p.string()] = p
}
func (c *Cave) getPos(x, y, z int) *Pos {
var p *Pos
var ok bool
if p, ok = c.positions[c.buildKey(x, y, z)]; !ok {
p = NewPos(x, y, z)
c.addPos(p)
type step struct {
coord coord
equip int
}
return p
}
func (c *Cave) buildKey(x, y, z int) string {
return fmt.Sprintf(
"(%d,%d,%d)",
x, y, z,
)
}
distances := map[step]int{
step{coord: coord{0, 0}, equip: ToolTorch}: 0,
}
func (c *Cave) getGeoIndex(x, y, z int) int {
p := c.getPos(x, y, z)
if p.geo < 0 {
if x == 0 && y == 0 {
p.geo = 0
} else if x == target.x && y == target.y {
p.geo = 0
} else if y == 0 {
p.geo = x * 16807
} else if x == 0 {
p.geo = y * 48271
} else {
p.geo = c.erosion(x-1, y, z) * c.erosion(x, y-1, z)
for len(queue) > 0 {
item := (heap.Pop(&queue)).(*Item)
if item.pos.x == m.target.x && item.pos.y == m.target.y && item.equip == ToolTorch {
return item.time
}
// Check if we're wandering too far away
if item.pos.x > bailFactor*m.target.x || item.pos.y > bailFactor*m.target.y {
continue
}
if t, ok := distances[step{coord: item.pos, equip: item.equip}]; ok && t < item.time {
continue
}
for _, n := range m.Neighbors(item.pos, item.equip) {
d := step{coord: n.pos, equip: n.equip}
if t, ok := distances[step{coord: n.pos, equip: n.equip}]; !ok || item.time+n.time < t {
distances[d] = item.time + n.time
heap.Push(&queue, &Item{pos: n.pos, time: item.time + n.time, equip: n.equip})
}
}
}
return p.geo
return 0
}
func (c *Cave) erosion(x, y, z int) int {
p := c.getPos(x, y, z)
if p.erosion < 0 {
p.erosion = (c.getGeoIndex(x, y, z) + z) % 20183
}
return p.erosion
}
func (c *Cave) risk(x, y, z int) int {
return c.erosion(x, y, z) % 3
}
type Pos struct {
x, y, z int
geo, erosion int
}
func NewPos(x, y, z int) *Pos {
r := &Pos{
x: x,
y: y,
z: z,
geo: -1,
erosion: -1,
}
return r
}
func (p *Pos) equals(n *Pos) bool {
return p.x == n.x && p.y == n.y && p.z == n.z
}
func (p *Pos) string() string {
return fmt.Sprintf(
"(%d,%d,%d)",
p.x, p.y, p.z,
)
}
func stdinToStringSlice() []string {
func StdinToStringSlice() []string {
var input []string
scanner := bufio.NewScanner(os.Stdin)
for scanner.Scan() {
@@ -144,12 +77,3 @@ func stdinToStringSlice() []string {
}
return input
}
func Atoi(i string) int {
var ret int
var err error
if ret, err = strconv.Atoi(i); err != nil {
log.Fatal("Invalid Atoi: " + i)
}
return ret
}