package main
import (
"bufio"
"log"
"os"
"regexp"
"strconv"
"strings"
)
const gridSize = 5
type Grid [gridSize][gridSize]int
type Bingo struct {
marks []int
grids []Grid
}
type markData struct {
grid, row, col int
}
var re = regexp.MustCompile(`(\d+)`)
func main() {
if err := myMain(); err != nil {
log.Println(err)
}
}
func myMain() error {
bingo, err := parseInput()
if err != nil {
return err
}
log.Println(solveFirst(bingo))
log.Println(solveSecond(bingo))
return nil
}
func solveSecond(bingo Bingo) int {
var winners = map[int]struct{}{}
for mark, elem := range bingo.marks {
if mark < gridSize {
continue
}
marks := bingo.findMark(elem)
for _, m := range marks {
if bingo.checkRow(m.grid, m.row, mark) || bingo.checkCol(m.grid, m.col, mark) {
winners[m.grid] = struct{}{}
if len(winners) == len(bingo.grids) {
log.Println(bingo.gridValue(m.grid, mark), bingo.marks[mark])
return bingo.gridValue(m.grid, mark) * bingo.marks[mark]
}
}
}
}
return 0
}
func solveFirst(bingo Bingo) int {
for mark, elem := range bingo.marks {
if mark < gridSize {
continue
}
marks := bingo.findMark(elem)
for _, m := range marks {
if bingo.checkRow(m.grid, m.row, mark) || bingo.checkCol(m.grid, m.col, mark) {
return bingo.gridValue(m.grid, mark) * bingo.marks[mark]
}
}
}
return 0
}
func (b Bingo) gridValue(gridnum int, mark int) int {
var sum int
for _, line := range b.grids[gridnum] {
for _, elem := range line {
if !b.isMarked(elem, mark) {
sum += elem
}
}
}
return sum
}
func (b Bingo) checkRow(gridnum int, row int, mark int) bool {
for _, elem := range b.grids[gridnum][row] {
if !b.isMarked(elem, mark) {
return false
}
}
return true
}
func (b Bingo) checkCol(gridnum int, col int, mark int) bool {
for row := 0; row < gridSize; row++ {
elem := b.grids[gridnum][row][col]
if !b.isMarked(elem, mark) {
return false
}
}
return true
}
func (b Bingo) isMarked(elem int, maxMark int) bool {
for i := 0; i <= maxMark; i++ {
if b.marks[i] == elem {
return true
}
}
return false
}
func (b Bingo) findMark(item int) []markData {
var ret []markData
for gridnum := range b.grids {
if m, ok := b.findInGrid(gridnum, item); ok {
ret = append(ret, m)
}
}
return ret
}
func (b Bingo) findInGrid(gridnum int, item int) (markData, bool) {
for row, line := range b.grids[gridnum] {
for col, elem := range line {
if elem == item {
return markData{gridnum, row, col}, true
}
}
}
return markData{}, false
}
func parseInput() (Bingo, error) {
var ret = Bingo{}
fd, err := os.Open("input.txt")
if err != nil {
return ret, err
}
defer fd.Close()
buf := bufio.NewScanner(fd)
grid := Grid{}
gridLine := 0
for line := 0; buf.Scan(); line++ {
if line == 0 {
marks := strings.Split(buf.Text(), ",")
tmp := make([]int, len(marks))
for i, m := range marks {
tmp[i], err = strconv.Atoi(m)
if err != nil {
return ret, err
}
}
ret.marks = tmp
continue
}
if buf.Text() == "" {
if line != 1 {
ret.grids = append(ret.grids, grid)
}
grid = Grid{}
gridLine = 0
continue
}
tmp := re.FindAllString(buf.Text(), -1)
for i, elem := range tmp {
grid[gridLine][i], err = strconv.Atoi(elem)
if err != nil {
return ret, err
}
}
gridLine++
}
ret.grids = append(ret.grids, grid)
return ret, nil
}