Day 18 & Day 20 done
This commit is contained in:
@@ -1,94 +1,224 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"os"
|
||||
"time"
|
||||
"io/ioutil"
|
||||
"strings"
|
||||
|
||||
helpers "git.bullercodeworks.com/brian/adventofcode/helpers"
|
||||
h "git.bullercodeworks.com/brian/adventofcode/helpers"
|
||||
)
|
||||
|
||||
var maze *Maze
|
||||
type State struct {
|
||||
Position h.Coordinate3d
|
||||
Distance int
|
||||
}
|
||||
|
||||
var filename string
|
||||
var directions []h.Coordinate3d
|
||||
|
||||
func main() {
|
||||
file := "input"
|
||||
var manual bool
|
||||
if helpers.GetArgNumber(1) != "" {
|
||||
file = helpers.GetArgNumber(1)
|
||||
filename = "input"
|
||||
if h.GetArgNumber(1) != "" {
|
||||
filename = h.GetArgNumber(1)
|
||||
}
|
||||
if helpers.GetArgNumber(2) == "manual" {
|
||||
manual = true
|
||||
|
||||
directions = []h.Coordinate3d{{X: 0, Y: -1, Z: 0}, {X: 1, Y: 0, Z: 0}, {X: 0, Y: 1, Z: 0}, {X: -1, Y: 0, Z: 0}}
|
||||
part := h.GetArgNumber(2)
|
||||
if part != "2" {
|
||||
part1(filename)
|
||||
} else {
|
||||
part2(filename)
|
||||
}
|
||||
maze = NewMaze(file)
|
||||
if manual {
|
||||
runmanual(maze)
|
||||
}
|
||||
part1()
|
||||
//part2(inp)
|
||||
}
|
||||
|
||||
func part1() {
|
||||
maze.GetStart().steps = 0
|
||||
ProcessNode(maze.GetStart(), 0)
|
||||
fmt.Println("Distance:", maze.GetEnd().steps)
|
||||
}
|
||||
|
||||
func ProcessNode(m *MazeCoord, steps int) {
|
||||
fmt.Println("Processing Node", m)
|
||||
if maze.IsEnd(m.X, m.Y) {
|
||||
fmt.Println(" End")
|
||||
return
|
||||
}
|
||||
for _, neighbor := range []*MazeCoord{m.N, m.E, m.S, m.W} {
|
||||
if neighbor == nil {
|
||||
continue
|
||||
}
|
||||
if m.steps+1 < neighbor.steps {
|
||||
neighbor.steps = m.steps + 1
|
||||
if !neighbor.visited {
|
||||
ProcessNode(neighbor, m.steps+1)
|
||||
func part1(filename string) {
|
||||
maze := loadMaze(filename)
|
||||
queue, visited := []State{{Position: maze.Start}}, map[h.Coordinate3d]bool{maze.Start: true}
|
||||
var st State
|
||||
for {
|
||||
st, queue = queue[0], queue[1:]
|
||||
for _, d := range directions {
|
||||
next := h.Coordinate3d{X: st.Position.X + d.X, Y: st.Position.Y + d.Y, Z: 0}
|
||||
if next == maze.End {
|
||||
fmt.Println(st.Distance + 1)
|
||||
return
|
||||
}
|
||||
if maze.MazeMap[next] && !visited[next] {
|
||||
visited[next] = true
|
||||
p, ok := maze.Portals[next]
|
||||
if ok {
|
||||
next = p.To
|
||||
}
|
||||
queue = append(queue, State{next, st.Distance + 1})
|
||||
}
|
||||
}
|
||||
}
|
||||
m.visited = true
|
||||
}
|
||||
|
||||
func runmanual(m *Maze) {
|
||||
var err error
|
||||
var inp string
|
||||
m.Print()
|
||||
func part2(filename string) {
|
||||
maze := loadMaze(filename)
|
||||
queue, visited := []State{{Position: maze.Start}}, map[h.Coordinate3d]bool{{X: maze.Start.X, Y: maze.Start.Y, Z: 0}: true}
|
||||
var st State
|
||||
for {
|
||||
reader := bufio.NewReader(os.Stdin)
|
||||
inp, err = reader.ReadString('\n')
|
||||
if err != nil {
|
||||
fmt.Println("Input Error:", err.Error())
|
||||
continue
|
||||
st, queue = queue[0], queue[1:]
|
||||
for _, d := range directions {
|
||||
next := h.Coordinate3d{X: st.Position.X + d.X, Y: st.Position.Y + d.Y, Z: st.Position.Z}
|
||||
if next == maze.End {
|
||||
fmt.Println(st.Distance + 1)
|
||||
return
|
||||
}
|
||||
if maze.MazeMap[h.Coordinate3d{X: next.X, Y: next.Y, Z: 0}] && !visited[next] {
|
||||
visited[next] = true
|
||||
p, ok := maze.Portals[h.Coordinate3d{X: next.X, Y: next.Y, Z: 0}]
|
||||
if ok && (st.Position.Z > 0 || !p.Outer) {
|
||||
next = h.Coordinate3d{X: p.To.X, Y: p.To.Y, Z: st.Position.Z}
|
||||
if p.Outer {
|
||||
next.Z--
|
||||
} else {
|
||||
next.Z++
|
||||
}
|
||||
visited[next] = true
|
||||
}
|
||||
queue = append(queue, State{next, st.Distance + 1})
|
||||
}
|
||||
}
|
||||
var valid bool
|
||||
switch inp[0] {
|
||||
case 'N', 'n':
|
||||
valid = m.MoveNorth()
|
||||
case 'E', 'e':
|
||||
valid = m.MoveEast()
|
||||
case 'S', 's':
|
||||
valid = m.MoveSouth()
|
||||
case 'W', 'w':
|
||||
valid = m.MoveWest()
|
||||
case 'Q', 'q':
|
||||
fmt.Println("Quitting")
|
||||
break
|
||||
}
|
||||
fmt.Println(helpers.CLEAR_SCREEN)
|
||||
m.Print()
|
||||
if m.IsDone() {
|
||||
fmt.Println("DONE!")
|
||||
break
|
||||
}
|
||||
if !valid {
|
||||
fmt.Println("Invalid Move")
|
||||
}
|
||||
time.Sleep(time.Second / 2)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
func loadMaze(filename string) Maze {
|
||||
ret := Maze{
|
||||
MazeMap: make(map[h.Coordinate3d]bool),
|
||||
Outer: Square{},
|
||||
Inner: Square{},
|
||||
Portals: make(map[h.Coordinate3d]Portal),
|
||||
}
|
||||
input, _ := ioutil.ReadFile(filename)
|
||||
lines := make([]string, 0)
|
||||
for _, line := range strings.Split(string(input), "\n") {
|
||||
lines = append(lines, line)
|
||||
}
|
||||
//outer, inner := Square{Tl: h.Coordinate3d{X: 2, Y: 2, Z: 0}, Br: h.Coordinate3d{X: len(lines[0]) - 3, Y: len(lines) - 3, Z: 0}}, Square{}
|
||||
// Find the outer top-left
|
||||
var done bool
|
||||
for y := 0; y < len(lines); y++ {
|
||||
for x := 0; x < len(lines[y]); x++ {
|
||||
if lines[y][x] == '#' || lines[y][x] == '.' {
|
||||
ret.Outer.Tl = h.Coordinate3d{X: x, Y: y, Z: 0}
|
||||
done = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if done {
|
||||
break
|
||||
}
|
||||
}
|
||||
// Now find the outer bottom-righ
|
||||
done = false
|
||||
for y := len(lines) - 1; y > ret.Outer.Tl.Y; y-- {
|
||||
for x := len(lines[y]) - 1; x > ret.Outer.Tl.X; x-- {
|
||||
if lines[y][x] == '#' || lines[y][x] == '.' {
|
||||
ret.Outer.Br = h.Coordinate3d{X: x, Y: y, Z: 0}
|
||||
done = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if done {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// Find the inner top-left
|
||||
done = false
|
||||
for y := ret.Outer.Tl.Y; y < ret.Outer.Br.Y; y++ {
|
||||
for x := ret.Outer.Tl.X; x < ret.Outer.Br.X; x++ {
|
||||
if lines[y][x] != '#' && lines[y][x] != '.' {
|
||||
// Found it.
|
||||
ret.Inner.Tl = h.Coordinate3d{X: x - 1, Y: y - 1, Z: 0}
|
||||
done = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if done {
|
||||
break
|
||||
}
|
||||
}
|
||||
// Ok, now find the inner bottom-right
|
||||
done = false
|
||||
for y := ret.Outer.Br.Y - 1; y > ret.Outer.Tl.Y; y-- {
|
||||
for x := ret.Outer.Br.X - 1; x > ret.Outer.Tl.X; x-- {
|
||||
if lines[y][x] != '#' && lines[y][x] != '.' {
|
||||
// Found it
|
||||
ret.Inner.Br = h.Coordinate3d{X: x + 1, Y: y + 1, Z: 0}
|
||||
done = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if done {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
for y := ret.Outer.Tl.Y; y <= ret.Outer.Br.Y; y++ {
|
||||
for x := ret.Outer.Tl.X; x <= ret.Outer.Br.X; x++ {
|
||||
if lines[y][x] == '.' {
|
||||
ret.MazeMap[h.Coordinate3d{X: x, Y: y, Z: 0}] = true
|
||||
|
||||
var label string
|
||||
var pos h.Coordinate3d
|
||||
var outerPortal bool
|
||||
if y == ret.Outer.Tl.Y {
|
||||
label = lines[y-2][x:x+1] + lines[y-1][x:x+1]
|
||||
pos = h.Coordinate3d{X: x, Y: y - 1, Z: 0}
|
||||
outerPortal = true
|
||||
} else if y == ret.Outer.Br.Y {
|
||||
label = lines[y+1][x:x+1] + lines[y+2][x:x+1]
|
||||
pos = h.Coordinate3d{X: x, Y: y + 1, Z: 0}
|
||||
outerPortal = true
|
||||
} else if x == ret.Outer.Tl.X {
|
||||
label = lines[y][x-2 : x]
|
||||
pos = h.Coordinate3d{X: x - 1, Y: y, Z: 0}
|
||||
outerPortal = true
|
||||
} else if x == ret.Outer.Br.X {
|
||||
label = lines[y][x+1 : x+3]
|
||||
pos = h.Coordinate3d{X: x + 1, Y: y, Z: 0}
|
||||
outerPortal = true
|
||||
} else if y == ret.Inner.Br.Y && x > ret.Inner.Tl.X && x < ret.Inner.Br.X {
|
||||
label = lines[y-2][x:x+1] + lines[y-1][x:x+1]
|
||||
pos = h.Coordinate3d{X: x, Y: y - 1, Z: 0}
|
||||
} else if y == ret.Inner.Tl.Y && x > ret.Inner.Tl.X && x < ret.Inner.Br.X {
|
||||
label = lines[y+1][x:x+1] + lines[y+2][x:x+1]
|
||||
pos = h.Coordinate3d{X: x, Y: y + 1, Z: 0}
|
||||
} else if x == ret.Inner.Br.X && y > ret.Inner.Tl.Y && y < ret.Inner.Br.Y {
|
||||
label = lines[y][x-2 : x]
|
||||
pos = h.Coordinate3d{X: x - 1, Y: y, Z: 0}
|
||||
} else if x == ret.Inner.Tl.X && y > ret.Inner.Tl.Y && y < ret.Inner.Br.Y {
|
||||
label = lines[y][x+1 : x+3]
|
||||
pos = h.Coordinate3d{X: x + 1, Y: y, Z: 0}
|
||||
}
|
||||
|
||||
if label == "AA" {
|
||||
ret.Start = h.Coordinate3d{X: x, Y: y, Z: 0}
|
||||
} else if label == "ZZ" {
|
||||
ret.End = h.Coordinate3d{X: x, Y: y, Z: 0}
|
||||
} else if label != "" {
|
||||
ret.Portals[pos] = Portal{Label: label, From: h.Coordinate3d{X: x, Y: y, Z: 0}, Outer: outerPortal}
|
||||
ret.MazeMap[pos] = true
|
||||
}
|
||||
} else {
|
||||
// Make sure we don't overwrite anything
|
||||
if _, ok := ret.MazeMap[h.Coordinate3d{X: x, Y: y, Z: 0}]; !ok {
|
||||
ret.MazeMap[h.Coordinate3d{X: x, Y: y, Z: 0}] = false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for i, p1 := range ret.Portals {
|
||||
for _, p2 := range ret.Portals {
|
||||
if p1.Label == p2.Label && p1.From != p2.From {
|
||||
p1.To = p2.From
|
||||
ret.Portals[i] = p1
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user