-
Notifications
You must be signed in to change notification settings - Fork 0
/
main.go
112 lines (95 loc) · 2.42 KB
/
main.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
// -*- compile-command: "go run main.go ../example1.txt ../input.txt"; -*-
package main
import (
"flag"
"fmt"
"log"
"regexp"
"strings"
. "github.com/gmlewis/advent-of-code-2021/enum"
"github.com/gmlewis/advent-of-code-2021/maps"
"github.com/gmlewis/advent-of-code-2021/must"
)
var logf = log.Printf
var printf = fmt.Printf
func main() {
flag.Parse()
Each(flag.Args(), process)
}
func process(filename string) {
logf("Processing %v ...", filename)
buf := must.ReadFile(filename)
parts := strings.Split(buf, "\n\n")
numbers := strings.Split(parts[0], ",")
boards := Map(parts[1:], parseBoard)
best := Reduce(boards, &tup{}, func(board *BoardT, acc *tup) *tup {
turns := board.play(numbers)
if acc.board == nil || turns < acc.turns {
acc.turns = turns
acc.board = board
}
return acc
})
sum := best.board.unmarkedSum()
logf("unmarkedSum=%v, lastNum=%v", sum, best.board.lastNum)
printf("Solution: %v\n", sum*best.board.lastNum)
}
type tup struct {
board *BoardT
turns int
}
type BoardT struct {
unmarked map[string]string // number => "y,x"
marked map[string]string // "y,x" => number
row map[string][]string
col map[string][]string
lastNum int
}
func (b *BoardT) unmarkedSum() int {
return maps.Reduce(b.unmarked, 0, func(k, v string, acc int) int {
return acc + must.Atoi(k)
})
}
func (b *BoardT) play(numbers []string) int {
b.row = map[string][]string{}
b.col = map[string][]string{}
for i, num := range numbers {
if b.bingo() {
return i
}
if k, ok := b.unmarked[num]; ok {
b.lastNum = must.Atoi(num)
b.marked[k] = num
parts := strings.Split(k, ",")
y := parts[0]
x := parts[1]
b.row[y] = append(b.row[y], num)
b.col[x] = append(b.col[x], num)
delete(b.unmarked, num)
}
}
return len(numbers)
}
func (b *BoardT) bingo() bool {
if len(b.marked) < 5 {
return false
}
f := func(m map[string][]string) bool {
return Any(maps.Map(m, maps.ValueLen[string, string]), Equals(5))
}
return f(b.row) || f(b.col)
}
var whitespaceRE = regexp.MustCompile(`\s+`)
func parseBoard(puz string) *BoardT {
b := &BoardT{unmarked: map[string]string{}, marked: map[string]string{}}
lines := strings.Split(puz, "\n")
for y, line := range lines {
line = whitespaceRE.ReplaceAllString(line, " ")
cols := strings.Split(strings.TrimSpace(line), " ")
for x, v := range cols {
b.unmarked[v] = fmt.Sprintf("%v,%v", y, x)
}
}
// logf("board: %#v", b.unmarked)
return b
}