package main import ( "bufio" "fmt" "os" "strings" ) // SeatMap ... type SeatMap []rune func (s SeatMap) ray(stride int, x, y int, dir [2]int) ([2]int, bool) { h := len(s) / stride x += dir[0] y += dir[1] for y >= 0 && y < h && x >= 0 && x < stride { r := s[(y*stride)+x] if r == '#' { return [2]int{x, y}, true } else if r == 'L' { break } x += dir[0] y += dir[1] } return [2]int{-1, -1}, false } // StepAdjacent ... func (s SeatMap) StepAdjacent(stride int) bool { oldSeatMap := make(SeatMap, len(s)) copy(oldSeatMap, s) var dirty bool for y := 0; y < len(s)/stride; y++ { i := y * stride for x := 0; x < stride; x++ { j := i + x if oldSeatMap[j] == '.' { continue } var numTakenSeats int for v := y - 1; v < y+2; v++ { for u := x - 1; u < x+2; u++ { if u == x && v == y { continue } if u >= 0 && u < stride && v >= 0 && v < len(s)/stride { if oldSeatMap[(v*stride)+u] == '#' { numTakenSeats++ } } } } if oldSeatMap[j] == 'L' && numTakenSeats == 0 { s[j] = '#' dirty = true } else if oldSeatMap[j] == '#' && numTakenSeats >= 4 { s[j] = 'L' dirty = true } } } return dirty } // StepRay ... func (s SeatMap) StepRay(stride int) bool { rays := [][2]int{ {-1, -1}, {0, -1}, {1, -1}, {1, 0}, {1, 1}, {0, 1}, {-1, 1}, {-1, 0}, } oldSeatMap := make(SeatMap, len(s)) copy(oldSeatMap, s) var dirty bool for y := 0; y < len(s)/stride; y++ { i := y * stride for x := 0; x < stride; x++ { j := i + x if oldSeatMap[j] == '.' { continue } var numTakenSeats int for _, ray := range rays { if _, ok := oldSeatMap.ray(stride, x, y, ray); ok { numTakenSeats++ } } if oldSeatMap[j] == 'L' && numTakenSeats == 0 { s[j] = '#' dirty = true } else if oldSeatMap[j] == '#' && numTakenSeats >= 5 { s[j] = 'L' dirty = true } } } return dirty } func (s SeatMap) String(stride int) string { var result strings.Builder result.Grow(len(s) * 2) fmt.Fprintf(&result, "╭") for x := 1; x < stride+3; x++ { fmt.Fprintf(&result, "─") } fmt.Fprintf(&result, "╮\n") for y := 0; y < len(s)/stride; y++ { fmt.Fprintf(&result, "│ ") i := y * stride for x := 0; x < stride; x++ { fmt.Fprintf(&result, "%c", s[i+x]) } fmt.Fprintf(&result, " │\n") } fmt.Fprintf(&result, "╰") for x := 1; x < stride+3; x++ { fmt.Fprintf(&result, "─") } fmt.Fprintf(&result, "╯") return result.String() } // Task1 ... func Task1(seatMap SeatMap, stride int, print bool) int { if print { fmt.Println(seatMap.String(stride)) } for seatMap.StepAdjacent(stride) { if print { fmt.Println(seatMap.String(stride)) } } var result int for _, r := range seatMap { if r == '#' { result++ } } return result } // Task2 ... func Task2(seatMap SeatMap, stride int, print bool) int { if print { fmt.Println(seatMap.String(stride)) } for seatMap.StepRay(stride) { if print { fmt.Println(seatMap.String(stride)) } } var result int for _, r := range seatMap { if r == '#' { result++ } } return result } func main() { file, _ := os.Open("input.txt") scanner := bufio.NewScanner(file) var stride int input := make([]rune, 0, 100) for scanner.Scan() { line := scanner.Text() if stride == 0 { stride = len(line) } input = append(input, []rune(line)...) } file.Close() seatMap := make(SeatMap, len(input)) copy(seatMap, input) result := Task1(seatMap, stride, false) fmt.Printf("Task 1: %d\n", result) copy(seatMap, input) result = Task2(seatMap, stride, false) fmt.Printf("Task 2: %d\n", result) }