package main import ( "bufio" "fmt" "os" "time" ) func main() { start := time.Now() partOne() duration := time.Since(start) partTwo() duration2 := time.Since(start) fmt.Printf("p1: %s, p2: %s\n", duration, duration2-duration) } type cell struct { taken int // 1: someone there; 0: empty seat bool // t: seat available; f: open floor } type waitingRoom struct { seats [][]cell maxCol int maxRow int } func (w *waitingRoom) parseRow(s string) { row := []cell{} for _, r := range s { switch { case r == 'L': row = append(row, cell{taken: 0, seat: true}) case r == '.': row = append(row, cell{taken: 0, seat: false}) } } w.seats = append(w.seats, row) } func (w *waitingRoom) countNeighborsPartOne(row, col int) int { c := 0 if row-1 > -1 { c = c + w.seats[row-1][col].taken // north if col-1 > -1 { c = c + w.seats[row-1][col-1].taken // northwest } if col+1 < w.maxCol { c = c + w.seats[row-1][col+1].taken // northheast } } if row+1 < w.maxRow { c = c + w.seats[row+1][col].taken // south if col+1 < w.maxCol { c = c + w.seats[row+1][col+1].taken // southeast } if col-1 > -1 { c = c + w.seats[row+1][col-1].taken // southwest } } if col-1 > -1 { c = c + w.seats[row][col-1].taken // west } if col+1 < w.maxCol { c = c + w.seats[row][col+1].taken // east } return c } func (w *waitingRoom) makeNextStepPartOne() *waitingRoom { newRoom := &waitingRoom{ seats: make([][]cell, w.maxRow), maxCol: w.maxCol, maxRow: w.maxRow, } for r := range w.seats { newRoom.seats[r] = make([]cell, newRoom.maxCol) for c := range w.seats[r] { if w.seats[r][c].seat && w.seats[r][c].taken == 0 && w.countNeighborsPartOne(r, c) == 0 { newRoom.seats[r][c].seat = w.seats[r][c].seat newRoom.seats[r][c].taken = 1 } else if w.seats[r][c].seat && w.seats[r][c].taken == 1 && w.countNeighborsPartOne(r, c) >= 4 { newRoom.seats[r][c].seat = w.seats[r][c].seat newRoom.seats[r][c].taken = 0 } else { newRoom.seats[r][c].seat = w.seats[r][c].seat newRoom.seats[r][c].taken = w.seats[r][c].taken } } } return newRoom } func (w *waitingRoom) countNeighborsPartTwo(row, col int) int { c := 0 trow := row tcol := col // south for trow < w.maxRow-1 { trow = trow + 1 if w.seats[trow][col].seat { c = c + w.seats[trow][col].taken break } } trow = row // north for trow > 0 { trow = trow - 1 if w.seats[trow][col].seat { c = c + w.seats[trow][col].taken break } } trow = row // west for tcol > 0 { tcol = tcol - 1 if w.seats[row][tcol].seat { c = c + w.seats[row][tcol].taken break } } tcol = col // east for tcol < w.maxCol-1 { tcol = tcol + 1 if w.seats[row][tcol].seat { c = c + w.seats[row][tcol].taken break } } tcol = col // southeast for trow < w.maxRow-1 && tcol < w.maxCol-1 { trow = trow + 1 tcol = tcol + 1 if w.seats[trow][tcol].seat { c = c + w.seats[trow][tcol].taken break } } trow = row tcol = col // southwest for trow < w.maxRow-1 && tcol > 0 { trow = trow + 1 tcol = tcol - 1 if w.seats[trow][tcol].seat { c = c + w.seats[trow][tcol].taken break } } trow = row tcol = col // northeast for trow > 0 && tcol < w.maxCol-1 { trow = trow - 1 tcol = tcol + 1 if w.seats[trow][tcol].seat { c = c + w.seats[trow][tcol].taken break } } trow = row tcol = col // northwest for trow > 0 && tcol > 0 { trow = trow - 1 tcol = tcol - 1 if w.seats[trow][tcol].seat { c = c + w.seats[trow][tcol].taken break } } return c } func (w *waitingRoom) makeNextStepPartTwo() *waitingRoom { newRoom := &waitingRoom{ seats: make([][]cell, w.maxRow), maxCol: w.maxCol, maxRow: w.maxRow, } for r := range w.seats { newRoom.seats[r] = make([]cell, newRoom.maxCol) for c := range w.seats[r] { if w.seats[r][c].seat && w.seats[r][c].taken == 0 && w.countNeighborsPartTwo(r, c) == 0 { newRoom.seats[r][c].seat = w.seats[r][c].seat newRoom.seats[r][c].taken = 1 } else if w.seats[r][c].seat && w.seats[r][c].taken == 1 && w.countNeighborsPartTwo(r, c) >= 5 { newRoom.seats[r][c].seat = w.seats[r][c].seat newRoom.seats[r][c].taken = 0 } else { newRoom.seats[r][c].seat = w.seats[r][c].seat newRoom.seats[r][c].taken = w.seats[r][c].taken } } } return newRoom } func (w *waitingRoom) countFilledSeats() int { count := 0 for r := range w.seats { for c := range w.seats[r] { count = count + w.seats[r][c].taken } } return count } func (w *waitingRoom) print() { for r := range w.seats { s := "" for c := range w.seats[r] { if !w.seats[r][c].seat { s = s + "." } else if w.seats[r][c].taken == 0 { s = s + "L" } else if w.seats[r][c].taken == 1 { s = s + "#" } } fmt.Println(s) } } func checkStasis(old, new *waitingRoom) bool { for r := range old.seats { for c := range old.seats[r] { if old.seats[r][c].seat && old.seats[r][c].taken != new.seats[r][c].taken { return false } } } return true } func partOne() { f, _ := os.Open("input") reader := bufio.NewReader(f) scanner := bufio.NewScanner(reader) oldRoom := &waitingRoom{} for scanner.Scan() { line := scanner.Text() oldRoom.parseRow(line) } oldRoom.maxCol = len(oldRoom.seats[0]) oldRoom.maxRow = len(oldRoom.seats) for { newRoom := oldRoom.makeNextStepPartOne() if checkStasis(newRoom, oldRoom) { fmt.Println(newRoom.countFilledSeats()) return } oldRoom = newRoom } } func partTwo() { f, _ := os.Open("input") reader := bufio.NewReader(f) scanner := bufio.NewScanner(reader) oldRoom := &waitingRoom{} for scanner.Scan() { line := scanner.Text() oldRoom.parseRow(line) } oldRoom.maxCol = len(oldRoom.seats[0]) oldRoom.maxRow = len(oldRoom.seats) for { newRoom := oldRoom.makeNextStepPartTwo() if checkStasis(newRoom, oldRoom) { fmt.Println(newRoom.countFilledSeats()) return } oldRoom = newRoom } }