Watch
1
0
Fork
You've already forked advent-of-code
0
advent-of-code/2021/day4/main.go
2021-12-04 21:20:57 -08:00

148 lines
2.4 KiB
Go

package main
import (
"fmt"
"strings"
"github.com/fatih/color"
"github.com/jdkaplan/advent-of-code/aoc"
)
type input struct {
numbers []int
boards []board
}
func parseInput(text string) input {
sections := strings.Split(text, "\n\n")
var nums []int
for _, n := range strings.Split(sections[0], ",") {
nums = append(nums, aoc.MustInt(n))
}
var boards []board
for _, block := range sections[1:] {
b := newBoard()
for r, row := range strings.Split(block, "\n") {
for c, n := range strings.Fields(row) {
b.nums[r][c] = aoc.MustInt(n)
}
}
boards = append(boards, b)
}
return input{numbers: nums, boards: boards}
}
type board struct {
nums *[5][5]int
marked *[5][5]bool
won bool
}
func newBoard() board {
return board{
nums: &[5][5]int{},
marked: &[5][5]bool{},
}
}
func (b board) String() string {
var s strings.Builder
for r, row := range b.nums {
for c, n := range row {
if b.marked[r][c] {
color.New(color.FgGreen, color.Bold).Fprintf(&s, "%2d ", n)
} else {
fmt.Fprintf(&s, "%2d ", n)
}
}
s.WriteRune('\n')
}
return s.String()
}
func (b *board) call(x int) (win bool) {
if b.won {
return false
}
for r, row := range b.nums {
for c, n := range row {
if n == x {
b.marked[r][c] = true
if b.win(r, c) {
return true
}
}
}
}
return
}
func (b board) win(r, c int) bool {
return b.winRow(r) || b.winCol(c)
}
func (b board) winRow(r int) bool {
for c := 0; c < 5; c++ {
if !b.marked[r][c] {
return false
}
}
return true
}
func (b board) winCol(c int) bool {
for r := 0; r < 5; r++ {
if !b.marked[r][c] {
return false
}
}
return true
}
func (b board) score(x int) int {
var sum int
for r, row := range b.nums {
for c, n := range row {
if !b.marked[r][c] {
sum += n
}
}
}
return x * sum
}
func part1(text string) int {
inp := parseInput(text)
for _, n := range inp.numbers {
for _, b := range inp.boards {
if b.call(n) {
return b.score(n)
}
}
}
return len(inp.numbers)
}
func part2(text string) int {
inp := parseInput(text)
var wins int
for _, n := range inp.numbers {
for i, b := range inp.boards {
if b.call(n) {
// Set on the original in inp, not the copy in b.
inp.boards[i].won = true
wins++
if wins == len(inp.boards) {
return b.score(n)
}
}
}
}
return len(inp.numbers)
}
func main() {
text := aoc.ReadFile("./input/day4.txt")
fmt.Println(part1(text))
fmt.Println(part2(text))
}