package main import ( "fmt" "strings" h "git.bullercodeworks.com/brian/adventofcode/helpers" ) func main() { inp := h.StdinToStringSlice() boards := buildBoards(inp[1:]) draws := parseDraws(inp[0]) part1(boards, draws) part2(boards, draws) } func part1(boards []Board, draws []int) { var winners []Board for i := range draws { for b := range boards { if boards[b].Mark(draws[i]) { winners = append(winners, boards[b]) } } if len(winners) > 0 { break } } for w := range winners { fmt.Println("# Part 1") fmt.Println(winners[w]) fmt.Println("Score:", winners[w].Score()) fmt.Println() } } func part2(boards []Board, draws []int) { var winners []Board for i := range draws { for b := range boards { if boards[b].Mark(draws[i]) { winners = append(winners, boards[b]) } } // Remove all winners from boards for i := range winners { for b := range boards { if winners[i].String() == boards[b].String() { boards = append(boards[:b], boards[b+1:]...) break } } } if len(boards) == 0 { break } } fmt.Println("# Part 2") fmt.Println("Last Winner") fmt.Println(winners[len(winners)-1]) fmt.Println("Score:", winners[len(winners)-1].Score()) fmt.Println() } func parseDraws(inp string) []int { var ret []int pts := strings.Split(inp, ",") for i := range pts { ret = append(ret, h.Atoi(pts[i])) } return ret } type Spot struct { value int marked bool } type Board struct { spots map[h.Coordinate]Spot draws []int } func NewBoard(inp []string) Board { b := Board{ spots: make(map[h.Coordinate]Spot), } for y := range inp { row := strings.Fields(strings.TrimSpace(inp[y])) for x := range row { v := h.Atoi(row[x]) b.spots[h.Coordinate{X: x, Y: y}] = Spot{value: v} } } return b } func buildBoards(inp []string) []Board { var boards []Board var boardStr []string for i := range inp { if inp[i] == "" { // start/end of a board if len(boardStr) == 5 { boards = append(boards, NewBoard(boardStr)) } boardStr = []string{} } else { boardStr = append(boardStr, inp[i]) } } if len(boardStr) == 5 { boards = append(boards, NewBoard(boardStr)) } return boards } // Mark adds a number to the draws and returns whether this board has won func (b *Board) Mark(v int) bool { b.draws = append(b.draws, v) for k := range b.spots { s := b.spots[k] if b.spots[k].value == v { s.marked = true b.spots[k] = s return b.Won() } } return b.Won() } func (b *Board) Won() bool { for y := 0; y < 5; y++ { if b.CheckRowForWin(y) { return true } } for x := 0; x < 5; x++ { if b.CheckColForWin(x) { return true } } return false } func (b *Board) CheckRowForWin(y int) bool { for x := 0; x < 5; x++ { if b.spots[c(x, y)].marked == false { return false } } return true } func (b *Board) CheckColForWin(x int) bool { for y := 0; y < 5; y++ { if b.spots[c(x, y)].marked == false { return false } } return true } func (b *Board) Score() int { var unmarked int for y := 0; y < 5; y++ { for x := 0; x < 5; x++ { if b.spots[c(x, y)].marked == false { unmarked += b.spots[c(x, y)].value } } } return unmarked * b.draws[len(b.draws)-1] } func (b Board) String() string { var ret string for y := 0; y < 5; y++ { for x := 0; x < 5; x++ { c := c(x, y) marked := " " if b.spots[c].marked { marked = "X" } ret = fmt.Sprintf("%s%s: %2d[%v] ", ret, c, b.spots[c].value, marked) } ret = ret + "\n" } return ret } func c(x, y int) h.Coordinate { return h.Coordinate{X: x, Y: y} }