264 lines
4.7 KiB
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 "-"
|
|
}
|