143 lines
3.1 KiB
Go
143 lines
3.1 KiB
Go
|
package main
|
||
|
|
||
|
import (
|
||
|
"AoC2020/helper"
|
||
|
"fmt"
|
||
|
"os"
|
||
|
)
|
||
|
|
||
|
func main() {
|
||
|
args := os.Args[1:]
|
||
|
input, err := helper.GetInput(args[0])
|
||
|
if err != nil {
|
||
|
fmt.Println(err)
|
||
|
}
|
||
|
fields := setFields(input)
|
||
|
printFields(fields)
|
||
|
fmt.Println(countOccupiedSeat(runMachine(fields, getOcuupiedNeighbours, 4)))
|
||
|
fmt.Println(countOccupiedSeat(runMachine(fields, getOccupiedVisibleSeats, 5)))
|
||
|
}
|
||
|
|
||
|
func runMachine(field [][]rune, neighbourFunction func(int, int, [][]rune) int, maxOccupied int) [][]rune {
|
||
|
changed := true
|
||
|
for changed {
|
||
|
newField := run(field, neighbourFunction, maxOccupied)
|
||
|
changed = !fieldsEqual(newField, field)
|
||
|
field = newField
|
||
|
}
|
||
|
return field
|
||
|
}
|
||
|
|
||
|
func run(fields [][]rune, neighbourFunction func(int, int, [][]rune) int, maxOccupied int) [][]rune {
|
||
|
var newField = make([][]rune, len(fields))
|
||
|
for i, _ := range newField {
|
||
|
newField[i] = make([]rune, len(fields[0]))
|
||
|
copy(newField[i], fields[i])
|
||
|
}
|
||
|
for i := 0; i < len(fields[0]); i++ {
|
||
|
for j := 0; j < len(fields); j++ {
|
||
|
if fields[j][i] == 'L' && neighbourFunction(i, j, fields) == 0 {
|
||
|
newField[j][i] = '#'
|
||
|
}
|
||
|
if fields[j][i] == '#' && neighbourFunction(i, j, fields) >= maxOccupied {
|
||
|
newField[j][i] = 'L'
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return newField
|
||
|
}
|
||
|
|
||
|
func fieldsEqual(field1 [][]rune, field2 [][]rune) bool {
|
||
|
for i := 0; i < len(field1[0]); i++ {
|
||
|
for j := 0; j < len(field1); j++ {
|
||
|
if field1[j][i] != field2[j][i] {
|
||
|
return false
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return true
|
||
|
}
|
||
|
|
||
|
func getOcuupiedNeighbours(x int, y int, field [][]rune) int {
|
||
|
neighbours := [][]int{{x - 1, y - 1}, {x, y - 1}, {x + 1, y - 1}, {x + 1, y}, {x + 1, y + 1}, {x, y + 1}, {x - 1, y + 1}, {x - 1, y}}
|
||
|
count := 0
|
||
|
for _, val := range neighbours {
|
||
|
if isOccupied(val[0], val[1], field) {
|
||
|
count++
|
||
|
}
|
||
|
}
|
||
|
return count
|
||
|
}
|
||
|
|
||
|
func getOccupiedVisibleSeats(x int, y int, field [][]rune) int {
|
||
|
directions := [][]int{{-1, -1}, {0,-1}, {1,-1}, {+1, 0}, {1,1}, {0,1}, {-1,1}, {-1, 0}}
|
||
|
count := 0
|
||
|
for _, val := range directions {
|
||
|
if getVisibleSeat(x, y, val, field) == '#' {
|
||
|
count++
|
||
|
}
|
||
|
}
|
||
|
return count
|
||
|
}
|
||
|
|
||
|
func getVisibleSeat(x int, y int, direction []int, field [][]rune) rune {
|
||
|
px := x + direction[0]
|
||
|
py := y + direction[1]
|
||
|
for py < len(field) && py >= 0 && px < len(field[0]) && px >= 0 {
|
||
|
if field[py][px] != '.' {
|
||
|
return field[py][px]
|
||
|
}
|
||
|
px += direction[0]
|
||
|
py += direction[1]
|
||
|
}
|
||
|
return '.'
|
||
|
}
|
||
|
|
||
|
func isOccupied(x int, y int, field [][]rune) bool {
|
||
|
if y > len(field)-1 || y < 0 {
|
||
|
return false
|
||
|
}
|
||
|
if x > len(field[0])-1 || x < 0 {
|
||
|
return false
|
||
|
}
|
||
|
if field[y][x] == 35 {
|
||
|
return true
|
||
|
}
|
||
|
return false
|
||
|
}
|
||
|
|
||
|
func printFields(fields [][]rune) {
|
||
|
for _, val := range fields {
|
||
|
fmt.Println(string(val))
|
||
|
}
|
||
|
fmt.Println()
|
||
|
}
|
||
|
|
||
|
func setFields(input []string) [][]rune {
|
||
|
var field = make([][]rune, len(input))
|
||
|
for i, val := range input {
|
||
|
field[i] = stringToRuneArr(val)
|
||
|
}
|
||
|
return field
|
||
|
}
|
||
|
|
||
|
func stringToRuneArr(input string) []rune {
|
||
|
var arr = make([]rune, len(input))
|
||
|
for i, val := range input {
|
||
|
arr[i] = val
|
||
|
}
|
||
|
return arr
|
||
|
}
|
||
|
|
||
|
func countOccupiedSeat(field [][]rune) int {
|
||
|
count := 0
|
||
|
for i := 0; i < len(field[0]); i++ {
|
||
|
for j := 0; j < len(field); j++ {
|
||
|
if field[j][i] == '#' {
|
||
|
count++
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return count
|
||
|
}
|