This commit is contained in:
2022-12-22 14:18:12 +01:00
parent dc8232fee3
commit dd56a59f48
3 changed files with 369 additions and 0 deletions

333
day22/common/forcefield.go Normal file
View File

@@ -0,0 +1,333 @@
package common
import (
"bufio"
"strconv"
)
type Tile byte
const (
None Tile = iota
Empty
Wall
)
type Direction byte
const (
East Direction = iota
West
North
South
)
type Traveler struct {
facing Direction
x int
y int
}
type Map struct {
tiles [][]Tile
traveler Traveler
isCubic bool
}
func (tileMap *Map) GetNextTile() (int, int, Direction) {
nextX := tileMap.traveler.x
nextY := tileMap.traveler.y
nextDirection := tileMap.traveler.facing
switch nextDirection {
case East:
if nextX + 1 < len(tileMap.tiles[nextY]) && tileMap.tiles[nextY][nextX+1] == Empty {
nextX++
} else if nextX + 1 == len(tileMap.tiles[nextY]) || tileMap.tiles[nextY][nextX+1] == None {
if tileMap.isCubic {
if nextX == 149 {
if tileMap.tiles[149-nextY][99] == Empty {
nextX = 99
nextY = 149 - nextY
nextDirection = West
}
} else if nextX == 99 && nextY < 100 {
if tileMap.tiles[49][nextY+50] == Empty {
nextX = nextY + 50
nextY = 49
nextDirection = North
}
} else if nextX == 99 {
if tileMap.tiles[149-nextY][149] == Empty {
nextX = 149
nextY = 149 - nextY
nextDirection = West
}
} else {
if tileMap.tiles[149][nextY-100] == Empty {
nextX = nextY - 100
nextY = 149
nextDirection = North
}
}
} else {
for i := 0; i < len(tileMap.tiles[nextY]); i++ {
if tileMap.tiles[nextY][i] != None {
if tileMap.tiles[nextY][i] == Empty {
nextX = i
}
break
}
}
}
}
case West:
if nextX - 1 >= 0 && tileMap.tiles[nextY][nextX-1] == Empty {
nextX--
} else if nextX - 1 < 0 || tileMap.tiles[nextY][nextX-1] == None {
if tileMap.isCubic {
if nextX == 50 && nextY < 50 {
if tileMap.tiles[149-nextY][0] == Empty {
nextX = 0
nextY = 149 - nextY
nextDirection = East
}
} else if nextX == 50 {
if tileMap.tiles[100][nextY-50] == Empty {
nextX = nextY - 50
nextY = 100
nextDirection = South
}
} else if nextY < 150 {
if tileMap.tiles[149-nextY][50] == Empty {
nextX = 50
nextY = 149 - nextY
nextDirection = East
}
} else {
if tileMap.tiles[0][nextY-100] == Empty {
nextX = nextY - 100
nextY = 0
nextDirection = South
}
}
} else {
for i := len(tileMap.tiles[nextY]) - 1; i >= 0; i-- {
if tileMap.tiles[nextY][i] != None {
if tileMap.tiles[nextY][i] == Empty {
nextX = i
}
break
}
}
}
}
case North:
if nextY - 1 >= 0 && tileMap.tiles[nextY-1][nextX] == Empty {
nextY--
} else if nextY - 1 < 0 || tileMap.tiles[nextY-1][nextX] == None {
if tileMap.isCubic {
if nextX < 50 {
if tileMap.tiles[nextX+50][50] == Empty {
nextY = nextX + 50
nextX = 50
nextDirection = East
}
} else if nextX < 100 {
if tileMap.tiles[nextX+100][0] == Empty {
nextY = nextX + 100
nextX = 0
nextDirection = East
}
} else {
if tileMap.tiles[199][nextX-100] == Empty {
nextX = nextX - 100
nextY = 199
}
}
} else {
for i := len(tileMap.tiles) - 1; i >= 0; i-- {
if tileMap.tiles[i][nextX] != None {
if tileMap.tiles[i][nextX] == Empty {
nextY = i
}
break
}
}
}
}
case South:
if nextY + 1 < len(tileMap.tiles) && tileMap.tiles[nextY+1][nextX] == Empty {
nextY++
} else if nextY + 1 == len(tileMap.tiles) || tileMap.tiles[nextY+1][nextX] == None {
if tileMap.isCubic {
if nextX < 50 {
if tileMap.tiles[0][nextX+100] == Empty {
nextX = nextX + 100
nextY = 0
}
} else if nextX < 100 {
if tileMap.tiles[nextX+100][49] == Empty {
nextY = nextX + 100
nextX = 49
nextDirection = West
}
} else {
if tileMap.tiles[nextX-50][99] == Empty {
nextY = nextX - 50
nextX = 99
nextDirection = West
}
}
} else {
for i := 0; i < len(tileMap.tiles); i++ {
if tileMap.tiles[i][nextX] != None {
if tileMap.tiles[i][nextX] == Empty {
nextY = i
}
break
}
}
}
}
}
return nextX, nextY, nextDirection
}
func (tileMap *Map) GetPassword() int {
password := 1000 * (tileMap.traveler.y + 1) + 4 * (tileMap.traveler.x + 1)
switch tileMap.traveler.facing {
case South:
password += 1
case West:
password += 2
case North:
password += 3
}
return password
}
type Instruction interface {
Apply(*Map)
}
type Move struct {
nTiles int
}
func (instruction Move) Apply(tileMap *Map) {
for i := 0; i < instruction.nTiles; i++ {
nextX, nextY, nextDirection := tileMap.GetNextTile()
tileMap.traveler.x = nextX
tileMap.traveler.y = nextY
tileMap.traveler.facing = nextDirection
}
}
type RotateClockwise struct {}
func (instruction RotateClockwise) Apply(tileMap *Map) {
switch tileMap.traveler.facing {
case East:
tileMap.traveler.facing = South
case South:
tileMap.traveler.facing = West
case West:
tileMap.traveler.facing = North
case North:
tileMap.traveler.facing = East
}
}
type RotateCounterclockwise struct {}
func (instruction RotateCounterclockwise) Apply(tileMap *Map) {
switch tileMap.traveler.facing {
case East:
tileMap.traveler.facing = North
case South:
tileMap.traveler.facing = East
case West:
tileMap.traveler.facing = South
case North:
tileMap.traveler.facing = West
}
}
func Parse(scanner bufio.Scanner, isCubic bool) (Map, []Instruction) {
tileMap := Map{}
instructions := []Instruction{}
longestRow := 0
for scanner.Scan() {
line := scanner.Text()
if line == "" {
scanner.Scan()
line := scanner.Text()
for i := 0; i < len(line); i++ {
if line[i] >= '0' && line[i] <= '9' {
j := i
for j < len(line) && line[j] >= '0' && line[j] <= '9' {
j++
}
nTiles, _ := strconv.Atoi(line[i:j])
instructions = append(instructions, Move{nTiles})
i = j - 1
} else if line[i] == 'L' {
instructions = append(instructions, RotateCounterclockwise{})
} else if line[i] == 'R' {
instructions = append(instructions, RotateClockwise{})
}
}
} else {
if len(line) > longestRow {
longestRow = len(line)
}
tileRow := make([]Tile, len(line))
for i := range line {
switch line[i] {
case ' ':
tileRow[i] = None
case '.':
tileRow[i] = Empty
case '#':
tileRow[i] = Wall
}
}
tileMap.tiles = append(tileMap.tiles, tileRow)
}
}
for i := range tileMap.tiles {
for len(tileMap.tiles[i]) < longestRow {
tileMap.tiles[i] = append(tileMap.tiles[i], None)
}
}
for i := range tileMap.tiles[0] {
if tileMap.tiles[0][i] == Empty {
tileMap.traveler = Traveler{East, i, 0}
break
}
}
tileMap.isCubic = isCubic
return tileMap, instructions
}