2022 Day 23 Complete
This commit is contained in:
202
2022/day22/input
Normal file
202
2022/day22/input
Normal file
File diff suppressed because one or more lines are too long
308
2022/day22/input-m
Normal file
308
2022/day22/input-m
Normal file
File diff suppressed because one or more lines are too long
422
2022/day22/main.go
Normal file
422
2022/day22/main.go
Normal file
@@ -0,0 +1,422 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
|
||||
h "git.bullercodeworks.com/brian/adventofcode/helpers"
|
||||
)
|
||||
|
||||
func main() {
|
||||
inp := h.StdinToStringSlice()
|
||||
//part1(inp)
|
||||
part2(inp)
|
||||
}
|
||||
func part1(inp []string) {
|
||||
board, inst := inp[:len(inp)-2], inp[len(inp)-1]
|
||||
b := BuildBoard(board)
|
||||
var count int
|
||||
var turn byte
|
||||
fmt.Println(b)
|
||||
fmt.Println(b.pos)
|
||||
for len(inst) > 0 {
|
||||
count, turn, inst = getNextInstructions(inst)
|
||||
b.Move(count)
|
||||
if turn == 'L' || turn == 'R' {
|
||||
b.Turn(turn)
|
||||
}
|
||||
}
|
||||
fmt.Println("Password:", b.Password())
|
||||
}
|
||||
|
||||
func part2(inp []string) {
|
||||
board, inst := inp[:len(inp)-2], inp[len(inp)-1]
|
||||
b := BuildCubeBoard(board)
|
||||
var count int
|
||||
var turn byte
|
||||
fmt.Println(b)
|
||||
fmt.Println(b.pos)
|
||||
for len(inst) > 0 {
|
||||
count, turn, inst = getNextInstructions(inst)
|
||||
b.Move(count)
|
||||
if turn == 'L' || turn == 'R' {
|
||||
b.Turn(turn)
|
||||
}
|
||||
}
|
||||
fmt.Println("Password:", b.Password())
|
||||
}
|
||||
|
||||
func getNextInstructions(inst string) (int, byte, string) {
|
||||
for i := range inst {
|
||||
if inst[i] == 'L' || inst[i] == 'R' {
|
||||
return h.Atoi(inst[:i]), inst[i], inst[i+1:]
|
||||
}
|
||||
}
|
||||
return h.Atoi(inst), 0, ""
|
||||
}
|
||||
|
||||
const (
|
||||
dirR = iota
|
||||
dirD
|
||||
dirL
|
||||
dirU
|
||||
dirErr
|
||||
|
||||
sideTop = iota
|
||||
sideBottom
|
||||
sideRight
|
||||
sideLeft
|
||||
sideFront
|
||||
sideBack
|
||||
)
|
||||
|
||||
type CubeBoard struct {
|
||||
Top *CubeBoardSide
|
||||
Bottom *CubeBoardSide
|
||||
Left *CubeBoardSide
|
||||
Right *CubeBoardSide
|
||||
Front *CubeBoardSide
|
||||
Back *CubeBoardSide
|
||||
|
||||
// Pos now holds:
|
||||
// y, x, dir, side
|
||||
pos []int
|
||||
}
|
||||
|
||||
// For the purposes of directions, we treat the board like this:
|
||||
// [T]
|
||||
// [B][L][F][R]
|
||||
// [B]
|
||||
// So up from left, front, back, and right are all top
|
||||
// Up from bottom is front
|
||||
// Down from bottom is back
|
||||
// Up from top is back
|
||||
// Down from top is front
|
||||
// So you can continually go left on the main level and circumnavigate the cube
|
||||
// Continually going up from anywhere will eventually get you bouncing between top and back
|
||||
// Continually going down from anywhere will eventually get you bouncing between bottom and back
|
||||
func BuildCubeBoard(inp []string) *CubeBoard {
|
||||
cb := CubeBoard{}
|
||||
var side string
|
||||
for i := 0; i < len(inp); i++ {
|
||||
if len(inp) == 0 {
|
||||
break
|
||||
}
|
||||
side = inp[i]
|
||||
i++
|
||||
cbs := BuildCubeBoardSide(inp[i : i+len(inp[i])])
|
||||
switch side {
|
||||
case "Top":
|
||||
cb.Top = cbs
|
||||
case "Bottom":
|
||||
cb.Bottom = cbs
|
||||
case "Left":
|
||||
cb.Left = cbs
|
||||
case "Right":
|
||||
cb.Right = cbs
|
||||
case "Front":
|
||||
cb.Front = cbs
|
||||
case "Back":
|
||||
cb.Back = cbs
|
||||
}
|
||||
i = i + cbs.Size() - 1
|
||||
}
|
||||
cb.pos = []int{0, 0, dirR, sideTop}
|
||||
return &cb
|
||||
}
|
||||
func (cb *CubeBoard) Size() int { return cb.Top.Size() }
|
||||
func (cb *CubeBoard) Move(count int) {
|
||||
|
||||
}
|
||||
func (cb *CubeBoard) GetPosUp() []int {
|
||||
y := cb.pos[0]
|
||||
x := cb.pos[1]
|
||||
dir := cb.pos[2]
|
||||
side := cb.pos[3]
|
||||
if y == 0 {
|
||||
// Going to another side
|
||||
switch side {
|
||||
case sideTop:
|
||||
side = sideBack
|
||||
case sideBottom:
|
||||
side = sideFront
|
||||
case sideFront:
|
||||
side = sideTop
|
||||
case sideBack:
|
||||
side = sideTop
|
||||
case sideLeft:
|
||||
side = sideTop
|
||||
case sideRight:
|
||||
side = sideTop
|
||||
}
|
||||
}
|
||||
return []int{y, x, dir, side}
|
||||
}
|
||||
func (cb *CubeBoard) GetPosDown() []int {
|
||||
y := cb.pos[0]
|
||||
x := cb.pos[1]
|
||||
dir := cb.pos[2]
|
||||
side := cb.pos[3]
|
||||
if y == cb.Size()-1 {
|
||||
// Going to another side
|
||||
switch side {
|
||||
case sideTop:
|
||||
side = sideFront
|
||||
case sideBottom:
|
||||
side = sideBack
|
||||
case sideFront:
|
||||
side = sideBottom
|
||||
case sideBack:
|
||||
side = sideBottom
|
||||
case sideLeft:
|
||||
side = sideBottom
|
||||
case sideRight:
|
||||
side = sideBottom
|
||||
}
|
||||
} else {
|
||||
y = y + 1
|
||||
}
|
||||
return []int{y, x, dir, side}
|
||||
}
|
||||
func (cb *CubeBoard) GetPosRight() []int {
|
||||
y := cb.pos[0]
|
||||
x := cb.pos[1]
|
||||
dir := cb.pos[2]
|
||||
side := cb.pos[3]
|
||||
if x == cb.Size()-1 {
|
||||
// Going to another side
|
||||
switch side {
|
||||
case sideTop:
|
||||
side = sideRight
|
||||
case sideBottom:
|
||||
side = sideRight
|
||||
case sideFront:
|
||||
side = sideRight
|
||||
case sideBack:
|
||||
side = sideLeft
|
||||
case sideLeft:
|
||||
side = sideFront
|
||||
case sideRight:
|
||||
side = sideBack
|
||||
}
|
||||
} else {
|
||||
y = y + 1
|
||||
}
|
||||
return []int{y, x, dir, side}
|
||||
}
|
||||
|
||||
// Get the current pos' side
|
||||
func (cb *CubeBoard) Side() *CubeBoardSide {
|
||||
switch cb.pos[3] {
|
||||
case sideTop:
|
||||
return cb.Top
|
||||
case sideBottom:
|
||||
return cb.Bottom
|
||||
case sideFront:
|
||||
return cb.Front
|
||||
case sideBack:
|
||||
return cb.Back
|
||||
case sideLeft:
|
||||
return cb.Left
|
||||
case sideRight:
|
||||
return cb.Right
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func (cb *CubeBoard) Turn(dir byte) {
|
||||
if dir == 'R' {
|
||||
cb.pos[2] = (cb.pos[2] + 1) % dirErr
|
||||
} else if dir == 'L' {
|
||||
cb.pos[2] = (cb.pos[2] - 1 + dirErr) % dirErr
|
||||
}
|
||||
}
|
||||
func (cb *CubeBoard) Tile(y, x, side int) byte {
|
||||
switch side {
|
||||
case sideTop:
|
||||
return cb.Top.Tile(y, x)
|
||||
case sideBottom:
|
||||
return cb.Bottom.Tile(y, x)
|
||||
case sideLeft:
|
||||
return cb.Left.Tile(y, x)
|
||||
case sideRight:
|
||||
return cb.Right.Tile(y, x)
|
||||
case sideFront:
|
||||
return cb.Front.Tile(y, x)
|
||||
case sideBack:
|
||||
return cb.Back.Tile(y, x)
|
||||
}
|
||||
return 0
|
||||
}
|
||||
func (cb *CubeBoard) Password() int {
|
||||
return 0
|
||||
}
|
||||
|
||||
type CubeBoardSide struct {
|
||||
spots [][]byte
|
||||
}
|
||||
|
||||
func BuildCubeBoardSide(inp []string) *CubeBoardSide {
|
||||
cbs := CubeBoardSide{}
|
||||
fmt.Println("Building CBS from:", inp)
|
||||
cbs.spots = make([][]byte, len(inp))
|
||||
for y := range inp {
|
||||
row := make([]byte, len(inp[y]))
|
||||
for x := range inp[y] {
|
||||
row[x] = inp[y][x]
|
||||
}
|
||||
cbs.spots[y] = row
|
||||
}
|
||||
return &cbs
|
||||
}
|
||||
func (cbs *CubeBoardSide) Size() int {
|
||||
return len(cbs.spots)
|
||||
}
|
||||
func (cbs *CubeBoardSide) Tile(y, x int) byte {
|
||||
if len(cbs.spots) < y && len(cbs.spots[y]) < x {
|
||||
return cbs.spots[y][x]
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
type Board struct {
|
||||
spots [][]byte
|
||||
// pos holds
|
||||
// y, x, dir
|
||||
pos []int
|
||||
}
|
||||
|
||||
func BuildBoard(inp []string) *Board {
|
||||
maxX := math.MinInt
|
||||
for y := range inp {
|
||||
maxX = h.Max(maxX, len(inp[y]))
|
||||
}
|
||||
b := Board{
|
||||
spots: make([][]byte, len(inp)),
|
||||
}
|
||||
for y := range inp {
|
||||
sl := make([]byte, maxX)
|
||||
for x := range inp[y] {
|
||||
sl[x] = inp[y][x]
|
||||
}
|
||||
b.spots[y] = sl
|
||||
}
|
||||
|
||||
b.pos = make([]int, 3)
|
||||
for x := range b.spots[0] {
|
||||
if b.spots[0][x] == '.' {
|
||||
b.pos = []int{0, x, dirR}
|
||||
break
|
||||
}
|
||||
}
|
||||
return &b
|
||||
}
|
||||
func (b *Board) Password() int {
|
||||
return ((b.pos[0] + 1) * 1000) + ((b.pos[1] + 1) * 4) + b.pos[2]
|
||||
}
|
||||
func (b *Board) Tile(y, x int) byte {
|
||||
if len(b.spots) > y && len(b.spots[y]) > x {
|
||||
return b.spots[y][x]
|
||||
}
|
||||
return 0
|
||||
}
|
||||
func (b *Board) GetNextPos() []int {
|
||||
switch b.pos[2] {
|
||||
case dirU:
|
||||
return b.GetPosUp()
|
||||
case dirR:
|
||||
return b.GetPosRight()
|
||||
case dirD:
|
||||
return b.GetPosDown()
|
||||
case dirL:
|
||||
return b.GetPosLeft()
|
||||
}
|
||||
return []int{-1, -1}
|
||||
}
|
||||
func (b *Board) GetPosUp() []int {
|
||||
x := b.pos[1]
|
||||
y := ((b.pos[0] - 1) + len(b.spots)) % len(b.spots)
|
||||
for (b.spots[y][x] == 0 || b.spots[y][x] == 32) && y != b.pos[0] {
|
||||
y = ((y - 1) + len(b.spots)) % len(b.spots)
|
||||
}
|
||||
return []int{y, x}
|
||||
}
|
||||
func (b *Board) GetPosRight() []int {
|
||||
y := b.pos[0]
|
||||
x := (b.pos[1] + 1) % len(b.spots[y])
|
||||
for (b.spots[y][x] == 0 || b.spots[y][x] == 32) && x != b.pos[1] {
|
||||
x = (x + 1) % len(b.spots[y])
|
||||
}
|
||||
return []int{y, x}
|
||||
}
|
||||
func (b *Board) GetPosDown() []int {
|
||||
x := b.pos[1]
|
||||
y := (b.pos[0] + 1) % len(b.spots)
|
||||
for (b.spots[y][x] == 0 || b.spots[y][x] == 32) && y != b.pos[0] {
|
||||
y = (y + 1) % len(b.spots)
|
||||
}
|
||||
return []int{y, x}
|
||||
}
|
||||
func (b *Board) GetPosLeft() []int {
|
||||
y := b.pos[0]
|
||||
x := ((b.pos[1] - 1) + len(b.spots[y])) % len(b.spots[y])
|
||||
for (b.spots[y][x] == 0 || b.spots[y][x] == 32) && x != b.pos[1] {
|
||||
x = ((x - 1) + len(b.spots[y])) % len(b.spots[y])
|
||||
}
|
||||
return []int{y, x}
|
||||
}
|
||||
|
||||
func (b *Board) Move(count int) {
|
||||
var to []int
|
||||
for count > 0 {
|
||||
switch b.pos[2] {
|
||||
case dirU:
|
||||
to = b.GetPosUp()
|
||||
case dirR:
|
||||
to = b.GetPosRight()
|
||||
case dirD:
|
||||
to = b.GetPosDown()
|
||||
case dirL:
|
||||
to = b.GetPosLeft()
|
||||
}
|
||||
if b.Tile(to[0], to[1]) == '.' {
|
||||
count--
|
||||
b.pos[0], b.pos[1] = to[0], to[1]
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (b *Board) Turn(dir byte) {
|
||||
if dir == 'R' {
|
||||
b.pos[2] = (b.pos[2] + 1) % dirErr
|
||||
} else if dir == 'L' {
|
||||
b.pos[2] = (b.pos[2] - 1 + dirErr) % dirErr
|
||||
}
|
||||
}
|
||||
|
||||
func (b Board) String() string {
|
||||
var ret string
|
||||
for y := range b.spots {
|
||||
for x := range b.spots[y] {
|
||||
bt := b.spots[y][x]
|
||||
if b.pos[1] == x && b.pos[0] == y {
|
||||
switch b.pos[2] {
|
||||
case dirU:
|
||||
bt = '^'
|
||||
case dirR:
|
||||
bt = '>'
|
||||
case dirD:
|
||||
bt = 'v'
|
||||
case dirL:
|
||||
bt = '<'
|
||||
default:
|
||||
bt = '!'
|
||||
}
|
||||
}
|
||||
ret = ret + fmt.Sprint(string(bt))
|
||||
}
|
||||
ret = ret + "\n"
|
||||
}
|
||||
return ret
|
||||
}
|
156
2022/day22/problem
Normal file
156
2022/day22/problem
Normal file
@@ -0,0 +1,156 @@
|
||||
Advent of Code
|
||||
|
||||
• [About]
|
||||
• [Events]
|
||||
• [Shop]
|
||||
• [Settings]
|
||||
• [Log Out]
|
||||
|
||||
br0xen (AoC++) 36*
|
||||
|
||||
var y=2022;
|
||||
|
||||
• [Calendar]
|
||||
• [AoC++]
|
||||
• [Sponsors]
|
||||
• [Leaderboard]
|
||||
• [Stats]
|
||||
|
||||
Our sponsors help make Advent of Code possible:
|
||||
Infi - De kerstman wil weer cadeaus bezorgen maar komt tot de ontdekking dat zijn
|
||||
Kerstman Positioning System (KPS) niet meer werkt. Kan jij hem helpen?
|
||||
|
||||
--- Day 22: Monkey Map ---
|
||||
|
||||
The monkeys take you on a surprisingly easy trail through the jungle. They're even
|
||||
going in roughly the right direction according to your handheld device's Grove
|
||||
Positioning System.
|
||||
|
||||
As you walk, the monkeys explain that the grove is protected by a force field. To pass
|
||||
through the force field, you have to enter a password; doing so involves tracing a
|
||||
specific path on a strangely-shaped board.
|
||||
|
||||
At least, you're pretty sure that's what you have to do; the elephants aren't exactly
|
||||
fluent in monkey.
|
||||
|
||||
The monkeys give you notes that they took when they last saw the password entered
|
||||
(your puzzle input).
|
||||
|
||||
For example:
|
||||
|
||||
...#
|
||||
.#..
|
||||
#...
|
||||
....
|
||||
...#.......#
|
||||
........#...
|
||||
..#....#....
|
||||
..........#.
|
||||
...#....
|
||||
.....#..
|
||||
.#......
|
||||
......#.
|
||||
|
||||
10R5L5R10L4R5L5
|
||||
|
||||
The first half of the monkeys' notes is a map of the board. It is comprised of a set
|
||||
of open tiles (on which you can move, drawn .) and solid walls (tiles which you cannot
|
||||
enter, drawn #).
|
||||
|
||||
The second half is a description of the path you must follow. It consists of
|
||||
alternating numbers and letters:
|
||||
|
||||
• A number indicates the number of tiles to move in the direction you are facing. If
|
||||
you run into a wall, you stop moving forward and continue with the next
|
||||
instruction.
|
||||
• A letter indicates whether to turn 90 degrees clockwise (R) or counterclockwise
|
||||
(L). Turning happens in-place; it does not change your current tile.
|
||||
|
||||
So, a path like 10R5 means "go forward 10 tiles, then turn clockwise 90 degrees, then
|
||||
go forward 5 tiles".
|
||||
|
||||
You begin the path in the leftmost open tile of the top row of tiles. Initially, you
|
||||
are facing to the right (from the perspective of how the map is drawn).
|
||||
|
||||
If a movement instruction would take you off of the map, you wrap around to the other
|
||||
side of the board. In other words, if your next tile is off of the board, you should
|
||||
instead look in the direction opposite of your current facing as far as you can until
|
||||
you find the opposite edge of the board, then reappear there.
|
||||
|
||||
For example, if you are at A and facing to the right, the tile in front of you is
|
||||
marked B; if you are at C and facing down, the tile in front of you is marked D:
|
||||
|
||||
...#
|
||||
.#..
|
||||
#...
|
||||
....
|
||||
...#.D.....#
|
||||
........#...
|
||||
B.#....#...A
|
||||
.....C....#.
|
||||
...#....
|
||||
.....#..
|
||||
.#......
|
||||
......#.
|
||||
|
||||
It is possible for the next tile (after wrapping around) to be a wall; this still
|
||||
counts as there being a wall in front of you, and so movement stops before you
|
||||
actually wrap to the other side of the board.
|
||||
|
||||
By drawing the last facing you had with an arrow on each tile you visit, the full path
|
||||
taken by the above example looks like this:
|
||||
|
||||
>>v#
|
||||
.#v.
|
||||
#.v.
|
||||
..v.
|
||||
...#...v..v#
|
||||
>>>v...>#.>>
|
||||
..#v...#....
|
||||
...>>>>v..#.
|
||||
...#....
|
||||
.....#..
|
||||
.#......
|
||||
......#.
|
||||
|
||||
To finish providing the password to this strange input device, you need to determine
|
||||
numbers for your final row, column, and facing as your final position appears from the
|
||||
perspective of the original map. Rows start from 1 at the top and count downward;
|
||||
columns start from 1 at the left and count rightward. (In the above example, row 1,
|
||||
column 1 refers to the empty space with no tile on it in the top-left corner.) Facing
|
||||
is 0 for right (>), 1 for down (v), 2 for left (<), and 3 for up (^). The final
|
||||
password is the sum of 1000 times the row, 4 times the column, and the facing.
|
||||
|
||||
In the above example, the final row is 6, the final column is 8, and the final facing
|
||||
is 0. So, the final password is 1000 * 6 + 4 * 8 + 0: 6032.
|
||||
|
||||
Follow the path given in the monkeys' notes. What is the final password?
|
||||
|
||||
To begin, get your puzzle input.
|
||||
|
||||
Answer: _____________________ [ [Submit] ]
|
||||
|
||||
You can also [Shareon Twitter Mastodon] this puzzle.
|
||||
|
||||
References
|
||||
|
||||
Visible links
|
||||
. https://adventofcode.com/
|
||||
. https://adventofcode.com/2022/about
|
||||
. https://adventofcode.com/2022/events
|
||||
. https://teespring.com/stores/advent-of-code
|
||||
. https://adventofcode.com/2022/settings
|
||||
. https://adventofcode.com/2022/auth/logout
|
||||
. Advent of Code Supporter
|
||||
https://adventofcode.com/2022/support
|
||||
. https://adventofcode.com/2022
|
||||
. https://adventofcode.com/2022
|
||||
. https://adventofcode.com/2022/support
|
||||
. https://adventofcode.com/2022/sponsors
|
||||
. https://adventofcode.com/2022/leaderboard
|
||||
. https://adventofcode.com/2022/stats
|
||||
. https://adventofcode.com/2022/sponsors
|
||||
. https://aoc.infi.nl/?mtm_campaign=aoc2022&mtm_source=aoc
|
||||
. https://adventofcode.com/2022/day/22/input
|
||||
. https://twitter.com/intent/tweet?text=%22Monkey+Map%22+%2D+Day+22+%2D+Advent+of+Code+2022&url=https%3A%2F%2Fadventofcode%2Ecom%2F2022%2Fday%2F22&related=ericwastl&hashtags=AdventOfCode
|
||||
. javascript:void(0);
|
14
2022/day22/testinput
Normal file
14
2022/day22/testinput
Normal file
@@ -0,0 +1,14 @@
|
||||
...#
|
||||
.#..
|
||||
#...
|
||||
....
|
||||
...#.......#
|
||||
........#...
|
||||
..#....#....
|
||||
..........#.
|
||||
...#....
|
||||
.....#..
|
||||
.#......
|
||||
......#.
|
||||
|
||||
10R5L5R10L4R5L5
|
32
2022/day22/testinput-m
Normal file
32
2022/day22/testinput-m
Normal file
@@ -0,0 +1,32 @@
|
||||
Top
|
||||
...#
|
||||
.#..
|
||||
#...
|
||||
....
|
||||
Back
|
||||
...#
|
||||
....
|
||||
..#.
|
||||
....
|
||||
Left
|
||||
....
|
||||
....
|
||||
...#
|
||||
....
|
||||
Front
|
||||
...#
|
||||
#...
|
||||
....
|
||||
..#.
|
||||
Bottom
|
||||
...#
|
||||
....
|
||||
.#..
|
||||
....
|
||||
Right
|
||||
....
|
||||
.#..
|
||||
....
|
||||
..#.
|
||||
|
||||
10R5L5R10L4R5L5
|
Reference in New Issue
Block a user