198 lines
3.5 KiB
Go
198 lines
3.5 KiB
Go
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(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(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}
|
|
}
|