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 "-" }