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,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
}

View File

@@ -1,228 +1,42 @@
package main
import (
"bytes"
"fmt"
helpers "git.bullercodeworks.com/brian/adventofcode/helpers"
h "git.bullercodeworks.com/brian/adventofcode/helpers"
)
type MazeMap map[h.Coordinate3d]bool
type Maze struct {
start *MazeCoord
end *MazeCoord
maze map[string]*MazeCoord
portals map[string]*Portal
current *MazeCoord
BotX, BotY int
TopX, TopY int
MazeMap
Outer Square
Inner Square
Portals map[h.Coordinate3d]Portal
Start h.Coordinate3d
End h.Coordinate3d
}
func NewMaze(file string) *Maze {
inp := helpers.FileToBytes(file)
lines := bytes.Split(inp, []byte{'\n'})
m := Maze{
maze: make(map[string]*MazeCoord),
portals: make(map[string]*Portal),
}
for yk, yv := range lines {
for xk, xv := range yv {
if xv == '.' || xv == '#' {
m.maze[c(xk, yk)] = &MazeCoord{
X: xk,
Y: yk,
Value: xv,
steps: helpers.MAX_INT,
}
}
}
}
// Now hook up neighbor coords
for _, v := range m.maze {
if v.X < m.BotX {
m.BotX = v.X
}
if v.X > m.TopX {
m.TopX = v.X
}
if v.Y < m.BotY {
m.BotY = v.Y
}
if v.Y > m.TopY {
m.TopY = v.Y
}
var d *MazeCoord
var ok bool
// Hook up north
if d, ok = m.maze[c(v.X, v.Y-1)]; ok {
v.N = d
} else if v.Value == '.' {
// North Portal
name := string([]byte{lines[v.Y-2][v.X], lines[v.Y-1][v.X]})
var p *Portal
if p, ok = m.portals[name]; ok {
v.N = m.maze[c(p.X1, p.Y1)]
m.maze[c(p.X1, p.Y1)].S = v
p.X2 = v.X
p.Y2 = v.Y
} else {
m.portals[name] = &Portal{
Name: name,
X1: v.X,
Y1: v.Y,
}
}
}
// Hook up east
if d, ok = m.maze[c(v.X+1, v.Y)]; ok {
v.E = d
} else if v.Value == '.' {
// East Portal
name := string([]byte{lines[v.Y][v.X+1], lines[v.Y][v.X+2]})
var p *Portal
if p, ok = m.portals[name]; ok {
v.E = m.maze[c(p.X1, p.Y1)]
m.maze[c(p.X1, p.Y1)].W = v
p.X2 = v.X
p.Y2 = v.Y
} else {
m.portals[name] = &Portal{
Name: name,
X1: v.X,
Y1: v.Y,
}
}
}
// Hook up south
if d, ok = m.maze[c(v.X, v.Y+1)]; ok {
v.S = d
} else if v.Value == '.' {
// South Portal
name := string([]byte{lines[v.Y+1][v.X], lines[v.Y+2][v.X]})
var p *Portal
if p, ok = m.portals[name]; ok {
v.S = m.maze[c(p.X1, p.Y1)]
m.maze[c(p.X1, p.Y1)].N = v
fmt.Println(v.S, "<=>", m.maze[c(p.X1, p.Y1)].N)
p.X2 = v.X
p.Y2 = v.Y
} else {
m.portals[name] = &Portal{
Name: name,
X1: v.X,
Y1: v.Y,
}
}
}
// Hook up west
if d, ok = m.maze[c(v.X-1, v.Y)]; ok {
v.W = d
} else if v.Value == '.' {
// West Portal
name := string([]byte{lines[v.Y][v.X-2], lines[v.Y][v.X-1]})
var p *Portal
if p, ok = m.portals[name]; ok {
v.W = m.maze[c(p.X1, p.Y1)]
m.maze[c(p.X1, p.Y1)].E = v
p.X2 = v.X
p.Y2 = v.Y
} else {
m.portals[name] = &Portal{
Name: name,
X1: v.X,
Y1: v.Y,
}
}
}
}
st := m.portals["AA"]
m.current = m.maze[c(st.X1, st.Y1)]
return &m
}
func (m *Maze) MoveNorth() bool {
if m.current.N != nil && m.current.N.Value == '.' {
m.current = m.current.N
return true
}
return false
}
func (m *Maze) MoveEast() bool {
if m.current.E != nil && m.current.E.Value == '.' {
m.current = m.current.E
return true
}
return false
}
func (m *Maze) MoveSouth() bool {
if m.current.S != nil && m.current.S.Value == '.' {
m.current = m.current.S
return true
}
return false
}
func (m *Maze) MoveWest() bool {
if m.current.W != nil && m.current.W.Value == '.' {
m.current = m.current.W
return true
}
return false
}
func (m *Maze) Print() {
for y := m.BotY; y <= m.TopY; y++ {
for x := m.BotX; x <= m.TopX; x++ {
if m.current.X == x && m.current.Y == y {
fmt.Print("%")
} else {
if v, ok := m.maze[c(x, y)]; ok {
fmt.Print(string(v.Value))
func (m *Maze) Print(visited map[h.Coordinate3d]bool) {
for y := m.Outer.Tl.Y - 1; y < m.Outer.Br.Y+1; y++ {
for x := m.Outer.Tl.X - 1; x < m.Outer.Br.X+1; x++ {
c := h.Coordinate3d{X: x, Y: y, Z: 0}
if _, pok := m.Portals[c]; pok {
fmt.Print("*")
//} else if m.Inner.IsInBorder(c) {
// fmt.Print("$")
//} else if m.Inner.ContainsButNotBorder(c) {
// fmt.Print(" ")
} else if m.MazeMap[c] {
if v, ok := visited[c]; ok && v {
fmt.Print(h.FILL_CHAR)
} else {
fmt.Print(" ")
fmt.Print(".")
}
} else {
fmt.Print("#")
}
}
fmt.Println()
}
}
func (m *Maze) GetStart() *MazeCoord {
start := m.portals["AA"]
return m.maze[c(start.X1, start.Y1)]
}
func (m *Maze) IsDone() bool {
return m.IsEnd(m.current.X, m.current.Y)
}
func (m *Maze) GetEnd() *MazeCoord {
end := m.portals["ZZ"]
return m.maze[c(end.X1, end.Y1)]
}
func (m *Maze) IsEnd(x, y int) bool {
return x == m.GetEnd().X && y == m.GetEnd().Y
}
type Portal struct {
Name string
X1, Y1, X2, Y2 int
}
type MazeCoord struct {
X, Y int
N, E, S, W *MazeCoord
Value byte
visited bool
steps int
}
func c(x, y int) string {
return fmt.Sprintf("[%d, %d]", x, y)
}

10
2019/day20/portal.go Normal file
View File

@@ -0,0 +1,10 @@
package main
import h "git.bullercodeworks.com/brian/adventofcode/helpers"
type Portal struct {
Label string
From h.Coordinate3d
To h.Coordinate3d
Outer bool
}

28
2019/day20/square.go Normal file
View File

@@ -0,0 +1,28 @@
package main
import h "git.bullercodeworks.com/brian/adventofcode/helpers"
type Square struct {
Tl h.Coordinate3d
Br h.Coordinate3d
}
func (s *Square) Contains(p h.Coordinate3d) bool {
return p.X >= s.Tl.X && p.Y >= s.Tl.Y && p.X <= s.Br.X && p.Y <= s.Br.Y
}
func (s *Square) IsInBorder(p h.Coordinate3d) bool {
if !s.Contains(p) {
return false
}
if p.Y == s.Tl.Y || p.Y == s.Br.Y {
return p.X >= s.Tl.X || p.X <= s.Br.X
} else if p.X == s.Tl.X || p.X == s.Br.X {
return p.Y >= s.Tl.Y || p.Y <= s.Br.Y
}
return false
}
func (s *Square) ContainsButNotBorder(p h.Coordinate3d) bool {
return s.Contains(p) && !s.IsInBorder(p)
}

37
2019/day20/testinput2 Normal file
View File

@@ -0,0 +1,37 @@
Z L X W C
Z P Q B K
###########.#.#.#.#######.###############
#...#.......#.#.......#.#.......#.#.#...#
###.#.#.#.#.#.#.#.###.#.#.#######.#.#.###
#.#...#.#.#...#.#.#...#...#...#.#.......#
#.###.#######.###.###.#.###.###.#.#######
#...#.......#.#...#...#.............#...#
#.#########.#######.#.#######.#######.###
#...#.# F R I Z #.#.#.#
#.###.# D E C H #.#.#.#
#.#...# #...#.#
#.###.# #.###.#
#.#....OA WB..#.#..ZH
#.###.# #.#.#.#
CJ......# #.....#
####### #######
#.#....CK #......IC
#.###.# #.###.#
#.....# #...#.#
###.### #.#.#.#
XF....#.# RF..#.#.#
#####.# #######
#......CJ NM..#...#
###.#.# #.###.#
RE....#.# #......RF
###.### X X L #.#.#.#
#.....# F Q P #.#.#.#
###.###########.###.#######.#########.###
#.....#...#.....#.......#...#.....#.#...#
#####.#.###.#######.#######.###.###.#.#.#
#.......#.......#.#.#.#.#...#...#...#.#.#
#####.###.#####.#.#.#.#.###.###.#.###.###
#.......#.....#.#...#...............#...#
#############.#.#.###.###################
A O F N
A A D M