This commit is contained in:
2022-12-23 14:01:40 +01:00
parent dd56a59f48
commit 43ebc47a01
3 changed files with 266 additions and 0 deletions

228
day23/common/seeds.go Normal file
View File

@@ -0,0 +1,228 @@
package common
import (
"bufio"
"fmt"
"math"
)
type Tile byte
const (
Empty Tile = iota
Elf
)
type Direction byte
const (
East Direction = iota
West
North
South
)
func (direction Direction) GetNext() Direction {
switch direction {
case North:
return South
case South:
return West
case West:
return East
default:
return North
}
}
type Coordinates struct {
x int
y int
}
type Map struct {
tiles map[Coordinates]Tile
currentRound Direction
boundedCoordinates []Coordinates
}
func (tileMap *Map) Round() bool {
nextCoordinates := map[Coordinates][]Coordinates{}
isFinalRound := true
for coordinates, tile := range tileMap.tiles {
if tile == Elf {
neighbor := false
outer:
for i := -1; i <= 1; i++ {
for j := -1; j <= 1; j++ {
if i != 0 || j != 0 {
if tile, ok := tileMap.tiles[Coordinates{coordinates.x+i, coordinates.y+j}]; ok && tile == Elf {
neighbor = true
break outer
}
}
}
}
if !neighbor {
continue
}
var nextC Coordinates
round := tileMap.currentRound
move := false
loop:
for i := 0; i < 4; i++ {
switch round {
case North:
tile1, ok1 := tileMap.tiles[Coordinates{coordinates.x-1, coordinates.y-1}]
tile2, ok2 := tileMap.tiles[Coordinates{coordinates.x, coordinates.y-1}]
tile3, ok3 := tileMap.tiles[Coordinates{coordinates.x+1, coordinates.y-1}]
nextC = Coordinates{coordinates.x, coordinates.y-1}
if (!ok1 || tile1 == Empty) && (!ok2 || tile2 == Empty) && (!ok3 || tile3 == Empty) {
move = true
break loop
}
case South:
tile1, ok1 := tileMap.tiles[Coordinates{coordinates.x-1, coordinates.y+1}]
tile2, ok2 := tileMap.tiles[Coordinates{coordinates.x, coordinates.y+1}]
tile3, ok3 := tileMap.tiles[Coordinates{coordinates.x+1, coordinates.y+1}]
nextC = Coordinates{coordinates.x, coordinates.y+1}
if (!ok1 || tile1 == Empty) && (!ok2 || tile2 == Empty) && (!ok3 || tile3 == Empty) {
move = true
break loop
}
case West:
tile1, ok1 := tileMap.tiles[Coordinates{coordinates.x-1, coordinates.y-1}]
tile2, ok2 := tileMap.tiles[Coordinates{coordinates.x-1, coordinates.y}]
tile3, ok3 := tileMap.tiles[Coordinates{coordinates.x-1, coordinates.y+1}]
nextC = Coordinates{coordinates.x-1, coordinates.y}
if (!ok1 || tile1 == Empty) && (!ok2 || tile2 == Empty) && (!ok3 || tile3 == Empty) {
move = true
break loop
}
case East:
tile1, ok1 := tileMap.tiles[Coordinates{coordinates.x+1, coordinates.y-1}]
tile2, ok2 := tileMap.tiles[Coordinates{coordinates.x+1, coordinates.y}]
tile3, ok3 := tileMap.tiles[Coordinates{coordinates.x+1, coordinates.y+1}]
nextC = Coordinates{coordinates.x+1, coordinates.y}
if (!ok1 || tile1 == Empty) && (!ok2 || tile2 == Empty) && (!ok3 || tile3 == Empty) {
move = true
break loop
}
}
round = round.GetNext()
}
if move {
if _, okc := nextCoordinates[nextC]; !okc {
nextCoordinates[nextC] = []Coordinates{}
}
nextCoordinates[nextC] = append(nextCoordinates[nextC], coordinates)
}
}
}
for nextC := range nextCoordinates {
if len(nextCoordinates[nextC]) == 1 {
tileMap.tiles[nextCoordinates[nextC][0]] = Empty
tileMap.tiles[nextC] = Elf
isFinalRound = false
}
}
tileMap.currentRound = tileMap.currentRound.GetNext()
return isFinalRound
}
func (tileMap *Map) GetEmpty() int {
nEmpty := 0
for x := tileMap.boundedCoordinates[0].x; x <= tileMap.boundedCoordinates[1].x; x++ {
for y := tileMap.boundedCoordinates[0].y; y <= tileMap.boundedCoordinates[1].y; y++ {
if tileMap.tiles[Coordinates{x, y}] == Empty {
nEmpty++
}
}
}
return nEmpty
}
func (tileMap *Map) Bound() {
minX := math.MaxInt32
minY := math.MaxInt32
maxX := math.MinInt32
maxY := math.MinInt32
for coordinates, tile := range tileMap.tiles {
if tile == Elf {
if coordinates.x < minX {
minX = coordinates.x
}
if coordinates.x > maxX {
maxX = coordinates.x
}
if coordinates.y < minY {
minY = coordinates.y
}
if coordinates.y > maxY {
maxY = coordinates.y
}
}
}
tileMap.boundedCoordinates = []Coordinates{{minX, minY}, {maxX, maxY}}
for x := minX; x <= maxX; x++ {
for y := minY; y <= maxY; y++ {
c := Coordinates{x, y}
if _, ok := tileMap.tiles[c]; !ok {
tileMap.tiles[c] = Empty
}
}
}
}
func (tileMap *Map) Print() {
for y := tileMap.boundedCoordinates[0].y; y <= tileMap.boundedCoordinates[1].y; y++ {
for x := tileMap.boundedCoordinates[0].x; x <= tileMap.boundedCoordinates[1].x; x++ {
switch tileMap.tiles[Coordinates{x, y}] {
case Empty:
fmt.Print(".")
case Elf:
fmt.Print("#")
}
}
fmt.Println()
}
}
func Parse(scanner bufio.Scanner) Map {
tileMap := Map{}
tileMap.tiles = make(map[Coordinates]Tile)
i := 0
for scanner.Scan() {
line := scanner.Text()
for j := range line {
switch line[j] {
case '.':
tileMap.tiles[Coordinates{j, i}] = Empty
case '#':
tileMap.tiles[Coordinates{j, i}] = Elf
}
}
i++
}
tileMap.currentRound = North
return tileMap
}