Day 18 & Day 20 done

This commit is contained in:
2020-11-03 15:09:13 -06:00
parent 4f1712ceb0
commit d4a45d2b67
12 changed files with 447 additions and 479 deletions

View File

@@ -1,170 +1,153 @@
package main
import (
"bufio"
"fmt"
"io"
"log"
"os"
helpers "git.bullercodeworks.com/brian/adventofcode/helpers"
)
type state struct {
Pos helpers.Coordinate3d
Steps int
}
func main() {
file := "input"
if helpers.GetArgNumber(1) != "" {
file = helpers.GetArgNumber(1)
}
v := NewVault(file)
part1(v)
f, err := os.Open(file)
if err != nil {
log.Fatal(err)
}
defer f.Close()
part := helpers.GetArgNumber(2)
if part != "2" {
part1(f)
} else {
part2(f)
}
}
var keylist int
var allNodes map[string]*Node
func part1(v *Vault) {
keylist = v.keylist
allNodes = make(map[string]*Node)
for k, v := range v.vault {
if v {
x, y, z := unc(k)
n := Node{
X: x,
Y: y,
Z: z,
steps: helpers.MAX_INT,
}
allNodes[c([]int{x, y})] = &n
}
}
for _, v := range allNodes {
n, ok := allNodes[c([]int{v.X, v.Y + 1})]
if ok {
v.N = n
}
e, ok := allNodes[c([]int{v.X + 1, v.Y})]
if ok {
v.E = e
}
s, ok := allNodes[c([]int{v.X, v.Y - 1})]
if ok {
v.S = s
}
w, ok := allNodes[c([]int{v.X - 1, v.Y})]
if ok {
v.W = w
}
}
start := allNodes[c([]int{v.start.X, v.start.Y})]
start.steps = 0
ProcessNode(start, 0, 0)
func part1(r io.Reader) {
vault, doors, keys, start, allkeys := readVault(r)
fmt.Println(search(vault, doors, keys, start, allkeys, 0))
}
type Node struct {
X, Y, Z int
N, E, S, W *Node
steps int
visited bool
func part2(r io.Reader) {
vault, doors, keys, start, allKeys := readVault(r)
directions := []helpers.Coordinate{{X: 0, Y: -1}, {X: 1, Y: 0}, {X: 0, Y: 1}, {X: -1, Y: 0}}
vault[start] = false
for _, d := range directions {
vault[helpers.Coordinate{X: start.X + d.X, Y: start.Y + d.Y}] = false
}
total := 0
haveKeys := allKeys
for x := 0; x < start.X; x++ {
for y := 0; y < start.Y; y++ {
haveKeys ^= keys[helpers.Coordinate{X: x, Y: y}]
}
}
total += search(vault, doors, keys, helpers.Coordinate{X: start.X - 1, Y: start.Y - 1}, allKeys, haveKeys)
haveKeys = allKeys
for x := start.X + 1; x <= start.X*2; x++ {
for y := 0; y < start.Y; y++ {
haveKeys ^= keys[helpers.Coordinate{X: x, Y: y}]
}
}
total += search(vault, doors, keys, helpers.Coordinate{X: start.X + 1, Y: start.Y - 1}, allKeys, haveKeys)
haveKeys = allKeys
for x := start.X + 1; x <= start.X*2; x++ {
for y := start.Y + 1; y <= start.Y*2; y++ {
haveKeys ^= keys[helpers.Coordinate{X: x, Y: y}]
}
}
total += search(vault, doors, keys, helpers.Coordinate{X: start.X + 1, Y: start.Y + 1}, allKeys, haveKeys)
haveKeys = allKeys
for x := 0; x < start.X; x++ {
for y := start.Y + 1; y <= start.Y*2; y++ {
haveKeys ^= keys[helpers.Coordinate{X: x, Y: y}]
}
}
total += search(vault, doors, keys, helpers.Coordinate{X: start.X - 1, Y: start.Y + 1}, allKeys, haveKeys)
fmt.Println(total)
}
func ProcessNode(n *Node, steps, keys int) {
if n.Z&keylist == keylist {
fmt.Println("Steps to all Keys:", steps)
return
}
for _, neighbor := range []*Node{n.N, n.E, n.S, n.W} {
if neighbor == nil {
continue
}
wrk, ok := allNodes[c([]int{neighbor.X, neighbor.Y})]
if ok {
if n.steps+1 < wrk.steps {
wrk.steps = n.steps + 1
if !wrk.visited {
ProcessNode(wrk, n.steps+1, keys)
func readVault(r io.Reader) (map[helpers.Coordinate]bool, map[helpers.Coordinate]int, map[helpers.Coordinate]int, helpers.Coordinate, int) {
scan := bufio.NewScanner(r)
var start helpers.Coordinate
var x, y, allkeys int
v := make(map[helpers.Coordinate]bool)
doors, keys := make(map[helpers.Coordinate]int), make(map[helpers.Coordinate]int)
for scan.Scan() {
x = 0
for _, c := range scan.Text() {
if c != '#' {
v[helpers.Coordinate{X: x, Y: y}] = true
if c == '@' {
start = helpers.Coordinate{X: x, Y: y}
} else if c != '.' {
if c < 'a' {
k := 1 << (c - 'A')
doors[helpers.Coordinate{X: x, Y: y}] = k
allkeys |= k
} else {
k := 1 << (c - 'a')
keys[helpers.Coordinate{X: x, Y: y}] = k
allkeys |= k
}
}
}
x++
}
y++
}
if err := scan.Err(); err != nil {
log.Fatal(err)
}
return v, doors, keys, start, allkeys
}
type state struct {
X, Y int
keys int
steps int
}
func FindPath(vault map[string]bool, doors, keys map[string]int, start helpers.Coordinate, keylist, currkeys int) int {
queue := []state{state{X: start.X, Y: start.Y, keys: currkeys}}
visited := make(map[string]bool)
func search(vault map[helpers.Coordinate]bool, doors, keys map[helpers.Coordinate]int, start helpers.Coordinate, allKeys, haveKeys int) int {
directions := []helpers.Coordinate{{X: 0, Y: -1}, {X: 1, Y: 0}, {X: 0, Y: 1}, {X: -1, Y: 0}}
queue, visited := []state{{Pos: helpers.Coordinate3d{X: start.X, Y: start.Y, Z: haveKeys}}}, make(map[helpers.Coordinate3d]bool)
var st state
for {
st, queue = queue[0], queue[1:]
fmt.Println(st.keys&keylist, keylist)
if st.keys&keylist == keylist {
return st.steps
if st.Pos.Z&allKeys == allKeys {
return st.Steps
}
visited[c([]int{st.X, st.Y, st.keys})] = true
for _, v := range []*helpers.Coordinate{
start.GetNorthCoord(), start.GetEastCoord(),
start.GetSouthCoord(), start.GetWestCoord(),
} {
wrk := helpers.NewCoordinate3d(v.X, v.Y, st.keys)
if !vault[helpers.NewCoordinate(wrk.X, wrk.Y).String()] || visited[wrk.String()] {
continue // Already been here, or can't be here
visited[st.Pos] = true
for _, d := range directions {
next := helpers.Coordinate3d{X: st.Pos.X + d.X, Y: st.Pos.Y + d.Y, Z: st.Pos.Z}
if !vault[helpers.Coordinate{X: next.X, Y: next.Y}] || visited[next] {
continue
}
door, ok := doors[helpers.NewCoordinate(wrk.X, wrk.Y).String()]
if ok && wrk.Z&door != door {
fmt.Println("Hit door")
continue // Space exists, but we can't open the door
door, ok := doors[helpers.Coordinate{X: next.X, Y: next.Y}]
if ok && next.Z&door != door {
continue
}
key, ok := keys[helpers.NewCoordinate(wrk.X, wrk.Y).String()]
key, ok := keys[helpers.Coordinate{X: next.X, Y: next.Y}]
if ok {
fmt.Println("Getting Key")
wrk.Z |= key // Pick up the key
next.Z |= key
}
queue = append(queue, state{X: wrk.X, Y: wrk.Y, keys: wrk.Z, steps: st.steps + 1})
queue = append(queue, state{Pos: next, Steps: st.Steps + 1})
}
}
}
func isDoor(b byte) bool {
return 'A' <= b && b <= 'Z'
}
func isKey(b byte) bool {
return 'a' <= b && b <= 'z'
}
func keyToDoor(b byte) byte {
return (b - 'a') + 'A'
}
func doorToKey(b byte) byte {
return (b - 'A') + 'a'
}
func keyInt(b byte) int {
return 1 << (b - 'a')
}
func doorInt(b byte) int {
return 1 << (b - 'A')
}
func c(vals []int) string {
if len(vals) == 2 {
return fmt.Sprintf("[%d, %d]", vals[0], vals[1])
} else if len(vals) == 3 {
return fmt.Sprintf("[%d, %d, %d]", vals[0], vals[1], vals[2])
}
return ""
}
func unc(c string) (int, int, int) {
var x, y, z int
_, err := fmt.Sscanf(c, "[%d, %d, %d]", &x, &y, &z)
if err == nil {
return x, y, z
}
_, err = fmt.Sscanf(c, "[%d, %d]", &x, &y)
if err != nil {
panic(err)
}
return x, y, 0
}

3
2019/day18/testinput Normal file
View File

@@ -0,0 +1,3 @@
#########
#b.A.@.a#
#########

5
2019/day18/testinput2 Normal file
View File

@@ -0,0 +1,5 @@
########################
#f.D.E.e.C.b.A.@.a.B.c.#
######################.#
#d.....................#
########################

5
2019/day18/testinput3 Normal file
View File

@@ -0,0 +1,5 @@
########################
#...............b.C.D.f#
#.######################
#.....@.a.B.c.d.A.e.F.g#
########################

9
2019/day18/testinput4 Normal file
View File

@@ -0,0 +1,9 @@
#################
#i.G..c...e..H.p#
########.########
#j.A..b...f..D.o#
########@########
#k.E..a...g..B.n#
########.########
#l.F..d...h..C.m#
#################

6
2019/day18/testinput5 Normal file
View File

@@ -0,0 +1,6 @@
########################
#@..............ac.GI.b#
###d#e#f################
###A#B#C################
###g#h#i################
########################

View File

@@ -1,62 +0,0 @@
package main
import (
"bytes"
"fmt"
helpers "git.bullercodeworks.com/brian/adventofcode/helpers"
)
type Vault struct {
maxX, maxY int
start helpers.Coordinate
vault map[string]bool
keys map[string]int
doors map[string]int
keylist int
}
func NewVault(file string) *Vault {
inp := helpers.FileToBytes(file)
wrk := bytes.Split(inp, []byte{'\n'})
v := Vault{
vault: make(map[string]bool),
keys: make(map[string]int),
doors: make(map[string]int),
}
v.maxY = len(wrk)
v.maxX = len(wrk[0])
for y, yv := range wrk {
for x, xv := range yv {
if xv == '@' {
v.start = *helpers.NewCoordinate(x, y)
xv = '.'
}
v.vault[helpers.NewCoordinate(x, y).String()] = (xv != '#')
if isKey(xv) {
k := keyInt(xv)
v.keys[helpers.NewCoordinate(x, y).String()] = k
v.keylist |= k
} else if isDoor(xv) {
d := doorInt(xv)
v.doors[helpers.NewCoordinate(x, y).String()] = d
v.keylist |= d
}
}
}
return &v
}
func (v *Vault) Print() {
for y := 0; y < v.maxY; y++ {
for x := 0; x < v.maxX; x++ {
if v.vault[helpers.NewCoordinate(x, y).String()] {
fmt.Print(".")
} else {
fmt.Print("#")
}
}
fmt.Println()
}
}