18 Commits
Author SHA1 Message Date
xuu a5ebbe25d0 chore: save hacker rank 2024-06-10 21:26:09 -06:00
xuu 50af2114d4 add ranger
Go Bump / bump (push) Failing after 6s
Go Test / build (push) Failing after 21s
2024-04-05 16:27:02 -06:00
xuu f8fa61672f chore: fixes
Go Bump / bump (push) Successful in 7s
Go Test / build (push) Successful in 35s
2024-01-22 16:07:16 -07:00
xuu 951c2c298a chore(aos): add compress graph
Go Bump / bump (push) Successful in 9s
Go Test / build (push) Failing after 24s
2024-01-12 12:09:44 -07:00
xuu 328a0f3eb3 chore(aoc): add FibHeap DecreaseKey
Go Bump / bump (push) Successful in 8s
Go Test / build (push) Successful in 40s
2024-01-09 20:41:23 -07:00
xuu 7d7402f054 chore(day17): implement fibHeap for faster priority queue
Go Test / build (pull_request) Successful in 37s
Go Bump / bump (push) Successful in 7s
Go Test / build (push) Successful in 39s
2024-01-09 13:53:30 -07:00
xuu 7585526634 chore(day17): simplify FindPath. A* is still slower :|
Go Test / build (pull_request) Failing after 4m27s
2024-01-04 17:15:44 -07:00
xuu 924c8d74f3 chore(day17): disable heuristic. runs faster!? 2024-01-02 20:57:02 -07:00
xuu 22184ed9c7 chore(aoc): initial graph attempt 2024-01-02 17:02:12 -07:00
xuu 74a952e82b chore(day19): add part 2
Go Bump / bump (push) Successful in 6s
Go Test / build (push) Successful in 1m30s
2024-01-01 19:15:36 -07:00
xuu 62f8338227 chore: organization day19 2024-01-01 19:15:36 -07:00
xuu 39c6f8ed4d chore: add day 19 pt 1 2024-01-01 19:15:36 -07:00
xuu 2c959c109b tests(day17): disable solution
Go Bump / bump (push) Successful in 7s
Go Test / build (push) Successful in 49s
2024-01-01 14:19:00 -07:00
xuu eb1eaaab43 chore(day17): add open list for A*
Go Bump / bump (push) Successful in 8s
Go Test / build (push) Failing after 4m29s
2024-01-01 14:12:53 -07:00
xuu adc01f4df9 chore(day17): log output
Go Bump / bump (push) Successful in 6s
Go Test / build (push) Successful in 40s
2024-01-01 12:44:08 -07:00
xuu fd85530d88 chore(day17): simplify interfaces. add docs
Go Bump / bump (push) Successful in 12s
Go Test / build (push) Successful in 46s
2024-01-01 10:59:40 -07:00
xuu 0d78959bea chore(day17): fix missing changes
Go Test / build (pull_request) Successful in 37s
Go Bump / bump (push) Successful in 7s
Go Test / build (push) Successful in 34s
2024-01-01 09:57:08 -07:00
xuu 86f2f7a6f2 chore(day17): implent A* path finder
Go Bump / bump (push) Successful in 8s
Go Test / build (pull_request) Successful in 51s
Go Test / build (push) Successful in 35s
2024-01-01 09:29:25 -07:00
28 changed files with 2611 additions and 252 deletions

No files matched your search

+1 -1
View File
@@ -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 }}."
+6
View File
@@ -0,0 +1,6 @@
-----BEGIN SSH SIGNATURE-----
U1NIU0lHAAAAAQAAADMAAAALc3NoLWVkMjU1MTkAAAAgZ+OuJYdd3UiUbyBuO1RlsQR20a
Qm5mKneuMxRjGo3zkAAAAEZmlsZQAAAAAAAAAGc2hhNTEyAAAAUwAAAAtzc2gtZWQyNTUx
OQAAAED8T4C6WILXYZ1KxqDIlVhlrAEjr1Vc+tn8ypcVM3bN7iOexVvuUuvm90nr8eEwKU
acrdDxmq2S+oysQbK+pMUE
-----END SSH SIGNATURE-----
+185 -115
View File
@@ -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,75 +25,44 @@ func TestPriorityQueue(t *testing.T) {
is := is.New(t)
type elem [2]int
less := func(a, b elem) bool {
return b[0] < a[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 TestGraph(t *testing.T) {
// g := aoc.Graph[int, uint](7)
// g.AddEdge(0, 1, 2)
// g.AddEdge(0, 2, 6)
// g.AddEdge(1, 3, 5)
// g.AddEdge(2, 3, 8)
// g.AddEdge(3, 4, 10)
// g.AddEdge(3, 5, 15)
// g.AddEdge(4, 6, 2)
// g.AddEdge(5, 6, 6)
// // g.Dijkstra(0)
// }
func ExamplePriorityQueue() {
type memo struct {
pt int
score int
}
less := func(a, b memo) bool { return a.score < b.score }
less := func(a, b *memo) bool { return a.score < b.score }
adj := map[int][][2]int{
0: {{1, 2}, {2, 6}},
@@ -169,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) {
@@ -188,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})
}
}
}
@@ -208,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})
}
+167 -79
View File
@@ -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)) }
@@ -20,118 +20,206 @@ type result struct {
func (r result) String() string { return fmt.Sprintf("%#v", r) }
func run(scan *bufio.Scanner) (*result, error) {
var m aoc.Map[rune]
var m aoc.Map[int16, rune]
for scan.Scan() {
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
}
func search(m aoc.Map[rune], minSteps, maxSteps int) int {
type direction int8
type rotate int8
type Point = aoc.Point[int16]
type Map = aoc.Map[int16, rune]
const (
CW rotate = 1
CCW rotate = -1
)
// rotate for changing direction
type rotate int8
var (
U = aoc.Point{-1, 0}
R = aoc.Point{0, 1}
D = aoc.Point{1, 0}
L = aoc.Point{0, -1}
)
const (
CW rotate = 1
CCW rotate = -1
)
var Direction = []aoc.Point{U, R, D, L}
// diretion of path steps
type direction int8
var Directions = make(map[aoc.Point]direction, len(Direction))
for k, v := range Direction {
Directions[v] = direction(k)
var (
U = Point{-1, 0}
R = Point{0, 1}
D = Point{1, 0}
L = Point{0, -1}
)
var directions = []Point{U, R, D, L}
var directionIDX = func() map[Point]direction {
m := make(map[Point]direction, len(directions))
for k, v := range directions {
m[v] = direction(k)
}
return m
}()
rows, cols := m.Size()
target := aoc.Point{rows - 1, cols - 1}
// position on the map
type position struct {
loc Point
direction Point
steps int8
}
func (p position) step() position {
return position{p.loc.Add(p.direction), p.direction, p.steps + 1}
}
func (p position) rotateAndStep(towards rotate) position {
d := directions[(int8(directionIDX[p.direction])+int8(towards)+4)%4]
return position{p.loc.Add(d), d, 1}
}
// implements FindPath graph interface
type graph struct {
min, max int8
m Map
target Point
reads int
seenFn func(a position) position
}
// Neighbors returns valid steps from given position. if at target returns none.
func (g *graph) Neighbors(current position) []position {
var nbs []position
if current.steps == 0 {
return []position{
{R, R, 1},
{D, D, 1},
}
}
if current.loc == g.target {
return nil
}
if left := current.rotateAndStep(CCW); current.steps >= g.min && g.m.Valid(left.loc) {
nbs = append(nbs, left)
}
type position struct {
loc aoc.Point
direction aoc.Point
steps int
if right := current.rotateAndStep(CW); current.steps >= g.min && g.m.Valid(right.loc) {
nbs = append(nbs, right)
}
step := func(p position) position {
return position{p.loc.Add(p.direction), p.direction, p.steps + 1}
if forward := current.step(); current.steps < g.max && g.m.Valid(forward.loc) {
nbs = append(nbs, forward)
}
rotateAndStep := func(p position, towards rotate) position {
d := Direction[(int8(Directions[p.direction])+int8(towards)+4)%4]
// fmt.Println(towards, Directions[p.direction], "->", Directions[d])
return position{p.loc.Add(d), d, 1}
return nbs
}
// Cost calculates heat cost to neighbor from map
func (g *graph) Cost(a, b position) int16 {
g.reads++
_, r, _ := g.m.Get(b.loc)
return int16(r - '0')
}
// Potential calculates distance to target
// func (g *graph) Potential(a position) int16 {
// return aoc.ManhattanDistance(a.loc, g.target)
// }
// 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
}
type memo struct {
cost int
position
// 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 g.seenFn != nil {
return g.seenFn(a)
}
less := func(a, b memo) bool {
if a.cost != b.cost {
return a.cost < b.cost
}
if a.position.loc != b.position.loc {
return b.position.loc.Less(a.position.loc)
}
if a.position.direction != b.position.direction {
return b.position.direction.Less(a.position.direction)
}
return a.steps < b.steps
return a
}
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}
pq := aoc.PriorityQueue(less)
pq.Enqueue(memo{position: position{direction: D}})
pq.Enqueue(memo{position: position{direction: R}})
visited := aoc.Set[position]()
g := graph{min: minSteps, max: maxSteps, m: m, target: target, seenFn: seenFn}
for !pq.IsEmpty() {
current, _ := pq.Dequeue()
cost, path, closed := aoc.FindPath[int16, position](&g, position{loc: start}, position{loc: target})
if current.loc == target && current.steps >= minSteps {
return current.cost
}
log("total map reads = ", g.reads, "cost = ", cost)
printGraph(m, path, closed, g.seenFn)
return int(cost)
}
seen := position{loc: current.loc, direction: current.direction, steps: current.steps}
// 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
}
if visited.Has(seen) {
// fmt.Println("visited", seen)
continue
}
visited.Add(seen)
clpt := make(map[position]position, len(closed))
for pt := range closed {
clpt[position{loc: pt.loc, steps: pt.steps}] = pt
}
// fmt.Print("\033[2J\033[H")
// fmt.Println("step ", current.steps, " dir ", Directions[current.direction], " steps ", " score ", current.cost, current.loc)
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 c == 0 {
// fmt.Printf("% 5d", r)
// }
if left := rotateAndStep(current.position, CCW); current.steps >= minSteps && m.Valid(left.loc) {
_, cost, _ := m.Get(left.loc)
// fmt.Println("turn left", current, left)
pq.Enqueue(memo{cost: current.cost + int(cost-'0'), position: left})
}
if pt, ok := pts[Point{int16(r), int16(c)}]; ok {
if seenFn != nil {
pt = seenFn(pt)
}
_ = pt
// fmt.Printf("% 5d", closed[pt])
fmt.Print("*")
if right := rotateAndStep(current.position, CW); current.steps >= minSteps && m.Valid(right.loc) {
_, cost, _ := m.Get(right.loc)
// fmt.Println("turn right", current, right)
pq.Enqueue(memo{cost: current.cost + int(cost-'0'), position: right})
}
continue
}
if forward := step(current.position); current.steps < maxSteps && m.Valid(forward.loc) {
_, cost, _ := m.Get(forward.loc)
// fmt.Println("go forward", current, forward)
pq.Enqueue(memo{cost: current.cost + int(cost-'0'), position: forward})
// fmt.Print(" ....")
fmt.Print(" ")
}
fmt.Println("")
}
return -1
fmt.Println("")
}
+9 -9
View File
@@ -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)
}
+2 -2
View File
@@ -45,7 +45,7 @@ func run(scan *bufio.Scanner) (*result, error) {
}, nil
}
var OFFSET = map[string]aoc.Point{
var OFFSET = map[string]aoc.Point[int]{
"R": {0, 1},
"D": {1, 0},
"L": {0, -1},
@@ -77,7 +77,7 @@ func fromColor(c string) aoc.Vector {
}
func findArea(vecs []aoc.Vector) int {
shoelace := []aoc.Point{{0, 0}}
shoelace := []aoc.Point[int]{{0, 0}}
borderLength := 0
for _, vec := range vecs {
+17
View File
@@ -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
View File
@@ -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
View File
@@ -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}
}
+41
View File
@@ -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 -3
View File
@@ -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
+183 -15
View File
@@ -1,23 +1,32 @@
package aoc
import (
"cmp"
"fmt"
"sort"
"strings"
"golang.org/x/exp/maps"
)
type Vector struct {
Offset Point
Offset Point[int]
Scale int
}
func (v Vector) Point() Point {
func (v Vector) Point() Point[int] {
return v.Offset.Scale(v.Scale)
}
type Point [2]int
type Point[T integer] [2]T
func (p Point) Add(a Point) Point {
return Point{p[0] + a[0], p[1] + a[1]}
func (p Point[T]) Add(a Point[T]) Point[T] {
return Point[T]{p[0] + a[0], p[1] + a[1]}
}
func (p Point) Scale(m int) Point {
return Point{p[0] * m, p[1] * m}
func (p Point[T]) Scale(m T) Point[T] {
return Point[T]{p[0] * m, p[1] * m}
}
func (p Point) Less(b Point) bool {
func (p Point[T]) Less(b Point[T]) bool {
if p[0] != b[0] {
return p[0] < b[0]
}
@@ -41,7 +50,7 @@ func Transpose[T any](matrix [][]T) [][]T {
}
// NumPoints the number of the points inside an outline plus the number of points in the outline
func NumPoints(outline []Point, borderLength int) int {
func NumPoints(outline []Point[int], borderLength int) int {
// shoelace - find the float area in a shape
sum := 0
for _, p := range Pairwise(outline) {
@@ -56,23 +65,182 @@ func NumPoints(outline []Point, borderLength int) int {
return (ABS(area) - borderLength/2 + 1) + borderLength
}
type Map[T any] [][]T
type Map[I integer, T any] [][]T
func (m *Map[T]) Get(p Point) (Point, T, bool) {
func (m *Map[I, T]) Get(p Point[I]) (Point[I], T, bool) {
var zero T
if !m.Valid(p) {
return [2]int{0, 0}, zero, false
return [2]I{0, 0}, zero, false
}
return p, (*m)[p[0]][p[1]], true
}
func (m *Map[T]) Size() (int, int) {
func (m *Map[I, T]) Size() (I, I) {
if m == nil || len(*m) == 0 {
return 0, 0
}
return len(*m), len((*m)[0])
return I(len(*m)), I(len((*m)[0]))
}
func (m *Map[T]) Valid(p Point) 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
}
}
}
}
+69
View File
@@ -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) {}
+109
View File
@@ -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)
}
}
+2
View File
@@ -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
+2
View File
@@ -0,0 +1,2 @@
8 90
13 47 74 12 89 74 18 38
View File
Whitespace-only changes.
+44
View File
@@ -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},
},
)
}
+10 -10
View File
@@ -3,19 +3,19 @@ package aoc
import "cmp"
type uinteger interface {
uint | uint8 | uint16 | uint32 | uint64
~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64
}
type sinteger interface {
int | int8 | int16 | int32 | int64
~int | ~int8 | ~int16 | ~int32 | ~int64
}
type integer interface {
sinteger | uinteger
}
// type float interface {
// complex64 | complex128 | float32 | float64
// }
// type number interface{ integer | float }
type float interface {
complex64 | complex128 | float32 | float64
}
type number interface{ integer | float }
// greatest common divisor (GCD) via Euclidean algorithm
func GCD[T integer](a, b T) T {
@@ -46,17 +46,17 @@ func LCM[T integer](integers ...T) T {
return result
}
func Sum[T integer](arr ...T) T {
func Sum[T number](arr ...T) T {
var acc T
for _, a := range arr {
acc += a
}
return acc
}
func SumFunc[T any, U integer](fn func(T) U, input ...T) U {
func SumFunc[T any, U number](fn func(T) U, input ...T) U {
return Sum(SliceMap(fn, input...)...)
}
func SumIFunc[T any, U integer](fn func(int, T) U, input ...T) U {
func SumIFunc[T any, U number](fn func(int, T) U, input ...T) U {
return Sum(SliceIMap(fn, input...)...)
}
@@ -71,7 +71,7 @@ func Power2(n int) int {
return p
}
func ABS(i int) int {
func ABS[I integer](i I) I {
if i < 0 {
return -i
}
+33
View File
@@ -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)
}
+15
View File
@@ -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
}
+84
View File
@@ -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
}
}
+193
View File
@@ -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})
}
+12
View File
@@ -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
}
}
}
}
+51 -3
View File
@@ -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"
+304 -15
View File
@@ -1,35 +1,324 @@
package aoc
import (
"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) {
func (pq *priorityQueue[T]) Insert(elem *T) {
pq.totalEnqueue++
pq.elems = append(pq.elems, elem)
sort.Slice(pq.elems, func(i, j int) bool { return pq.less(pq.elems[j], pq.elems[i]) })
pq.maxDepth = max(pq.maxDepth, len(pq.elems))
}
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
}
type DS[T comparable] struct {
*priorityQueue[T, []T]
*set[T]
// ManhattanDistance the distance between two points measured along axes at right angles.
func ManhattanDistance[T integer](a, b Point[T]) T {
return ABS(a[0]-b[0]) + ABS(a[1]-b[1])
}
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
// 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
}
// 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
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
potential C
parent *node
position N
}
newPath := func(n *node) []N {
var path []N
for n.parent != nil {
path = append(path, n.position)
n = n.parent
}
path = append(path, n.position)
Reverse(path)
return path
}
less := func(a, b *node) bool {
return a.cost+a.potential < b.cost+b.potential
}
closed := make(map[N]C)
open := FibHeap(less)
open.Insert(&node{position: start, potential: potentialFn(start)})
closed[start] = zero
for !open.IsEmpty() {
current := open.ExtractMin()
for _, nb := range g.Neighbors(current.position) {
next := &node{
position: nb,
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
}
}
}
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)
}
}
+9
View File
@@ -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
View File
@@ -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})
}