diff --git a/day22/common/forcefield.go b/day22/common/forcefield.go new file mode 100644 index 0000000..dcfc6ed --- /dev/null +++ b/day22/common/forcefield.go @@ -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 +} diff --git a/day22/ex1/main.go b/day22/ex1/main.go new file mode 100644 index 0000000..c5d7feb --- /dev/null +++ b/day22/ex1/main.go @@ -0,0 +1,18 @@ +package main + +import ( + "aoc2022/day22/common" + "bufio" + "fmt" + "os" +) + +func main() { + tileMap, instructions := common.Parse(*bufio.NewScanner(os.Stdin), false) + + for _, instruction := range instructions { + instruction.Apply(&tileMap) + } + + fmt.Println(tileMap.GetPassword()) +} diff --git a/day22/ex2/main.go b/day22/ex2/main.go new file mode 100644 index 0000000..5a96c34 --- /dev/null +++ b/day22/ex2/main.go @@ -0,0 +1,18 @@ +package main + +import ( + "aoc2022/day22/common" + "bufio" + "fmt" + "os" +) + +func main() { + tileMap, instructions := common.Parse(*bufio.NewScanner(os.Stdin), true) + + for _, instruction := range instructions { + instruction.Apply(&tileMap) + } + + fmt.Println(tileMap.GetPassword()) +}