Trying to finish up 2019
This commit is contained in:
@@ -1,23 +1,127 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
helpers "git.bullercodeworks.com/brian/adventofcode/helpers"
|
||||
)
|
||||
|
||||
var maxX, maxY int
|
||||
var vault map[helpers.Coordinate]byte
|
||||
var keys map[helpers.Coordinate]byte
|
||||
var doors map[helpers.Coordinate]byte
|
||||
|
||||
func main() {
|
||||
file := "input"
|
||||
if helpers.GetArgNumber(1) != "" {
|
||||
file = helpers.GetArgNumber(1)
|
||||
}
|
||||
v := NewVault(file)
|
||||
v.Print()
|
||||
part1(v)
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
type Node struct {
|
||||
X, Y, Z int
|
||||
N, E, S, W *Node
|
||||
steps int
|
||||
visited bool
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
var st state
|
||||
for {
|
||||
st, queue = queue[0], queue[1:]
|
||||
fmt.Println(st.keys&keylist, keylist)
|
||||
if st.keys&keylist == keylist {
|
||||
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
|
||||
}
|
||||
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
|
||||
}
|
||||
key, ok := keys[helpers.NewCoordinate(wrk.X, wrk.Y).String()]
|
||||
if ok {
|
||||
fmt.Println("Getting Key")
|
||||
wrk.Z |= key // Pick up the key
|
||||
}
|
||||
queue = append(queue, state{X: wrk.X, Y: wrk.Y, keys: wrk.Z, steps: st.steps + 1})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func isDoor(b byte) bool {
|
||||
@@ -34,3 +138,33 @@ func keyToDoor(b byte) byte {
|
||||
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
|
||||
}
|
||||
|
@@ -2,7 +2,6 @@ package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
helpers "git.bullercodeworks.com/brian/adventofcode/helpers"
|
||||
@@ -10,9 +9,11 @@ import (
|
||||
|
||||
type Vault struct {
|
||||
maxX, maxY int
|
||||
vault map[helpers.Coordinate]byte
|
||||
keys map[helpers.Coordinate]byte
|
||||
doors map[helpers.Coordinate]byte
|
||||
start helpers.Coordinate
|
||||
vault map[string]bool
|
||||
keys map[string]int
|
||||
doors map[string]int
|
||||
keylist int
|
||||
}
|
||||
|
||||
func NewVault(file string) *Vault {
|
||||
@@ -20,55 +21,41 @@ func NewVault(file string) *Vault {
|
||||
wrk := bytes.Split(inp, []byte{'\n'})
|
||||
|
||||
v := Vault{
|
||||
vault: make(map[helpers.Coordinate]byte),
|
||||
keys: make(map[helpers.Coordinate]byte),
|
||||
doors: make(map[helpers.Coordinate]byte),
|
||||
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 {
|
||||
v.vault[*helpers.NewCoordinate(x, y)] = xv
|
||||
if xv == '@' {
|
||||
v.start = *helpers.NewCoordinate(x, y)
|
||||
xv = '.'
|
||||
}
|
||||
v.vault[helpers.NewCoordinate(x, y).String()] = (xv != '#')
|
||||
if isKey(xv) {
|
||||
v.keys[*helpers.NewCoordinate(x, y)] = xv
|
||||
k := keyInt(xv)
|
||||
v.keys[helpers.NewCoordinate(x, y).String()] = k
|
||||
v.keylist |= k
|
||||
} else if isDoor(xv) {
|
||||
v.doors[*helpers.NewCoordinate(x, y)] = xv
|
||||
d := doorInt(xv)
|
||||
v.doors[helpers.NewCoordinate(x, y).String()] = d
|
||||
v.keylist |= d
|
||||
}
|
||||
}
|
||||
}
|
||||
return &v
|
||||
}
|
||||
|
||||
func (v *Vault) findKey(door byte) (helpers.Coordinate, error) {
|
||||
var r helpers.Coordinate
|
||||
if !isDoor(door) {
|
||||
return r, errors.New("Invalid Door")
|
||||
}
|
||||
for k := range v.keys {
|
||||
if v.keys[k] == doorToKey(door) {
|
||||
return k, nil
|
||||
}
|
||||
}
|
||||
return r, errors.New("No key for that door")
|
||||
}
|
||||
|
||||
func (v *Vault) findDoor(key byte) (helpers.Coordinate, error) {
|
||||
var r helpers.Coordinate
|
||||
if !isKey(key) {
|
||||
return r, errors.New("Invalid Key")
|
||||
}
|
||||
for k := range v.doors {
|
||||
if v.doors[k] == keyToDoor(key) {
|
||||
return k, nil
|
||||
}
|
||||
}
|
||||
return r, errors.New("No door for that key")
|
||||
}
|
||||
|
||||
func (v *Vault) Print() {
|
||||
for y := 0; y < v.maxY; y++ {
|
||||
for x := 0; x < v.maxX; x++ {
|
||||
fmt.Print(string(v.vault[*helpers.NewCoordinate(x, y)]))
|
||||
if v.vault[helpers.NewCoordinate(x, y).String()] {
|
||||
fmt.Print(".")
|
||||
} else {
|
||||
fmt.Print("#")
|
||||
}
|
||||
}
|
||||
fmt.Println()
|
||||
}
|
||||
|
Reference in New Issue
Block a user