Compare commits
16
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a5ebbe25d0
|
||
|
|
50af2114d4
|
||
|
|
f8fa61672f
|
||
|
|
951c2c298a
|
||
|
|
328a0f3eb3
|
||
|
|
7d7402f054
|
||
|
|
7585526634
|
||
|
|
924c8d74f3
|
||
|
|
22184ed9c7
|
||
|
|
74a952e82b | ||
|
|
62f8338227 | ||
|
|
39c6f8ed4d | ||
|
|
2c959c109b
|
||
|
|
eb1eaaab43
|
||
|
|
adc01f4df9
|
||
|
|
fd85530d88
|
No files matched your search
@@ -28,6 +28,6 @@ jobs:
|
||||
go-version: 1.21.3
|
||||
|
||||
- name: Test
|
||||
run: go test --race -cover ./...
|
||||
run: go test -timeout 240s -race -cover ./...
|
||||
|
||||
- run: echo "🍏 This job's status is ${{ job.status }}."
|
||||
@@ -0,0 +1,6 @@
|
||||
-----BEGIN SSH SIGNATURE-----
|
||||
U1NIU0lHAAAAAQAAADMAAAALc3NoLWVkMjU1MTkAAAAgZ+OuJYdd3UiUbyBuO1RlsQR20a
|
||||
Qm5mKneuMxRjGo3zkAAAAEZmlsZQAAAAAAAAAGc2hhNTEyAAAAUwAAAAtzc2gtZWQyNTUx
|
||||
OQAAAED8T4C6WILXYZ1KxqDIlVhlrAEjr1Vc+tn8ypcVM3bN7iOexVvuUuvm90nr8eEwKU
|
||||
acrdDxmq2S+oysQbK+pMUE
|
||||
-----END SSH SIGNATURE-----
|
||||
+185
-102
@@ -9,66 +9,6 @@ import (
|
||||
aoc "go.sour.is/advent-of-code"
|
||||
)
|
||||
|
||||
func TestReverse(t *testing.T) {
|
||||
is := is.New(t)
|
||||
|
||||
is.Equal(aoc.Reverse([]int{1, 2, 3, 4}), []int{4, 3, 2, 1})
|
||||
}
|
||||
|
||||
func TestLCM(t *testing.T) {
|
||||
is := is.New(t)
|
||||
|
||||
is.Equal(aoc.LCM([]int{}...), 0)
|
||||
is.Equal(aoc.LCM(5), 5)
|
||||
is.Equal(aoc.LCM(5, 3), 15)
|
||||
is.Equal(aoc.LCM(5, 3, 2), 30)
|
||||
}
|
||||
|
||||
func TestReadStringToInts(t *testing.T) {
|
||||
is := is.New(t)
|
||||
|
||||
is.Equal(aoc.ReadStringToInts([]string{"1", "2", "3"}), []int{1, 2, 3})
|
||||
}
|
||||
|
||||
func TestRepeat(t *testing.T) {
|
||||
is := is.New(t)
|
||||
|
||||
is.Equal(aoc.Repeat(5, 3), []int{5, 5, 5})
|
||||
}
|
||||
|
||||
func TestPower2(t *testing.T) {
|
||||
is := is.New(t)
|
||||
|
||||
is.Equal(aoc.Power2(0), 1)
|
||||
is.Equal(aoc.Power2(1), 2)
|
||||
is.Equal(aoc.Power2(2), 4)
|
||||
}
|
||||
|
||||
func TestABS(t *testing.T) {
|
||||
is := is.New(t)
|
||||
|
||||
is.Equal(aoc.ABS(1), 1)
|
||||
is.Equal(aoc.ABS(0), 0)
|
||||
is.Equal(aoc.ABS(-1), 1)
|
||||
}
|
||||
|
||||
func TestTranspose(t *testing.T) {
|
||||
is := is.New(t)
|
||||
|
||||
is.Equal(
|
||||
aoc.Transpose(
|
||||
[][]int{
|
||||
{1, 1},
|
||||
{0, 0},
|
||||
{1, 1},
|
||||
},
|
||||
),
|
||||
[][]int{
|
||||
{1, 0, 1},
|
||||
{1, 0, 1},
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
func TestList(t *testing.T) {
|
||||
is := is.New(t)
|
||||
@@ -85,62 +25,44 @@ func TestPriorityQueue(t *testing.T) {
|
||||
is := is.New(t)
|
||||
|
||||
type elem [2]int
|
||||
less := func(a, b elem) bool {
|
||||
return a[0] < b[0]
|
||||
less := func(b, a *elem) bool {
|
||||
return (*a)[0] < (*b)[0]
|
||||
}
|
||||
|
||||
pq := aoc.PriorityQueue(less)
|
||||
|
||||
pq.Enqueue(elem{1, 4})
|
||||
pq.Enqueue(elem{3, 2})
|
||||
pq.Enqueue(elem{2, 3})
|
||||
pq.Enqueue(elem{4, 1})
|
||||
pq.Insert(&elem{1, 4})
|
||||
pq.Insert(&elem{3, 2})
|
||||
pq.Insert(&elem{2, 3})
|
||||
pq.Insert(&elem{4, 1})
|
||||
|
||||
v, ok := pq.Dequeue()
|
||||
is.True(ok)
|
||||
is.Equal(v, elem{4, 1})
|
||||
v := pq.ExtractMin()
|
||||
is.True(v != nil)
|
||||
is.Equal(v, &elem{4, 1})
|
||||
|
||||
v, ok = pq.Dequeue()
|
||||
is.True(ok)
|
||||
is.Equal(v, elem{3, 2})
|
||||
v = pq.ExtractMin()
|
||||
is.True(v != nil)
|
||||
is.Equal(v, &elem{3, 2})
|
||||
|
||||
v, ok = pq.Dequeue()
|
||||
is.True(ok)
|
||||
is.Equal(v, elem{2, 3})
|
||||
v = pq.ExtractMin()
|
||||
is.True(v != nil)
|
||||
is.Equal(v, &elem{2, 3})
|
||||
|
||||
v, ok = pq.Dequeue()
|
||||
is.True(ok)
|
||||
is.Equal(v, elem{1, 4})
|
||||
v = pq.ExtractMin()
|
||||
is.True(v != nil)
|
||||
is.Equal(v, &elem{1, 4})
|
||||
|
||||
v, ok = pq.Dequeue()
|
||||
is.True(!ok)
|
||||
is.Equal(v, elem{})
|
||||
v = pq.ExtractMin()
|
||||
is.True(v == nil)
|
||||
}
|
||||
|
||||
func TestSet(t *testing.T) {
|
||||
is := is.New(t)
|
||||
|
||||
s := aoc.Set(1, 2, 3)
|
||||
is.True(!s.Has(0))
|
||||
is.True(s.Has(1))
|
||||
is.True(s.Has(2))
|
||||
is.True(s.Has(3))
|
||||
is.True(!s.Has(4))
|
||||
|
||||
s.Add(4)
|
||||
is.True(s.Has(4))
|
||||
|
||||
items := s.Items()
|
||||
sort.Ints(items)
|
||||
is.Equal(items, []int{1, 2, 3, 4})
|
||||
}
|
||||
|
||||
func ExamplePriorityQueue() {
|
||||
type memo struct {
|
||||
pt int
|
||||
score int
|
||||
}
|
||||
less := func(a, b memo) bool { return b.score < a.score }
|
||||
less := func(a, b *memo) bool { return a.score < b.score }
|
||||
|
||||
adj := map[int][][2]int{
|
||||
0: {{1, 2}, {2, 6}},
|
||||
@@ -156,10 +78,10 @@ func ExamplePriorityQueue() {
|
||||
dist := aoc.DefaultMap[int](int(^uint(0) >> 1))
|
||||
|
||||
dist.Set(0, 0)
|
||||
pq.Enqueue(memo{0, 0})
|
||||
pq.Insert(&memo{0, 0})
|
||||
|
||||
for !pq.IsEmpty() {
|
||||
m, _ := pq.Dequeue()
|
||||
m := pq.ExtractMin()
|
||||
|
||||
u := m.pt
|
||||
if visited.Has(u) {
|
||||
@@ -175,7 +97,7 @@ func ExamplePriorityQueue() {
|
||||
|
||||
if !visited.Has(v) && du+w < dv {
|
||||
dist.Set(v, du+w)
|
||||
pq.Enqueue(memo{v, du + w})
|
||||
pq.Insert(&memo{v, du + w})
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -195,3 +117,164 @@ func ExamplePriorityQueue() {
|
||||
// point 5 is 22 steps away.
|
||||
// point 6 is 19 steps away.
|
||||
}
|
||||
func TestGraph(t *testing.T) {
|
||||
is := is.New(t)
|
||||
|
||||
var adjacencyList = map[int][]int{
|
||||
2: {3, 5, 1},
|
||||
1: {2, 4},
|
||||
3: {6, 2},
|
||||
4: {1, 5, 7},
|
||||
5: {2, 6, 8, 4},
|
||||
6: {3, 0, 9, 5},
|
||||
7: {4, 8},
|
||||
8: {5, 9, 7},
|
||||
9: {6, 0, 8},
|
||||
}
|
||||
|
||||
g := aoc.Graph(aoc.WithAdjacencyList[int, int](adjacencyList))
|
||||
is.Equal(g.Neighbors(1), []int{2, 4})
|
||||
is.Equal(map[int][]int(g.AdjacencyList()), adjacencyList)
|
||||
}
|
||||
|
||||
func ExampleFibHeap() {
|
||||
type memo struct {
|
||||
pt int
|
||||
score int
|
||||
}
|
||||
less := func(a, b *memo) bool { return (*a).score < (*b).score }
|
||||
|
||||
adj := map[int][][2]int{
|
||||
0: {{1, 2}, {2, 6}},
|
||||
1: {{3, 5}},
|
||||
2: {{3, 8}},
|
||||
3: {{4, 10}, {5, 15}},
|
||||
4: {{6, 2}},
|
||||
5: {{6, 6}},
|
||||
}
|
||||
|
||||
pq := aoc.FibHeap(less)
|
||||
visited := aoc.Set([]int{}...)
|
||||
dist := aoc.DefaultMap[int](int(^uint(0) >> 1))
|
||||
|
||||
dist.Set(0, 0)
|
||||
pq.Insert(&memo{0, 0})
|
||||
|
||||
for !pq.IsEmpty() {
|
||||
m := pq.ExtractMin()
|
||||
|
||||
u := m.pt
|
||||
if visited.Has(u) {
|
||||
continue
|
||||
}
|
||||
visited.Add(u)
|
||||
|
||||
du, _ := dist.Get(u)
|
||||
|
||||
for _, edge := range adj[u] {
|
||||
v, w := edge[0], edge[1]
|
||||
dv, _ := dist.Get(v)
|
||||
|
||||
if !visited.Has(v) && du+w < dv {
|
||||
dist.Set(v, du+w)
|
||||
pq.Insert(&memo{v, du + w})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
items := dist.Items()
|
||||
sort.Slice(items, func(i, j int) bool { return items[i].K < items[j].K })
|
||||
for _, v := range items {
|
||||
fmt.Printf("point %d is %d steps away.\n", v.K, v.V)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// point 0 is 0 steps away.
|
||||
// point 1 is 2 steps away.
|
||||
// point 2 is 6 steps away.
|
||||
// point 3 is 7 steps away.
|
||||
// point 4 is 17 steps away.
|
||||
// point 5 is 22 steps away.
|
||||
// point 6 is 19 steps away.
|
||||
}
|
||||
|
||||
func TestFibHeap(t *testing.T) {
|
||||
is := is.New(t)
|
||||
|
||||
type elem [2]int
|
||||
less := func(a, b *elem) bool {
|
||||
return (*a)[0] < (*b)[0]
|
||||
}
|
||||
|
||||
pq := aoc.FibHeap(less)
|
||||
|
||||
pq.Insert(&elem{1, 4})
|
||||
pq.Insert(&elem{3, 2})
|
||||
pq.Insert(&elem{2, 3})
|
||||
pq.Insert(&elem{4, 1})
|
||||
|
||||
v := pq.ExtractMin()
|
||||
is.True(v != nil)
|
||||
is.Equal(v, &elem{1, 4})
|
||||
|
||||
pq.Insert(&elem{5, 8})
|
||||
pq.Insert(&elem{6, 7})
|
||||
pq.Insert(&elem{7, 6})
|
||||
pq.Insert(&elem{8, 5})
|
||||
|
||||
v = pq.ExtractMin()
|
||||
is.True(v != nil)
|
||||
is.Equal(v, &elem{2, 3})
|
||||
|
||||
v = pq.ExtractMin()
|
||||
is.True(v != nil)
|
||||
is.Equal(v, &elem{3, 2})
|
||||
|
||||
v = pq.ExtractMin()
|
||||
is.True(v != nil)
|
||||
is.Equal(v, &elem{4, 1})
|
||||
|
||||
v = pq.ExtractMin()
|
||||
is.True(v != nil)
|
||||
is.Equal(v, &elem{5, 8})
|
||||
|
||||
m := aoc.FibHeap(less)
|
||||
m.Insert(&elem{1, 99})
|
||||
m.Insert(&elem{12, 9})
|
||||
m.Insert(&elem{11, 10})
|
||||
m.Insert(&elem{10, 11})
|
||||
m.Insert(&elem{9, 12})
|
||||
|
||||
pq.Merge(m)
|
||||
|
||||
v = pq.Find(func(t *elem) bool {
|
||||
return (*t)[0] == 6
|
||||
})
|
||||
is.Equal(v, &elem{6, 7})
|
||||
|
||||
v = pq.Find(func(t *elem) bool {
|
||||
return (*t)[0] == 12
|
||||
})
|
||||
is.Equal(v, &elem{12, 9})
|
||||
|
||||
v = pq.ExtractMin()
|
||||
is.True(v != nil)
|
||||
is.Equal(v, &elem{1, 99})
|
||||
|
||||
pq.DecreaseKey(
|
||||
func(t *elem) bool { return t[0] == 12 },
|
||||
func(t *elem) { t[0] = 3 },
|
||||
)
|
||||
|
||||
v = pq.ExtractMin()
|
||||
is.True(v != nil)
|
||||
is.Equal(v, &elem{3, 9})
|
||||
|
||||
var keys []int
|
||||
for !pq.IsEmpty() {
|
||||
v := pq.ExtractMin()
|
||||
fmt.Println(v)
|
||||
keys = append(keys, v[0])
|
||||
}
|
||||
is.Equal(keys, []int{6, 7, 8, 9, 10, 11})
|
||||
}
|
||||
+66
-27
@@ -8,7 +8,7 @@ import (
|
||||
aoc "go.sour.is/advent-of-code"
|
||||
)
|
||||
|
||||
// var log = aoc.Log
|
||||
var log = aoc.Log
|
||||
|
||||
func main() { aoc.MustResult(aoc.Runner(run)) }
|
||||
|
||||
@@ -26,10 +26,14 @@ func run(scan *bufio.Scanner) (*result, error) {
|
||||
text := scan.Text()
|
||||
m = append(m, []rune(text))
|
||||
}
|
||||
log("start day 17")
|
||||
|
||||
result := result{}
|
||||
result.valuePT1 = search(m, 1, 3)
|
||||
result.valuePT2 = search(m, 4, 10)
|
||||
result.valuePT1 = search(m, 1, 3, seenFn)
|
||||
log("result from part 1 = ", result.valuePT1)
|
||||
|
||||
result.valuePT2 = search(m, 4, 10, nil)
|
||||
log("result from part 2 = ", result.valuePT2)
|
||||
|
||||
return &result, nil
|
||||
}
|
||||
@@ -86,6 +90,7 @@ type graph struct {
|
||||
m Map
|
||||
target Point
|
||||
reads int
|
||||
seenFn func(a position) position
|
||||
}
|
||||
|
||||
// Neighbors returns valid steps from given position. if at target returns none.
|
||||
@@ -114,6 +119,7 @@ func (g *graph) Neighbors(current position) []position {
|
||||
if forward := current.step(); current.steps < g.max && g.m.Valid(forward.loc) {
|
||||
nbs = append(nbs, forward)
|
||||
}
|
||||
|
||||
return nbs
|
||||
}
|
||||
|
||||
@@ -125,12 +131,13 @@ func (g *graph) Cost(a, b position) int16 {
|
||||
}
|
||||
|
||||
// Potential calculates distance to target
|
||||
func (g *graph) Potential(a, b position) int16 {
|
||||
return aoc.ManhattanDistance(a.loc, b.loc)
|
||||
}
|
||||
// func (g *graph) Potential(a position) int16 {
|
||||
// return aoc.ManhattanDistance(a.loc, g.target)
|
||||
// }
|
||||
|
||||
func (g *graph) Target(a position) bool {
|
||||
if a.loc == g.target && a.steps >= g.min {
|
||||
// Target returns true when target reached. receives node and cost.
|
||||
func (g *graph) Target(a position, c int16) bool {
|
||||
if a.loc == g.target && a.steps >= g.min && a.steps <= g.max {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
@@ -138,47 +145,79 @@ func (g *graph) Target(a position) bool {
|
||||
|
||||
// Seen attempt at simplifying the seen to use horizontal/vertical and no steps.
|
||||
// It returns correct for part1 but not part 2..
|
||||
// func (g *graph) Seen(a position) position {
|
||||
// if a.direction == U {
|
||||
// a.direction = D
|
||||
// }
|
||||
// if a.direction == L {
|
||||
// a.direction = R
|
||||
// }
|
||||
// a.steps = 0
|
||||
// return a
|
||||
// }
|
||||
func (g *graph) Seen(a position) position {
|
||||
if g.seenFn != nil {
|
||||
return g.seenFn(a)
|
||||
}
|
||||
return a
|
||||
}
|
||||
|
||||
func search(m Map, minSteps, maxSteps int8) int {
|
||||
func seenFn(a position) position {
|
||||
if a.direction == U {
|
||||
a.direction = D
|
||||
}
|
||||
if a.direction == L {
|
||||
a.direction = R
|
||||
}
|
||||
// a.steps = 0
|
||||
return a
|
||||
}
|
||||
|
||||
func search(m Map, minSteps, maxSteps int8, seenFn func(position) position) int {
|
||||
rows, cols := m.Size()
|
||||
start := Point{}
|
||||
target := Point{rows - 1, cols - 1}
|
||||
|
||||
g := graph{min: minSteps, max: maxSteps, m: m, target: target}
|
||||
cost, path := aoc.FindPath[int16, position](&g, position{loc: start}, position{loc: target})
|
||||
g := graph{min: minSteps, max: maxSteps, m: m, target: target, seenFn: seenFn}
|
||||
|
||||
fmt.Println("total map reads = ", g.reads)
|
||||
printGraph(m, path)
|
||||
cost, path, closed := aoc.FindPath[int16, position](&g, position{loc: start}, position{loc: target})
|
||||
|
||||
log("total map reads = ", g.reads, "cost = ", cost)
|
||||
printGraph(m, path, closed, g.seenFn)
|
||||
|
||||
return int(cost)
|
||||
}
|
||||
|
||||
// printGraph with the path overlay
|
||||
func printGraph(m Map, path []position) {
|
||||
// printGraph with the path/cost overlay
|
||||
func printGraph(m Map, path []position, closed map[position]int16, seenFn func(a position) position) {
|
||||
pts := make(map[Point]position, len(path))
|
||||
for _, pt := range path {
|
||||
pts[pt.loc] = pt
|
||||
}
|
||||
|
||||
clpt := make(map[position]position, len(closed))
|
||||
for pt := range closed {
|
||||
clpt[position{loc: pt.loc, steps: pt.steps}] = pt
|
||||
}
|
||||
|
||||
for r, row := range m {
|
||||
// if r == 0 {
|
||||
// for c := range row {
|
||||
// if c == 0 {
|
||||
// fmt.Print(" ")
|
||||
// }
|
||||
// fmt.Printf("% 5d", c)
|
||||
// }
|
||||
// fmt.Println("")
|
||||
// }
|
||||
for c := range row {
|
||||
if _, ok := pts[Point{int16(r), int16(c)}]; ok {
|
||||
// if c == 0 {
|
||||
// fmt.Printf("% 5d", r)
|
||||
// }
|
||||
|
||||
if pt, ok := pts[Point{int16(r), int16(c)}]; ok {
|
||||
if seenFn != nil {
|
||||
pt = seenFn(pt)
|
||||
}
|
||||
_ = pt
|
||||
// fmt.Printf("% 5d", closed[pt])
|
||||
fmt.Print("*")
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
fmt.Print(".")
|
||||
// fmt.Print(" ....")
|
||||
fmt.Print(" ")
|
||||
}
|
||||
fmt.Println("")
|
||||
}
|
||||
|
||||
+11
-11
@@ -13,8 +13,8 @@ import (
|
||||
//go:embed example.txt
|
||||
var example []byte
|
||||
|
||||
// //go:embed input.txt
|
||||
// var input []byte
|
||||
//go:embed input.txt
|
||||
var input []byte
|
||||
|
||||
func TestExample(t *testing.T) {
|
||||
is := is.New(t)
|
||||
@@ -28,14 +28,14 @@ func TestExample(t *testing.T) {
|
||||
is.Equal(result.valuePT2, 94)
|
||||
}
|
||||
|
||||
// func TestSolution(t *testing.T) {
|
||||
// is := is.New(t)
|
||||
// scan := bufio.NewScanner(bytes.NewReader(input))
|
||||
func TestSolution(t *testing.T) {
|
||||
is := is.New(t)
|
||||
scan := bufio.NewScanner(bytes.NewReader(input))
|
||||
|
||||
// result, err := run(scan)
|
||||
// is.NoErr(err)
|
||||
result, err := run(scan)
|
||||
is.NoErr(err)
|
||||
|
||||
// t.Log(result)
|
||||
// is.Equal(result.valuePT1, 843)
|
||||
// is.Equal(result.valuePT2, 1017)
|
||||
// }
|
||||
t.Log(result)
|
||||
is.Equal(result.valuePT1, 843)
|
||||
is.Equal(result.valuePT2, 1017)
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
px{a<2006:qkq,m>2090:A,rfg}
|
||||
pv{a>1716:R,A}
|
||||
lnx{m>1548:A,A}
|
||||
rfg{s<537:gd,x>2440:R,A}
|
||||
qs{s>3448:A,lnx}
|
||||
qkq{x<1416:A,crn}
|
||||
crn{x>2662:A,R}
|
||||
in{s<1351:px,qqz}
|
||||
qqz{s>2770:qs,m<1801:hdj,R}
|
||||
gd{a>3333:R,R}
|
||||
hdj{m>838:A,pv}
|
||||
|
||||
{x=787,m=2655,a=1222,s=2876}
|
||||
{x=1679,m=44,a=2067,s=496}
|
||||
{x=2036,m=264,a=79,s=2244}
|
||||
{x=2461,m=1339,a=466,s=291}
|
||||
{x=2127,m=1623,a=2188,s=1013}
|
||||
+780
@@ -0,0 +1,780 @@
|
||||
ztj{s<2703:A,m<1025:vk,ztl}
|
||||
nqt{a>3513:R,s>2424:R,m>929:R,A}
|
||||
mr{s>2281:R,A}
|
||||
gf{x>2746:R,a<3379:jcl,R}
|
||||
gkv{x>2579:qlx,s>322:rxv,R}
|
||||
gdl{x<2917:A,s>82:A,s<54:R,R}
|
||||
hzc{m<1277:R,m>1355:A,x>953:A,R}
|
||||
xs{x>2337:ft,m>1444:A,R}
|
||||
hs{m<235:A,a<2424:A,x<3026:pvh,hqk}
|
||||
cls{a<1361:zch,s<3630:tnh,a<2359:px,spb}
|
||||
gq{m<1157:A,R}
|
||||
hc{m<2726:A,s>1302:A,R}
|
||||
lt{x>3157:A,a<3669:R,R}
|
||||
sf{x<3199:R,s>2680:jrl,x>3718:jh,R}
|
||||
hr{m>1737:A,A}
|
||||
bgg{x<171:A,x<283:R,R}
|
||||
pgb{m<1624:ksc,x>2675:bzc,bzn}
|
||||
zm{m<2599:sjc,m>3497:A,m<2946:A,A}
|
||||
gbb{x>860:bxv,a<2306:br,msc}
|
||||
gsl{x>53:A,A}
|
||||
zs{x<1669:kp,x<2690:ns,s>2951:cls,tvv}
|
||||
qhq{x<1264:A,m<1728:A,R}
|
||||
gg{s<239:A,s>340:R,x>3642:A,R}
|
||||
ktx{m>2620:R,m>2073:R,a<3539:R,R}
|
||||
xg{x<3497:fp,sgc}
|
||||
pms{m<3366:R,x>3570:A,R}
|
||||
gsb{x>2077:A,A}
|
||||
xf{s>3779:A,R}
|
||||
tfs{s>3844:rb,s<3703:scg,bk}
|
||||
bgb{a>2837:R,a>2812:A,A}
|
||||
nvk{s<2358:mr,x>2818:nqt,x<2757:lf,R}
|
||||
fg{a>1961:A,x<68:R,R}
|
||||
cfz{x>1567:A,m>951:A,a<2959:R,A}
|
||||
ljt{m>950:A,m<557:R,m<745:A,R}
|
||||
zcq{m>1403:th,fd}
|
||||
tbv{a>1532:R,R}
|
||||
dq{m>960:R,csz}
|
||||
tvv{a<2619:zh,m>1623:kb,vh}
|
||||
dzz{s>3136:R,s<2702:A,a>2889:R,R}
|
||||
lg{a<66:A,s>784:A,s>263:A,A}
|
||||
zfk{s<463:R,x>3180:A,R}
|
||||
bdh{s>356:A,s>193:A,m>482:R,R}
|
||||
tc{m>3454:R,x>3211:A,A}
|
||||
tz{x>3191:R,a<1319:R,R}
|
||||
cpn{m<2478:A,a<2228:A,a>3262:A,A}
|
||||
qmt{x<2144:R,flt}
|
||||
nsp{m<379:R,R}
|
||||
sxt{s<1011:A,a>1135:A,rl}
|
||||
bjg{m>973:lz,x>243:hh,a>1789:xl,xmg}
|
||||
cj{x>2137:nst,m<3002:A,s>3193:jc,pfr}
|
||||
lmc{a>2967:A,A}
|
||||
tv{m>1493:A,m<769:A,R}
|
||||
khc{m>2346:mbr,s>596:kvr,a<274:fzh,tb}
|
||||
zbk{s>1140:qrt,x>1818:pv,a>540:gt,gxc}
|
||||
kk{s>3728:R,s>3683:R,m<562:A,A}
|
||||
jv{m<848:zpq,a>1225:fsv,ztj}
|
||||
shb{a<242:A,m>2625:R,R}
|
||||
fhg{m>1372:R,A}
|
||||
dg{x>1246:qd,s<3289:lbf,a<1032:zzp,ks}
|
||||
cfq{s>2689:A,s>2613:R,A}
|
||||
gl{m>2798:cqm,s>3029:cnl,m>2233:A,qc}
|
||||
tkv{m<1884:A,A}
|
||||
fdm{m<1549:tgt,x<2498:kdf,s>528:jz,lt}
|
||||
vx{x<2948:xc,mgp}
|
||||
bs{m<687:A,R}
|
||||
kp{x>609:dkr,tqc}
|
||||
xpj{x<934:A,a>1772:A,A}
|
||||
rhd{x>956:A,a<2471:A,a<3414:A,A}
|
||||
srg{m>1381:A,s<264:A,A}
|
||||
szv{s>453:mff,nzj}
|
||||
ldl{a>3906:A,A}
|
||||
rxv{m<1632:R,m>1700:R,R}
|
||||
ch{s<3588:A,a<639:A,R}
|
||||
sc{s>2789:A,a<1419:R,R}
|
||||
gk{m>415:R,x>508:A,a<3053:R,R}
|
||||
rs{s<1893:R,m>2997:R,x<2049:R,R}
|
||||
ncn{s<722:R,m>3562:A,s>773:jm,vr}
|
||||
kz{x>3160:A,A}
|
||||
xxt{s>1035:R,a<942:R,R}
|
||||
pfr{m<3520:A,A}
|
||||
nh{a<638:mv,s>865:vm,nrf}
|
||||
sg{s>3051:vps,m>2918:A,zhs}
|
||||
xnj{x>3494:A,m>584:A,a<1897:A,R}
|
||||
jg{s<2380:R,a<2211:A,A}
|
||||
cqm{s<3107:R,a>3295:R,m>3224:R,A}
|
||||
hgv{m<203:A,s>107:R,A}
|
||||
vqt{x<2609:xkn,bnt}
|
||||
ft{s>3154:A,m>1087:R,A}
|
||||
qv{a>621:A,a>259:xp,m<2439:fbv,kpq}
|
||||
lzv{x<2186:gpt,lsb}
|
||||
lx{x>3655:A,s>2359:A,s>2271:R,R}
|
||||
xfj{s<407:sxx,R}
|
||||
tnh{x<3164:vx,js}
|
||||
mbr{s<671:A,R}
|
||||
tbn{m<2151:A,x<3001:R,R}
|
||||
zhp{m<3768:fgp,x>3307:rv,kj}
|
||||
qd{s<3201:A,s>3491:hgt,x>1468:A,R}
|
||||
qdk{s<1950:R,R}
|
||||
vn{s>2814:A,m>386:A,A}
|
||||
lv{x>3090:A,s>2406:znh,R}
|
||||
km{m>2029:A,m>1871:A,s<2456:A,R}
|
||||
ppc{m>2718:R,x<2889:A,x>3361:A,R}
|
||||
bk{a<3189:A,m>846:R,R}
|
||||
ht{s>2582:jts,x<3333:hx,rgx}
|
||||
bb{x<3122:A,x>3258:R,m>3625:A,A}
|
||||
fd{m>650:R,x<450:A,a<2254:gb,gk}
|
||||
dcf{s>1084:tzp,gbb}
|
||||
pm{x>3659:A,m<3539:R,A}
|
||||
hj{a>3260:hrn,A}
|
||||
ds{m>767:A,m>718:A,R}
|
||||
ccv{a<2781:R,a<2905:hd,s<1781:A,qdk}
|
||||
vh{s<2473:lpg,m>643:cmn,s>2647:vkk,ht}
|
||||
zld{x<3737:A,xst}
|
||||
djf{x<748:R,R}
|
||||
jfx{m>1768:gz,m>802:jfs,m<437:cl,snl}
|
||||
vft{x<2121:dn,m<2486:kf,x<2180:qmt,vsj}
|
||||
bc{m<369:hs,a<2050:dfd,m>584:mx,vqt}
|
||||
dn{a<799:vbr,m<1868:A,s<1387:skb,rs}
|
||||
kxl{a<1795:A,s>3664:A,s<3514:R,R}
|
||||
bh{x>3971:A,R}
|
||||
pv{x>1877:R,s<517:R,m>2313:R,A}
|
||||
vzj{s<1879:cth,vc}
|
||||
fc{a<2156:ths,zbc}
|
||||
cs{a>2745:A,x>2067:A,s>2357:R,A}
|
||||
nsj{a>2800:A,m<2010:R,R}
|
||||
lsb{a>2810:R,x>2463:A,m>2877:R,bz}
|
||||
nl{x<2336:A,x>2529:A,A}
|
||||
pk{m<2800:A,s>3027:R,x<487:A,A}
|
||||
bzn{m<1838:R,A}
|
||||
qrt{s>1765:R,s>1529:A,s>1302:zdc,kzp}
|
||||
srn{m<3131:zbr,a>3269:phc,x<2610:R,xd}
|
||||
lz{m<1282:pzk,s>1085:gld,A}
|
||||
spb{x<3144:krj,sx}
|
||||
mqz{m>467:sm,m<282:R,s<969:hhs,jfp}
|
||||
mff{s<632:A,x>625:R,dzt}
|
||||
hgt{m<2577:A,s<3667:A,s>3805:R,R}
|
||||
xpv{a<3077:R,R}
|
||||
rf{m>3497:gv,a>334:vhk,A}
|
||||
rsc{s>1811:A,jk}
|
||||
vkl{a>1095:A,a<912:R,R}
|
||||
mpn{a>3161:pdk,x>3461:zld,ff}
|
||||
pzk{s>1180:R,m>1114:R,x>299:A,R}
|
||||
vf{x<492:R,s<3334:R,R}
|
||||
kjv{m<719:bc,vhc}
|
||||
ks{m>2088:kxl,a>1906:ll,gq}
|
||||
vm{m>1632:vb,qcr}
|
||||
ph{a<2292:qzf,A}
|
||||
xn{x<2461:qln,R}
|
||||
px{a<1762:xg,x>3186:jfx,fc}
|
||||
fzz{x<3174:mq,a>1103:nn,m<533:bgn,mdq}
|
||||
xl{x>116:lmr,m<712:nvq,a>2807:jmf,R}
|
||||
br{s>958:xxt,x<537:bnn,a<1228:R,ssr}
|
||||
mcl{x>3441:R,s<2530:R,R}
|
||||
gn{a<3598:R,a>3777:A,x>861:A,R}
|
||||
scg{a>3029:A,s>3661:A,R}
|
||||
kr{m<471:R,hz}
|
||||
xfc{s>3354:R,R}
|
||||
th{a>1860:vf,a>789:pk,mt}
|
||||
nm{s<2242:A,x>3062:kz,R}
|
||||
xp{m<2732:R,a<441:R,A}
|
||||
fzh{a>101:A,x>3191:R,A}
|
||||
bn{x<3725:R,a>499:R,R}
|
||||
kmh{s>1727:A,a>1678:A,a<1550:A,A}
|
||||
dj{m<2927:R,m>3578:A,x>1056:R,A}
|
||||
jz{x>3123:A,a>3678:A,x>2902:R,R}
|
||||
qq{m<3557:A,m>3852:A,a<1950:R,A}
|
||||
nrv{m>1238:qcd,mqz}
|
||||
pmd{x>3502:R,gdl}
|
||||
ll{s>3570:A,s<3419:R,x>946:A,R}
|
||||
td{x<1875:A,a>1161:A,A}
|
||||
jt{m>1937:A,s<430:tkv,R}
|
||||
pp{s<1233:mzr,m>2932:vsl,ccv}
|
||||
ssr{s<903:R,R}
|
||||
qcd{m>1677:R,R}
|
||||
sv{x<3042:fv,s<3775:tc,m<3706:ct,dm}
|
||||
qsg{x>3287:vvt,dbq}
|
||||
cdt{x<3342:kx,a>1677:btj,nth}
|
||||
jrl{m>1242:A,m>940:R,m<793:R,R}
|
||||
dzt{s<732:A,A}
|
||||
dk{m>1342:rmq,hdt}
|
||||
rn{x<3645:A,R}
|
||||
fx{s>1211:jpn,s>785:nrv,m<1357:pd,dcg}
|
||||
nvh{a<2086:kmh,x<2940:A,m<2730:R,pms}
|
||||
cb{x<581:sd,psf}
|
||||
mq{m>678:A,x>2970:qf,a<881:A,ck}
|
||||
qfn{s>298:A,R}
|
||||
rss{s>1618:rsl,frj}
|
||||
sp{x<3759:R,a>512:A,m>3807:R,R}
|
||||
dns{m>270:A,x<2335:R,s>3567:R,R}
|
||||
dsr{x<2503:R,m>969:A,x>3358:R,A}
|
||||
jfs{s>3760:R,R}
|
||||
zpq{x<2139:td,s>2466:nl,A}
|
||||
vk{s<2893:A,a<803:A,s>2986:R,A}
|
||||
rbn{a>3902:zp,m>472:A,R}
|
||||
tvn{m<2544:R,A}
|
||||
lqf{a<3601:rnx,a<3691:A,fz}
|
||||
ls{m<1384:A,R}
|
||||
rnk{a>3786:R,m<2367:A,zl}
|
||||
pdk{x>3398:R,s>2636:tnq,a>3510:xt,km}
|
||||
gm{x>1475:sg,zdv}
|
||||
ps{s>2886:A,A}
|
||||
ndh{a<979:fkj,a>1636:A,s>2743:tz,nf}
|
||||
zhs{s>2501:R,a<3309:A,s>2306:A,R}
|
||||
zht{a>1418:A,A}
|
||||
fn{x>3198:A,a>3957:R,m>3278:A,A}
|
||||
xc{m>1714:xfc,a>2574:cmr,A}
|
||||
gld{m<1414:R,x<381:A,m<1444:A,R}
|
||||
pz{m>3006:R,A}
|
||||
fkp{a>3424:R,m<3526:A,A}
|
||||
fqc{a<2473:tv,m>2350:cj,a<2565:xs,vv}
|
||||
bnt{s>1011:R,x>3453:A,R}
|
||||
xzq{a<3766:lqf,a<3888:kgd,s<1399:zmt,lp}
|
||||
clh{a<1003:A,s>3818:A,ntv}
|
||||
rq{s>2799:R,m<1088:A,A}
|
||||
jfp{s<1113:A,R}
|
||||
hh{x<466:A,R}
|
||||
md{s>1194:R,R}
|
||||
hm{a>1759:gsb,R}
|
||||
vb{s>1454:A,s<1082:kxs,a>1134:A,hc}
|
||||
rsl{a<3803:gh,st}
|
||||
tjb{x>2545:A,x>1949:A,R}
|
||||
zsp{s<3356:R,A}
|
||||
bg{x>1362:A,R}
|
||||
lbf{m>1460:A,mnr}
|
||||
bt{s<856:R,s>1189:ppc,x>2845:R,R}
|
||||
ct{a<1119:A,x>3291:A,m<3487:A,A}
|
||||
drn{s>2455:R,x>3658:A,x>3401:R,A}
|
||||
xst{m>2109:R,a>2952:A,a<2839:R,R}
|
||||
pr{a>3195:xxm,R}
|
||||
rnx{s<926:A,a>3544:R,A}
|
||||
ngl{a<2849:kzb,x>1007:R,vq}
|
||||
fhq{m<1694:R,m>3210:A,a>1513:A,A}
|
||||
ttd{x>952:R,m>216:R,m>132:R,A}
|
||||
tg{a>447:R,m<3009:R,s<3685:R,A}
|
||||
cgl{x>2271:A,s>3239:R,s<2541:cs,A}
|
||||
jh{a>3871:R,s<2611:A,R}
|
||||
vlx{m>2576:A,a<3152:R,m>1231:A,R}
|
||||
fh{s>1137:R,s<937:R,djf}
|
||||
xz{x<2419:sl,x<3456:rt,m>3040:fs,crn}
|
||||
pj{a<887:sq,s<3315:A,R}
|
||||
kjt{m<990:hqc,nkr}
|
||||
tb{m>1009:A,A}
|
||||
ppm{a<1310:R,a<1850:R,a<2261:R,R}
|
||||
jm{x<1054:R,a<579:R,A}
|
||||
fsf{x<3020:R,R}
|
||||
xxm{a<3299:R,R}
|
||||
pvh{s>929:A,R}
|
||||
bfx{a<3017:A,a>3351:gn,grz}
|
||||
fp{x<2966:tbv,x<3308:R,R}
|
||||
krr{x<677:tvn,A}
|
||||
vdz{m<3388:R,x<844:A,R}
|
||||
hzf{s>385:R,s<196:A,A}
|
||||
jjf{x>3217:A,m<616:qfn,dr}
|
||||
nq{x>2432:lg,m<1705:A,R}
|
||||
cmn{a<3539:rtg,a>3754:sf,dv}
|
||||
sq{a>365:R,m>2615:A,s>3324:A,A}
|
||||
xqf{x<554:A,m>1924:A,x>1244:A,R}
|
||||
gxc{a<350:A,s>506:fhg,vl}
|
||||
qx{a<3727:A,R}
|
||||
nzq{m<1027:R,s>1843:R,A}
|
||||
rv{a<3212:R,x>3734:R,m>3888:tq,tn}
|
||||
lrn{m>1353:kq,s<3039:jv,gx}
|
||||
nf{m>2662:A,x<3529:A,m>2179:A,R}
|
||||
zlz{a<750:mc,clh}
|
||||
kf{a>756:A,R}
|
||||
gj{m<1030:A,a>1937:R,R}
|
||||
gb{s<3174:A,s<3470:A,A}
|
||||
tnq{x>3001:A,R}
|
||||
zqv{m>691:A,R}
|
||||
kj{x<2954:psp,x>3147:mg,a>3127:mjb,A}
|
||||
tgn{a>1711:lkc,s>541:qt,R}
|
||||
npt{x<772:R,x>900:R,s<1084:R,A}
|
||||
cx{x>3400:lxp,lbv}
|
||||
vvt{s>278:R,A}
|
||||
vqq{x<3192:R,A}
|
||||
tq{s>2456:R,s<2301:R,x>3451:A,A}
|
||||
xxx{m<2342:R,A}
|
||||
dkr{a<2409:dg,m<1437:lvf,x>1274:gm,qdc}
|
||||
fs{s>1657:pbv,m<3482:A,m>3677:R,R}
|
||||
tpg{m<1159:A,x>3135:R,gmf}
|
||||
qln{a<2906:A,a>2928:R,a<2918:R,A}
|
||||
lvf{x<1270:bfx,x<1455:bzz,qk}
|
||||
xlq{m<334:A,s>1515:A,A}
|
||||
sx{m<1833:tfs,hf}
|
||||
gpt{a>2836:zxd,a>2730:R,A}
|
||||
krn{x>1155:ckd,s<1260:A,m>2770:A,zht}
|
||||
sk{m>348:R,x>1377:A,m>153:A,R}
|
||||
rl{a<984:R,R}
|
||||
ntd{a<819:dns,qnm}
|
||||
grz{x>890:A,a<3172:A,A}
|
||||
kt{x>967:A,R}
|
||||
qs{m<1546:A,R}
|
||||
js{x>3672:qmv,a>2929:hdn,hcs}
|
||||
bzz{m<647:sk,bg}
|
||||
vv{s>2934:sj,R}
|
||||
lbp{s>2775:R,R}
|
||||
zxd{x>1854:A,R}
|
||||
crn{s>1724:R,rn}
|
||||
jc{x>1851:R,s<3672:A,m<3477:A,R}
|
||||
xxh{m>1324:qqn,qm}
|
||||
pn{s<976:A,m<2297:R,A}
|
||||
fv{s>3818:A,s<3658:R,s<3743:R,A}
|
||||
ck{x>2824:R,m<316:R,A}
|
||||
vdp{x<3490:A,A}
|
||||
xq{m>184:A,x>3334:A,A}
|
||||
fz{m>3339:R,m>2690:R,x>2493:R,R}
|
||||
jf{m<1773:R,x>659:R,A}
|
||||
xd{a<3143:A,R}
|
||||
svq{a<3528:A,R}
|
||||
cl{x>3473:A,R}
|
||||
qf{x>3076:A,R}
|
||||
ktb{m<3197:A,s<704:R,s>1154:A,A}
|
||||
gbj{m<158:R,m<302:R,m>336:R,R}
|
||||
ff{s<2459:lmc,s>2743:R,nsj}
|
||||
rcn{s>3821:R,x>2847:A,a<2261:R,A}
|
||||
xkn{x>2134:R,x>1785:A,A}
|
||||
pf{a>3576:A,s>3815:A,s>3737:R,R}
|
||||
ntv{s<3659:R,A}
|
||||
psf{m>575:R,a<2611:A,m>319:R,R}
|
||||
fqz{a>3321:bx,vdp}
|
||||
tzp{x<554:ph,a>2615:lm,krn}
|
||||
pht{s>625:fh,x>606:ffn,sxb}
|
||||
zz{m<1836:ql,s>1299:hp,m<3200:shb,A}
|
||||
snl{s>3863:R,a<2001:xnj,kk}
|
||||
qdc{a<3128:ngl,a>3442:rnk,x<874:zm,gl}
|
||||
rsz{m>1017:R,x<2038:A,m<443:R,dzz}
|
||||
frj{m>1063:md,a>3826:rbn,s>1317:lb,zkk}
|
||||
bbt{a>3364:A,a<3152:R,R}
|
||||
lpg{x>3231:fqz,x<2909:nvk,s<2283:nm,lv}
|
||||
sd{s<1984:R,a>1624:A,m<729:A,A}
|
||||
spq{x<3000:A,s>148:A,R}
|
||||
fsv{s<2728:gj,m<1078:fpf,s>2917:R,R}
|
||||
rmq{s<3098:A,x<182:fg,cpn}
|
||||
msc{x>326:A,xxx}
|
||||
drg{a>1618:hzf,s>486:zjl,a>619:hzc,A}
|
||||
hx{x>3100:R,m<249:hnq,R}
|
||||
ksc{a>3214:A,x>2913:R,R}
|
||||
kxs{x<3497:R,s>949:A,A}
|
||||
xv{s>311:A,R}
|
||||
kd{x<3492:A,ppm}
|
||||
st{s<1839:R,m>810:R,pgj}
|
||||
ntb{m>3358:spq,m>2731:zhg,s<116:R,A}
|
||||
lqz{a>3814:A,A}
|
||||
fb{x>2177:tg,bjd}
|
||||
dcg{a<3359:pgb,rch}
|
||||
khp{a<2918:A,x>3796:R,m>378:R,A}
|
||||
hhs{x<3165:A,R}
|
||||
bnn{a<1158:R,x<228:A,A}
|
||||
nx{m>469:R,x>3876:R,x<3760:A,A}
|
||||
vl{m>1539:A,a>468:A,s>326:R,A}
|
||||
qmv{s<3328:R,A}
|
||||
rt{m<2818:fbx,R}
|
||||
hcs{x<3425:zsp,mk}
|
||||
mn{m<2363:A,R}
|
||||
sm{m<839:A,x>2835:A,s>1035:A,A}
|
||||
zn{x<2270:R,a>798:R,s>3678:R,A}
|
||||
qqn{m>1794:jt,a<3748:fdm,gkv}
|
||||
hdn{s>3198:A,s>3046:R,ngq}
|
||||
mg{x>3205:R,s<2688:R,A}
|
||||
sgc{x<3807:fhq,x<3919:A,bh}
|
||||
qhl{m>2988:A,x>3259:drn,xpv}
|
||||
zbr{x<2841:R,m>2724:R,R}
|
||||
rjb{x>2706:R,R}
|
||||
qp{m>1140:drg,tgn}
|
||||
kkk{s>1408:vzj,m<1501:dnp,s<833:dmc,dcf}
|
||||
cmr{a>3290:R,m>1084:R,m>506:R,A}
|
||||
lbv{m<3300:R,a<923:A,s<2435:bb,qq}
|
||||
mjb{m<3900:R,a>3686:A,R}
|
||||
clg{s>1434:nvh,m>3229:rsh,bt}
|
||||
hrn{a>3478:R,a>3380:R,m>1194:R,A}
|
||||
zhd{s>1275:R,m>3076:R,m<2721:A,R}
|
||||
hnq{x>2834:A,R}
|
||||
tbt{x>3131:A,m<3435:R,A}
|
||||
phc{a>3375:A,a<3306:R,A}
|
||||
vq{x<800:R,s>2917:R,x<922:R,R}
|
||||
kq{s<3392:sc,a>1260:hm,m>2319:fb,htk}
|
||||
fbx{a>3317:A,m<2345:A,R}
|
||||
cm{m<2219:R,m>2264:R,R}
|
||||
csz{s>3528:R,A}
|
||||
nst{x>2459:A,A}
|
||||
lf{a<3121:R,x<2716:R,m<818:R,A}
|
||||
xsp{x<2980:R,a>2817:A,A}
|
||||
qm{x<2949:kr,x<3428:jjf,s<456:jtt,jqn}
|
||||
qt{s<744:A,x<1059:R,s>816:R,A}
|
||||
zc{x>3545:qx,a>3625:vn,A}
|
||||
cxk{a>1449:ntt,s>1617:xbr,s>1504:R,xqf}
|
||||
cg{x>2245:zx,x<1956:zbk,vft}
|
||||
zkk{m<649:A,a>3680:R,R}
|
||||
bx{a<3661:A,x<3529:A,a>3778:R,R}
|
||||
mv{s>1300:rsc,khc}
|
||||
qjt{x<3376:A,R}
|
||||
mgp{x>3029:zq,A}
|
||||
fpf{a>1769:R,x>2049:A,s<2923:A,R}
|
||||
lhc{s>1662:A,m>1543:A,a<3599:tl,vfn}
|
||||
mzr{a<2819:R,R}
|
||||
psp{s<2611:A,a>3354:A,a>3056:A,A}
|
||||
vc{m<1333:cb,mp}
|
||||
bzc{m<1850:R,m<1953:A,R}
|
||||
kb{m<2614:mpn,m>3380:zhp,gqd}
|
||||
dv{a<3677:cfq,x<3383:R,s<2710:R,rq}
|
||||
xh{s<2524:A,R}
|
||||
vr{s>754:A,x<643:A,A}
|
||||
sj{s<3498:R,s<3711:R,m<1518:A,R}
|
||||
bq{a<1413:R,m>3189:A,a<1750:R,R}
|
||||
bgn{m<197:A,m<353:gbq,xh}
|
||||
jl{x>2858:R,m<476:R,R}
|
||||
vbr{x<2055:R,m>2096:A,R}
|
||||
ngq{a>3426:R,s<3009:A,a<3210:A,R}
|
||||
krj{x>2852:pjd,gf}
|
||||
dp{m>1430:A,A}
|
||||
xkm{m<1913:kjv,vz}
|
||||
vg{x>224:R,a>1513:A,m<323:A,R}
|
||||
jmf{s<1182:A,a>3547:A,A}
|
||||
vqr{a>3441:ljt,A}
|
||||
ckd{m>3131:R,a<1567:R,m>2271:R,A}
|
||||
bp{s>3270:A,s>3133:R,R}
|
||||
pc{x>3663:A,m<491:R,A}
|
||||
mx{m>663:bs,m<622:tjb,gkn}
|
||||
qhh{x<1947:A,m>3589:A,R}
|
||||
ths{a>2010:dp,R}
|
||||
znh{m>662:A,x>2990:R,R}
|
||||
fph{a>2941:R,s<1649:R,R}
|
||||
nkr{x<1012:npt,m>1326:A,s>1224:R,R}
|
||||
zbc{x>2881:R,x>2784:rcn,x>2722:xf,rjb}
|
||||
hp{s>1600:R,s>1465:R,a>263:R,R}
|
||||
kdf{s>420:R,m>1639:R,x>2176:A,R}
|
||||
hkl{s<3823:bn,m>3668:sp,s>3936:A,A}
|
||||
lp{m>3026:tbt,s>1876:R,bj}
|
||||
zmt{a>3930:fn,a<3915:bcz,ktb}
|
||||
jqn{a<3862:pc,m<761:R,a<3938:ldl,A}
|
||||
hms{x>3072:A,s<1921:R,A}
|
||||
sn{s>774:A,s>753:R,x>547:A,A}
|
||||
kx{m>1998:tbn,A}
|
||||
mqc{m<2308:A,m>3052:A,m>2635:R,A}
|
||||
qdj{a>2946:zgm,a<2669:fqc,m>2271:lzv,ndr}
|
||||
xt{a>3826:A,x<3063:A,A}
|
||||
kvr{m>1390:R,x>3294:A,R}
|
||||
hz{x>2278:A,x<1949:A,A}
|
||||
fkj{x<3168:A,s<2741:R,R}
|
||||
tn{m<3831:R,s>2560:R,A}
|
||||
zjl{s>694:R,R}
|
||||
ndr{a<2827:cgl,x<2240:rsz,xn}
|
||||
btj{m<1813:qs,m<2042:jg,cm}
|
||||
bjd{x<1891:A,s>3600:A,A}
|
||||
gjg{m>2075:rjd,a<3588:fx,s<809:xxh,rss}
|
||||
zch{s<3538:hl,m<2003:zlz,dz}
|
||||
nrf{s>428:vkl,s>146:qsg,a>957:pmd,dxn}
|
||||
vhc{s>1085:tpg,jxf}
|
||||
lb{m<643:xlq,a>3717:svn,m>911:dsr,ds}
|
||||
zdc{x>1803:R,A}
|
||||
bzj{s>3689:A,m<2560:R,R}
|
||||
flt{s>1360:A,x>2163:A,A}
|
||||
qg{s>1039:A,A}
|
||||
dm{m<3816:A,s<3853:R,A}
|
||||
xmg{m>752:A,x>137:jzj,gsl}
|
||||
bcz{a<3903:R,R}
|
||||
lkc{a>3188:A,m<900:A,m>1018:A,R}
|
||||
jxf{s<527:srg,A}
|
||||
gx{m>486:dq,ntd}
|
||||
bd{s>2400:A,x>3671:A,s>2281:R,A}
|
||||
qc{s<2673:R,A}
|
||||
lm{a<3182:dj,a>3635:lqz,a>3407:R,R}
|
||||
qnm{m<247:R,a>1687:R,m>389:A,A}
|
||||
zq{s>3263:R,s>3111:R,R}
|
||||
mk{s>3246:A,m>2016:R,s<3088:A,R}
|
||||
rql{a<3077:xsp,s>2761:jl,s>2722:R,A}
|
||||
vj{s<2785:ndh,kd}
|
||||
in{s>2178:zs,skv}
|
||||
xrc{s>712:sn,A}
|
||||
jp{a<2589:R,A}
|
||||
pgj{a>3929:R,x>2479:A,A}
|
||||
jts{x>3530:R,A}
|
||||
gv{s>3739:A,R}
|
||||
mnr{s>2737:R,A}
|
||||
tgt{m>1439:R,s>292:R,A}
|
||||
xvs{a<2848:A,A}
|
||||
vps{a>3227:A,x<1588:R,A}
|
||||
jzj{m<672:A,s<1122:R,R}
|
||||
zzp{x<901:ch,R}
|
||||
sl{s>1542:A,s>1296:R,x>1931:A,zxz}
|
||||
rjd{a>3500:xzq,s<1086:qj,xz}
|
||||
kgd{s>1426:A,a>3812:A,R}
|
||||
dmc{m<2947:szv,kqx}
|
||||
hbk{m<3419:A,R}
|
||||
htk{a<729:R,a>1042:A,a>861:R,zn}
|
||||
zp{s<1255:A,A}
|
||||
qlx{m>1631:R,x>3329:R,R}
|
||||
skv{x<1606:kkk,a<1440:ggv,a<3018:xkm,gjg}
|
||||
zl{m>3149:A,a>3596:A,R}
|
||||
sjc{m>2149:A,A}
|
||||
ggv{x>2600:nh,cg}
|
||||
pd{a<3356:pr,x<2700:xfj,a<3465:zbd,xv}
|
||||
vhk{a<614:A,a>735:A,m>3340:A,R}
|
||||
bz{x<2317:R,s<3304:A,A}
|
||||
zbd{m>889:zfk,bdh}
|
||||
vsj{a<598:zhd,R}
|
||||
qzf{a>1455:R,x>340:A,s<1196:R,R}
|
||||
dz{m<3157:qv,x>3473:hkl,a>877:sv,rf}
|
||||
rtg{a>2957:R,A}
|
||||
qk{a>3252:svq,s>3213:R,m>548:cfz,R}
|
||||
zx{a>871:sxt,a>314:mn,a>186:zz,nq}
|
||||
kcd{x<2880:R,s>94:R,R}
|
||||
hqc{m<796:R,m>890:rhd,a<2192:A,xvs}
|
||||
ffn{m>350:jp,a<2088:ttd,a>2817:R,R}
|
||||
sz{m<1599:R,x>2121:ktx,m<3075:bbt,qhh}
|
||||
jtt{a<3836:zqv,m<876:gg,A}
|
||||
lmr{a<2718:A,a<3149:R,R}
|
||||
zdv{s>3010:R,lr}
|
||||
jcl{m<1659:A,R}
|
||||
mdq{a<479:R,A}
|
||||
dnp{m<537:pht,s<885:qp,x<582:bjg,kjt}
|
||||
lxp{m>2932:A,lx}
|
||||
kqx{s<513:hbk,a<1592:ncn,a>3119:xrc,kt}
|
||||
cnl{x<1035:R,m<2338:A,R}
|
||||
mp{m<2347:xpj,a>2221:vdz,bq}
|
||||
rgx{s<2542:R,R}
|
||||
rb{s<3903:A,A}
|
||||
jk{m>2376:R,x>3391:R,m<1198:R,R}
|
||||
zgm{s>3092:bzj,sz}
|
||||
gt{a>1014:R,m<2365:ls,R}
|
||||
jpn{s>1819:hj,a>3326:vqr,ljm}
|
||||
nzj{s>254:R,m>2156:R,x<991:jf,qhq}
|
||||
gh{m>856:A,nsp}
|
||||
kpq{a<110:A,x>3312:R,x<3090:R,R}
|
||||
hl{x<3177:pj,bp}
|
||||
gs{a<180:R,s>3703:R,R}
|
||||
gz{m>3188:R,R}
|
||||
lft{s>2829:ps,gbj}
|
||||
kzb{m>2754:A,a<2674:A,A}
|
||||
vz{a>2453:pp,clg}
|
||||
tqc{x<360:dk,zcq}
|
||||
bxv{a<2317:A,m<2884:pn,fkp}
|
||||
ztl{a<590:R,x<2295:R,x>2529:R,R}
|
||||
vkk{a>3382:zc,x>3140:xrl,m<384:lft,rql}
|
||||
fbv{s<3805:R,s>3881:R,a>172:R,R}
|
||||
gbq{m>279:A,x<3717:R,x<3898:A,R}
|
||||
svn{s<1485:R,A}
|
||||
skb{s>589:R,s>295:R,x>2063:A,A}
|
||||
mc{a>272:A,x>3488:gs,s>3786:A,fsf}
|
||||
pbv{x<3811:R,a>3290:A,m<3444:R,A}
|
||||
gkn{s<1377:A,A}
|
||||
nth{a<1084:bd,A}
|
||||
vsl{a<2799:A,a<2901:bgb,fph}
|
||||
lr{x<1407:A,s>2654:R,s<2373:A,R}
|
||||
dbq{m<1824:R,s>291:R,A}
|
||||
hdt{s>3011:R,s>2681:A,bgg}
|
||||
nvq{m>597:R,x>47:R,A}
|
||||
qj{s>674:pz,s>313:srn,ntb}
|
||||
fgp{a>3257:R,mcl}
|
||||
pjd{s<3848:vlx,A}
|
||||
gmf{s<1729:A,A}
|
||||
kzp{x>1746:A,x>1670:A,m>2460:A,A}
|
||||
tl{m<888:A,m<1289:A,R}
|
||||
zh{m<1334:fzz,s>2674:vj,m<2347:cdt,cx}
|
||||
ql{s<1432:A,a>258:R,A}
|
||||
rch{s<485:R,vqq}
|
||||
hf{a<3208:R,pf}
|
||||
bj{x<2870:R,m<2489:A,R}
|
||||
zhg{x>3190:A,s>144:R,m<2941:A,R}
|
||||
rsh{x<3060:R,a<1833:pm,R}
|
||||
ntt{a>1930:R,a<1611:A,A}
|
||||
hd{s>1811:A,R}
|
||||
dfd{x<2726:A,qg}
|
||||
gqd{a>3471:qjt,qhl}
|
||||
xrl{x>3598:khp,m>284:lbp,m<100:R,xq}
|
||||
zxz{m<2818:A,R}
|
||||
vfn{s>1502:R,x>955:R,s>1440:A,R}
|
||||
dr{s<370:A,x>3070:R,R}
|
||||
cth{a<2210:cxk,a>3174:lhc,krr}
|
||||
xbr{m<1775:R,m>3200:A,A}
|
||||
nn{m>718:R,x>3641:nx,A}
|
||||
dxn{s<55:hr,x>3309:A,a<824:kcd,mqc}
|
||||
mt{a<423:R,a>555:R,R}
|
||||
hqk{a>2663:A,s<888:R,a<2564:R,A}
|
||||
ns{a<2307:lrn,qdj}
|
||||
sxb{s>318:vg,hgv}
|
||||
ljm{s<1457:A,m>763:A,s>1648:R,A}
|
||||
qcr{s<1460:R,m<548:hms,a>1054:A,nzq}
|
||||
sxx{a>3455:A,R}
|
||||
|
||||
{x=378,m=450,a=211,s=36}
|
||||
{x=220,m=1090,a=338,s=879}
|
||||
{x=117,m=124,a=2136,s=128}
|
||||
{x=1392,m=1408,a=126,s=16}
|
||||
{x=2038,m=278,a=901,s=1801}
|
||||
{x=323,m=1703,a=964,s=571}
|
||||
{x=265,m=358,a=456,s=34}
|
||||
{x=1513,m=144,a=525,s=1341}
|
||||
{x=355,m=2036,a=814,s=1179}
|
||||
{x=937,m=701,a=2026,s=1349}
|
||||
{x=1292,m=766,a=2805,s=16}
|
||||
{x=319,m=26,a=83,s=1193}
|
||||
{x=600,m=5,a=242,s=76}
|
||||
{x=117,m=1415,a=1636,s=1057}
|
||||
{x=87,m=1530,a=1686,s=386}
|
||||
{x=36,m=957,a=1712,s=300}
|
||||
{x=2570,m=49,a=661,s=442}
|
||||
{x=643,m=698,a=1593,s=854}
|
||||
{x=1450,m=1410,a=289,s=1342}
|
||||
{x=1690,m=376,a=584,s=3715}
|
||||
{x=1942,m=570,a=1726,s=1192}
|
||||
{x=420,m=475,a=1410,s=863}
|
||||
{x=550,m=662,a=2140,s=105}
|
||||
{x=241,m=2370,a=756,s=26}
|
||||
{x=705,m=425,a=1000,s=160}
|
||||
{x=1763,m=914,a=197,s=555}
|
||||
{x=2267,m=323,a=70,s=147}
|
||||
{x=497,m=392,a=1959,s=360}
|
||||
{x=428,m=1375,a=415,s=236}
|
||||
{x=1800,m=96,a=403,s=1227}
|
||||
{x=216,m=381,a=1217,s=1031}
|
||||
{x=3129,m=304,a=811,s=1753}
|
||||
{x=555,m=59,a=3254,s=2896}
|
||||
{x=397,m=1518,a=740,s=496}
|
||||
{x=905,m=217,a=1234,s=2319}
|
||||
{x=283,m=2490,a=309,s=1156}
|
||||
{x=1777,m=624,a=96,s=2053}
|
||||
{x=1031,m=481,a=1014,s=198}
|
||||
{x=155,m=205,a=2460,s=832}
|
||||
{x=123,m=25,a=3962,s=3662}
|
||||
{x=3242,m=396,a=519,s=150}
|
||||
{x=2632,m=1307,a=3594,s=1714}
|
||||
{x=147,m=285,a=1020,s=40}
|
||||
{x=1498,m=1133,a=241,s=1263}
|
||||
{x=1977,m=323,a=1594,s=241}
|
||||
{x=807,m=1042,a=702,s=295}
|
||||
{x=70,m=455,a=1328,s=108}
|
||||
{x=2392,m=27,a=158,s=44}
|
||||
{x=528,m=671,a=2003,s=935}
|
||||
{x=1539,m=2002,a=168,s=479}
|
||||
{x=2121,m=195,a=901,s=1116}
|
||||
{x=251,m=51,a=380,s=745}
|
||||
{x=793,m=1959,a=598,s=605}
|
||||
{x=137,m=261,a=714,s=1548}
|
||||
{x=2783,m=486,a=2065,s=914}
|
||||
{x=574,m=387,a=250,s=28}
|
||||
{x=3,m=829,a=1862,s=2}
|
||||
{x=846,m=2476,a=841,s=1810}
|
||||
{x=1020,m=114,a=463,s=323}
|
||||
{x=4,m=970,a=192,s=142}
|
||||
{x=942,m=2297,a=125,s=1638}
|
||||
{x=1664,m=2275,a=2086,s=290}
|
||||
{x=682,m=93,a=143,s=2033}
|
||||
{x=1613,m=356,a=463,s=632}
|
||||
{x=633,m=268,a=150,s=798}
|
||||
{x=1743,m=1455,a=56,s=487}
|
||||
{x=2774,m=103,a=739,s=77}
|
||||
{x=1760,m=2631,a=81,s=138}
|
||||
{x=461,m=1688,a=1543,s=1712}
|
||||
{x=1182,m=14,a=566,s=3270}
|
||||
{x=680,m=467,a=1920,s=297}
|
||||
{x=1281,m=2355,a=704,s=1340}
|
||||
{x=142,m=65,a=589,s=20}
|
||||
{x=1412,m=559,a=677,s=2106}
|
||||
{x=905,m=2761,a=1526,s=648}
|
||||
{x=399,m=667,a=1901,s=27}
|
||||
{x=2241,m=3411,a=1786,s=321}
|
||||
{x=1395,m=1278,a=508,s=1112}
|
||||
{x=363,m=35,a=218,s=1280}
|
||||
{x=829,m=115,a=304,s=192}
|
||||
{x=1397,m=599,a=861,s=838}
|
||||
{x=824,m=2140,a=88,s=1736}
|
||||
{x=661,m=276,a=502,s=731}
|
||||
{x=585,m=14,a=705,s=473}
|
||||
{x=747,m=95,a=829,s=805}
|
||||
{x=2006,m=323,a=982,s=168}
|
||||
{x=795,m=193,a=473,s=1531}
|
||||
{x=687,m=428,a=972,s=1154}
|
||||
{x=254,m=426,a=281,s=552}
|
||||
{x=171,m=369,a=382,s=1369}
|
||||
{x=964,m=10,a=322,s=2007}
|
||||
{x=1960,m=183,a=2153,s=1967}
|
||||
{x=2315,m=170,a=41,s=727}
|
||||
{x=189,m=901,a=307,s=3026}
|
||||
{x=757,m=1235,a=1316,s=335}
|
||||
{x=836,m=3023,a=453,s=2355}
|
||||
{x=2187,m=2140,a=683,s=2560}
|
||||
{x=1772,m=468,a=1812,s=1329}
|
||||
{x=783,m=601,a=1339,s=3291}
|
||||
{x=570,m=172,a=1794,s=120}
|
||||
{x=1207,m=1572,a=700,s=758}
|
||||
{x=1961,m=3652,a=702,s=153}
|
||||
{x=1094,m=435,a=19,s=938}
|
||||
{x=3328,m=166,a=247,s=216}
|
||||
{x=1500,m=2012,a=1561,s=59}
|
||||
{x=12,m=2269,a=8,s=796}
|
||||
{x=193,m=1137,a=328,s=13}
|
||||
{x=120,m=1179,a=59,s=1829}
|
||||
{x=499,m=650,a=1049,s=1803}
|
||||
{x=2761,m=1431,a=389,s=1322}
|
||||
{x=456,m=2766,a=2165,s=348}
|
||||
{x=2387,m=12,a=2140,s=556}
|
||||
{x=387,m=7,a=1514,s=1137}
|
||||
{x=1111,m=608,a=581,s=965}
|
||||
{x=1055,m=181,a=754,s=67}
|
||||
{x=74,m=2582,a=66,s=546}
|
||||
{x=5,m=956,a=1013,s=657}
|
||||
{x=262,m=189,a=2496,s=233}
|
||||
{x=518,m=2821,a=851,s=825}
|
||||
{x=351,m=1981,a=221,s=34}
|
||||
{x=995,m=165,a=36,s=2286}
|
||||
{x=1636,m=335,a=936,s=447}
|
||||
{x=763,m=692,a=1527,s=210}
|
||||
{x=301,m=559,a=1815,s=2640}
|
||||
{x=959,m=2852,a=232,s=53}
|
||||
{x=136,m=153,a=206,s=11}
|
||||
{x=1533,m=42,a=2014,s=136}
|
||||
{x=341,m=378,a=37,s=577}
|
||||
{x=220,m=1451,a=185,s=421}
|
||||
{x=1086,m=3265,a=1184,s=2960}
|
||||
{x=143,m=2701,a=602,s=173}
|
||||
{x=628,m=1016,a=1642,s=223}
|
||||
{x=597,m=641,a=1331,s=651}
|
||||
{x=809,m=1843,a=1111,s=2189}
|
||||
{x=1385,m=1352,a=238,s=1969}
|
||||
{x=515,m=1374,a=125,s=913}
|
||||
{x=798,m=2743,a=1798,s=1045}
|
||||
{x=2999,m=1787,a=1168,s=188}
|
||||
{x=57,m=77,a=2652,s=56}
|
||||
{x=1231,m=304,a=1288,s=523}
|
||||
{x=1031,m=381,a=558,s=267}
|
||||
{x=721,m=883,a=2995,s=22}
|
||||
{x=304,m=846,a=1525,s=30}
|
||||
{x=446,m=2969,a=412,s=674}
|
||||
{x=187,m=418,a=1187,s=571}
|
||||
{x=810,m=515,a=819,s=1393}
|
||||
{x=740,m=3392,a=1128,s=1114}
|
||||
{x=137,m=631,a=1208,s=1707}
|
||||
{x=653,m=2468,a=952,s=811}
|
||||
{x=33,m=70,a=518,s=464}
|
||||
{x=3318,m=2,a=3661,s=64}
|
||||
{x=50,m=548,a=1657,s=704}
|
||||
{x=2272,m=2684,a=1597,s=2220}
|
||||
{x=185,m=339,a=460,s=517}
|
||||
{x=8,m=1651,a=1810,s=354}
|
||||
{x=548,m=833,a=1703,s=759}
|
||||
{x=551,m=358,a=390,s=468}
|
||||
{x=202,m=2260,a=597,s=632}
|
||||
{x=453,m=1811,a=754,s=2449}
|
||||
{x=353,m=101,a=1835,s=72}
|
||||
{x=1451,m=453,a=162,s=13}
|
||||
{x=125,m=2120,a=627,s=981}
|
||||
{x=5,m=283,a=1755,s=194}
|
||||
{x=973,m=835,a=62,s=1184}
|
||||
{x=346,m=1348,a=442,s=210}
|
||||
{x=4,m=1242,a=136,s=196}
|
||||
{x=2388,m=1336,a=1991,s=2873}
|
||||
{x=561,m=2335,a=1059,s=627}
|
||||
{x=838,m=3226,a=159,s=1053}
|
||||
{x=2578,m=49,a=1920,s=2432}
|
||||
{x=710,m=342,a=182,s=534}
|
||||
{x=1997,m=1509,a=946,s=1849}
|
||||
{x=810,m=249,a=495,s=257}
|
||||
{x=363,m=274,a=2742,s=25}
|
||||
{x=506,m=565,a=2584,s=731}
|
||||
{x=508,m=2073,a=21,s=1826}
|
||||
{x=1413,m=780,a=779,s=378}
|
||||
{x=1097,m=47,a=98,s=402}
|
||||
{x=536,m=2,a=2710,s=1499}
|
||||
{x=548,m=2845,a=2095,s=555}
|
||||
{x=2963,m=2206,a=1920,s=875}
|
||||
{x=1783,m=367,a=1245,s=594}
|
||||
{x=409,m=18,a=408,s=119}
|
||||
{x=1554,m=3613,a=3002,s=87}
|
||||
{x=232,m=197,a=63,s=1372}
|
||||
{x=412,m=1355,a=1673,s=1667}
|
||||
{x=261,m=142,a=123,s=1187}
|
||||
{x=1396,m=779,a=287,s=60}
|
||||
{x=28,m=1350,a=585,s=861}
|
||||
{x=1123,m=329,a=1166,s=62}
|
||||
{x=2292,m=73,a=123,s=596}
|
||||
{x=2400,m=1430,a=390,s=1313}
|
||||
{x=638,m=2856,a=44,s=488}
|
||||
{x=294,m=1534,a=1075,s=1914}
|
||||
{x=1233,m=71,a=253,s=3058}
|
||||
{x=1536,m=805,a=158,s=738}
|
||||
{x=2903,m=119,a=2344,s=2387}
|
||||
{x=142,m=1768,a=940,s=881}
|
||||
{x=301,m=2748,a=739,s=766}
|
||||
{x=127,m=18,a=141,s=1398}
|
||||
+255
@@ -0,0 +1,255 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
_ "embed"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
aoc "go.sour.is/advent-of-code"
|
||||
)
|
||||
|
||||
// var log = aoc.Log
|
||||
|
||||
func main() { aoc.MustResult(aoc.Runner(run)) }
|
||||
|
||||
type result struct {
|
||||
valuePT1 int
|
||||
valuePT2 uint
|
||||
}
|
||||
|
||||
func (r result) String() string { return fmt.Sprintf("%#v", r) }
|
||||
|
||||
func run(scan *bufio.Scanner) (*result, error) {
|
||||
|
||||
var workflows = make(map[string][]rule)
|
||||
var parts []part
|
||||
|
||||
for scan.Scan() {
|
||||
text := strings.TrimSuffix(scan.Text(), "}")
|
||||
if len(text) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
// Is Part
|
||||
if p, ok := scanPart(text); ok {
|
||||
parts = append(parts, p)
|
||||
continue
|
||||
}
|
||||
|
||||
if name, r, ok := scanRule(text); ok {
|
||||
workflows[name] = r
|
||||
}
|
||||
}
|
||||
|
||||
var result result
|
||||
result.valuePT1 = solveWorkflow(parts, workflows)
|
||||
result.valuePT2 = solveRanges(workflows)
|
||||
|
||||
return &result, nil
|
||||
}
|
||||
|
||||
type part struct {
|
||||
x, m, a, s int
|
||||
}
|
||||
|
||||
func (p part) String() string {
|
||||
return fmt.Sprintf("{x:%v m:%v a:%v s:%v}", p.x, p.m, p.a, p.s)
|
||||
}
|
||||
func scanPart(text string) (part, bool) {
|
||||
var p part
|
||||
|
||||
// Is Part
|
||||
if text[0] == '{' {
|
||||
for _, s := range strings.Split(text[1:], ",") {
|
||||
a, b, _ := strings.Cut(s, "=")
|
||||
i := aoc.Atoi(b)
|
||||
switch a {
|
||||
case "x":
|
||||
p.x = i
|
||||
case "m":
|
||||
p.m = i
|
||||
case "a":
|
||||
p.a = i
|
||||
case "s":
|
||||
p.s = i
|
||||
}
|
||||
}
|
||||
return p, true
|
||||
}
|
||||
return p, false
|
||||
}
|
||||
|
||||
type rule struct {
|
||||
match string
|
||||
op string
|
||||
value int
|
||||
queue string
|
||||
}
|
||||
|
||||
func scanRule(text string) (string, []rule, bool) {
|
||||
name, text, _ := strings.Cut(text, "{")
|
||||
var r []rule
|
||||
for _, s := range strings.Split(text, ",") {
|
||||
if a, b, ok := strings.Cut(s, "<"); ok {
|
||||
b, c, _ := strings.Cut(b, ":")
|
||||
r = append(r, rule{
|
||||
match: a,
|
||||
op: "<",
|
||||
value: aoc.Atoi(b),
|
||||
queue: c,
|
||||
})
|
||||
|
||||
continue
|
||||
}
|
||||
if a, b, ok := strings.Cut(s, ">"); ok {
|
||||
b, c, _ := strings.Cut(b, ":")
|
||||
r = append(r, rule{
|
||||
match: a,
|
||||
op: ">",
|
||||
value: aoc.Atoi(b),
|
||||
queue: c,
|
||||
})
|
||||
continue
|
||||
}
|
||||
|
||||
// default queue comes last
|
||||
r = append(r, rule{queue: s})
|
||||
break
|
||||
}
|
||||
return name, r, len(r) > 0
|
||||
}
|
||||
func (r rule) Match(p part) bool {
|
||||
var value int
|
||||
|
||||
switch r.match {
|
||||
case "x":
|
||||
value = p.x
|
||||
case "m":
|
||||
value = p.m
|
||||
case "a":
|
||||
value = p.a
|
||||
case "s":
|
||||
value = p.s
|
||||
default:
|
||||
return true // default to new queue
|
||||
}
|
||||
|
||||
if r.op == ">" && value > r.value {
|
||||
return true
|
||||
} else if r.op == "<" && value < r.value {
|
||||
return true
|
||||
}
|
||||
return false // no match
|
||||
}
|
||||
|
||||
func solveWorkflow(parts []part, workflows map[string][]rule) int {
|
||||
// var rejected []part
|
||||
var accepted []part
|
||||
|
||||
for _, p := range parts {
|
||||
workflow := "in"
|
||||
|
||||
nextStep:
|
||||
for workflow != "" {
|
||||
for _, r := range workflows[workflow] {
|
||||
if !r.Match(p) {
|
||||
continue
|
||||
}
|
||||
workflow = r.queue
|
||||
|
||||
if workflow == "A" {
|
||||
accepted = append(accepted, p)
|
||||
workflow = ""
|
||||
break nextStep
|
||||
}
|
||||
if workflow == "R" {
|
||||
// rejected = append(rejected, p)
|
||||
workflow = ""
|
||||
break nextStep
|
||||
}
|
||||
|
||||
continue nextStep
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sum := 0
|
||||
for _, p := range accepted {
|
||||
sum += p.x
|
||||
sum += p.m
|
||||
sum += p.a
|
||||
sum += p.s
|
||||
}
|
||||
return sum
|
||||
}
|
||||
|
||||
func solveRanges(workflows map[string][]rule) uint {
|
||||
|
||||
pq := aoc.PriorityQueue(func(a, b *queue) bool { return false })
|
||||
pq.Insert(&queue{
|
||||
"in",
|
||||
block{
|
||||
ranger{1, 4000},
|
||||
ranger{1, 4000},
|
||||
ranger{1, 4000},
|
||||
ranger{1, 4000},
|
||||
}})
|
||||
|
||||
var accepted []block
|
||||
// var rejected []block
|
||||
|
||||
for !pq.IsEmpty() {
|
||||
current := pq.ExtractMin()
|
||||
for _, rule := range workflows[current.name] {
|
||||
next := &queue{name: rule.queue, block: current.block}
|
||||
|
||||
switch rule.match {
|
||||
case "x":
|
||||
current.x, next.x = split(current.x, rule.value, rule.op == ">")
|
||||
case "m":
|
||||
current.m, next.m = split(current.m, rule.value, rule.op == ">")
|
||||
case "a":
|
||||
current.a, next.a = split(current.a, rule.value, rule.op == ">")
|
||||
case "s":
|
||||
current.s, next.s = split(current.s, rule.value, rule.op == ">")
|
||||
}
|
||||
|
||||
switch next.name {
|
||||
case "R":
|
||||
// rejected = append(rejected, next.block)
|
||||
|
||||
case "A":
|
||||
accepted = append(accepted, next.block)
|
||||
|
||||
default:
|
||||
pq.Insert(next)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var sum uint
|
||||
for _, a := range accepted {
|
||||
sum += uint((a.x[1] - a.x[0] + 1) * (a.m[1] - a.m[0] + 1) * (a.a[1] - a.a[0] + 1) * (a.s[1] - a.s[0] + 1))
|
||||
}
|
||||
|
||||
return sum
|
||||
}
|
||||
|
||||
type ranger [2]int
|
||||
type block struct {
|
||||
x, m, a, s ranger
|
||||
}
|
||||
type queue struct {
|
||||
name string
|
||||
block
|
||||
}
|
||||
|
||||
func split(a ranger, n int, gt bool) (current ranger, next ranger) {
|
||||
if gt { // x > N => [0,N] [N++,inf]
|
||||
return ranger{a[0], n}, ranger{n + 1, a[1]}
|
||||
}
|
||||
|
||||
// x < N => [N,inf] [0,N--]
|
||||
return ranger{n, a[1]}, ranger{a[0], n - 1}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"testing"
|
||||
|
||||
_ "embed"
|
||||
|
||||
"github.com/matryer/is"
|
||||
)
|
||||
|
||||
//go:embed example.txt
|
||||
var example []byte
|
||||
|
||||
//go:embed input.txt
|
||||
var input []byte
|
||||
|
||||
func TestExample(t *testing.T) {
|
||||
is := is.New(t)
|
||||
scan := bufio.NewScanner(bytes.NewReader(example))
|
||||
|
||||
result, err := run(scan)
|
||||
is.NoErr(err)
|
||||
|
||||
t.Log(result)
|
||||
is.Equal(result.valuePT1, 19114)
|
||||
is.Equal(result.valuePT2, uint(167409079868000))
|
||||
}
|
||||
|
||||
func TestSolution(t *testing.T) {
|
||||
is := is.New(t)
|
||||
scan := bufio.NewScanner(bytes.NewReader(input))
|
||||
|
||||
result, err := run(scan)
|
||||
is.NoErr(err)
|
||||
|
||||
t.Log(result)
|
||||
is.Equal(result.valuePT1, 377025)
|
||||
is.Equal(result.valuePT2, uint(135506683246673))
|
||||
}
|
||||
@@ -1,8 +1,6 @@
|
||||
module go.sour.is/advent-of-code
|
||||
|
||||
go 1.21.4
|
||||
|
||||
toolchain go1.21.5
|
||||
go 1.22.0
|
||||
|
||||
require (
|
||||
github.com/matryer/is v1.4.1
|
||||
|
||||
@@ -1,5 +1,14 @@
|
||||
package aoc
|
||||
|
||||
import (
|
||||
"cmp"
|
||||
"fmt"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/exp/maps"
|
||||
)
|
||||
|
||||
type Vector struct {
|
||||
Offset Point[int]
|
||||
Scale int
|
||||
@@ -58,7 +67,7 @@ func NumPoints(outline []Point[int], borderLength int) int {
|
||||
|
||||
type Map[I integer, T any] [][]T
|
||||
|
||||
func (m *Map[I,T]) Get(p Point[I]) (Point[I], T, bool) {
|
||||
func (m *Map[I, T]) Get(p Point[I]) (Point[I], T, bool) {
|
||||
var zero T
|
||||
if !m.Valid(p) {
|
||||
return [2]I{0, 0}, zero, false
|
||||
@@ -66,13 +75,172 @@ func (m *Map[I,T]) Get(p Point[I]) (Point[I], T, bool) {
|
||||
|
||||
return p, (*m)[p[0]][p[1]], true
|
||||
}
|
||||
func (m *Map[I,T]) Size() (I, I) {
|
||||
func (m *Map[I, T]) Size() (I, I) {
|
||||
if m == nil || len(*m) == 0 {
|
||||
return 0, 0
|
||||
}
|
||||
return I(len(*m)), I(len((*m)[0]))
|
||||
}
|
||||
func (m *Map[I,T]) Valid(p Point[I]) bool {
|
||||
func (m *Map[I, T]) Valid(p Point[I]) bool {
|
||||
rows, cols := m.Size()
|
||||
return p[0] >= 0 && p[0] < rows && p[1] >= 0 && p[1] < cols
|
||||
}
|
||||
|
||||
type cmap[C number, N comparable] struct {
|
||||
base pather[C, N]
|
||||
neighbors map[N]map[N]C
|
||||
}
|
||||
|
||||
func (m *cmap[C, N]) Cost(a, b N) C {
|
||||
if v, ok := m.neighbors[a]; ok {
|
||||
return v[b]
|
||||
}
|
||||
return 0
|
||||
}
|
||||
func (m *cmap[C, N]) Neighbors(n N) []N {
|
||||
if v, ok := m.neighbors[n]; ok {
|
||||
return maps.Keys(v)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func (m *cmap[C, N]) Target(n N, c C) bool {
|
||||
return m.base.Target(n, c)
|
||||
}
|
||||
func (m *cmap[C, N]) String() string {
|
||||
var b = &strings.Builder{}
|
||||
|
||||
for k, nbs := range m.neighbors {
|
||||
fmt.Fprintln(b, k)
|
||||
for to, c := range nbs {
|
||||
fmt.Fprintln(b, " ", to, c)
|
||||
}
|
||||
}
|
||||
|
||||
return b.String()
|
||||
}
|
||||
|
||||
func CompressMap[C number, N comparable](p pather[C, N], start N) pather[C, N] {
|
||||
var next = []N{start}
|
||||
var visited = make(map[N]map[N]C)
|
||||
|
||||
var n N
|
||||
for len(next) > 0 {
|
||||
n, next = next[len(next)-1], next[:len(next)-1]
|
||||
|
||||
if _, ok := visited[n]; ok {
|
||||
continue
|
||||
}
|
||||
|
||||
nbs := p.Neighbors(n)
|
||||
if len(nbs) == 2 {
|
||||
a, b := nbs[0], nbs[1]
|
||||
if to, ok := visited[a]; ok {
|
||||
to[b] = to[n] + p.Cost(n, b)
|
||||
delete(to, n)
|
||||
visited[a] = to
|
||||
} else if to, ok := visited[b]; ok {
|
||||
to[a] = to[n] + p.Cost(n, a)
|
||||
delete(to, n)
|
||||
visited[b] = to
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
visited[n] = make(map[N]C)
|
||||
next = append(next, nbs...)
|
||||
for _, to := range nbs {
|
||||
visited[n][to] = p.Cost(n, to)
|
||||
}
|
||||
}
|
||||
|
||||
return &cmap[C, N]{base: p, neighbors: visited}
|
||||
}
|
||||
|
||||
type adjacencyList[V any, C comparable] map[C][]V
|
||||
type graph[V any, W cmp.Ordered, C comparable] map[C]*vertex[V, W]
|
||||
type graphOption[V any, W cmp.Ordered, C comparable] func(g *graph[V, W, C])
|
||||
type vertex[V any, W cmp.Ordered] struct {
|
||||
Value V
|
||||
Edges edges[V, W]
|
||||
}
|
||||
|
||||
func (v *vertex[V, W]) Neighbors() []V {
|
||||
var nbs []V
|
||||
sort.Sort(v.Edges)
|
||||
for _, e := range v.Edges {
|
||||
nbs = append(nbs, e.Vertex.Value)
|
||||
}
|
||||
return nbs
|
||||
}
|
||||
|
||||
type edge[V any, W cmp.Ordered] struct {
|
||||
Vertex *vertex[V, W]
|
||||
Weight W
|
||||
}
|
||||
type edges[V any, W cmp.Ordered] []edge[V, W]
|
||||
|
||||
func (e edges[V, W]) Len() int { return len(e) }
|
||||
func (e edges[V, W]) Less(i, j int) bool { return e[i].Weight < e[j].Weight }
|
||||
func (e edges[V, W]) Swap(i, j int) { e[i], e[j] = e[j], e[i] }
|
||||
|
||||
func Graph[V any, W cmp.Ordered, C comparable](opts ...graphOption[V, W, C]) *graph[V, W, C] {
|
||||
g := make(graph[V, W, C])
|
||||
for _, opt := range opts {
|
||||
opt(&g)
|
||||
}
|
||||
return &g
|
||||
}
|
||||
func (g *graph[V, W, C]) AddVertex(id C, value V) {
|
||||
(*g)[id] = &vertex[V, W]{Value: value}
|
||||
}
|
||||
func (g *graph[V, W, C]) AddEdge(from, to C, w W) {
|
||||
if g == nil {
|
||||
return
|
||||
}
|
||||
if _, ok := (*g)[from]; !ok {
|
||||
return
|
||||
}
|
||||
if _, ok := (*g)[to]; !ok {
|
||||
return
|
||||
}
|
||||
|
||||
(*g)[from].Edges = append((*g)[from].Edges, edge[V, W]{(*g)[to], w})
|
||||
}
|
||||
func (g *graph[V, W, C]) Neighbors(v C) []V {
|
||||
if g == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return (*g)[v].Neighbors()
|
||||
}
|
||||
func (g *graph[V, W, C]) AdjacencyList() adjacencyList[V, C] {
|
||||
m := make(map[C][]V)
|
||||
for id, v := range *g {
|
||||
if len(v.Edges) == 0 {
|
||||
continue
|
||||
}
|
||||
m[id] = v.Neighbors()
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
func WithAdjacencyList[W cmp.Ordered, C comparable](list adjacencyList[C, C]) graphOption[C, W, C] {
|
||||
var zeroW W
|
||||
return func(g *graph[C, W, C]) {
|
||||
for vertex, edges := range list {
|
||||
if _, ok := (*g)[vertex]; !ok {
|
||||
g.AddVertex(vertex, vertex)
|
||||
}
|
||||
|
||||
// add edges to vertex
|
||||
for _, edge := range edges {
|
||||
// add edge as vertex, if not added
|
||||
if _, ok := (*g)[edge]; !ok {
|
||||
g.AddVertex(edge, edge)
|
||||
}
|
||||
|
||||
g.AddEdge(vertex, edge, zeroW) // no weights in this adjacency list
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
import "os"
|
||||
import "bufio"
|
||||
import "strconv"
|
||||
import "strings"
|
||||
|
||||
|
||||
var input1 = strings.NewReader(`
|
||||
6
|
||||
1 2 5 3 6 4
|
||||
`)
|
||||
|
||||
var input2 = strings.NewReader(`
|
||||
15
|
||||
1 14 3 7 4 5 15 6 13 10 11 2 12 8 9
|
||||
`)
|
||||
|
||||
var input3 = os.Stdin
|
||||
|
||||
func main() {
|
||||
var length int
|
||||
var tree *node
|
||||
|
||||
scanner := bufio.NewScanner(input1)
|
||||
for scanner.Scan() {
|
||||
if length == 0 {
|
||||
length, _ = strconv.Atoi(scanner.Text())
|
||||
continue
|
||||
}
|
||||
|
||||
for _, txt := range strings.Fields(scanner.Text()) {
|
||||
if v, err := strconv.Atoi(txt); err == nil {
|
||||
tree = insert(tree, &node{value: v})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foo(input{1, "hi"})
|
||||
|
||||
fmt.Println(tree)
|
||||
}
|
||||
|
||||
type node struct {
|
||||
value int
|
||||
left *node
|
||||
right *node
|
||||
}
|
||||
|
||||
func insert(root, n *node) *node {
|
||||
if root == nil {
|
||||
return n
|
||||
}
|
||||
if root.value > n.value {
|
||||
root.left = insert(root.left, n)
|
||||
return root
|
||||
}
|
||||
root.right = insert(root.right, n)
|
||||
return root
|
||||
}
|
||||
|
||||
func (n *node) String() string {
|
||||
if n == nil { return "" }
|
||||
return fmt.Sprintf("%v %v%v", n.value, n.left.String(), n.right.String())
|
||||
}
|
||||
|
||||
type input struct{a int; b string}
|
||||
func foo (in input) {}
|
||||
@@ -0,0 +1,109 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
aoc "go.sour.is/advent-of-code"
|
||||
)
|
||||
|
||||
/*
|
||||
* Complete the 'cookies' function below.
|
||||
*
|
||||
* The function is expected to return an INTEGER.
|
||||
* The function accepts following parameters:
|
||||
* 1. INTEGER k
|
||||
* 2. INTEGER_ARRAY A
|
||||
*/
|
||||
|
||||
func cookies(k int32, A []int32) int32 {
|
||||
var i int32
|
||||
// fmt.Println(" ", A)
|
||||
// sort.Slice(A, func(i, j int) bool { return A[j] < A[i]})
|
||||
// for A[len(A)-1] < k {
|
||||
// if len(A) < 2 {
|
||||
// return -1
|
||||
// }
|
||||
// // fmt.Println(" ", A[len(A)-1], " + 2x", A[len(A)-2], 2*A[len(A)-2] + A[len(A)-1])
|
||||
// A[len(A)-2] = 2*A[len(A)-2] + A[len(A)-1]
|
||||
// A = A[:len(A)-1]
|
||||
|
||||
// for j:=len(A)-1; j>0 && A[j] > A[j-1]; j-- {
|
||||
// A[j], A[j-1] = A[j-1], A[j]
|
||||
// }
|
||||
// i++
|
||||
// fmt.Println("A", len(A), i)
|
||||
// }
|
||||
|
||||
pq := aoc.FibHeap(func(a, b *int32) bool { return *a < *b })
|
||||
for i := range A {
|
||||
pq.Insert(&A[i])
|
||||
}
|
||||
for !pq.IsEmpty() && *pq.GetMin() < k {
|
||||
first := *pq.ExtractMin()
|
||||
second := *pq.ExtractMin()
|
||||
third := first + 2*second
|
||||
|
||||
pq.Insert(&third)
|
||||
i++
|
||||
}
|
||||
|
||||
return i
|
||||
}
|
||||
|
||||
func main() {
|
||||
reader := bufio.NewReaderSize(os.Stdin, 16*1024*1024)
|
||||
|
||||
stdout, err := os.Create("/dev/stderr")
|
||||
checkError(err)
|
||||
|
||||
defer stdout.Close()
|
||||
|
||||
writer := bufio.NewWriterSize(stdout, 16*1024*1024)
|
||||
|
||||
firstMultipleInput := strings.Split(strings.TrimSpace(readLine(reader)), " ")
|
||||
|
||||
nTemp, err := strconv.ParseInt(firstMultipleInput[0], 10, 64)
|
||||
checkError(err)
|
||||
n := int32(nTemp)
|
||||
|
||||
kTemp, err := strconv.ParseInt(firstMultipleInput[1], 10, 64)
|
||||
checkError(err)
|
||||
k := int32(kTemp)
|
||||
|
||||
ATemp := strings.Split(strings.TrimSpace(readLine(reader)), " ")
|
||||
|
||||
var A []int32
|
||||
|
||||
for i := 0; i < int(n); i++ {
|
||||
AItemTemp, err := strconv.ParseInt(ATemp[i], 10, 64)
|
||||
checkError(err)
|
||||
AItem := int32(AItemTemp)
|
||||
A = append(A, AItem)
|
||||
}
|
||||
|
||||
result := cookies(k, A)
|
||||
|
||||
fmt.Fprintf(writer, "%d\n", result)
|
||||
|
||||
writer.Flush()
|
||||
}
|
||||
|
||||
func readLine(reader *bufio.Reader) string {
|
||||
str, _, err := reader.ReadLine()
|
||||
if err == io.EOF {
|
||||
return ""
|
||||
}
|
||||
|
||||
return strings.TrimRight(string(str), "\r\n")
|
||||
}
|
||||
|
||||
func checkError(err error) {
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
1000000 105823341
|
||||
10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 1Line truncated
|
||||
@@ -0,0 +1,2 @@
|
||||
8 90
|
||||
13 47 74 12 89 74 18 38
|
||||
Whitespace-only changes.
@@ -0,0 +1,44 @@
|
||||
package aoc_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/matryer/is"
|
||||
aoc "go.sour.is/advent-of-code"
|
||||
)
|
||||
|
||||
func TestReverse(t *testing.T) {
|
||||
is := is.New(t)
|
||||
|
||||
is.Equal(aoc.Reverse([]int{1, 2, 3, 4}), []int{4, 3, 2, 1})
|
||||
}
|
||||
|
||||
func TestReadStringToInts(t *testing.T) {
|
||||
is := is.New(t)
|
||||
|
||||
is.Equal(aoc.ReadStringToInts([]string{"1", "2", "3"}), []int{1, 2, 3})
|
||||
}
|
||||
|
||||
func TestRepeat(t *testing.T) {
|
||||
is := is.New(t)
|
||||
|
||||
is.Equal(aoc.Repeat(5, 3), []int{5, 5, 5})
|
||||
}
|
||||
|
||||
func TestTranspose(t *testing.T) {
|
||||
is := is.New(t)
|
||||
|
||||
is.Equal(
|
||||
aoc.Transpose(
|
||||
[][]int{
|
||||
{1, 1},
|
||||
{0, 0},
|
||||
{1, 1},
|
||||
},
|
||||
),
|
||||
[][]int{
|
||||
{1, 0, 1},
|
||||
{1, 0, 1},
|
||||
},
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package aoc_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/matryer/is"
|
||||
aoc "go.sour.is/advent-of-code"
|
||||
)
|
||||
|
||||
func TestLCM(t *testing.T) {
|
||||
is := is.New(t)
|
||||
|
||||
is.Equal(aoc.LCM([]int{}...), 0)
|
||||
is.Equal(aoc.LCM(5), 5)
|
||||
is.Equal(aoc.LCM(5, 3), 15)
|
||||
is.Equal(aoc.LCM(5, 3, 2), 30)
|
||||
}
|
||||
|
||||
func TestPower2(t *testing.T) {
|
||||
is := is.New(t)
|
||||
|
||||
is.Equal(aoc.Power2(0), 1)
|
||||
is.Equal(aoc.Power2(1), 2)
|
||||
is.Equal(aoc.Power2(2), 4)
|
||||
}
|
||||
|
||||
func TestABS(t *testing.T) {
|
||||
is := is.New(t)
|
||||
|
||||
is.Equal(aoc.ABS(1), 1)
|
||||
is.Equal(aoc.ABS(0), 0)
|
||||
is.Equal(aoc.ABS(-1), 1)
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package main
|
||||
|
||||
|
||||
func countChan(n int) <-chan int {
|
||||
ch := make(chan int)
|
||||
|
||||
go func() {
|
||||
for i := range n {
|
||||
ch <- i
|
||||
}
|
||||
close(ch)
|
||||
}()
|
||||
|
||||
return ch
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
package main
|
||||
|
||||
// export GOEXPERIMENT=rangefunc
|
||||
import "iter"
|
||||
|
||||
func Step(start, stop, step int) iter.Seq[int] {
|
||||
if step < 0 {
|
||||
return func(yield func(int) bool) {
|
||||
for i := start; i <= start && i > stop; i += step {
|
||||
next := yield(i)
|
||||
if !next {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if step > 0 {
|
||||
return func(yield func(int) bool) {
|
||||
for i := start; i >= start && i < stop; i += step {
|
||||
next := yield(i)
|
||||
if !next {
|
||||
println("stopped!")
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return func(yield func(int) bool) { yield(start) }
|
||||
}
|
||||
|
||||
func Fib() iter.Seq[uint] {
|
||||
return func(yield func(uint) bool) {
|
||||
previous, value := uint(1), uint(1)
|
||||
next := yield(value)
|
||||
for next {
|
||||
next = yield(value)
|
||||
value, previous = value+previous, value
|
||||
if value < previous {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func Fizzbuzzed[T int | uint](from iter.Seq[T]) iter.Seq2[T, string] {
|
||||
pull, stop := iter.Pull(from)
|
||||
return func(yield func(T, string) bool) {
|
||||
defer stop()
|
||||
for {
|
||||
var fizzbuzz string
|
||||
p, ok := pull()
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
if p%3 == 0 {
|
||||
fizzbuzz = "fizz"
|
||||
}
|
||||
if p%5 == 0 {
|
||||
fizzbuzz += "buzz"
|
||||
}
|
||||
if !yield(p, fizzbuzz) {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// func main() {
|
||||
// for i, v := range Fizzbuzzed(Fib()) {
|
||||
// println(i, v)
|
||||
// }
|
||||
// }
|
||||
|
||||
func countScan(n int) (func() bool, func() int) {
|
||||
pos := -1
|
||||
return func() bool {
|
||||
pos++
|
||||
return pos < n
|
||||
}, func() int {
|
||||
return pos
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,193 @@
|
||||
package main_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/matryer/is"
|
||||
)
|
||||
|
||||
// func BenchmarkChan(b *testing.B) {
|
||||
// sum := 0
|
||||
|
||||
// for n := range countChan(b.N) {
|
||||
// sum += n
|
||||
// }
|
||||
// b.StopTimer()
|
||||
// b.Log(sum)
|
||||
// }
|
||||
|
||||
// func BenchmarkScan(b *testing.B) {
|
||||
// sum := 0
|
||||
// scan, value := countScan(b.N)
|
||||
// for scan() {
|
||||
// sum += value()
|
||||
// }
|
||||
// b.StopTimer()
|
||||
// b.Log(sum)
|
||||
// }
|
||||
|
||||
// func BenchmarkRange(b *testing.B) {
|
||||
// sum := 0
|
||||
// for n := range countRF(b.N) {
|
||||
// sum += n
|
||||
// }
|
||||
// b.StopTimer()
|
||||
// b.Log(sum)
|
||||
// }
|
||||
|
||||
// func TestRangeS(t *testing.T) {
|
||||
// for i := range Step(0, 10, 3) {
|
||||
// t.Log(i)
|
||||
// }
|
||||
|
||||
// for i := range Step(10, 0, -3) {
|
||||
// t.Log(i)
|
||||
// }
|
||||
// }
|
||||
|
||||
func TestSelect(t *testing.T) {
|
||||
done1 := make(chan struct{})
|
||||
done2 := make(chan struct{})
|
||||
|
||||
go func() {
|
||||
close(done1)
|
||||
close(done2)
|
||||
}()
|
||||
|
||||
for i, ch := range []chan struct{}{done1, done2} {
|
||||
<-ch
|
||||
println("closed", i)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGCD(t *testing.T) {
|
||||
is := is.New(t)
|
||||
is.Equal(gcdOfStrings("ABAB", "ABABAB"), "AB")
|
||||
is.Equal(gcdOfStrings("ABAB", "ABABABAB"), "ABAB")
|
||||
is.Equal(gcdOfStrings("ABC", "ABCABC"), "ABC")
|
||||
is.Equal(gcdOfStrings("ABC", "ABCDEF"), "")
|
||||
is.Equal(gcdOfStrings("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"), "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA")
|
||||
}
|
||||
func gcdOfStrings(str1 string, str2 string) string {
|
||||
if len(str1) == 0 {
|
||||
return ""
|
||||
}
|
||||
runes1 := []rune(str1)
|
||||
runes2 := []rune(str2)
|
||||
|
||||
n := max(len(runes1), len(runes2))
|
||||
m := min(len(runes1), len(runes2))
|
||||
|
||||
if len(runes2) == m {
|
||||
runes1, runes2 = runes2, runes1
|
||||
}
|
||||
|
||||
if isRepeating(runes1, runes2) {
|
||||
return string(runes1)
|
||||
}
|
||||
|
||||
for i := n; i > 0; i-- {
|
||||
if runes1[i%len(runes1)] != runes2[i%len(runes2)] {
|
||||
return ""
|
||||
}
|
||||
gcd := runes2[:i]
|
||||
if isRepeating(gcd, runes1) && isRepeating(gcd, runes2) {
|
||||
return string(gcd)
|
||||
}
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
func isRepeating(str1, str2 []rune) bool {
|
||||
if len(str1) > len(str2) {
|
||||
return false
|
||||
}
|
||||
if len(str2)%len(str1) != 0 {
|
||||
return false
|
||||
}
|
||||
for i := range str2 {
|
||||
if str1[i%len(str1)] != str2[i] {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func canPlaceFlowers(flowerbed []int, n int) bool {
|
||||
var c int
|
||||
|
||||
for i := 0; i < len(flowerbed); i++ {
|
||||
if (i == 0 || flowerbed[i-1] == 0) &&
|
||||
flowerbed[i] == 0 &&
|
||||
(i == len(flowerbed)-1 || flowerbed[i+1] == 0) {
|
||||
c++
|
||||
flowerbed[i] = 1
|
||||
}
|
||||
}
|
||||
|
||||
return c >= n
|
||||
}
|
||||
|
||||
func TestFlowers(t *testing.T) {
|
||||
is := is.New(t)
|
||||
is.Equal(canPlaceFlowers([]int{1, 0, 0, 0, 1}, 1), true)
|
||||
is.Equal(canPlaceFlowers([]int{0, 0, 1, 0, 1}, 1), true)
|
||||
is.Equal(canPlaceFlowers([]int{1, 0, 1, 0, 0}, 1), true)
|
||||
}
|
||||
|
||||
func dailyTemperatures(temperatures []int) []int {
|
||||
answers := make([]int, len(temperatures))
|
||||
var stack [][2]int
|
||||
push := func(v int) {
|
||||
if len(stack) == 0 {
|
||||
stack = append(stack, [2]int{v, 1})
|
||||
return
|
||||
}
|
||||
end := len(stack)-1
|
||||
if v < stack[end][0]{
|
||||
stack = append(stack, [2]int{v, 1})
|
||||
return
|
||||
|
||||
}
|
||||
if v == stack[end][0] {
|
||||
stack[len(stack)-1][1]++
|
||||
return
|
||||
}
|
||||
|
||||
var vs = [2]int{v, 1}
|
||||
// for ; end>0; end-- {
|
||||
// if stack[end][0]<vs[0] {
|
||||
// vs[1]+=stack[end][1]
|
||||
// continue
|
||||
// }
|
||||
// break
|
||||
// }
|
||||
stack = append(stack, vs)
|
||||
}
|
||||
|
||||
for i := len(temperatures) - 2; i >= 0; i-- {
|
||||
push(temperatures[i+1])
|
||||
currentTemp := temperatures[i]
|
||||
days := 1
|
||||
end := len(stack)-1
|
||||
for j := range stack {
|
||||
nextTemp := stack[end-j]
|
||||
if currentTemp < nextTemp[0] {
|
||||
answers[i] = days
|
||||
break
|
||||
}
|
||||
days+=nextTemp[1]
|
||||
}
|
||||
}
|
||||
|
||||
return answers
|
||||
}
|
||||
|
||||
func TestTemps(t *testing.T) {
|
||||
is := is.New(t)
|
||||
is.Equal(dailyTemperatures(
|
||||
[]int{73, 74, 75, 71, 69, 72, 76, 73}),
|
||||
[]int{1, 1, 4, 2, 1, 1, 0, 0})
|
||||
is.Equal(dailyTemperatures(
|
||||
[]int{99,99,99,99,100}), []int{4,3,2,1,0})
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package main
|
||||
|
||||
|
||||
func countRF(n int) func(yield func(int) bool) {
|
||||
return func(yield func(int) bool) {
|
||||
for i := range n {
|
||||
if !yield(i) {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,25 +2,70 @@ package aoc
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"flag"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"runtime/pprof"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
var cpuprofile = flag.String("cpuprofile", "", "write cpu profile to `file`")
|
||||
var memprofile = flag.String("memprofile", "", "write memory profile to `file`")
|
||||
|
||||
func Runner[R any, F func(*bufio.Scanner) (R, error)](run F) (R, error) {
|
||||
if len(os.Args) != 2 {
|
||||
if len(os.Args) < 2 {
|
||||
Log("Usage:", filepath.Base(os.Args[0]), "FILE")
|
||||
os.Exit(22)
|
||||
}
|
||||
|
||||
input, err := os.Open(os.Args[1])
|
||||
inputFilename := os.Args[1]
|
||||
os.Args = append(os.Args[:1], os.Args[2:]...)
|
||||
|
||||
flag.Parse()
|
||||
Log(cpuprofile, memprofile, *cpuprofile, *memprofile)
|
||||
if *cpuprofile != "" {
|
||||
Log("enabled cpu profile")
|
||||
f, err := os.Create(*cpuprofile)
|
||||
if err != nil {
|
||||
log.Fatal("could not create CPU profile: ", err)
|
||||
}
|
||||
defer f.Close() // error handling omitted for example
|
||||
Log("write cpu profile to", f.Name())
|
||||
if err := pprof.StartCPUProfile(f); err != nil {
|
||||
log.Fatal("could not start CPU profile: ", err)
|
||||
}
|
||||
defer pprof.StopCPUProfile()
|
||||
}
|
||||
|
||||
if *memprofile != "" {
|
||||
Log("enabled mem profile")
|
||||
defer func() {
|
||||
f, err := os.Create(*memprofile)
|
||||
if err != nil {
|
||||
log.Fatal("could not create memory profile: ", err)
|
||||
}
|
||||
Log("write mem profile to", f.Name())
|
||||
defer f.Close() // error handling omitted for example
|
||||
runtime.GC() // get up-to-date statistics
|
||||
if err := pprof.WriteHeapProfile(f); err != nil {
|
||||
log.Fatal("could not write memory profile: ", err)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
|
||||
input, err := os.Open(inputFilename)
|
||||
if err != nil {
|
||||
Log(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
scan := bufio.NewScanner(input)
|
||||
|
||||
return run(scan)
|
||||
}
|
||||
|
||||
@@ -33,7 +78,10 @@ func MustResult[T any](result T, err error) {
|
||||
Log("result", result)
|
||||
}
|
||||
|
||||
func Log(v ...any) { fmt.Fprintln(os.Stderr, v...) }
|
||||
func Log(v ...any) {
|
||||
fmt.Fprint(os.Stderr, time.Now(), ": ")
|
||||
fmt.Fprintln(os.Stderr, v...)
|
||||
}
|
||||
func Logf(format string, v ...any) {
|
||||
if !strings.HasSuffix(format, "\n") {
|
||||
format += "\n"
|
||||
|
||||
@@ -1,60 +1,91 @@
|
||||
package aoc
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math/bits"
|
||||
"sort"
|
||||
)
|
||||
|
||||
type priorityQueue[T any, U []T] struct {
|
||||
elems U
|
||||
less func(a, b T) bool
|
||||
type priorityQueue[T any] struct {
|
||||
elems []*T
|
||||
less func(a, b *T) bool
|
||||
maxDepth int
|
||||
totalEnqueue int
|
||||
totalDequeue int
|
||||
}
|
||||
|
||||
func PriorityQueue[T any, U []T](less func(a, b T) bool) *priorityQueue[T, U] {
|
||||
return &priorityQueue[T, U]{less: less}
|
||||
// PriorityQueue implements a simple slice based queue.
|
||||
// less is the function for sorting. reverse a and b to reverse the sort.
|
||||
// T is the item
|
||||
// U is a slice of T
|
||||
func PriorityQueue[T any](less func(a, b *T) bool) *priorityQueue[T] {
|
||||
return &priorityQueue[T]{less: less}
|
||||
}
|
||||
func (pq *priorityQueue[T, U]) Enqueue(elem T) {
|
||||
pq.elems = append(pq.elems, elem)
|
||||
func (pq *priorityQueue[T]) Insert(elem *T) {
|
||||
pq.totalEnqueue++
|
||||
|
||||
pq.elems = append(pq.elems, elem)
|
||||
pq.maxDepth = max(pq.maxDepth, len(pq.elems))
|
||||
sort.Slice(pq.elems, func(i, j int) bool { return pq.less(pq.elems[i], pq.elems[j]) })
|
||||
}
|
||||
func (pq *priorityQueue[T, I]) IsEmpty() bool {
|
||||
func (pq *priorityQueue[T]) IsEmpty() bool {
|
||||
return len(pq.elems) == 0
|
||||
}
|
||||
func (pq *priorityQueue[T, I]) Dequeue() (T, bool) {
|
||||
var elem T
|
||||
func (pq *priorityQueue[T]) ExtractMin() *T {
|
||||
pq.totalDequeue++
|
||||
|
||||
var elem *T
|
||||
if pq.IsEmpty() {
|
||||
return elem, false
|
||||
return elem
|
||||
}
|
||||
|
||||
sort.Slice(pq.elems, func(i, j int) bool { return pq.less(pq.elems[j], pq.elems[i]) })
|
||||
pq.elems, elem = pq.elems[:len(pq.elems)-1], pq.elems[len(pq.elems)-1]
|
||||
return elem, true
|
||||
return elem
|
||||
}
|
||||
|
||||
// ManhattanDistance the distance between two points measured along axes at right angles.
|
||||
func ManhattanDistance[T integer](a, b Point[T]) T {
|
||||
return ABS(a[1]-b[1]) + ABS(a[0]-b[0])
|
||||
return ABS(a[0]-b[0]) + ABS(a[1]-b[1])
|
||||
}
|
||||
|
||||
type pather[C number, N any] interface {
|
||||
type pather[C number, N comparable] interface {
|
||||
// Neighbors returns all neighbors to node N that should be considered next.
|
||||
Neighbors(N) []N
|
||||
|
||||
// Cost returns
|
||||
Cost(a, b N) C
|
||||
Potential(a, b N) C
|
||||
|
||||
// Target returns true when target reached. receives node and cost.
|
||||
Target(N, C) bool
|
||||
|
||||
// OPTIONAL:
|
||||
// Add heuristic for running as A* search.
|
||||
// Potential(N) C
|
||||
|
||||
// Seen modify value used by seen pruning.
|
||||
// Seen(N) N
|
||||
// Target returns true if target reached.
|
||||
// Target(N) bool
|
||||
|
||||
}
|
||||
|
||||
type Path[C number, N any] []N
|
||||
|
||||
func FindPath[C integer, N comparable](g pather[C, N], start, end N) (C, Path[C, N]) {
|
||||
// FindPath uses the A* path finding algorithem.
|
||||
// g is the graph source that implements the pather interface.
|
||||
//
|
||||
// C is an numeric type for calculating cost/potential
|
||||
// N is the node values. is comparable for storing in visited table for pruning.
|
||||
//
|
||||
// start, end are nodes that dileniate the start and end of the search path.
|
||||
// The returned values are the calculated cost and the path taken from start to end.
|
||||
func FindPath[C integer, N comparable](g pather[C, N], start, end N) (C, []N, map[N]C) {
|
||||
var zero C
|
||||
closed := make(map[N]bool)
|
||||
|
||||
var seenFn = func(a N) N { return a }
|
||||
if s, ok := g.(interface{ Seen(N) N }); ok {
|
||||
seenFn = s.Seen
|
||||
}
|
||||
|
||||
var potentialFn = func(N) C { var zero C; return zero }
|
||||
if p, ok := g.(interface{ Potential(N) C }); ok {
|
||||
potentialFn = p.Potential
|
||||
}
|
||||
|
||||
type node struct {
|
||||
cost C
|
||||
@@ -63,7 +94,7 @@ func FindPath[C integer, N comparable](g pather[C, N], start, end N) (C, Path[C,
|
||||
position N
|
||||
}
|
||||
|
||||
NewPath := func(n *node) []N {
|
||||
newPath := func(n *node) []N {
|
||||
var path []N
|
||||
for n.parent != nil {
|
||||
path = append(path, n.position)
|
||||
@@ -75,56 +106,219 @@ func FindPath[C integer, N comparable](g pather[C, N], start, end N) (C, Path[C,
|
||||
return path
|
||||
}
|
||||
|
||||
less := func(a, b node) bool {
|
||||
return b.cost+b.potential < a.cost+a.potential
|
||||
less := func(a, b *node) bool {
|
||||
return a.cost+a.potential < b.cost+b.potential
|
||||
}
|
||||
|
||||
pq := PriorityQueue(less)
|
||||
pq.Enqueue(node{position: start})
|
||||
closed := make(map[N]C)
|
||||
open := FibHeap(less)
|
||||
|
||||
defer func() {
|
||||
fmt.Println("queue max depth = ", pq.maxDepth, "total enqueue = ", pq.totalEnqueue)
|
||||
}()
|
||||
open.Insert(&node{position: start, potential: potentialFn(start)})
|
||||
closed[start] = zero
|
||||
|
||||
var seenFn = func(a N) N { return a }
|
||||
if s, ok := g.(interface{ Seen(N) N }); ok {
|
||||
seenFn = s.Seen
|
||||
}
|
||||
|
||||
var targetFn = func(a N) bool { return true }
|
||||
if s, ok := g.(interface{ Target(N) bool }); ok {
|
||||
targetFn = s.Target
|
||||
}
|
||||
|
||||
for !pq.IsEmpty() {
|
||||
current, _ := pq.Dequeue()
|
||||
cost, potential, n := current.cost, current.potential, current.position
|
||||
|
||||
seen := seenFn(n)
|
||||
if closed[seen] {
|
||||
continue
|
||||
}
|
||||
closed[seen] = true
|
||||
|
||||
if cost > 0 && potential == zero && targetFn(current.position) {
|
||||
return cost, NewPath(¤t)
|
||||
}
|
||||
|
||||
for _, nb := range g.Neighbors(n) {
|
||||
seen := seenFn(nb)
|
||||
if closed[seen] {
|
||||
continue
|
||||
}
|
||||
|
||||
cost := g.Cost(n, nb) + current.cost
|
||||
nextPath := node{
|
||||
for !open.IsEmpty() {
|
||||
current := open.ExtractMin()
|
||||
for _, nb := range g.Neighbors(current.position) {
|
||||
next := &node{
|
||||
position: nb,
|
||||
parent: ¤t,
|
||||
cost: cost,
|
||||
potential: g.Potential(nb, end),
|
||||
parent: current,
|
||||
cost: g.Cost(current.position, nb) + current.cost,
|
||||
potential: potentialFn(nb),
|
||||
}
|
||||
|
||||
seen := seenFn(nb)
|
||||
cost, ok := closed[seen]
|
||||
if !ok || next.cost < cost {
|
||||
open.Insert(next)
|
||||
closed[seen] = next.cost
|
||||
}
|
||||
|
||||
if next.potential == zero && g.Target(next.position, next.cost) {
|
||||
return next.cost, newPath(next), closed
|
||||
}
|
||||
pq.Enqueue(nextPath)
|
||||
}
|
||||
}
|
||||
return zero, nil
|
||||
return zero, nil, closed
|
||||
}
|
||||
|
||||
type fibTree[T any] struct {
|
||||
value *T
|
||||
parent *fibTree[T]
|
||||
child []*fibTree[T]
|
||||
mark bool
|
||||
}
|
||||
|
||||
func (t *fibTree[T]) Value() *T { return t.value }
|
||||
func (t *fibTree[T]) addAtEnd(n *fibTree[T]) {
|
||||
n.parent = t
|
||||
t.child = append(t.child, n)
|
||||
}
|
||||
|
||||
type fibHeap[T any] struct {
|
||||
trees []*fibTree[T]
|
||||
least *fibTree[T]
|
||||
count uint
|
||||
less func(a, b *T) bool
|
||||
}
|
||||
|
||||
func FibHeap[T any](less func(a, b *T) bool) *fibHeap[T] {
|
||||
return &fibHeap[T]{less: less}
|
||||
}
|
||||
|
||||
func (h *fibHeap[T]) GetMin() *T {
|
||||
return h.least.value
|
||||
}
|
||||
|
||||
func (h *fibHeap[T]) IsEmpty() bool { return h.least == nil }
|
||||
|
||||
func (h *fibHeap[T]) Insert(v *T) {
|
||||
ntree := &fibTree[T]{value: v}
|
||||
h.trees = append(h.trees, ntree)
|
||||
if h.least == nil || h.less(v, h.least.value) {
|
||||
h.least = ntree
|
||||
}
|
||||
h.count++
|
||||
}
|
||||
|
||||
func (h *fibHeap[T]) ExtractMin() *T {
|
||||
smallest := h.least
|
||||
if smallest != nil {
|
||||
// Remove smallest from root trees.
|
||||
for i := range h.trees {
|
||||
pos := h.trees[i]
|
||||
if pos == smallest {
|
||||
h.trees[i] = h.trees[len(h.trees)-1]
|
||||
h.trees = h.trees[:len(h.trees)-1]
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// Add children to root
|
||||
h.trees = append(h.trees, smallest.child...)
|
||||
smallest.child = smallest.child[:0]
|
||||
|
||||
h.least = nil
|
||||
if len(h.trees) > 0 {
|
||||
h.consolidate()
|
||||
}
|
||||
|
||||
h.count--
|
||||
return smallest.value
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *fibHeap[T]) consolidate() {
|
||||
aux := make([]*fibTree[T], bits.Len(h.count)+1)
|
||||
for _, x := range h.trees {
|
||||
order := len(x.child)
|
||||
|
||||
// consolidate the larger roots under smaller roots of same order until we have at most one tree per order.
|
||||
for aux[order] != nil {
|
||||
y := aux[order]
|
||||
if h.less(y.value, x.value) {
|
||||
x, y = y, x
|
||||
}
|
||||
x.addAtEnd(y)
|
||||
aux[order] = nil
|
||||
order++
|
||||
}
|
||||
aux[order] = x
|
||||
}
|
||||
|
||||
h.trees = h.trees[:0]
|
||||
// move ordered trees to root and find least node.
|
||||
for _, k := range aux {
|
||||
if k != nil {
|
||||
k.parent = nil
|
||||
h.trees = append(h.trees, k)
|
||||
if h.least == nil || h.less(k.value, h.least.value) {
|
||||
h.least = k
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (h *fibHeap[T]) Merge(a *fibHeap[T]) {
|
||||
h.trees = append(h.trees, a.trees...)
|
||||
h.count += a.count
|
||||
if h.least == nil || a.least != nil && h.less(a.least.value, h.least.value) {
|
||||
h.least = a.least
|
||||
}
|
||||
}
|
||||
|
||||
func (h *fibHeap[T]) find(fn func(*T) bool) *fibTree[T] {
|
||||
var st []*fibTree[T]
|
||||
st = append(st, h.trees...)
|
||||
var tr *fibTree[T]
|
||||
|
||||
for len(st) > 0 {
|
||||
tr, st = st[0], st[1:]
|
||||
ro := *tr.value
|
||||
if fn(&ro) {
|
||||
break
|
||||
}
|
||||
st = append(st, tr.child...)
|
||||
}
|
||||
|
||||
return tr
|
||||
}
|
||||
|
||||
func (h *fibHeap[T]) Find(fn func(*T) bool) *T {
|
||||
if needle := h.find(fn); needle != nil {
|
||||
return needle.value
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *fibHeap[T]) DecreaseKey(find func(*T) bool, decrease func(*T)) {
|
||||
needle := h.find(find)
|
||||
if needle == nil {
|
||||
return
|
||||
}
|
||||
decrease(needle.value)
|
||||
|
||||
if h.less(needle.value, h.least.value) {
|
||||
h.least = needle
|
||||
}
|
||||
|
||||
if parent := needle.parent; parent != nil {
|
||||
if h.less(needle.value, parent.value) {
|
||||
h.cut(needle)
|
||||
h.cascadingCut(parent)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (h *fibHeap[T]) cut(x *fibTree[T]) {
|
||||
parent := x.parent
|
||||
for i := range parent.child {
|
||||
pos := parent.child[i]
|
||||
if pos == x {
|
||||
parent.child[i] = parent.child[len(parent.child)-1]
|
||||
parent.child = parent.child[:len(parent.child)-1]
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
x.parent = nil
|
||||
x.mark = false
|
||||
h.trees = append(h.trees, x)
|
||||
|
||||
if h.less(x.value, h.least.value) {
|
||||
h.least = x
|
||||
}
|
||||
}
|
||||
|
||||
func (h *fibHeap[T]) cascadingCut(y *fibTree[T]) {
|
||||
if y.parent != nil {
|
||||
if !y.mark {
|
||||
y.mark = true
|
||||
return
|
||||
}
|
||||
|
||||
h.cut(y)
|
||||
h.cascadingCut(y.parent)
|
||||
}
|
||||
}
|
||||
@@ -57,3 +57,12 @@ func (m *defaultMap[K, V]) Items() []pair[K, V] {
|
||||
}
|
||||
return items
|
||||
}
|
||||
|
||||
func In[C comparable](n C, haystack ...C) bool {
|
||||
for _, h := range haystack {
|
||||
if n == h {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
package aoc_test
|
||||
|
||||
import (
|
||||
"sort"
|
||||
"testing"
|
||||
|
||||
"github.com/matryer/is"
|
||||
aoc "go.sour.is/advent-of-code"
|
||||
)
|
||||
|
||||
func TestSet(t *testing.T) {
|
||||
is := is.New(t)
|
||||
|
||||
s := aoc.Set(1, 2, 3)
|
||||
is.True(!s.Has(0))
|
||||
is.True(s.Has(1))
|
||||
is.True(s.Has(2))
|
||||
is.True(s.Has(3))
|
||||
is.True(!s.Has(4))
|
||||
|
||||
s.Add(4)
|
||||
is.True(s.Has(4))
|
||||
|
||||
items := s.Items()
|
||||
sort.Ints(items)
|
||||
is.Equal(items, []int{1, 2, 3, 4})
|
||||
}
|
||||
Reference in new issue
Block a user