The last remaining bit is to scan the instructions array for groups of consecutive entries. My current plan is to start with probably 4 instructions and scan forward for the same consecutive set occurring again; if the count of other occurrences ever dips below 3, drop the most recently added set of 2 and pull the remaining entries into program A. Then repeat for programs B and C, and check that the list of instructions is now empty. Finally, compare each chunk successively to the full string of instructions to produce some combination of A,B,Cs to satisfy the requirements, and feed all that into the program's inputs.
277 lines
5.9 KiB
Go
277 lines
5.9 KiB
Go
package days
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
|
|
u "parnic.com/aoc2019/utilities"
|
|
)
|
|
|
|
type camViewCellType int
|
|
type botFacing int
|
|
|
|
const (
|
|
cellTypeScaffold camViewCellType = iota
|
|
cellTypeOpen
|
|
cellTypeInvalid
|
|
)
|
|
|
|
const (
|
|
botFacingUp botFacing = iota
|
|
botFacingLeft
|
|
botFacingDown
|
|
botFacingRight
|
|
|
|
botFacingFirst = botFacingUp
|
|
botFacingLast = botFacingRight
|
|
)
|
|
|
|
const (
|
|
dirLeft dirType = 1
|
|
dirRight dirType = -1
|
|
)
|
|
|
|
var (
|
|
day17AdjacentOffsets = []u.Vec2i{
|
|
{X: -1, Y: 0},
|
|
{X: 1, Y: 0},
|
|
{X: 0, Y: -1},
|
|
{X: 0, Y: 1},
|
|
}
|
|
)
|
|
|
|
type Day17 struct {
|
|
program u.IntcodeProgram
|
|
grid [][]camViewCellType
|
|
botLocation u.Vec2i
|
|
botFacingDir botFacing
|
|
endLocation u.Vec2i
|
|
}
|
|
|
|
func (d *Day17) Parse() {
|
|
d.program = u.LoadIntcodeProgram("17p")
|
|
d.grid = [][]camViewCellType{{}}
|
|
}
|
|
|
|
func (d Day17) Num() int {
|
|
return 17
|
|
}
|
|
|
|
func (d Day17) Draw() {
|
|
for y := range d.grid {
|
|
for x := range d.grid[y] {
|
|
switch d.grid[y][x] {
|
|
case cellTypeOpen:
|
|
fmt.Print(" ")
|
|
case cellTypeScaffold:
|
|
char := "█"
|
|
color := u.ColorBlack
|
|
if d.botLocation.X == x && d.botLocation.Y == y {
|
|
switch d.botFacingDir {
|
|
case botFacingUp:
|
|
char = "^"
|
|
case botFacingLeft:
|
|
char = "<"
|
|
case botFacingDown:
|
|
char = "v"
|
|
case botFacingRight:
|
|
char = ">"
|
|
}
|
|
} else if d.endLocation.X == x && d.endLocation.Y == y {
|
|
char = "@"
|
|
} else {
|
|
color = u.ColorWhite
|
|
}
|
|
fmt.Printf("%s%s%s%s", u.BackgroundWhite, color, char, u.TextReset)
|
|
}
|
|
}
|
|
fmt.Println()
|
|
}
|
|
}
|
|
|
|
func (d Day17) getAdjacentScaffolds(y, x int) []u.Vec2i {
|
|
retval := make([]u.Vec2i, 0)
|
|
for _, offset := range day17AdjacentOffsets {
|
|
offY := y + offset.Y
|
|
offX := x + offset.X
|
|
if offY < 0 || offY >= len(d.grid) ||
|
|
offX < 0 || offX >= len(d.grid[0]) {
|
|
continue
|
|
}
|
|
|
|
if d.grid[offY][offX] == cellTypeScaffold {
|
|
retval = append(retval, u.Vec2i{X: offX, Y: offY})
|
|
}
|
|
}
|
|
|
|
return retval
|
|
}
|
|
|
|
func (d Day17) getNumSurroundingScaffolds(y, x int) int {
|
|
return len(d.getAdjacentScaffolds(y, x))
|
|
}
|
|
|
|
func (d Day17) forEachCellOfType(t camViewCellType, f func(y, x int)) {
|
|
for y := range d.grid {
|
|
for x := range d.grid[y] {
|
|
if d.grid[y][x] == t {
|
|
f(y, x)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func (d Day17) getNewFacingDir(currentDir botFacing, turnDir dirType) botFacing {
|
|
currentDir += botFacing(turnDir)
|
|
if currentDir < botFacingFirst {
|
|
currentDir = botFacingLast
|
|
} else if currentDir > botFacingLast {
|
|
currentDir = botFacingFirst
|
|
}
|
|
|
|
return currentDir
|
|
}
|
|
|
|
func (d Day17) getCellTypeInDirection(y, x int, facingDir botFacing) (camViewCellType, int, int) {
|
|
newX := x
|
|
newY := y
|
|
switch facingDir {
|
|
case botFacingUp:
|
|
newY--
|
|
case botFacingLeft:
|
|
newX--
|
|
case botFacingDown:
|
|
newY++
|
|
case botFacingRight:
|
|
newX++
|
|
}
|
|
|
|
if newY < 0 || newY >= len(d.grid) || newX < 0 || newX >= len(d.grid[0]) {
|
|
return cellTypeInvalid, newY, newX
|
|
}
|
|
|
|
return d.grid[newY][newX], newY, newX
|
|
}
|
|
|
|
func (d *Day17) Part1() string {
|
|
y := 0
|
|
d.program.RunIn(func(inputStep int) int64 {
|
|
return 0
|
|
}, func(val int64, state u.IntcodeProgramState) {
|
|
rVal := rune(val)
|
|
switch rVal {
|
|
case '\n':
|
|
y++
|
|
d.grid = append(d.grid, make([]camViewCellType, 0))
|
|
case '#':
|
|
d.grid[y] = append(d.grid[y], cellTypeScaffold)
|
|
case '.':
|
|
d.grid[y] = append(d.grid[y], cellTypeOpen)
|
|
case '^', '<', 'v', '>':
|
|
d.botLocation = u.Vec2i{X: len(d.grid[y]), Y: y}
|
|
d.grid[y] = append(d.grid[y], cellTypeScaffold)
|
|
switch rVal {
|
|
case '^':
|
|
d.botFacingDir = botFacingUp
|
|
case '<':
|
|
d.botFacingDir = botFacingLeft
|
|
case 'v':
|
|
d.botFacingDir = botFacingDown
|
|
case '>':
|
|
d.botFacingDir = botFacingRight
|
|
}
|
|
}
|
|
})
|
|
|
|
for y := len(d.grid) - 1; y >= 0; y-- {
|
|
if len(d.grid[y]) == 0 {
|
|
d.grid = d.grid[0 : len(d.grid)-1]
|
|
}
|
|
}
|
|
|
|
alignmentParameterTotal := 0
|
|
d.forEachCellOfType(cellTypeScaffold, func(y, x int) {
|
|
if numSurrounding := d.getNumSurroundingScaffolds(y, x); numSurrounding == 4 {
|
|
alignmentParameterTotal += y * x
|
|
} else if numSurrounding == 1 {
|
|
if d.botLocation.X != x || d.botLocation.Y != y {
|
|
d.endLocation = u.Vec2i{X: x, Y: y}
|
|
}
|
|
}
|
|
})
|
|
|
|
// d.Draw()
|
|
|
|
return fmt.Sprintf("Alignment parameter sum: %s%d%s", u.TextBold, alignmentParameterTotal, u.TextReset)
|
|
}
|
|
|
|
func (d *Day17) Part2() string {
|
|
instructions := make([]string, 0)
|
|
|
|
pos := d.botLocation
|
|
botFacingDir := d.botFacingDir
|
|
for {
|
|
if pos == d.endLocation {
|
|
fmt.Println()
|
|
break
|
|
}
|
|
|
|
adj := d.getAdjacentScaffolds(pos.Y, pos.X)
|
|
turnDirection := dirType(0)
|
|
if botFacingDir == botFacingUp || botFacingDir == botFacingDown {
|
|
if u.ArrayContains(adj, u.Vec2i{X: pos.X - 1, Y: pos.Y}) {
|
|
if botFacingDir == botFacingUp {
|
|
turnDirection = dirLeft
|
|
} else if botFacingDir == botFacingDown {
|
|
turnDirection = dirRight
|
|
}
|
|
} else if u.ArrayContains(adj, u.Vec2i{X: pos.X + 1, Y: pos.Y}) {
|
|
if botFacingDir == botFacingUp {
|
|
turnDirection = dirRight
|
|
} else if botFacingDir == botFacingDown {
|
|
turnDirection = dirLeft
|
|
}
|
|
}
|
|
} else {
|
|
if u.ArrayContains(adj, u.Vec2i{X: pos.X, Y: pos.Y - 1}) {
|
|
if botFacingDir == botFacingLeft {
|
|
turnDirection = dirRight
|
|
} else if botFacingDir == botFacingRight {
|
|
turnDirection = dirLeft
|
|
}
|
|
} else if u.ArrayContains(adj, u.Vec2i{X: pos.X, Y: pos.Y + 1}) {
|
|
if botFacingDir == botFacingLeft {
|
|
turnDirection = dirLeft
|
|
} else if botFacingDir == botFacingRight {
|
|
turnDirection = dirRight
|
|
}
|
|
}
|
|
}
|
|
|
|
if turnDirection == 0 {
|
|
panic("at an invalid location somehow")
|
|
}
|
|
|
|
dirAscii := "L"
|
|
if turnDirection == dirRight {
|
|
dirAscii = "R"
|
|
}
|
|
instructions = append(instructions, dirAscii)
|
|
|
|
botFacingDir = d.getNewFacingDir(botFacingDir, turnDirection)
|
|
numMoved := 0
|
|
for {
|
|
cell, newY, newX := d.getCellTypeInDirection(pos.Y, pos.X, botFacingDir)
|
|
if cell != cellTypeScaffold {
|
|
break
|
|
}
|
|
pos.X = newX
|
|
pos.Y = newY
|
|
numMoved++
|
|
}
|
|
instructions = append(instructions, fmt.Sprintf("%d", numMoved))
|
|
}
|
|
|
|
return fmt.Sprintf("%s%s%s", u.TextBold, strings.Join(instructions, ","), u.TextReset)
|
|
}
|