-
Notifications
You must be signed in to change notification settings - Fork 0
/
main.go
97 lines (80 loc) · 1.95 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
// -*- compile-command: "go run main.go ../example1.txt ../input.txt"; -*-
package main
import (
"flag"
"fmt"
"log"
"regexp"
"sort"
"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)
}
var (
movesRE = regexp.MustCompile(`move (\d+) from (\d+) to (\d+)`)
)
func process(filename string) {
logf("Processing %v ...", filename)
parts := must.ReadSplitFile(filename, "\n\n")
stacks := parseStacks(parts[0])
stackKeys := maps.Keys(stacks)
stacks = moveCrates(stacks, parts[1])
sort.Strings(stackKeys)
solution := Reduce(stackKeys, "", takeTop(stacks))
printf("Solution: %v\n", solution)
}
type puzT map[string][]string
func moveCrates(puz puzT, cmds string) puzT {
for _, cmd := range strings.Split(strings.TrimSpace(cmds), "\n") {
m := movesRE.FindStringSubmatch(cmd)
if len(m) != 4 {
log.Fatalf("Bad move: %v", cmd)
}
num := must.Atoi(m[1])
from := m[2]
to := m[3]
puz.move(num, from, to)
}
return puz
}
func (p puzT) move(num int, from, to string) {
if len(p[from]) < num {
log.Fatalf("Cannot move %v from %v (%+v) to %v (%+v)!", num, from, p[from], to, p[to])
}
n := len(p[from])
crates := p[from][n-num : n]
p[to] = append(p[to], crates...)
p[from] = p[from][0 : n-num]
}
func takeTop(stacks puzT) func(stack, acc string) string {
return func(stack, acc string) string {
s := stacks[stack]
if len(s) == 0 {
return acc
}
return acc + s[len(s)-1]
}
}
func parseStacks(s string) puzT {
result := puzT{}
lines := strings.Split(s, "\n")
lastLine := len(lines) - 1
for i := lastLine - 1; i >= 0; i-- {
line := lines[i]
for x := 1; x < len(line); x += 4 {
crate := line[x : x+1]
if crate != " " {
stack := lines[lastLine][x : x+1]
result[stack] = append(result[stack], crate)
}
}
}
return result
}