adventofcode/2020/day11/main.go

264 lines
4.7 KiB
Go

package main
import (
"fmt"
h "git.bullercodeworks.com/brian/adventofcode/helpers"
)
const (
EMPTY = 'L'
FULL = '#'
FLOOR = '.'
N = iota
NE
E
SE
S
SW
W
NW
)
func main() {
fmt.Println("# Day 11")
inp := h.StdinToStringSlice()
pt := h.GetArgNumber(1)
if pt == "1" {
part1(inp)
} else {
part2(inp)
}
}
func part1(inp []string) {
fmt.Println("## Part 1")
w := BuildWaitingRoom(inp)
var last string
for w.String() != last {
last = w.String()
w.Tick()
}
fmt.Println(w)
fmt.Printf("At stabilization there are %d occupied seats\n", w.OccupiedSeats())
}
func part2(inp []string) {
fmt.Println("## Part 2")
w := BuildWaitingRoom(inp)
var last string
for w.String() != last {
last = w.String()
w.VisibleTick()
}
fmt.Println(w)
fmt.Printf("At stabilization there are %d occupied seats\n", w.OccupiedSeats())
}
type WaitingRoom struct {
Layout map[h.Coordinate]byte
NorthMost int
SouthMost int
EastMost int
WestMost int
}
func BuildWaitingRoom(inp []string) *WaitingRoom {
ret := WaitingRoom{
Layout: make(map[h.Coordinate]byte),
NorthMost: h.MAX_INT,
SouthMost: h.MIN_INT,
EastMost: h.MIN_INT,
WestMost: h.MAX_INT,
}
for y := range inp {
for x := range inp[y] {
ret.Layout[h.Coordinate{X: x, Y: y}] = inp[y][x]
if x < ret.WestMost {
ret.WestMost = x
}
if x > ret.EastMost {
ret.EastMost = x
}
}
if y < ret.NorthMost {
ret.NorthMost = y
}
if y > ret.SouthMost {
ret.SouthMost = y
}
}
return &ret
}
func (w *WaitingRoom) OccupiedSeats() int {
var ret int
for k := range w.Layout {
if !w.CoordEmpty(k) {
ret++
}
}
return ret
}
func (w *WaitingRoom) CoordEmpty(c h.Coordinate) bool {
return w.Layout[c] != FULL
}
func (w *WaitingRoom) ShouldFill(c h.Coordinate) bool {
if w.Layout[c] == FULL || w.Layout[c] == FLOOR {
return false
}
return w.CoordEmpty(c.North()) && w.CoordEmpty(c.NE()) && w.CoordEmpty(c.East()) && w.CoordEmpty(c.SE()) && w.CoordEmpty(c.South()) && w.CoordEmpty(c.SW()) && w.CoordEmpty(c.West()) && w.CoordEmpty(c.NW())
}
func (w *WaitingRoom) ShouldEmpty(c h.Coordinate) bool {
if w.Layout[c] == EMPTY || w.Layout[c] == FLOOR {
return false
}
var fullSeats int
for _, v := range []h.Coordinate{c.North(), c.NE(), c.East(), c.SE(), c.South(), c.SW(), c.West(), c.NW()} {
if !w.CoordEmpty(v) {
fullSeats++
if fullSeats >= 4 {
return true
}
}
}
return false
}
func (w *WaitingRoom) Tick() {
wrk := make(map[h.Coordinate]byte)
for k := range w.Layout {
wrk[k] = w.Layout[k]
switch w.Layout[k] {
case EMPTY:
if w.ShouldFill(k) {
wrk[k] = FULL
}
case FULL:
if w.ShouldEmpty(k) {
wrk[k] = EMPTY
}
}
}
for k := range wrk {
w.Layout[k] = wrk[k]
}
}
func (w *WaitingRoom) IsFloor(c h.Coordinate) bool {
return w.Layout[c] == FLOOR
}
func (w *WaitingRoom) GetCoordInDir(c h.Coordinate, dir int) h.Coordinate {
switch dir {
case N:
return c.North()
case NE:
return c.NE()
case E:
return c.East()
case SE:
return c.SE()
case S:
return c.South()
case SW:
return c.SW()
case W:
return c.West()
case NW:
return c.NW()
}
return c
}
func (w *WaitingRoom) DirectionEmpty(c h.Coordinate, dir int) bool {
c = w.GetCoordInDir(c, dir)
for w.IsFloor(c) {
c = w.GetCoordInDir(c, dir)
}
return w.CoordEmpty(c)
}
func (w *WaitingRoom) VisibleShouldFill(c h.Coordinate) bool {
if w.Layout[c] == FULL || w.Layout[c] == FLOOR {
return false
}
return w.DirectionEmpty(c, N) && w.DirectionEmpty(c, NE) && w.DirectionEmpty(c, E) && w.DirectionEmpty(c, SE) && w.DirectionEmpty(c, S) && w.DirectionEmpty(c, SW) && w.DirectionEmpty(c, W) && w.DirectionEmpty(c, NW)
}
func (w *WaitingRoom) VisibleShouldEmpty(c h.Coordinate) bool {
if w.Layout[c] == EMPTY || w.Layout[c] == FLOOR {
return false
}
var fullSeats int
for _, v := range []int{N, NE, E, SE, S, SW, W, NW} {
if !w.DirectionEmpty(c, v) {
fullSeats++
if fullSeats >= 5 {
return true
}
}
}
return false
}
func (w *WaitingRoom) VisibleTick() {
wrk := make(map[h.Coordinate]byte)
for k := range w.Layout {
wrk[k] = w.Layout[k]
switch w.Layout[k] {
case EMPTY:
if w.VisibleShouldFill(k) {
wrk[k] = FULL
}
case FULL:
if w.VisibleShouldEmpty(k) {
wrk[k] = EMPTY
}
}
}
for k := range wrk {
w.Layout[k] = wrk[k]
}
}
func (w WaitingRoom) String() string {
var ret string
for y := w.NorthMost; y <= w.SouthMost; y++ {
for x := w.WestMost; x <= w.EastMost; x++ {
ret = ret + string(w.Layout[h.Coordinate{X: x, Y: y}])
}
ret = ret + "\n"
}
return ret
}
func DirToStr(dir int) string {
switch dir {
case N:
return "N"
case NE:
return "NE"
case E:
return "E"
case SE:
return "SE"
case S:
return "S"
case SW:
return "SW"
case W:
return "W"
case NW:
return "NW"
}
return "-"
}