10 Commits

Author SHA1 Message Date
0a6d8ab256 Day 24 part 2
This isn't terribly slow (100ms right now) but I'd prefer it to be faster. I'm sure I could be smarter about which depths I'm scanning since a bunch of them can't possibly contain bugs, but whatever. This was about as rote and straightforward as I was expecting it to be, so at least there's that.
2022-06-26 19:44:06 -05:00
4c58e5c51c Day 24 part 1
I think I understand part 2, I just...ugh. It seems like it's going to be a beating of rote map implementation.
2022-06-26 10:24:54 -05:00
36615d7f06 Day 23 solution
This one takes around a second to arrive at the first answer and around 30 seconds to arrive at the second answer. I don't know why, since I'm just running the given program as fast as possible (is my interpreter slow?). Go channels should be about as fast as we can get here. Maybe it would actually run faster if everyone stopped and processed their inputs at the same time or something? I dunno.

Part 2 was pretty simple, though I feel like my idle detection could be improved. Seems to work, though.
2022-06-26 10:21:44 -05:00
334aaee7a5 Day 22 solution
Part 1 was very straightforward. I believe there are ways to calculate this answer without the complicated maths from part 2 and without actually applying each of the instructions, but I'm not concerned with finding it.

Part 2 was a big "nope" from me. I went out and found this answer and I don't understand it. I'm okay with that.
2022-06-25 15:43:45 -05:00
1a6529c7d2 Day 21 solution
Hopefully my logic is explained well enough in the comments for this one. We're just layering more programming languages on top of other programming languages. This is how you anger the computer gods and bring about the AI singularity.

I also made some general tweaks to the Intcode machine to make ASCII intcode machines dead simple to deal with. Is it worth the extra branches for each input and output instruction in the interpreter? Probably not...but I was never going to win any speed competitions anyway.
2022-06-24 23:20:31 -05:00
34e6055782 Day 20 solution
Part 1 was pretty much just day 18 again, but without doors and with an input data parsing skill check. I simplified day 18 and went with a basic Dijkstra algorithm after the DFS to crawl the maze which solved this just fine.

Part 2 messed me up more than I was expecting. The key feature for part 2 is changing up what the Dijkstra solver views as an "adjacent" node and injecting the appropriate depth as we traverse inner/outer portals. The main thing that tripped me up here from part 1 was that I needed to be carrying more data along with portals than just their locations, and I could no longer get away with storing the portals as pairs of their inner/outer locations, so a small refactor was needed. Once I made those corrections, it was mostly a matter of ironing out the "get neighbors" function to adhere to part 2's rules, which took me a lot of debugging to get just right.

Part 2 still took me longer than I'd care to admit. I had problems wrapping my head around the problem.
2022-06-22 23:35:29 -05:00
c4faba7636 Day 19 solution
I had some trouble with the logic of this puzzle in my head, and the visuals were too large to realistically render for me to spot-check my solution, so I kept getting part 2 wrong. I eventually realized what needed to be done to get the right answer, which was partially the realization that I needed to check +99 instead of +100, and partially that I probably didn't need to check the entire space, just the bounding points, at least for the initial filters.

And then I optimized it with a bisect instead of a linear search. Always a good idea when you need to narrow a large range to a single point.
2022-06-22 16:52:32 -05:00
982576dc68 Intcode Reset optimization
Initially I noticed that I was copying twice unnecessarily (once in init() after nulling out memory, and again after returning from init()). After cleaning that up, I realized that we don't need to create a new buffer at all if the program never malloc-ed, so sometimes we can skip the re-init and we can always avoid the double-copy. I don't know if this is actually measurable anywhere, but I spot-checked some results and I still seem to be getting the same answers, so I'm gonna roll with it.
2022-06-22 16:52:32 -05:00
19f91dbc50 Add bisect utility
This is too common of an optimization to not have this readily accessible. And I kinda like how this worked out, too. Go is fun. Plus this both speeds up and "fixes" day 14's part 2 solution (it was always giving a correct answer, but mostly by chance based on how the input numbers worked out).
2022-06-22 16:52:25 -05:00
2ef1e0656a Day 18 solution
This one was a doozy and took far more time than I'd like to admit. I hope it's the hardest problem of the year. My original solution gave correct answers, but took on the order of 3+ minutes to run, even with memoization (it wasn't finishing any time soon without it). I then tried dropping in some A* and Dijkstra libraries, but wasn't really happy with how things were progressing with them. Some research pointed me toward double-ended queues and priority queues as better solutions, which I should have come up with my own since they've been used along with memoization in other AoC's, and dropping those in took the runtimes down to 4-15 seconds on my m1 macbook air. Once I swapped out the memoized data structures from arrays to maps, the runtime finally dropped to a much more palatable 50-180 millisecond range.

I'm always suspicious when my solution is hundreds of lines of code, though, since you tend to see much more terse solutions from others in the AoC subreddit, but I attribute at least some of the bloat to "Go things" like how maps and arrays usually need to be "make"d first, how there's no easy "list comprehension" or "linq" style data structure queries, etc.

Finally: note that I've seen _dramatically_ different runtimes based on the input. One set of input I checked against ran in 30ms/10ms while another ran in 180ms/54ms. I guess it's never been promised that all inputs are created equally...
2022-06-22 16:52:18 -05:00
39 changed files with 2171 additions and 34 deletions

View File

@ -104,26 +104,10 @@ func (d *Day14) Part1() string {
func (d *Day14) Part2() string {
oreAvailable := int64(1000000000000)
estimate := oreAvailable / d.getOreRequiredForFuel(1)
high := estimate * 2
low := estimate
lastSuccess := low
lastFailure := high
fuelProduced := low
for math.Abs(float64(lastFailure-lastSuccess)) > 1 {
oreConsumed := d.getOreRequiredForFuel(fuelProduced)
adjustment := (lastFailure - lastSuccess) / 2
if oreConsumed < oreAvailable {
lastSuccess = fuelProduced
} else {
lastFailure = fuelProduced
adjustment = -adjustment
}
fuelProduced += adjustment
}
lastSuccess := u.Bisect(estimate, estimate*2, 1, func(val int64) bool {
oreConsumed := d.getOreRequiredForFuel(val)
return oreConsumed < oreAvailable
})
return fmt.Sprintf("Maximum fuel we can make from 1 trillion ore: %s%d%s", u.TextBold, lastSuccess, u.TextReset)
}

View File

@ -48,6 +48,7 @@ type Day17 struct {
func (d *Day17) Parse() {
d.program = u.LoadIntcodeProgram("17p")
// d.program.SetDebugASCIIPrint(true)
}
func (d Day17) Num() int {
@ -388,9 +389,8 @@ func (d *Day17) Part2() string {
row := 0
var outputState int
var lastOutput int64
var instructionStr string
d.program.RunIn(func(inputStep int) int64 {
return int64(instructionStr[inputStep-1])
panic("unexpected read")
}, func(val int64, state u.IntcodeProgramState) {
rVal := rune(val)
if outputState == 0 {
@ -401,7 +401,7 @@ func (d *Day17) Part2() string {
if rVal == '\n' && lastOutput == '\n' {
if outputState == 0 {
instructionStr = beforeGrid.solvePath(beforeBotLocation, beforeBotFacing)
d.program.FeedInputString(beforeGrid.solvePath(beforeBotLocation, beforeBotFacing))
}
outputState++
row = 0

345
days/18.go Normal file
View File

@ -0,0 +1,345 @@
package days
import (
"container/heap"
"fmt"
"math"
"strings"
u "parnic.com/aoc2019/utilities"
)
type day18Cell int
type day18Vec u.Vec2[int]
type day18Graph map[rune][]u.Pair[rune, int]
const (
day18CellWall day18Cell = iota
day18CellOpen
)
var (
day18AdjacentOffsets = []day18Vec{
{X: -1, Y: 0},
{X: 1, Y: 0},
{X: 0, Y: -1},
{X: 0, Y: 1},
}
)
type reachableKeysMemo struct {
pos rune
keysFound int
}
type minStepsMemo struct {
pos string
keysToFind int
keysFound int
}
type Day18 struct {
entrance day18Vec
grid [][]day18Cell
doors map[day18Vec]int
keys map[day18Vec]int
knownReachableKeys map[reachableKeysMemo][]u.Pair[rune, int]
knownMinimumSteps map[minStepsMemo]int
}
func (d *Day18) Parse() {
d.doors = make(map[day18Vec]int)
d.keys = make(map[day18Vec]int)
d.knownReachableKeys = make(map[reachableKeysMemo][]u.Pair[rune, int])
d.knownMinimumSteps = make(map[minStepsMemo]int, 0)
lines := u.GetStringLines("18p")
d.grid = make([][]day18Cell, len(lines))
for i, line := range lines {
d.grid[i] = make([]day18Cell, len(line))
for j, char := range line {
if char == '#' {
d.grid[i][j] = day18CellWall
} else if char == '.' {
d.grid[i][j] = day18CellOpen
} else if char == '@' {
d.grid[i][j] = day18CellOpen
d.entrance = day18Vec{X: j, Y: i}
} else if char >= 'A' && char <= 'Z' {
d.grid[i][j] = day18CellOpen
d.doors[day18Vec{X: j, Y: i}] = int(char - 'A')
} else if char >= 'a' && char <= 'z' {
d.grid[i][j] = day18CellOpen
d.keys[day18Vec{X: j, Y: i}] = int(char - 'a')
}
}
}
}
func (d Day18) Num() int {
return 18
}
func (d Day18) Draw(grid [][]day18Cell, keys, doors map[day18Vec]int, entrances ...day18Vec) {
for y := range grid {
for x := range grid[y] {
switch grid[y][x] {
case day18CellWall:
fmt.Print("█")
case day18CellOpen:
posVec := day18Vec{X: x, Y: y}
if _, exists := doors[posVec]; exists {
fmt.Printf("%c", rune(doors[posVec]+'A'))
} else if _, exists := keys[posVec]; exists {
fmt.Printf("%c", rune(keys[posVec]+'a'))
} else if u.ArrayContains(entrances, posVec) {
fmt.Print("@")
} else {
fmt.Print(".")
}
}
}
fmt.Println()
}
}
func (d Day18) findAdjacentCells(inPos day18Vec, keys, doors map[day18Vec]int, grid [][]day18Cell) []u.Pair[rune, int] {
found := make([]u.Pair[rune, int], 0)
getAdjacent := func(pos day18Vec) []day18Vec {
retAdjacent := make([]day18Vec, 0, len(day18AdjacentOffsets))
for _, off := range day18AdjacentOffsets {
offVec := day18Vec{X: pos.X + off.X, Y: pos.Y + off.Y}
if grid[offVec.Y][offVec.X] == day18CellWall {
continue
}
retAdjacent = append(retAdjacent, offVec)
}
return retAdjacent
}
queue := make([]u.Pair[int, day18Vec], 0)
visited := make(map[day18Vec]bool)
for _, adjacent := range getAdjacent(inPos) {
queue = append(queue, u.Pair[int, day18Vec]{First: 1, Second: adjacent})
}
for len(queue) > 0 {
next := queue[0]
queue = queue[1:]
if _, exists := visited[next.Second]; !exists {
visited[next.Second] = true
key, adjacentIsKey := keys[next.Second]
door, adjacentIsDoor := doors[next.Second]
if adjacentIsKey || adjacentIsDoor {
var rVal rune
if adjacentIsKey {
rVal = rune('a' + key)
} else if adjacentIsDoor {
rVal = rune('A' + door)
}
alreadyFound := false
for _, p := range found {
if p.First == rVal {
alreadyFound = true
break
}
}
if !alreadyFound {
found = append(found, u.Pair[rune, int]{First: rVal, Second: next.First})
continue
}
}
for _, neighbor := range getAdjacent(next.Second) {
if _, exists := visited[neighbor]; !exists {
queue = append(queue, u.Pair[int, day18Vec]{First: next.First + 1, Second: neighbor})
}
}
}
}
return found
}
type day18PriorityQueue struct {
distance int
neighbor rune
}
type day18PriorityQueueHeap []day18PriorityQueue
func (h day18PriorityQueueHeap) Len() int { return len(h) }
func (h day18PriorityQueueHeap) Less(i, j int) bool { return h[i].distance < h[j].distance }
func (h day18PriorityQueueHeap) Swap(i, j int) { h[i], h[j] = h[j], h[i] }
func (h *day18PriorityQueueHeap) Push(x any) {
*h = append(*h, x.(day18PriorityQueue))
}
func (h *day18PriorityQueueHeap) Pop() any {
old := *h
n := len(old)
x := old[n-1]
*h = old[0 : n-1]
return x
}
func (d Day18) reachableKeys(inPos rune, keysFound int, graph day18Graph) []u.Pair[rune, int] {
memo := reachableKeysMemo{
pos: inPos,
keysFound: keysFound,
}
if v, exists := d.knownReachableKeys[memo]; exists {
return v
}
ret := make([]u.Pair[rune, int], 0)
distance := make(map[rune]int)
ih := make(day18PriorityQueueHeap, 0)
for _, p := range graph[inPos] {
ih = append(ih, day18PriorityQueue{
distance: p.Second,
neighbor: p.First,
})
}
heap.Init(&ih)
for ih.Len() > 0 {
node := heap.Pop(&ih).(day18PriorityQueue)
// it's a key and we haven't picked it up yet...
if node.neighbor >= 'a' && node.neighbor <= 'z' && (1<<int(node.neighbor-'a')&keysFound) == 0 {
ret = append(ret, u.Pair[rune, int]{First: node.neighbor, Second: node.distance})
continue
}
// it's a door but we don't have the key yet...
if node.neighbor >= 'A' && node.neighbor <= 'Z' && ((1<<int(node.neighbor-'A'))&keysFound) == 0 {
continue
}
for _, p := range graph[node.neighbor] {
newDistance := node.distance + p.Second
if dist, exists := distance[p.First]; !exists || newDistance < dist {
distance[p.First] = newDistance
heap.Push(&ih, day18PriorityQueue{
distance: newDistance,
neighbor: p.First,
})
}
}
}
d.knownReachableKeys[memo] = ret
return ret
}
func (d Day18) minimumSteps(inPos string, keysToFind int, keysFound int, graph day18Graph) int {
memo := minStepsMemo{
pos: inPos,
keysToFind: keysToFind,
keysFound: keysFound,
}
if v, exists := d.knownMinimumSteps[memo]; exists {
return v
}
if keysToFind == 0 {
return 0
}
best := math.Inf(1)
for _, item := range inPos {
for _, p := range d.reachableKeys(item, keysFound, graph) {
sb := strings.Builder{}
oldIdx := strings.IndexRune(inPos, item)
for i := range inPos {
if i == oldIdx {
sb.WriteRune(p.First)
} else {
sb.WriteByte(inPos[i])
}
}
newKeys := keysFound + (1 << (p.First - 'a'))
dist := p.Second
dist += d.minimumSteps(sb.String(), keysToFind-1, newKeys, graph)
if float64(dist) < best {
best = float64(dist)
}
}
}
d.knownMinimumSteps[memo] = int(best)
return int(best)
}
func (d Day18) buildGraph(pos []day18Vec, keys map[day18Vec]int, doors map[day18Vec]int, grid [][]day18Cell) day18Graph {
graph := make(day18Graph)
for i, p := range pos {
adjacent := d.findAdjacentCells(p, keys, doors, grid)
graph[rune('1'+i)] = adjacent
}
for keyPos, keyType := range keys {
graph[rune('a'+keyType)] = d.findAdjacentCells(keyPos, keys, doors, grid)
}
for doorPos, doorType := range doors {
graph[rune('A'+doorType)] = d.findAdjacentCells(doorPos, keys, doors, grid)
}
return graph
}
func (d Day18) part2PatchMap(grid [][]day18Cell, entrance day18Vec) []day18Vec {
grid[entrance.Y-1][entrance.X] = day18CellWall
grid[entrance.Y][entrance.X-1] = day18CellWall
grid[entrance.Y][entrance.X] = day18CellWall
grid[entrance.Y][entrance.X+1] = day18CellWall
grid[entrance.Y+1][entrance.X] = day18CellWall
return []day18Vec{
{X: entrance.X - 1, Y: entrance.Y - 1},
{X: entrance.X + 1, Y: entrance.Y - 1},
{X: entrance.X - 1, Y: entrance.Y + 1},
{X: entrance.X + 1, Y: entrance.Y + 1},
}
}
func (d *Day18) Part1() string {
// fmt.Println("initial state:")
// d.Draw(d.grid, d.keys, d.doors, d.entrance)
graph := d.buildGraph([]day18Vec{d.entrance}, d.keys, d.doors, d.grid)
minSteps := d.minimumSteps("1", len(d.keys), 0, graph)
return fmt.Sprintf("Total distance traveled: %s%d%s", u.TextBold, minSteps, u.TextReset)
}
func (d *Day18) Part2() string {
// fmt.Println("initial state:")
grid := make([][]day18Cell, len(d.grid))
for i := range d.grid {
grid[i] = make([]day18Cell, len(d.grid[i]))
copy(grid[i], d.grid[i])
}
entrances := d.part2PatchMap(grid, d.entrance)
// d.Draw(grid, d.keys, d.doors, entrances...)
// clear memoized maps that (might have) came from part1
d.knownMinimumSteps = make(map[minStepsMemo]int)
d.knownReachableKeys = make(map[reachableKeysMemo][]u.Pair[rune, int])
graph := d.buildGraph(entrances, d.keys, d.doors, grid)
minSteps := d.minimumSteps("1234", len(d.keys), 0, graph)
return fmt.Sprintf("Total distance traveled: %s%d%s", u.TextBold, minSteps, u.TextReset)
}

146
days/19.go Normal file
View File

@ -0,0 +1,146 @@
package days
import (
"fmt"
u "parnic.com/aoc2019/utilities"
)
type Day19 struct {
program u.IntcodeProgram
}
func (d *Day19) Parse() {
d.program = u.LoadIntcodeProgram("19p")
}
func (d Day19) Num() int {
return 19
}
func (d *Day19) Part1() string {
grid := make([][]bool, 50)
for y := 0; y < len(grid); y++ {
grid[y] = make([]bool, 50)
}
count := int64(0)
for y := 0; y < 50; y++ {
for x := 0; x < 50; x++ {
d.program.Reset()
d.program.RunIn(func(inputStep int) int64 {
if inputStep == 1 {
return int64(x)
}
return int64(y)
}, func(val int64, state u.IntcodeProgramState) {
res := val == 1
grid[y][x] = res
if res {
count++
}
})
}
}
// fmt.Println("50x50 tractor view:")
// for y := 0; y < len(grid); y++ {
// for x := 0; x < len(grid[y]); x++ {
// if grid[y][x] {
// fmt.Print("█")
// } else {
// fmt.Print(" ")
// }
// }
// fmt.Println()
// }
return fmt.Sprintf("Points affected in 50x50 area: %s%d%s", u.TextBold, count, u.TextReset)
}
func (d *Day19) Part2() string {
f := func(x, y int) bool {
ret := false
d.program.Reset()
d.program.RunIn(func(inputStep int) int64 {
if inputStep == 1 {
return int64(x)
}
return int64(y)
}, func(val int64, state u.IntcodeProgramState) {
ret = val == 1
})
return ret
}
// find lower bound
// this may not be necessary, but helps seed the bisect with a known-good lower bound
startY := 0
startX := 0
for y := 1; startY == 0; y++ {
for x := 0; x < 10*y; x++ {
if f(x, y) {
startY = y
startX = x
break
}
}
}
lastGoodX := 0
threshold := 1
// add 100 to start y since we know it has to be a 100x100 square.
// since we multiply x by 10,000 for the final result, that tells us y cannot be 10k+
y := u.Bisect(startY+100, 9999, threshold, func(y int) bool {
foundX := false
for x := startX; ; x++ {
// check top left
if !f(x, y) {
if !foundX {
continue
} else {
return true
}
}
if !foundX {
foundX = true
}
// check top right
if !f(x+99, y) {
return true
}
// check bottom left
if !f(x, y+99) {
continue
}
// we believe the corners work, so run final validations on the full borders.
// this may not be necessary, but i've seen some rows end up shorter than a
// previous row because of the angle of the beam and our integer fidelity.
// plus it's really not that much more expensive to do to be certain we're correct.
for y2 := y; y2 < y+100; y2++ {
// right wall
if !f(x+99, y2) {
return true
}
// left wall
if !f(x, y2) {
return true
}
}
lastGoodX = x
return false
}
})
// since we invert our bisect success returns, we need to increment y to
// tip back over into the "success" range
y += threshold
result := (lastGoodX * 10000) + y
return fmt.Sprintf("Closest 100x100 square for the ship starts at %d,%d = %s%d%s", lastGoodX, y, u.TextBold, result, u.TextReset)
}

398
days/20.go Normal file
View File

@ -0,0 +1,398 @@
package days
import (
"container/heap"
"fmt"
"math"
"strings"
u "parnic.com/aoc2019/utilities"
)
type day20Cell int8
type day20Graph map[day20Portal][]u.Pair[day20Portal, int]
const (
day20CellWall day20Cell = iota
day20CellPath
day20CellDonutHole
)
var (
day20AdjacentOffsets = []u.Vec2i{
{X: -1, Y: 0},
{X: 1, Y: 0},
{X: 0, Y: -1},
{X: 0, Y: 1},
}
entrancePortal = day20Portal{name: "AA"}
exitPortal = day20Portal{name: "ZZ"}
)
type day20Portal struct {
name string
inner bool
depth int
}
type Day20 struct {
grid [][]day20Cell
entrance u.Vec2i
exit u.Vec2i
portals map[day20Portal]u.Vec2i
portalNames []string
}
func (d *Day20) Parse() {
d.portals = make(map[day20Portal]u.Vec2i)
d.portalNames = make([]string, 0)
lines := u.GetStringLines("20p")
d.grid = make([][]day20Cell, len(lines)-4)
currPortal := strings.Builder{}
for row, line := range lines {
y := row - 2
isGridRow := row >= 2 && row < len(lines)-2
if isGridRow {
d.grid[y] = make([]day20Cell, len(line)-4)
}
for col, ch := range lines[row] {
x := col - 2
isGridCol := col >= 2 && col < len(line)-2
if isGridRow && isGridCol {
if ch == '#' {
d.grid[y][x] = day20CellWall
} else if ch == '.' {
d.grid[y][x] = day20CellPath
} else {
d.grid[y][x] = day20CellDonutHole
}
}
if ch >= 'A' && ch <= 'Z' {
portalX := 0
portalY := 0
if len(line) > col+1 && line[col+1] >= 'A' && line[col+1] <= 'Z' {
currPortal.WriteRune(ch)
currPortal.WriteRune(rune(line[col+1]))
if len(line) > col+2 && line[col+2] == '.' {
portalY = y
portalX = x + 2
} else if col-1 >= 0 && line[col-1] == '.' {
portalY = y
portalX = x - 1
} else {
panic("!")
}
} else if len(lines) > row+1 && lines[row+1][col] >= 'A' && lines[row+1][col] <= 'Z' {
currPortal.WriteRune(ch)
currPortal.WriteRune(rune(lines[row+1][col]))
if len(lines) > row+2 && lines[row+2][col] == '.' {
portalY = y + 2
portalX = x
} else if row-1 >= 0 && lines[row-1][col] == '.' {
portalY = y - 1
portalX = x
} else {
panic("!")
}
}
if currPortal.Len() == 2 {
portalName := currPortal.String()
portalVec := u.Vec2i{X: portalX, Y: portalY}
if portalName == entrancePortal.name {
d.entrance = portalVec
} else if portalName == exitPortal.name {
d.exit = portalVec
} else {
portal := day20Portal{
name: portalName,
inner: !d.isOuterPortal(portalVec),
}
d.portals[portal] = portalVec
u.AddToArray(&d.portalNames, portalName)
}
currPortal.Reset()
}
}
}
}
}
func (d Day20) Num() int {
return 20
}
func (d Day20) isPortal(vec u.Vec2i) (bool, int) {
if d.grid[vec.Y][vec.X] != day20CellPath {
return false, 0
}
for i, name := range d.portalNames {
p, exists := d.portals[day20Portal{name: name, inner: !d.isOuterPortal(vec)}]
if exists && vec == p {
return true, i
}
}
return false, 0
}
func (d Day20) Draw() {
for y := range d.grid {
for x := range d.grid[y] {
switch d.grid[y][x] {
case day20CellWall:
fmt.Print("█")
case day20CellDonutHole:
fmt.Print(" ")
case day20CellPath:
posVec := u.Vec2i{X: x, Y: y}
if posVec == d.entrance {
fmt.Print("@")
} else if posVec == d.exit {
fmt.Print("!")
} else {
isPortal, portalIdx := d.isPortal(posVec)
if isPortal {
ch := 'a' + portalIdx
if ch > 'z' {
ch = 'A' + (portalIdx - 26)
}
fmt.Printf("%c", ch)
} else {
fmt.Print(" ")
}
}
}
}
fmt.Println()
}
}
func (d Day20) isOuterPortal(pos u.Vec2i) bool {
return pos.X == 0 || pos.Y == 0 || pos.X == len(d.grid[0])-1 || pos.Y == len(d.grid)-1
}
func (d Day20) findAdjacentCells(inPos u.Vec2i) []u.Pair[day20Portal, int] {
found := make([]u.Pair[day20Portal, int], 0)
getAdjacent := func(pos u.Vec2i) []u.Vec2i {
retAdjacent := make([]u.Vec2i, 0, len(day20AdjacentOffsets))
for _, off := range day20AdjacentOffsets {
offVec := u.Vec2i{X: pos.X + off.X, Y: pos.Y + off.Y}
if offVec.Y < 0 || offVec.Y >= len(d.grid) || offVec.X < 0 || offVec.X >= len(d.grid[0]) {
continue
}
if d.grid[offVec.Y][offVec.X] != day20CellPath {
continue
}
retAdjacent = append(retAdjacent, offVec)
}
return retAdjacent
}
queue := make([]u.Pair[int, u.Vec2i], 0)
visited := map[u.Vec2i]bool{
inPos: true,
}
for _, adjacent := range getAdjacent(inPos) {
queue = append(queue, u.Pair[int, u.Vec2i]{First: 1, Second: adjacent})
}
for len(queue) > 0 {
next := queue[0]
queue = queue[1:]
if _, exists := visited[next.Second]; !exists {
visited[next.Second] = true
adjacentIsPortal, portalIdx := d.isPortal(next.Second)
if adjacentIsPortal || next.Second == d.entrance || next.Second == d.exit {
var portalName string
if next.Second == d.entrance {
portalName = entrancePortal.name
} else if next.Second == d.exit {
portalName = exitPortal.name
} else {
portalName = d.portalNames[portalIdx]
}
alreadyFound := false
for _, p := range found {
if p.First.name == portalName {
alreadyFound = true
break
}
}
if !alreadyFound {
found = append(found, u.Pair[day20Portal, int]{First: day20Portal{
name: portalName,
inner: !d.isOuterPortal(next.Second),
}, Second: next.First})
continue
}
}
for _, neighbor := range getAdjacent(next.Second) {
if _, exists := visited[neighbor]; !exists {
queue = append(queue, u.Pair[int, u.Vec2i]{First: next.First + 1, Second: neighbor})
}
}
}
}
return found
}
type day20PriorityQueue struct {
distance int
neighbor day20Portal
}
type day20PriorityQueueHeap []day20PriorityQueue
func (h day20PriorityQueueHeap) Len() int { return len(h) }
func (h day20PriorityQueueHeap) Less(i, j int) bool { return h[i].distance < h[j].distance }
func (h day20PriorityQueueHeap) Swap(i, j int) { h[i], h[j] = h[j], h[i] }
func (h *day20PriorityQueueHeap) Push(x any) {
*h = append(*h, x.(day20PriorityQueue))
}
func (h *day20PriorityQueueHeap) Pop() any {
old := *h
n := len(old)
x := old[n-1]
*h = old[0 : n-1]
return x
}
func (d Day20) dijkstra(graph day20Graph, start, end day20Portal, neighborFunc func(inPortal day20Portal) []u.Pair[day20Portal, int]) int {
distance := make(map[day20Portal]int)
ih := day20PriorityQueueHeap{
day20PriorityQueue{
distance: 0,
neighbor: start,
},
}
heap.Init(&ih)
visited := make(map[day20Portal]bool)
for ih.Len() > 0 {
node := heap.Pop(&ih).(day20PriorityQueue)
if node.neighbor == end {
return node.distance
}
if _, exists := visited[node.neighbor]; exists {
continue
}
visited[node.neighbor] = true
for _, p := range neighborFunc(node.neighbor) {
if _, exists := visited[p.First]; exists {
continue
}
newDistance := node.distance + p.Second
if dist, exists := distance[p.First]; !exists || newDistance < dist {
distance[p.First] = newDistance
heap.Push(&ih, day20PriorityQueue{
distance: newDistance,
neighbor: p.First,
})
}
}
}
return math.MaxInt
}
func (d Day20) buildGraph() day20Graph {
graph := make(day20Graph, len(d.portals)+1)
adjacent := d.findAdjacentCells(d.entrance)
graph[entrancePortal] = adjacent
for portal, portalVec := range d.portals {
adjacent = d.findAdjacentCells(portalVec)
graph[portal] = adjacent
}
return graph
}
func (d Day20) getDepthNeighbors(graph day20Graph, portal day20Portal) []u.Pair[day20Portal, int] {
basePortal := portal
basePortal.depth = 0
baseNeighbors := graph[basePortal]
neighbors := make([]u.Pair[day20Portal, int], 0)
if portal.inner {
n := day20Portal{name: portal.name, inner: false, depth: portal.depth + 1}
neighbors = append(neighbors, u.Pair[day20Portal, int]{First: n, Second: 1})
}
if portal.depth == 0 {
for _, i := range baseNeighbors {
if i.First.inner || i.First.name == entrancePortal.name || i.First.name == exitPortal.name {
neighbors = append(neighbors, u.Pair[day20Portal, int]{First: i.First, Second: i.Second})
}
}
} else {
if !portal.inner {
n := day20Portal{name: portal.name, inner: true, depth: portal.depth - 1}
neighbors = append(neighbors, u.Pair[day20Portal, int]{First: n, Second: 1})
}
for _, i := range baseNeighbors {
if i.First.name != entrancePortal.name && i.First.name != exitPortal.name {
n := day20Portal{name: i.First.name, inner: i.First.inner, depth: portal.depth}
neighbors = append(neighbors, u.Pair[day20Portal, int]{First: n, Second: i.Second})
}
}
}
return neighbors
}
func (d *Day20) Part1() string {
// d.Draw()
graph := d.buildGraph()
for portal, adjacent := range graph {
if portal.name == entrancePortal.name {
continue
}
graph[portal] = append(adjacent, u.Pair[day20Portal, int]{First: day20Portal{name: portal.name, inner: !portal.inner}, Second: 1})
}
distance := d.dijkstra(graph, entrancePortal, exitPortal, func(inPortal day20Portal) []u.Pair[day20Portal, int] { return graph[inPortal] })
return fmt.Sprintf("Steps to traverse maze: %s%d%s", u.TextBold, distance, u.TextReset)
}
func (d *Day20) Part2() string {
graph := d.buildGraph()
distance := d.dijkstra(graph, entrancePortal, exitPortal, func(inPortal day20Portal) []u.Pair[day20Portal, int] { return d.getDepthNeighbors(graph, inPortal) })
return fmt.Sprintf("Steps to traverse recursive maze: %s%d%s", u.TextBold, distance, u.TextReset)
}

85
days/21.go Normal file
View File

@ -0,0 +1,85 @@
package days
import (
"fmt"
"strings"
u "parnic.com/aoc2019/utilities"
)
type Day21 struct {
program u.IntcodeProgram
}
func (d *Day21) Parse() {
d.program = u.LoadIntcodeProgram("21p")
// d.program.SetDebugASCIIPrint(true)
}
func (d Day21) Num() int {
return 21
}
func (d *Day21) Part1() string {
// if there's any hole up to 3 ahead of us but there's ground where we'd land if we jumped
// (a jump takes 4 spaces), go ahead and jump
cmds := []string{
// check if a hole at 1 or 2 ahead
"NOT A T",
"NOT B J",
// store that result in J
"OR T J",
// check if a hole at 3 ahead
"NOT C T",
// store hole in 1, 2, or 3 in T
"OR J T",
// set J true if hole in 1, 2, or 3
"OR T J",
// set J true if also no hole at 4 ahead
"AND D J",
"WALK",
}
instructionStr := strings.Join(cmds, "\n") + "\n"
d.program.FeedInputString(instructionStr)
res := d.program.Run()
return fmt.Sprintf("Hull damage value when walking: %s%d%s", u.TextBold, res, u.TextReset)
}
func (d *Day21) Part2() string {
// @
// #####.#.##.##.###
// ABCDEFGHI
// using the first program, this kills us. if we jump, we land at D and H becomes our new D, so it won't jump again.
// but if we waited to jump until we got one more ahead, we'd be ok.
// so now we want to know essentially the same thing as part 1, but also if our multiple (immediate second jump) would be successful.
// in problem terms, that's: if there's a hole at 1 or 2 ahead, and there's a hole at C with ground at H, and there's ground at D.
// so now for the above example we'd wait to jump until here:
// @
// #####.#.##.##.###
// ABCDEFGHI
// and all will be well.
cmds := []string{
// check if a hole at 1 or 2 ahead
"NOT A J",
"NOT B T",
// store that result in J
"OR T J",
// check if a hole at 3 ahead...
"NOT C T",
// and ground at 8 ahead (so we can immediately jump again if needed)...
"AND H T",
// combine those into J
"OR T J",
// and ensure we also still have a place to land if we jumped right away
"AND D J",
"RUN",
}
instructionStr := strings.Join(cmds, "\n") + "\n"
d.program.FeedInputString(instructionStr)
res := d.program.Run()
return fmt.Sprintf("Hull damage value when running: %s%d%s", u.TextBold, res, u.TextReset)
}

155
days/22.go Normal file
View File

@ -0,0 +1,155 @@
package days
import (
"fmt"
"math"
"math/big"
"strconv"
"strings"
u "parnic.com/aoc2019/utilities"
)
type day22Instruction int
const (
day22InstructionNewStack day22Instruction = iota
day22InstructionCut
day22InstructionDealIncrement
)
type day22Shuffle struct {
instruction day22Instruction
arg int
}
type Day22 struct {
shuffles []day22Shuffle
}
func (d *Day22) Parse() {
lines := u.GetStringLines("22p")
d.shuffles = make([]day22Shuffle, len(lines))
for idx, line := range lines {
split := strings.Split(line, " ")
if split[0] == "deal" {
if split[1] == "into" {
d.shuffles[idx] = day22Shuffle{instruction: day22InstructionNewStack}
} else if split[1] == "with" {
arg, err := strconv.Atoi(split[3])
if err != nil {
panic(err)
}
d.shuffles[idx] = day22Shuffle{
instruction: day22InstructionDealIncrement,
arg: arg,
}
}
} else if split[0] == "cut" {
arg, err := strconv.Atoi(split[1])
if err != nil {
panic(err)
}
d.shuffles[idx] = day22Shuffle{
instruction: day22InstructionCut,
arg: arg,
}
}
}
}
func (d Day22) Num() int {
return 22
}
func (d Day22) applyShuffle(s day22Shuffle, stack, scratch []int) {
switch s.instruction {
case day22InstructionNewStack:
for i := 0; i < len(stack)/2; i++ {
stack[i], stack[len(stack)-1-i] = stack[len(stack)-1-i], stack[i]
}
// there's probably a way to do these two in place...
case day22InstructionCut:
absArg := int(math.Abs(float64(s.arg)))
for i, v := range stack {
if s.arg > 0 {
if i < absArg {
scratch[len(scratch)-absArg+i] = v
} else {
scratch[i-absArg] = v
}
} else {
if i < absArg {
scratch[i] = stack[len(stack)-absArg+i]
} else {
scratch[i] = stack[i-absArg]
}
}
}
copy(stack, scratch)
case day22InstructionDealIncrement:
for i, v := range stack {
scratch[(i*s.arg)%len(stack)] = v
}
copy(stack, scratch)
}
}
func (d *Day22) Part1() string {
deckSize := 10007
// deckSize := 10
stack := make([]int, deckSize)
for i := range stack {
stack[i] = i
}
scratch := make([]int, len(stack))
for _, s := range d.shuffles {
d.applyShuffle(s, stack, scratch)
}
pos := -1
for i, v := range stack {
if v == 2019 {
pos = i
break
}
}
return fmt.Sprintf("Card 2019 is at position %s%d%s", u.TextBold, pos, u.TextReset)
}
func (d *Day22) Part2() string {
n, iter := big.NewInt(119315717514047), big.NewInt(101741582076661)
offset, increment := big.NewInt(0), big.NewInt(1)
for _, s := range d.shuffles {
switch s.instruction {
case day22InstructionNewStack:
increment.Mul(increment, big.NewInt(-1))
offset.Add(offset, increment)
case day22InstructionCut:
offset.Add(offset, big.NewInt(0).Mul(big.NewInt(int64(s.arg)), increment))
case day22InstructionDealIncrement:
increment.Mul(increment, big.NewInt(0).Exp(big.NewInt(int64(s.arg)), big.NewInt(0).Sub(n, big.NewInt(2)), n))
}
}
finalIncr := big.NewInt(0).Exp(increment, iter, n)
finalOffs := big.NewInt(0).Exp(increment, iter, n)
finalOffs.Sub(big.NewInt(1), finalOffs)
invmod := big.NewInt(0).Exp(big.NewInt(0).Sub(big.NewInt(1), increment), big.NewInt(0).Sub(n, big.NewInt(2)), n)
finalOffs.Mul(finalOffs, invmod)
finalOffs.Mul(finalOffs, offset)
answer := big.NewInt(0).Mul(big.NewInt(2020), finalIncr)
answer.Add(answer, finalOffs)
answer.Mod(answer, n)
return fmt.Sprintf("Card at position 2020: %s%d%s", u.TextBold, answer, u.TextReset)
}

170
days/23.go Normal file
View File

@ -0,0 +1,170 @@
package days
import (
"fmt"
"sync"
u "parnic.com/aoc2019/utilities"
)
type day23Computer struct {
program u.IntcodeProgram
id int
packetQueue chan u.Vec2[int64]
outputStep int
nextPacketDest int
sendingPacket u.Vec2[int64]
hasQueuedPacket bool
lastReceivedPacket u.Vec2[int64]
idle bool
}
func (d Day23) makeComputer(id int) *day23Computer {
c := &day23Computer{
program: d.program.Copy(),
id: id,
packetQueue: make(chan u.Vec2[int64]),
idle: true,
}
return c
}
type Day23 struct {
program u.IntcodeProgram
}
func (d *Day23) Parse() {
d.program = u.LoadIntcodeProgram("23p")
}
func (d Day23) Num() int {
return 23
}
func (d Day23) initComputers() []*day23Computer {
computers := make([]*day23Computer, 50)
for i := range computers {
computers[i] = d.makeComputer(i)
}
return computers
}
func (d Day23) execComputers(computers []*day23Computer, nat chan u.Vec2[int64]) *sync.WaitGroup {
wg := &sync.WaitGroup{}
wg.Add(len(computers))
for _, c := range computers {
go func(c *day23Computer) {
bootedUp := false
c.program.RunIn(func(inputStep int) int64 {
if !bootedUp {
bootedUp = true
return int64(c.id)
}
if c.hasQueuedPacket {
// fmt.Printf(" %d finished processing packet %v\n", c.id, c.lastReceivedPacket)
c.hasQueuedPacket = false
return c.lastReceivedPacket.Y
}
select {
case c.lastReceivedPacket = <-c.packetQueue:
// fmt.Printf("computer %d received packet %v\n", c.id, packet)
c.hasQueuedPacket = true
return c.lastReceivedPacket.X
default:
c.idle = true
return -1
}
}, func(val int64, state u.IntcodeProgramState) {
c.idle = false
switch c.outputStep {
case 0:
c.nextPacketDest = int(val)
case 1:
c.sendingPacket.X = val
case 2:
c.sendingPacket.Y = val
if c.nextPacketDest == 255 {
// fmt.Printf("computer %d sending %v to 255\n", c.id, c.sendingPacket)
nat <- c.sendingPacket
} else {
// fmt.Printf("computer %d sending %v to computer %d\n", c.id, c.sendingPacket, c.nextPacketDest)
computers[c.nextPacketDest].packetQueue <- c.sendingPacket
}
}
c.outputStep = (c.outputStep + 1) % 3
})
wg.Done()
}(c)
}
return wg
}
func (d *Day23) Part1() string {
computers := d.initComputers()
natChan := make(chan u.Vec2[int64])
wg := d.execComputers(computers, natChan)
answer := <-natChan
for _, c := range computers {
c.program.Stop()
}
// not really necessary, but let's make sure they all shut down in case
// we're running all days at once
wg.Wait()
return fmt.Sprintf("First packet sent to 255 Y value: %s%d%s", u.TextBold, answer.Y, u.TextReset)
}
func (d *Day23) Part2() string {
computers := d.initComputers()
natChan := make(chan u.Vec2[int64])
wg := d.execComputers(computers, natChan)
answerChan := make(chan int64)
go func() {
var currVal u.Vec2[int64]
var lastVal u.Vec2[int64]
hasReceived := false
for {
select {
case currVal = <-natChan:
hasReceived = true
default:
}
allIdle := true
for _, c := range computers {
if !c.idle {
allIdle = false
break
}
}
if allIdle && hasReceived {
// fmt.Printf("all idle, sending %v to computer 0\n", currVal)
if lastVal.Y == currVal.Y {
// fmt.Printf("found answer? %d\n", currVal.Y)
answerChan <- currVal.Y
}
computers[0].packetQueue <- currVal
lastVal = currVal
}
}
}()
answer := <-answerChan
for _, c := range computers {
c.program.Stop()
}
wg.Wait()
return fmt.Sprintf("First Y value sent to the NAT twice in a row: %s%d%s", u.TextBold, answer, u.TextReset)
}

289
days/24.go Normal file
View File

@ -0,0 +1,289 @@
package days
import (
"fmt"
"math"
u "parnic.com/aoc2019/utilities"
)
var (
day24AdjacentOffsets = []u.Vec2i{
{X: -1, Y: 0},
{X: 1, Y: 0},
{X: 0, Y: -1},
{X: 0, Y: 1},
}
)
type Day24 struct {
grid [][]bool
}
func (d *Day24) Parse() {
lines := u.GetStringLines("24p")
d.grid = make([][]bool, len(lines))
for i, line := range lines {
d.grid[i] = make([]bool, len(line))
for j, ch := range line {
d.grid[i][j] = ch == '#'
}
}
}
func (d Day24) Num() int {
return 24
}
func (d Day24) calcActivatedNeighbors(grid [][]bool, i, j int) int {
activatedNeighbors := 0
for _, o := range day24AdjacentOffsets {
newI := i + o.X
newJ := j + o.Y
if newI < 0 || newI >= len(grid) || newJ < 0 || newJ >= len(grid[i]) {
continue
}
if grid[newI][newJ] {
activatedNeighbors++
}
}
return activatedNeighbors
}
func (d Day24) recursiveCalcActivatedNeighbors(gridMap map[int][][]bool, mapIdx, i, j int) int {
activatedNeighbors := 0
numNeighbors := 0
thisGrid := gridMap[mapIdx]
for _, o := range day24AdjacentOffsets {
newI := i + o.X
newJ := j + o.Y
if newI < 0 || newI >= len(thisGrid) || newJ < 0 || newJ >= len(thisGrid[i]) {
continue
}
if newI == 2 && newJ == 2 {
continue
}
numNeighbors++
if thisGrid[newI][newJ] {
activatedNeighbors++
}
}
checkLower := (i == 1 && j == 2) ||
(i == 2 && (j == 1 || j == 3)) ||
(i == 3 && j == 2)
if checkLower {
if lowerGrid, exists := gridMap[mapIdx+1]; exists {
if i == 1 {
for _, b := range lowerGrid[0] {
numNeighbors++
if b {
activatedNeighbors++
}
}
} else if i == 2 {
if j == 1 {
for _, r := range lowerGrid {
numNeighbors++
if r[0] {
activatedNeighbors++
}
}
} else if j == 3 {
for _, r := range lowerGrid {
numNeighbors++
if r[len(lowerGrid[0])-1] {
activatedNeighbors++
}
}
}
} else if i == 3 {
for _, b := range lowerGrid[len(lowerGrid)-1] {
numNeighbors++
if b {
activatedNeighbors++
}
}
}
}
}
checkUpper := (i == 0) || (i == len(thisGrid)-1) ||
((i != 0 && i != len(thisGrid)) && (j == 0 || j == len(thisGrid[0])-1))
if checkUpper {
if upperGrid, exists := gridMap[mapIdx-1]; exists {
if i == 0 {
numNeighbors++
if upperGrid[1][2] {
activatedNeighbors++
}
} else if i == len(thisGrid)-1 {
numNeighbors++
if upperGrid[3][2] {
activatedNeighbors++
}
}
if j == 0 {
numNeighbors++
if upperGrid[2][1] {
activatedNeighbors++
}
} else if j == len(thisGrid[0])-1 {
numNeighbors++
if upperGrid[2][3] {
activatedNeighbors++
}
}
}
}
return activatedNeighbors
}
func (d Day24) calcRating(grid [][]bool) int {
rating := 0
for i, r := range grid {
for j := range r {
pow := (i * len(r)) + j
if grid[i][j] {
result := int(math.Pow(2, float64(pow)))
rating += result
}
}
}
return rating
}
func (d Day24) numBugs(gridMap map[int][][]bool) int {
ret := 0
for _, v := range gridMap {
for _, r := range v {
for _, b := range r {
if b {
ret++
}
}
}
}
return ret
}
func copy2d[T comparable](dest [][]T, src [][]T) {
for i, r := range src {
copy(dest[i], r)
}
}
func (d Day24) Draw(grid [][]bool) {
for _, r := range grid {
for _, c := range r {
if c {
fmt.Print("#")
} else {
fmt.Print(".")
}
}
fmt.Println()
}
fmt.Println()
}
func (d *Day24) Part1() string {
grid := make([][]bool, len(d.grid))
scratch := make([][]bool, len(grid))
for i, g := range d.grid {
grid[i] = make([]bool, len(g))
scratch[i] = make([]bool, len(g))
copy(grid[i], d.grid[i])
}
found := false
answer := 0
seenRatings := make([]int, 0)
for i := 1; !found; i++ {
// d.Draw(grid)
for i, r := range grid {
for j := range r {
numActivated := d.calcActivatedNeighbors(grid, i, j)
if grid[i][j] {
scratch[i][j] = numActivated == 1
} else {
scratch[i][j] = numActivated == 1 || numActivated == 2
}
}
}
rating := d.calcRating(scratch)
if u.ArrayContains(seenRatings, rating) {
found = true
// d.Draw(scratch)
answer = rating
}
seenRatings = append(seenRatings, rating)
copy2d(grid, scratch)
}
return fmt.Sprintf("First repeated biodiversity rating is %s%d%s", u.TextBold, answer, u.TextReset)
}
func (d *Day24) Part2() string {
makeGrid := func(initialGrid [][]bool) ([][]bool, [][]bool) {
grid := make([][]bool, len(d.grid))
scratch := make([][]bool, len(grid))
for i, g := range d.grid {
grid[i] = make([]bool, len(g))
scratch[i] = make([]bool, len(g))
if initialGrid != nil {
copy(grid[i], initialGrid[i])
}
}
return grid, scratch
}
gridMap := make(map[int][][]bool)
scratchMap := make(map[int][][]bool)
gridMap[0], scratchMap[0] = makeGrid(d.grid)
min := 0
max := 0
for i := 0; i < 200; i++ {
gridMap[min-1], scratchMap[min-1] = makeGrid(nil)
gridMap[max+1], scratchMap[max+1] = makeGrid(nil)
min, max = min-1, max+1
// if i == 10 {
// keys := u.MapKeys(gridMap)
// sort.Slice(keys, func(i, j int) bool { return keys[i] < keys[j] })
// for _, k := range keys {
// fmt.Println("Depth", k)
// d.Draw(gridMap[k])
// }
// fmt.Println("# bugs:", d.numBugs(gridMap))
// }
for depth, grid := range gridMap {
for i, r := range grid {
for j := range r {
if i == 2 && j == 2 {
continue
}
numActivated := d.recursiveCalcActivatedNeighbors(gridMap, depth, i, j)
if grid[i][j] {
scratchMap[depth][i][j] = numActivated == 1
} else {
scratchMap[depth][i][j] = numActivated == 1 || numActivated == 2
}
}
}
}
for d := range gridMap {
copy2d(gridMap[d], scratchMap[d])
}
}
return fmt.Sprintf("Bugs present after 200 minutes: %s%d%s", u.TextBold, d.numBugs(gridMap), u.TextReset)
}

81
inputs/18p.txt Normal file
View File

@ -0,0 +1,81 @@
#################################################################################
#...............#.......#...............#.........#.......#.......#.....#.......#
#.#########.#.###.#####.#.#.#######.#####.#######.#.#######.#.###.###.#.#.#####.#
#.#.#.....#.#.#...#...#..f#...#.....#...#...#.....#.........#...#.....#...#m....#
#.#.#.###.###.#.#####.#######.#######.#.#.#.#.#######.#########.###########.#####
#...#...#.#...#.......#.....#.#.......#.#.#.#...#...#...#.......#..h......#.....#
###.###.#.#.#########.#.###.#T#.#######.###.###.#B#.#.###.#######.#######.#####.#
#...#...#...#.....#...#...#.#...#.....#.#...#.#...#.#.#...#.........#...#.......#
#####.#######.###.#.###.#.#######.###.#.#.###.#####.###.#.###########.#.#######.#
#...#...#.....#.#...#.#.#.....#...#.....#.#.....#...#...#.#...........#.#.....#.#
#.#.###.#.#####.#####.#.#####.#.###.#####.#.###.#.###.#####.###########.#.###.#.#
#.#.....#.#.....#.........#...#...#.#...#.#...#..x#...W.....#.....#.....#.#...#.#
#.#######.###.#.#########.#.#####.###.#.#.###.#######.#######.###.#.#####.#.#####
#.........#...#.......#.#.#.#...#.....#.#.#.#.#.....#...#.....#...#.#.....#.....#
#.#########O#########.#.#.#.#.#.#.#####.#.#.#.###.#.#.###.#####.###.#.#########.#
#.#.........#.........#...#.#.#.#...#.#.#.#.......#.#.#...#...#.#.......#.....#.#
#.#####.#########.#########.#.#.###.#.#.#.#########.###.###.###.#####.###.###.#.#
#.....#...#.....#.#.........#.#.#.....#.#.....#.....#...#...........#.#...#e..#.#
#####.###.#K###.#.#####.#####.#.#######.#####.#####.#.#.###########.###.###.###.#
#...#.....#.#...#.......#.....#.#.......#.....#...#...#.#.........#.....#.#.#...#
#.#####.###.#.#########.#.#####.#.#####.#.#####.#.#######.#####.#.#######.#.#.#.#
#.#j..#.#...#a..#.....#.#.#.......#.....#.......#...........#.#.#.......#.#...#.#
#.#.#.#.#.#####.#.#####.#.#############.#.###################.#########.#.#####.#
#...#.#.#.#...#...#.....#.#..z..#.....#.#.....#.......#.....#...#...#...#...#...#
#.###.#.#.###.#####.#####.#.###.#.###.#######.#.#.#####.###.###.#.#.#.###.###.###
#.#...#.#.....#.#...#...#.#...#.#.#.#...#.....#.#.....#...#.....#.#...#.#...#...#
###.###.#####.#.#.###.#.#.###.#.#.#.###.#.###########.###.#######.#####.#.#.###.#
#...#...#...#.#.......#.#.....#.#.....#.#.#.............#...#...#...#.....#.#...#
#.#.#.#####.#.#############.###.###.###.#.#.#########.#####.###.#.#.#####.#.#.###
#.#.#.#.....#.............#...#.....#...#.#.....#...#.#.....#...#.#.#...#.#.#.#.#
#.###.#.#.###############.###.#####.#.#.#.#####.#.#.#.#.#####.###.#.#.#.#.#.#.#.#
#.#...#.#.......#.........#...#...#.#.#.#.#.....#.#...#.#.........#.#.#.#.#...#.#
#.#.#######.###.#.#########.###.#.###.#.#.#.###########.#.#########.#.#.#####.#.#
#.#.......#...#.#.#.......#...#.#.#...#.#.#...#.......#.#.#.......#...#.#...#c..#
#.#######.#.#.###.###.###.#####.#.#.###.#.###.#.#####.#.###.#####.#.###.#.#.###.#
#.L..q..#.#.#...#...#.#.#.....#.#...#...#...#.....#...#.....#.....#...#...#.#...#
#.#######.#####.###.#.#.#####.#.#####.#####.#######S#########.#############.#.###
#...#...#.#.......#...#.#.....#.#...#...#...#.....#.....#...#.#.....#.....#k#...#
#.#.#.#.#.#.#####.#####.#.#####.#.#.###.#.###.###.###.#.###.#.#.###.#.###.#.###.#
#.#...#.....#...........#.......#.#...........#.......#.....#...#.....#.....#...#
#######################################.@.#######################################
#.#...#...........#u....#...#.......#...............#.....#...................#.#
#.#.#.#.#####.###.#.#.#.#.#.#.#.#####.#.#####.#####.#.###.#.###.#############.#.#
#.#.#...#...#...#.#.#.#.#.#...#.#s....#.#.....#...#.#.#.#..p#.#.#.....#.....#...#
#.#.#######.###.###.#.###.#####.#.#####.#.#######.#.#.#.#####.#.#.###.#.###.###.#
#...#.........#.#...#.#...#...#...#...#.#...#.....#...#.......#.#.#.#.....#.#.#.#
#.###.#.#####.#.#.###.#.###.#######.#.#.#.#.#.###.#####.#######.#.#.#######.#.#.#
#...#.#.#.....#...#...#.#...#.....#.#...#.#.#.#...#.....#.......#.#...#.V...#...#
###.###.#.#########.###.#.#.#.###.#.###.###.#.#####.#.###.#######.###.#.#####.###
#.#.....#.#.....#...#.....#.#...#...#...#...#.#.....#.......#...#.#...#.#.....#.#
#.#######.#N#.#.#.#.#.#########.#.#######.###.#.#############.#.#.#.#.#.#.#####.#
#.......#.#.#.#.#.#.#.#...#.....#.#.....#.#.........#.........#.#...#.#.#.....U.#
#.#######.###.#.#.###.#.#P#.#######.###.#.###.#######.#########.#####.#.#######.#
#.#.....#...#.#.#.....#.#...#.......#...#...#...#.....#.......#.......#.#...#...#
#.#.###.###.#.#########.###.#.#######.#####.###.#.#####.###.###########.#.#.#.###
#...#...#.#.#.#.....#...#...#.#.....#...#...#...#.......#...#.........#.#.#.#.#.#
#.###.#.#.#.#.#.#.###.#######.#.###.###.#.#####.#####.#####.#.#######.#.#.#Q#.#.#
#.#...#...#.#...#...#.....#...#.#...#...#.....#.....#.#.Yi#.#.#...#...#.#.#.#...#
#.#.#######.###.###.#####.#.###.#.#.#.###.###.#######.#.#.#.#.###.#.###.#.#.###.#
#.#.......#...#.#.....#...#.#...#.#.#...#.#...#.......#.#.#.#...#.....#.#.#.#...#
#.#######.###.###.#.###.###.#####.#####.#.#.#.#.#######.#.#.###.#####.#.#.#.#####
#.#.....#.....#...#.#.#.........#.....#.#.#.#.#.#...#...#.#.#.#.#...#...#.#.....#
#.#.###.#######.#####.#########.#.#.###.#.#.#.#.#.###.###.#.#.#.#.#.#####.#####.#
#.#.#.....#.........#.#.....#.#.#.#b#...#.#.#.#.#.#..y#.#.#.#.#.#.#...#...#.....#
#.###.#####.#######.#.#.###.#.#.#.#.#.#####.###.#.#.###.#.###.#.#.###.#.###.###.#
#.E.#....d..#.......#...#.#.#.#.#.#.#...#...#...#.#...#.#...I.#...#..l#.#...#...#
###.#.#######.###########F#.#.#.###.###.#.#.#.###.###.#.#########.#.###.#.###J###
#...#...#...#...........#...#.......#...#.#.#.#.....#.G.#.......#.#.....#.#.#.#.#
#.#####.#.#########.#.#.#.#########.#.#.#.###.#####.###.#.###.#.#####.###.#.#.#.#
#..v..#...#.......#.#.#.#.#...#.....#.#.#...#.......#.#.#...#.#.....#.#...#.#...#
#####.#####.#####.###.###.#.#.#.#####.#.#Z#.#######X#.#.#####.#####.#.#.###.###.#
#...#.....#...#.....#...#...#.#.#...#.#.#.#.......#...#.....#.....#.#.#.#...#...#
#.#######.#.#.#####.###.#####.#.#.###.#.###.#.#####.#######.#.###.#.###.#.###.###
#.........#.#.#...#...#...#...#...#...#.#...#.#...#.#.R....g#.#...#.....#.#...#.#
#.###########.#.#.###.###.#.###.###.###.#.#####.#.#.#.#########.#########.#.###.#
#...#.#.....#...#.#.#.#...#..t#.#...#...#.#.....#...#...#.....#.#..n....#.M.#...#
###.#.#.#.#.#####.#.#.#.#####.###.#####.#.#.###########.#.###.#.#.#######.###.#.#
#...#...#.#.#..w#.#.#.#.....#...#.....#.#.#.......#.....#.#...#.#.#.D...#.....#.#
#C#######.#.#.#.#.#.#.###.#.###.#####.#.#.#######.#.#####.#.###.#.#.###.#######H#
#......o..#...#...#.......#...#.A.....#.#.........#r......#.....#.....#.........#
#################################################################################

3
inputs/18s1.txt Normal file
View File

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

5
inputs/18s2.txt Normal file
View File

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

5
inputs/18s3.txt Normal file
View File

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

9
inputs/18s4.txt 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
inputs/18s5.txt Normal file
View File

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

7
inputs/18s6.txt Normal file
View File

@ -0,0 +1,7 @@
#######
#a.#Cd#
##...##
##.@.##
##...##
#cB#Ab#
#######

7
inputs/18s7.txt Normal file
View File

@ -0,0 +1,7 @@
###############
#d.ABC.#.....a#
######...######
######.@.######
######...######
#b.....#.....c#
###############

7
inputs/18s8.txt Normal file
View File

@ -0,0 +1,7 @@
#############
#DcBa.#.GhKl#
#.###...#I###
#e#d#.@.#j#k#
###C#...###J#
#fEbA.#.FgHi#
#############

9
inputs/18s9.txt Normal file
View File

@ -0,0 +1,9 @@
#############
#g#f.D#..h#l#
#F###e#E###.#
#dCba...BcIJ#
#####.@.#####
#nK.L...G...#
#M###N#H###.#
#o#m..#i#jk.#
#############

1
inputs/19p.txt Normal file
View File

@ -0,0 +1 @@
109,424,203,1,21102,11,1,0,1105,1,282,21101,0,18,0,1105,1,259,2101,0,1,221,203,1,21102,1,31,0,1105,1,282,21102,1,38,0,1105,1,259,20102,1,23,2,21201,1,0,3,21102,1,1,1,21102,57,1,0,1106,0,303,2102,1,1,222,21002,221,1,3,20101,0,221,2,21101,0,259,1,21101,0,80,0,1105,1,225,21101,44,0,2,21102,91,1,0,1105,1,303,1202,1,1,223,21002,222,1,4,21102,259,1,3,21102,1,225,2,21102,225,1,1,21101,118,0,0,1106,0,225,21002,222,1,3,21101,163,0,2,21101,0,133,0,1106,0,303,21202,1,-1,1,22001,223,1,1,21102,148,1,0,1106,0,259,1202,1,1,223,20101,0,221,4,21001,222,0,3,21102,1,24,2,1001,132,-2,224,1002,224,2,224,1001,224,3,224,1002,132,-1,132,1,224,132,224,21001,224,1,1,21101,195,0,0,105,1,108,20207,1,223,2,21002,23,1,1,21102,-1,1,3,21102,1,214,0,1106,0,303,22101,1,1,1,204,1,99,0,0,0,0,109,5,2101,0,-4,249,22102,1,-3,1,22101,0,-2,2,22101,0,-1,3,21102,250,1,0,1106,0,225,21202,1,1,-4,109,-5,2105,1,0,109,3,22107,0,-2,-1,21202,-1,2,-1,21201,-1,-1,-1,22202,-1,-2,-2,109,-3,2106,0,0,109,3,21207,-2,0,-1,1206,-1,294,104,0,99,22102,1,-2,-2,109,-3,2105,1,0,109,5,22207,-3,-4,-1,1206,-1,346,22201,-4,-3,-4,21202,-3,-1,-1,22201,-4,-1,2,21202,2,-1,-1,22201,-4,-1,1,21202,-2,1,3,21101,0,343,0,1106,0,303,1106,0,415,22207,-2,-3,-1,1206,-1,387,22201,-3,-2,-3,21202,-2,-1,-1,22201,-3,-1,3,21202,3,-1,-1,22201,-3,-1,2,21201,-4,0,1,21101,384,0,0,1105,1,303,1105,1,415,21202,-4,-1,-4,22201,-4,-3,-4,22202,-3,-2,-2,22202,-2,-4,-4,22202,-3,-2,-3,21202,-4,-1,-2,22201,-3,-2,1,21202,1,1,-4,109,-5,2105,1,0

113
inputs/20p.txt Normal file
View File

@ -0,0 +1,113 @@
G R U E Z S S
W N C K Z G D
#################################.###########.###.#######.#########.#.#######.#####################################
#.#.......#.#.........#.#.#.....#.#.....#.#.#...#.....#.........#.....#...#.#...........#.......#.....#.....#.#...#
#.#####.###.###.###.#.#.#.###.###.#.###.#.#.###.#.###.###.#####.#.###.###.#.###.#########.###.###.#######.###.#.###
#.#.#.#...#...#.#.#.#.................#.#...#...#.#.#...#.#.....#.#.#.#.....................#.#.......#.........#.#
#.#.#.#.###.#####.#########.###########.#.#.#.###.#.#######.###.#.#.#####.###.#.###.#.###.#.###.#######.#######.#.#
#...#...#.#.#.#.........#...#...#.......#.#...#.......#.....#.#.#.....#.....#.#...#.#.#...#.#...#.#.........#.#.#.#
#.#.###.#.#.#.#####.#.#.#######.#.#######.###.#.###.#####.###.#####.#.###.#########.#.#.#######.#.#####.#####.#.#.#
#.#...#.#.#.#.#.....#.#.................#.#...#.#.#.....#...#.#.#...#...#.#.....#.#.#.#...#.#.#...........#.#.....#
###.###.#.#.#.#.#.#####.#.###.#########.#.#######.#.#####.###.#.#.#.#####.#.#.###.#.#######.#.#.###.#######.###.#.#
#...#.......#...#.#.#.#.#...#.#.........#.....#.......#.#.......#.#...#.....#.....#.#...#.........#...#.#.#.#.#.#.#
###.#######.#######.#.###########.#.#####.###.#####.###.#.#####.#.###.#.#.###.#.#######.###.#####.#####.#.#.#.#####
#.......#.#...#.......#.........#.#.#...#.#.#.#.....#.....#...#.#...#.#.#.#...#...#...#...#...#.#.#...........#.#.#
#.#.###.#.#.#########.#########.#.###.###.#.#####.#.###.#.#.#.#.#.###########.#.###.###.###.###.###.###.#.#####.#.#
#.#...#.....#.#...#.#.#.#.#.............#.....#...#...#.#.#.#...#...#.#.#.....#.........#...#.......#...#...#...#.#
###########.#.#.###.#.#.#.#######.#####.#.#####.#.#######.#####.###.#.#.#####.#.#.###.#####.###.#############.#.#.#
#.#.#.#.#.....#.#.....#.#.#.#.....#...#.#.....#.#.....#...#.#.#...#...#.#.#...#.#...#...#...#...#...#.#.......#.#.#
#.#.#.#.###.###.#####.#.#.#.#####.#.###.#.#########.#######.#.#.###.###.#.#.###.###.#####.#####.#.###.#####.#####.#
#.#...#.#...#.#.#...#...#.#.....#.#.....#.#...#.....#.......#.#.#...#.....#.#.#.#.......#.......#...#.#.#...#.#...#
#.#.#.#.###.#.#.###.#.###.#.#####.#.###.#.###.###.###.#.#.###.#.#.###.#.#.###.#.###.#####.#.#####.###.#.###.#.###.#
#.#.#.#.#...#.#...#...#.#.#...#...#...#.#.#.....#.#...#.#.#.....#.#...#.#.#.......#.......#...#.#.....#.........#.#
#.#.###.###.#.#.#####.#.#.#.###.#.#####.#.#.###.#.###.#.###.#.###.#.###.#####.#####.#####.#####.###.#########.#.#.#
#.....#...#.......#.#.#.......#.#.#...#.#...#.#.#.....#...#.#...#...#.#...#.......#...#.#...#...#...#.#.#.#.#.#.#.#
###.###.#######.###.#.#.#.#.#########.#.#####.#.#.#####.#######.#####.#.#####.#.#.###.#.#######.###.#.#.#.#.#.###.#
#.....#...#.#.#.......#.#.#.#.#.......#...#.....#.#.....#.......#.......#.#...#.#.#.#...#.....#.#.....#.#.#...#.#.#
###.###.###.#.#######.#.#####.#####.#.#.###.#########.#.###.#.#####.#####.###.#####.#######.###.###.###.#.#.###.#.#
#.....#.......#...#...#...#.#.#.#.#.#.#.#.......#.#...#.#.#.#...#.......#...#.......#...#.....#...#.#.........#...#
#.#####.#######.###.#.#.###.#.#.#.#.#.#.###.#.###.#.#####.#####.#####.#####.###.#######.###.###.###.#########.#.###
#...#...#...#.#.#...#.#.#.#.........#.....#.#.....#.......#.......#...#.............#...#...#.#.........#...#.#...#
#.###.###.###.#.#####.#.#.#.#####.#############.#######.#####.#####.#######.###########.###.#.###.#######.###.#.###
#...#...#...#...#.#...#...#.# S L B V G R #.#.#.#.....#.#.......#.#...#
#.###.#.#.#####.#.###.#.###.# D M E H X Q #.#.#.#####.#.###.#####.#.###
#.....#.#.................#.# #.........................#.#
#.###.###.#####.#.#.#.###.### #.#.#.###.#######.###.#.#.#.#
#.#.#.....#.#...#.#.#.#.....# RZ..#.#...#.....#.#...#.#.#.#..BE
#.#.#####.#.#####.#.#####.### #######.#####.#.#.#######.#.#
#.....#.#.....#.#.#.....#.#.# #.#.#.#.#.#...#.......#...#.#
###.###.###.#.#.#.#.###.#.#.# #.#.#.###.#####.#.#######.#.#
RI....#.....#.#.#...#.#.#.#....UW #.#.......#...#.#.#.#...#...#
#####.###############.###.### #.###.#####.#.#####.#.#.#####
#.....#.#.#...#.#.....#.#...# GW..........#.#.........#.#...#
#.###.#.#.#.###.###.###.##### #.###.#.#.###.#######.###.###
#...#...#.....#.#.......#....FM #.#...#.#.....#...#.........#
###.###.#.#.#.#.#.#########.# ###.#######.###.###########.#
AJ..#...#...#.#...#...#.....#.# #...#.#.#...#...#.#...#.#.#..GX
#.#.#########.#.#.#######.#.# #####.#.#######.#.###.#.#.###
#.....#.#.#.#.#.............# #...............#...#........DD
#######.#.#.###########.###.# ###.#######.###.#.#.#.#.###.#
#.....................#.#...# #.......#.....#...#.#.#.#...#
###.###.#.#.###.#####.####### #####.#########.###.#.###.###
GP..#...#.#.#.#.....#.#...#...# SG..#...#.....#...#.#.....#...#
#.###.#####.#.#.#.#.###.###.# #.#.###.#.#######.#######.###
#.#.....#.#.#.#.#.#.....#...# #.....#.#.#.#...#.#.#...#.#.#
#.#.#####.#########.#######.# #########.#.###.#.#.#.#####.#
#.....#...#..................SI DD....#........................UW
#.#######.#####.###.###.##### #.###.#####.#.###.#.###.#####
#.#.#...#...#.....#.#.#.#.#..AJ #.........#.#.#.#.#.#.....#.#
###.#.###.#.#########.###.#.# #.#####.###.#.#.#######.###.#
#.........#.#...#.....#.#.#.# #...#.....#.#...#.#.#.#.#....LM
#########.#.###.#.###.#.#.#.# #########.#.#.###.#.#.#####.#
AA......#.#.#.....#.#...#.....# #.#.#.#.#.#.#.#...#.#.#.....#
#.#####.#.#.###.#.#.###.#.### #.#.#.#.#########.#.#.#####.#
JO..........#...#...#.....#...# #.#.......#.#.............#.#
#####.###############.###.#.# #.#.#.#####.###.###.#.###.#.#
#.#.#...#.........#.#.#.#.#.# TX....#.............#.#...#...#
#.#.#######.#.#.#.#.###.###.# #.###.#.###.#####.###########
VH......#.....#.#.#.....#...#.# #.#...#.#...#...#.#.....#...#
#####.#.###########.###.##### #############.#####.###.#.#.#
#.....#.....#.#.......#.....# #.#...#...#.#.......#.#.#.#..RZ
#.#.#######.#.#######.#.##### #.###.###.#.###.#.###.#.#.###
#.#...........#.#............FW RN..#.....#...#.#.#.#.....#...#
#########.###.#.#.########### #.#.#.###.###.###.#.#####.###
#...#...#.#.....#.#.........# #...#.............#.......#.#
#.#.#.#################.#.#.# ###############.###########.#
AX..#...#.#...#.#...#...#.#.#..HR JO............#.#.#...........#
#.#.###.###.#.#.#####.###.#.# #.#.#####.#.#.###.#.#.#####.#
TX..#...#.......#...#.....#.#..EK #.#...#.#.#.......#.#...#.#..MM
###.#.###.#.#.#.#.###.#.#.### #.###.#.#######.#.###.###.#.#
#...#.....#.#...#.....#.....# #.#.#.....#.#...#...#.#.....#
#####.#.#.#####.###.#######.# R Y G U A M S #.#.#.#.###.#####.#.#.###.#.#
#.....#.#...#.....#.....#...# I Q P C X M Y #...#.#.#.....#...#.#...#.#.#
#####.#########.###.#####.###########.#####.###.###########.#####.###########.#.#######.#.###.#.#########.#.#####.#
#...#...#.#.......#.....#...#...#.....#.....#.....#.#.....#...#...........#...#...#...#.#.#.....#.#.......#.#.....#
#.#.#.###.###.#.#.#######.#####.###.###.###.#####.#.###.#.#.#########.#####.#####.#.#########.###.###.#####.###.#.#
#.#.......#...#.#.#.......#.....#.#.#.....#.#.....#...#.#.......#.#.#...#.......#.#.......#.#.#.#.....#.......#.#.#
#.#.#.#.#####.###########.#####.#.#.#.#.#.#####.###.###.#########.#.#.#######.###.#.#######.###.###.#.###.#.#.#.#.#
#.#.#.#...#.......#.......#.........#.#.#.....#.#.....#.........#.........#.#.#.....#.......#.......#.#.#.#.#.#.#.#
#######.#.#.#.#####.#.#########.#############.#.#.###.#######.#####.#.#####.#.#.#######.#####.#.#.###.#.#.#######.#
#.......#.#.#...#...#.#.........#.......#...#.#.....#.#.......#.....#...#.....#...........#.#.#.#.#.....#...#.....#
#.#.#.#####.#.#.#####.#.#######.#.###.###.###.#.###.#.#.###.#.#.#.###.#.#####.#.###.#.#.###.###.#.#.#.#####.#####.#
#.#.#.#.....#.#.#.....#...#.#.....#...#.......#.#...#.#...#.#.#.#...#.#.#.....#.#...#.#.......#.#.#.#...#.#.#.....#
#.###.###.#.###.###.#.#.###.#.#.#.#.###.###.#.#######.###.#.###.#######.#.#.#.#####.#.#.#.#############.#.#####.###
#.#.#.#.#.#...#.#...#.#.#.....#.#.#...#...#.#...#.....#...#...#...#.....#.#.#.....#.#.#.#.#.....#.#.#.......#...#.#
###.#.#.#.#.###.#####.#############.#.#.#.#.#######.###.###.###.#############.#####.#####.###.###.#.#.#####.###.#.#
#.......#.#.#.....#...#.#.......#...#.#.#.#.#.#.#.#...#...#.#.....#.#.#...#.....#.#.#...#...#.......#.....#...#...#
###.###.#.###.#########.#######.#####.#.#####.#.#.#.###.#######.###.#.#.#####.###.#.#.###.###.#####.#.#.###.###.###
#.....#.#.#.....#.....#.#.......#.#.#.#...#.......#.#.......#...#.....#.......#.........#.#.#.....#.#.#.#...#.....#
#.#####.#.###.#.#####.#.#######.#.#.#.#.#######.#.#.###.#####.#.###.#.###.#.#####.###.#####.#.#######.###.#.#.#.###
#.#.....#.#...#...#.......#.#.....#...#.#.#.....#...#.......#.#.....#.#...#...#.#...#...#.#.#.....#.#.#.#.#.#.#...#
#####.#.#.###.#######.#.###.###.#.#.###.#.#####.#######.#######.#.#####.###.###.###.#####.#.#.#####.###.#######.#.#
#.#.#.#.#.#.#.#...#...#...#.#.#.#...#.......#.#.....#.#.#...#...#.....#.#.......#.........#.#...#.#.........#.#.#.#
#.#.#######.#####.#####.###.#.#.#########.###.#####.#.#.#.#######.#########.#.###.#########.###.#.#.#########.#.#.#
#...#.#.#.#.....#.#...................#...#...#...#...#.....#...#.#...#...#.#.#.....#.#.......#.#.#.#.#.#.#...#.#.#
###.#.#.#.#.###.#.#####.#############.###.#.#.#.#.###.#.#.#####.#.#.#####.###.#.###.#.#####.###.#.#.#.#.#.###.#.###
#...........#.#.#...#...#.#.......#.#...#...#.#.#...#.#.#...#.#.......#.....#.#...#.#.#.#.#.....#.....#.#.....#...#
#####.#.#.#.#.###.#####.#.#.#.###.#.#.#######.#.###.#.#.###.#.#####.###.###.#.#.###.#.#.#.#.#####.###.#.#.#########
#.#...#.#.#.............#...#...#...#.....#...#...#...#.#.#.#...#...#...#.#...#.#...................#.............#
#.#####.#######.#.###.###.#.#.#####.#.#######.###.#####.#.###.#.#.#####.#.###.#.#.#####.###.#####.###.#.###.#.#####
#.......#.......#...#...#.#.#.#.........#.....#.....#.......#.#.......#.....#.#.#.....#...#.....#...#.#...#.#.....#
###################################.#######.###.#########.#######.#########.#######.###############################
Y S R S F F H
Q Y Q I M W R

19
inputs/20s1.txt Normal file
View File

@ -0,0 +1,19 @@
A
A
#######.#########
#######.........#
#######.#######.#
#######.#######.#
#######.#######.#
##### B ###.#
BC...## C ###.#
##.## ###.#
##...DE F ###.#
##### G ###.#
#########.#####.#
DE..#######...###.#
#.#########.###.#
FG..#########.....#
###########.#####
Z
Z

37
inputs/20s2.txt Normal file
View File

@ -0,0 +1,37 @@
A
A
#################.#############
#.#...#...................#.#.#
#.#.#.###.###.###.#########.#.#
#.#.#.......#...#.....#.#.#...#
#.#########.###.#####.#.#.###.#
#.............#.#.....#.......#
###.###########.###.#####.#.#.#
#.....# A C #.#.#.#
####### S P #####.#
#.#...# #......VT
#.#.#.# #.#####
#...#.# YN....#.#
#.###.# #####.#
DI....#.# #.....#
#####.# #.###.#
ZZ......# QG....#..AS
###.### #######
JO..#.#.# #.....#
#.#.#.# ###.#.#
#...#..DI BU....#..LF
#####.# #.#####
YN......# VT..#....QG
#.###.# #.###.#
#.#...# #.....#
###.### J L J #.#.###
#.....# O F P #.#...#
#.###.#####.#.#####.#####.###.#
#...#.#.#...#.....#.....#.#...#
#.#####.###.###.#.#.#########.#
#...#.#.....#...#.#.#.#.....#.#
#.###.#####.###.###.#.#.#######
#.#.........#...#.............#
#########.###.###.#############
B J C
U P P

37
inputs/20s3.txt 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

1
inputs/21p.txt Normal file

File diff suppressed because one or more lines are too long

100
inputs/22p.txt Normal file
View File

@ -0,0 +1,100 @@
deal into new stack
cut -2732
deal into new stack
deal with increment 57
cut 5974
deal into new stack
deal with increment 32
cut -1725
deal with increment 24
cut 6093
deal with increment 6
cut -2842
deal with increment 14
cut 2609
deal with increment 12
cut -6860
deal with increment 51
cut -6230
deal with increment 61
cut 3152
deal with increment 28
cut 2202
deal into new stack
deal with increment 60
cut 433
deal into new stack
cut -6256
deal with increment 13
deal into new stack
cut 8379
deal into new stack
deal with increment 54
cut 1120
deal with increment 16
cut -5214
deal with increment 63
deal into new stack
cut -8473
deal with increment 11
cut 228
deal with increment 45
cut -6755
deal with increment 50
cut -3391
deal with increment 44
cut -1341
deal with increment 28
cut -6788
deal with increment 52
cut 3062
deal with increment 41
cut 4541
deal with increment 57
cut -7962
deal with increment 56
cut 9621
deal with increment 57
cut 3881
deal with increment 36
deal into new stack
deal with increment 45
cut 522
deal with increment 9
deal into new stack
deal with increment 60
deal into new stack
deal with increment 12
cut -9181
deal with increment 63
deal into new stack
deal with increment 14
cut -2906
deal with increment 10
cut 848
deal with increment 75
cut 798
deal with increment 29
cut 1412
deal with increment 10
deal into new stack
cut -5295
deal into new stack
cut 4432
deal with increment 72
cut -7831
deal into new stack
cut 6216
deal into new stack
deal with increment 7
cut -1720
deal into new stack
cut -5465
deal with increment 70
cut -5173
deal with increment 7
cut 3874
deal with increment 65
cut 921
deal with increment 8
cut -3094

3
inputs/22s1.txt Normal file
View File

@ -0,0 +1,3 @@
deal with increment 7
deal into new stack
deal into new stack

3
inputs/22s2.txt Normal file
View File

@ -0,0 +1,3 @@
cut 6
deal with increment 7
deal into new stack

3
inputs/22s3.txt Normal file
View File

@ -0,0 +1,3 @@
deal with increment 7
deal with increment 9
cut -2

10
inputs/22s4.txt Normal file
View File

@ -0,0 +1,10 @@
deal into new stack
cut -2
deal with increment 7
cut 8
cut -4
deal with increment 7
cut 3
deal with increment 9
deal with increment 3
cut -1

1
inputs/23p.txt Normal file

File diff suppressed because one or more lines are too long

5
inputs/24p.txt Normal file
View File

@ -0,0 +1,5 @@
##..#
...##
.#.##
#..#.
..#..

5
inputs/24s1.txt Normal file
View File

@ -0,0 +1,5 @@
....#
#..#.
#..##
..#..
#....

5
inputs/24s2.txt Normal file
View File

@ -0,0 +1,5 @@
.....
.....
.....
#....
.#...

View File

@ -51,6 +51,13 @@ var dayMap = []day{
&days.Day15{},
&days.Day16{},
&days.Day17{},
&days.Day18{},
&days.Day19{},
&days.Day20{},
&days.Day21{},
&days.Day22{},
&days.Day23{},
&days.Day24{},
}
func main() {

26
utilities/bisect.go Normal file
View File

@ -0,0 +1,26 @@
package utilities
import (
"math"
)
// Bisect takes a known-good low and known-bad high value as the bounds
// to bisect, and a function to test each value for success or failure.
// If the function succeeds, the value is adjusted toward the maximum,
// and if the function fails, the value is adjusted toward the minimum.
// The final value is returned when the difference between the success
// and the failure is less than or equal to the acceptance threshold
// (usually 1, for integers).
func Bisect[T Number](low, high, threshold T, tryFunc func(val T) bool) T {
for T(math.Abs(float64(high-low))) > threshold {
currVal := low + ((high - low) / 2)
success := tryFunc(currVal)
if success {
low = currVal
} else {
high = currVal
}
}
return low
}

View File

@ -28,6 +28,8 @@ type IntcodeProgram struct {
program []int64
relativeBase int
haltRequested bool
printASCII bool
feedInput []rune
}
type IntcodeProgramState struct {
@ -128,20 +130,27 @@ func (p *IntcodeProgram) ensureMemoryCapacity(address int) {
}
func (p *IntcodeProgram) Reset() {
p.memory = nil
wiped := false
if len(p.memory) != len(p.program) {
wiped = true
p.memory = nil
}
p.init()
copy(p.memory, p.program)
if !wiped {
copy(p.memory, p.program)
}
p.relativeBase = 0
}
func (p *IntcodeProgram) Run() {
p.RunIn(func(int) int64 { return 0 }, func(int64, IntcodeProgramState) {})
func (p *IntcodeProgram) Run() int64 {
return p.RunIn(func(int) int64 { return 0 }, func(int64, IntcodeProgramState) {})
}
func (p *IntcodeProgram) RunIn(inputFunc ProvideInputFunc, outputFunc ReceiveOutputFunc) {
func (p *IntcodeProgram) RunIn(inputFunc ProvideInputFunc, outputFunc ReceiveOutputFunc) int64 {
p.init()
inputsRequested := 0
lastOutput := int64(0)
for instructionPointer := 0; instructionPointer < len(p.program) && !p.haltRequested; {
instruction := p.GetMemory(instructionPointer)
instructionPointer++
@ -178,13 +187,28 @@ func (p *IntcodeProgram) RunIn(inputFunc ProvideInputFunc, outputFunc ReceiveOut
case opInput:
inputsRequested++
param1 := p.GetMemory(instructionPointer)
p.setMemory(int(param1), inputFunc(inputsRequested), paramModes[0])
var inputVal int64
if len(p.feedInput) > 0 {
inputVal = int64(p.feedInput[0])
p.feedInput = p.feedInput[1:]
} else {
inputVal = inputFunc(inputsRequested)
}
if p.printASCII && inputVal <= 255 {
fmt.Printf("%c", rune(inputVal))
}
p.setMemory(int(param1), inputVal, paramModes[0])
instructionPointer += 1
case opOutput:
param1 := p.GetMemory(instructionPointer)
outputFunc(p.getParamValue(int(param1), paramModes[0]), p.makeState(instructionPointer))
param1Val := p.getParamValue(int(param1), paramModes[0])
if p.printASCII && param1Val <= 255 {
fmt.Printf("%c", rune(param1Val))
}
outputFunc(param1Val, p.makeState(instructionPointer))
lastOutput = param1Val
instructionPointer += 1
@ -250,8 +274,19 @@ func (p *IntcodeProgram) RunIn(inputFunc ProvideInputFunc, outputFunc ReceiveOut
}
p.haltRequested = false
return lastOutput
}
func (p *IntcodeProgram) Stop() {
p.haltRequested = true
}
func (p *IntcodeProgram) SetDebugASCIIPrint(enable bool) {
p.printASCII = enable
}
func (p *IntcodeProgram) FeedInputString(str string) {
p.feedInput = make([]rune, len(str))
copy(p.feedInput, []rune(str))
}

View File

@ -15,3 +15,13 @@ func MapValues[T comparable, U any](m map[T]U) []U {
}
return r
}
// CopyMap returns a copy of the passed-in map. Note: currently only works if [U]
// is not a map or slice.
func CopyMap[T comparable, U any](m map[T]U) map[T]U {
r := make(map[T]U)
for k, v := range m {
r[k] = v
}
return r
}

View File

@ -44,11 +44,16 @@ func (v Vec2[T]) Equals(other Vec2[T]) bool {
v.Y == other.Y
}
func (v Vec2[T]) ManhattanDistance(other Vec2[T]) T {
return T(math.Abs(float64(v.X-other.X)) + math.Abs(float64(v.Y-other.Y)))
}
func VecBetween[T Number](a, b Vec2[T]) Vec2[T] {
return Vec2[T]{
X: a.X - b.X,
Y: a.Y - b.Y,
}
return a.To(b)
}
func ManhattanDistance[T Number](a, b Vec2[T]) T {
return a.ManhattanDistance(b)
}
func (v Vec3[T]) Dot(other Vec3[T]) T {