5 Commits
Author SHA1 Message Date
xuu ad4dca6919 Merge remote-tracking branch 'origin/main' into day18
Go Test / build (pull_request) Failing after 10m26s
2023-12-27 14:06:22 -07:00
xuu 2057a30420 chore: cleanup base tools
Go Test / build (pull_request) Successful in 34s
2023-12-27 14:01:14 -07:00
xuu bcd90a57f3 chore: use shoelace and picks theorem
Go Test / build (pull_request) Successful in 57s
2023-12-27 13:46:42 -07:00
xuu b6501e80c9 chore: add day 18 pt 2
Go Test / build (pull_request) Failing after 34s
2023-12-27 13:18:49 -07:00
xuu be110c4dea chore: save day18
Go Test / build (pull_request) Failing after 34s
2023-12-20 11:27:20 -07:00
32 changed files with 334 additions and 2744 deletions

No files matched your search

+1 -1
View File
@@ -28,6 +28,6 @@ jobs:
go-version: 1.21.3 go-version: 1.21.3
- name: Test - name: Test
run: go test -timeout 240s -race -cover ./... run: go test --race -cover ./...
- run: echo "🍏 This job's status is ${{ job.status }}." - run: echo "🍏 This job's status is ${{ job.status }}."
-6
View File
@@ -1,6 +0,0 @@
-----BEGIN SSH SIGNATURE-----
U1NIU0lHAAAAAQAAADMAAAALc3NoLWVkMjU1MTkAAAAgZ+OuJYdd3UiUbyBuO1RlsQR20a
Qm5mKneuMxRjGo3zkAAAAEZmlsZQAAAAAAAAAGc2hhNTEyAAAAUwAAAAtzc2gtZWQyNTUx
OQAAAED8T4C6WILXYZ1KxqDIlVhlrAEjr1Vc+tn8ypcVM3bN7iOexVvuUuvm90nr8eEwKU
acrdDxmq2S+oysQbK+pMUE
-----END SSH SIGNATURE-----
+70 -257
View File
@@ -1,14 +1,72 @@
package aoc_test package aoc_test
import ( import (
"fmt"
"sort"
"testing" "testing"
"github.com/matryer/is" "github.com/matryer/is"
aoc "go.sour.is/advent-of-code" 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) { func TestList(t *testing.T) {
is := is.New(t) is := is.New(t)
@@ -21,260 +79,15 @@ func TestList(t *testing.T) {
is.Equal(a, 5) is.Equal(a, 5)
} }
func TestPriorityQueue(t *testing.T) {
is := is.New(t)
type elem [2]int
less := func(b, a *elem) bool {
return (*a)[0] < (*b)[0]
}
pq := aoc.PriorityQueue(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{4, 1})
v = pq.ExtractMin()
is.True(v != nil)
is.Equal(v, &elem{3, 2})
v = pq.ExtractMin()
is.True(v != nil)
is.Equal(v, &elem{2, 3})
v = pq.ExtractMin()
is.True(v != nil)
is.Equal(v, &elem{1, 4})
v = pq.ExtractMin()
is.True(v == nil)
}
func ExamplePriorityQueue() {
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.PriorityQueue(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 TestGraph(t *testing.T) { func TestGraph(t *testing.T) {
is := is.New(t) g := aoc.Graph[int, uint](7)
g.AddEdge(0, 1, 2)
var adjacencyList = map[int][]int{ g.AddEdge(0, 2, 6)
2: {3, 5, 1}, g.AddEdge(1, 3, 5)
1: {2, 4}, g.AddEdge(2, 3, 8)
3: {6, 2}, g.AddEdge(3, 4, 10)
4: {1, 5, 7}, g.AddEdge(3, 5, 15)
5: {2, 6, 8, 4}, g.AddEdge(4, 6, 2)
6: {3, 0, 9, 5}, g.AddEdge(5, 6, 6)
7: {4, 8}, // g.Dijkstra(0)
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})
} }
+1
View File
@@ -30,6 +30,7 @@ func TestExample1(t *testing.T) {
is.Equal(result.sum, 142) is.Equal(result.sum, 142)
} }
func TestExample2(t *testing.T) { func TestExample2(t *testing.T) {
is := is.New(t) is := is.New(t)
scan := bufio.NewScanner(bytes.NewReader(example2)) scan := bufio.NewScanner(bytes.NewReader(example2))
+1
View File
@@ -43,3 +43,4 @@ func TestSolution(t *testing.T) {
is.Equal(result.valuePT1, 110407) is.Equal(result.valuePT1, 110407)
is.Equal(result.valuePT2, 87273) is.Equal(result.valuePT2, 87273)
} }
+5 -4
View File
@@ -32,15 +32,15 @@ func run(scan *bufio.Scanner) (*result, error) {
options := make([]int, 2*(rows+cols)+2) options := make([]int, 2*(rows+cols)+2)
i := 0 i := 0
for j := 0; j <= rows-1; j++ { for j:=0; j<=rows-1; j++ {
options[i+0] = runCycle(m, ray{[2]int{j, -1}, RT}) options[i+0] = runCycle(m, ray{[2]int{j, -1}, RT})
options[i+1] = runCycle(m, ray{[2]int{j, cols}, LF}) options[i+1] = runCycle(m, ray{[2]int{j, cols}, LF})
i += 2 i+=2
} }
for j := 0; j <= cols-1; j++ { for j:=0; j<=cols-1; j++ {
options[i+0] = runCycle(m, ray{[2]int{-1, j}, DN}) options[i+0] = runCycle(m, ray{[2]int{-1, j}, DN})
options[i+1] = runCycle(m, ray{[2]int{rows, j}, UP}) options[i+1] = runCycle(m, ray{[2]int{rows, j}, UP})
i += 2 i+=2
} }
// fmt.Println(options) // fmt.Println(options)
@@ -96,6 +96,7 @@ func (m *Map) Get(p [2]int) rune {
return (*m)[p[0]][p[1]] return (*m)[p[0]][p[1]]
} }
func runCycle(m Map, r ray) int { func runCycle(m Map, r ray) int {
current := r current := r
+154 -165
View File
@@ -4,11 +4,12 @@ import (
"bufio" "bufio"
_ "embed" _ "embed"
"fmt" "fmt"
"sort"
aoc "go.sour.is/advent-of-code" aoc "go.sour.is/advent-of-code"
) )
var log = aoc.Log // var log = aoc.Log
func main() { aoc.MustResult(aoc.Runner(run)) } func main() { aoc.MustResult(aoc.Runner(run)) }
@@ -20,206 +21,194 @@ type result struct {
func (r result) String() string { return fmt.Sprintf("%#v", r) } func (r result) String() string { return fmt.Sprintf("%#v", r) }
func run(scan *bufio.Scanner) (*result, error) { func run(scan *bufio.Scanner) (*result, error) {
var m aoc.Map[int16, rune] var m Map
for scan.Scan() { for scan.Scan() {
text := scan.Text() text := scan.Text()
m = append(m, []rune(text)) m = append(m, []rune(text))
} }
log("start day 17")
result := result{} result := result{}
result.valuePT1 = search(m, 1, 3, seenFn) result.valuePT1 = search(m, 1, 3)
log("result from part 1 = ", result.valuePT1) result.valuePT2 = search(m, 4, 10)
result.valuePT2 = search(m, 4, 10, nil)
log("result from part 2 = ", result.valuePT2)
return &result, nil return &result, nil
} }
type Point = aoc.Point[int16]
type Map = aoc.Map[int16, rune]
// rotate for changing direction
type rotate int8
const (
CW rotate = 1
CCW rotate = -1
)
// diretion of path steps
type direction int8
var ( var (
U = Point{-1, 0} ZERO = point{0, 0}
R = Point{0, 1}
D = Point{1, 0} UP = point{-1, 0}
L = Point{0, -1} DN = point{1, 0}
LF = point{0, -1}
RT = point{0, 1}
INF = int(^uint(0) >> 1)
) )
var directions = []Point{U, R, D, L} type Map [][]rune
var directionIDX = func() map[Point]direction { func (m *Map) Get(p point) (point, int, bool) {
m := make(map[Point]direction, len(directions)) if !m.Valid(p) {
for k, v := range directions { return [2]int{0, 0}, 0, false
m[v] = direction(k)
} }
return m
}()
// position on the map return p, int((*m)[p[0]][p[1]] - '0'), true
type position struct {
loc Point
direction Point
steps int8
} }
func (m *Map) GetNeighbor(p point, d point) (point, int, bool) {
func (p position) step() position { return m.Get(p.add(d))
return position{p.loc.Add(p.direction), p.direction, p.steps + 1}
} }
func (p position) rotateAndStep(towards rotate) position { func (m *Map) Size() (int, int) {
d := directions[(int8(directionIDX[p.direction])+int8(towards)+4)%4] if m == nil || len(*m) == 0 {
return position{p.loc.Add(d), d, 1} return 0, 0
}
return len(*m), len((*m)[0])
} }
func (m *Map) Neighbors(p point) []point {
// implements FindPath graph interface var lis []point
type graph struct { for _, d := range []point{UP, DN, LF, RT} {
min, max int8 if p, _, ok := m.GetNeighbor(p, d); ok {
m Map lis = append(lis, p)
target Point }
reads int }
seenFn func(a position) position return lis
} }
func (m *Map) NeighborDirections(p point) []point {
// Neighbors returns valid steps from given position. if at target returns none. var lis []point
func (g *graph) Neighbors(current position) []position { for _, d := range []point{UP, DN, LF, RT} {
var nbs []position if m.Valid(p.add(d)) {
lis = append(lis, d)
if current.steps == 0 {
return []position{
{R, R, 1},
{D, D, 1},
} }
} }
return lis
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)
}
if right := current.rotateAndStep(CW); current.steps >= g.min && g.m.Valid(right.loc) {
nbs = append(nbs, right)
}
if forward := current.step(); current.steps < g.max && g.m.Valid(forward.loc) {
nbs = append(nbs, forward)
}
return nbs
} }
func (m *Map) Valid(p point) bool {
// 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
}
// 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)
}
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() rows, cols := m.Size()
start := Point{} return p[0] >= 0 && p[0] < rows && p[1] >= 0 && p[1] < cols
target := Point{rows - 1, cols - 1}
g := graph{min: minSteps, max: maxSteps, m: m, target: target, seenFn: seenFn}
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/cost overlay type memo struct {
func printGraph(m Map, path []position, closed map[position]int16, seenFn func(a position) position) { h int
pts := make(map[Point]position, len(path)) s int
for _, pt := range path { p point
pts[pt.loc] = pt d point
}
func (memo) sort(a, b memo) bool {
if a.h != b.h {
return a.h < b.h
} }
clpt := make(map[position]position, len(closed)) if a.s != b.s {
for pt := range closed { return a.s < b.s
clpt[position{loc: pt.loc, steps: pt.steps}] = pt
} }
for r, row := range m { if a.p != b.p {
// if r == 0 { return a.p.less(b.p)
// 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 pt, ok := pts[Point{int16(r), int16(c)}]; ok {
if seenFn != nil {
pt = seenFn(pt)
} }
_ = pt
// fmt.Printf("% 5d", closed[pt])
fmt.Print("*")
return a.d.less(b.d)
}
type priorityQueue[T any, U []T] struct {
elems U
sort func(a, b T) bool
}
func PriorityQueue[T any, U []T](sort func(a, b T) bool) *priorityQueue[T, U] {
return &priorityQueue[T, U]{sort: sort}
}
func (pq *priorityQueue[T, U]) Enqueue(elem T) {
pq.elems = append(pq.elems, elem)
sort.Slice(pq.elems, func(i, j int) bool { return pq.sort(pq.elems[i], pq.elems[j]) })
}
func (pq *priorityQueue[T, I]) IsEmpty() bool {
return len(pq.elems) == 0
}
func (pq *priorityQueue[T, I]) Dequeue() (T, bool) {
var elem T
if pq.IsEmpty() {
return elem, false
}
elem, pq.elems = pq.elems[0], pq.elems[1:]
return elem, true
}
func heuristic(m Map, p point) int {
rows, cols := m.Size()
return rows - p[0] + cols - p[1]
}
func search(m Map, minSize, maxSize int) int {
rows, cols := m.Size()
END := point{rows - 1, cols - 1}
visited := make(map[vector]int)
pq := PriorityQueue(memo{}.sort)
pq.Enqueue(memo{h: heuristic(m, point{0, 0}), p: point{0, 0}, d: DN})
for !pq.IsEmpty() {
mem, _ := pq.Dequeue()
fmt.Println(mem)
if mem.h > dmap(visited, vector{mem.p[0], mem.p[1], mem.d[0], mem.d[1]}, INF) {
continue continue
} }
// fmt.Print(" ....") if mem.p == END {
fmt.Print(" ") return mem.s
} }
fmt.Println("")
for _, nd := range m.NeighborDirections(mem.p) {
if nd[0] == 0 && mem.d == RT || nd[1] == 0 && mem.d == DN {
continue
} }
fmt.Println("")
dscore := 0
for _, size := range irange(1, maxSize+1) {
np := mem.p.add(nd.scale(size))
_, s, ok := m.Get(np)
if !ok {
break
}
dscore += s
pscore := mem.s + dscore
nh := heuristic(m, np) + pscore
vec := vector{np[0], np[1], nd[0], nd[1]}
if size >= minSize && nh < dmap(visited, vec, INF) {
pq.Enqueue(memo{nh, pscore, np, nd})
visited[vec] = nh
}
}
}
}
return 0
} }
func dmap[K comparable, V any](m map[K]V, k K, d V) V {
if v, ok := m[k]; ok {
return v
}
return d
}
func irange(a, b int) []int {
lis := make([]int, b-a)
for i := range lis {
lis[i] = i + a
}
return lis
}
type point [2]int
func (p point) add(a point) point { return point{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) less(a point) bool { return p[0] < a[0] || p[1] < a[1] }
type vector [4]int
+3 -2
View File
@@ -45,7 +45,7 @@ func run(scan *bufio.Scanner) (*result, error) {
}, nil }, nil
} }
var OFFSET = map[string]aoc.Point[int]{ var OFFSET = map[string]aoc.Point{
"R": {0, 1}, "R": {0, 1},
"D": {1, 0}, "D": {1, 0},
"L": {0, -1}, "L": {0, -1},
@@ -77,7 +77,7 @@ func fromColor(c string) aoc.Vector {
} }
func findArea(vecs []aoc.Vector) int { func findArea(vecs []aoc.Vector) int {
shoelace := []aoc.Point[int]{{0, 0}} shoelace := []aoc.Point{{0,0}}
borderLength := 0 borderLength := 0
for _, vec := range vecs { for _, vec := range vecs {
@@ -87,3 +87,4 @@ func findArea(vecs []aoc.Vector) int {
return aoc.NumPoints(shoelace, borderLength) return aoc.NumPoints(shoelace, borderLength)
} }
-17
View File
@@ -1,17 +0,0 @@
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
@@ -1,780 +0,0 @@
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
@@ -1,255 +0,0 @@
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
@@ -1,41 +0,0 @@
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))
}
+3 -1
View File
@@ -1,6 +1,8 @@
module go.sour.is/advent-of-code module go.sour.is/advent-of-code
go 1.22.0 go 1.21.4
toolchain go1.21.5
require ( require (
github.com/matryer/is v1.4.1 github.com/matryer/is v1.4.1
+8 -203
View File
@@ -1,36 +1,21 @@
package aoc package aoc
import (
"cmp"
"fmt"
"sort"
"strings"
"golang.org/x/exp/maps"
)
type Vector struct { type Vector struct {
Offset Point[int] Offset Point
Scale int Scale int
} }
func (v Vector) Point() Point[int] { func (v Vector) Point() Point {
return v.Offset.Scale(v.Scale) return v.Offset.Scale(v.Scale)
} }
type Point[T integer] [2]T type Point [2]int
func (p Point[T]) Add(a Point[T]) Point[T] { func (p Point) Add(a Point) Point {
return Point[T]{p[0] + a[0], p[1] + a[1]} return Point{p[0] + a[0], p[1] + a[1]}
} }
func (p Point[T]) Scale(m T) Point[T] { func (p Point) Scale(m int) Point {
return Point[T]{p[0] * m, p[1] * m} return Point{p[0] * m, p[1] * m}
}
func (p Point[T]) Less(b Point[T]) bool {
if p[0] != b[0] {
return p[0] < b[0]
}
return p[1] < b[1]
} }
func Transpose[T any](matrix [][]T) [][]T { func Transpose[T any](matrix [][]T) [][]T {
@@ -50,7 +35,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 // NumPoints the number of the points inside an outline plus the number of points in the outline
func NumPoints(outline []Point[int], borderLength int) int { func NumPoints(outline []Point, borderLength int) int {
// shoelace - find the float area in a shape // shoelace - find the float area in a shape
sum := 0 sum := 0
for _, p := range Pairwise(outline) { for _, p := range Pairwise(outline) {
@@ -64,183 +49,3 @@ func NumPoints(outline []Point[int], borderLength int) int {
// pick's theorem - find the number of points in a shape given its area // pick's theorem - find the number of points in a shape given its area
return (ABS(area) - borderLength/2 + 1) + borderLength return (ABS(area) - borderLength/2 + 1) + borderLength
} }
type Map[I integer, T any] [][]T
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
}
return p, (*m)[p[0]][p[1]], true
}
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 {
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
@@ -1,69 +0,0 @@
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
@@ -1,109 +0,0 @@
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
@@ -1,2 +0,0 @@
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
@@ -1,2 +0,0 @@
8 90
13 47 74 12 89 74 18 38
View File
Whitespace-only changes.
+1
View File
@@ -31,6 +31,7 @@ func Reverse[T any](arr []T) []T {
return arr return arr
} }
func SliceMap[T, U any](fn func(T) U, in ...T) []U { func SliceMap[T, U any](fn func(T) U, in ...T) []U {
lis := make([]U, len(in)) lis := make([]U, len(in))
for i := range lis { for i := range lis {
-44
View File
@@ -1,44 +0,0 @@
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},
},
)
}
+1
View File
@@ -2,6 +2,7 @@ package aoc
import "fmt" import "fmt"
type Node[T any] struct { type Node[T any] struct {
value T value T
pos int pos int
+10 -10
View File
@@ -3,19 +3,19 @@ package aoc
import "cmp" import "cmp"
type uinteger interface { type uinteger interface {
~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 uint | uint8 | uint16 | uint32 | uint64
} }
type sinteger interface { type sinteger interface {
~int | ~int8 | ~int16 | ~int32 | ~int64 int | int8 | int16 | int32 | int64
} }
type integer interface { type integer interface {
sinteger | uinteger sinteger | uinteger
} }
type float interface { // type float interface {
complex64 | complex128 | float32 | float64 // complex64 | complex128 | float32 | float64
} // }
type number interface{ integer | float } // type number interface{ integer | float }
// greatest common divisor (GCD) via Euclidean algorithm // greatest common divisor (GCD) via Euclidean algorithm
func GCD[T integer](a, b T) T { func GCD[T integer](a, b T) T {
@@ -46,17 +46,17 @@ func LCM[T integer](integers ...T) T {
return result return result
} }
func Sum[T number](arr ...T) T { func Sum[T integer](arr ...T) T {
var acc T var acc T
for _, a := range arr { for _, a := range arr {
acc += a acc += a
} }
return acc return acc
} }
func SumFunc[T any, U number](fn func(T) U, input ...T) U { func SumFunc[T any, U integer](fn func(T) U, input ...T) U {
return Sum(SliceMap(fn, input...)...) return Sum(SliceMap(fn, input...)...)
} }
func SumIFunc[T any, U number](fn func(int, T) U, input ...T) U { func SumIFunc[T any, U integer](fn func(int, T) U, input ...T) U {
return Sum(SliceIMap(fn, input...)...) return Sum(SliceIMap(fn, input...)...)
} }
@@ -71,7 +71,7 @@ func Power2(n int) int {
return p return p
} }
func ABS[I integer](i I) I { func ABS(i int) int {
if i < 0 { if i < 0 {
return -i return -i
} }
-33
View File
@@ -1,33 +0,0 @@
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
@@ -1,15 +0,0 @@
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
@@ -1,84 +0,0 @@
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
@@ -1,193 +0,0 @@
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
@@ -1,12 +0,0 @@
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
}
}
}
}
+4 -51
View File
@@ -2,70 +2,25 @@ package aoc
import ( import (
"bufio" "bufio"
"flag"
"fmt" "fmt"
"log"
"os" "os"
"path/filepath" "path/filepath"
"runtime"
"runtime/pprof"
"strings" "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) { 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") Log("Usage:", filepath.Base(os.Args[0]), "FILE")
os.Exit(22) os.Exit(22)
} }
inputFilename := os.Args[1] input, err := os.Open(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 { if err != nil {
Log(err) Log(err)
os.Exit(1) os.Exit(1)
} }
scan := bufio.NewScanner(input) scan := bufio.NewScanner(input)
return run(scan) return run(scan)
} }
@@ -78,10 +33,7 @@ func MustResult[T any](result T, err error) {
Log("result", result) Log("result", result)
} }
func Log(v ...any) { func Log(v ...any) { fmt.Fprintln(os.Stderr, v...) }
fmt.Fprint(os.Stderr, time.Now(), ": ")
fmt.Fprintln(os.Stderr, v...)
}
func Logf(format string, v ...any) { func Logf(format string, v ...any) {
if !strings.HasSuffix(format, "\n") { if !strings.HasSuffix(format, "\n") {
format += "\n" format += "\n"
@@ -89,6 +41,7 @@ func Logf(format string, v ...any) {
fmt.Fprintf(os.Stderr, format, v...) fmt.Fprintf(os.Stderr, format, v...)
} }
func ReadStringToInts(fields []string) []int { func ReadStringToInts(fields []string) []int {
return SliceMap(Atoi, fields...) return SliceMap(Atoi, fields...)
} }
+72 -293
View File
@@ -1,324 +1,103 @@
package aoc package aoc
import ( import (
"math/bits"
"sort" "sort"
) )
type priorityQueue[T any] struct { type PQElem[T any, I integer] struct {
elems []*T Value T
less func(a, b *T) bool Priority I
maxDepth int }
totalEnqueue int type PQList[T any, I integer] []PQElem[T, I]
totalDequeue int
func (pq PQList[T, I]) Len() int {
return len(pq)
}
func (pq PQList[T, I]) Less(i int, j int) bool {
return pq[i].Priority < pq[j].Priority
}
func (pq PQList[T, I]) Swap(i int, j int) {
pq[i], pq[j] = pq[j], pq[i]
} }
// PriorityQueue implements a simple slice based queue. var _ sort.Interface = (*PQList[rune, int])(nil)
// 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]) Insert(elem *T) {
pq.totalEnqueue++
pq.elems = append(pq.elems, elem) type PriorityQueue[T any, I integer] struct {
pq.maxDepth = max(pq.maxDepth, len(pq.elems)) elem PQList[T, I]
} }
func (pq *priorityQueue[T]) IsEmpty() bool {
return len(pq.elems) == 0
}
func (pq *priorityQueue[T]) ExtractMin() *T {
pq.totalDequeue++
var elem *T func (pq *PriorityQueue[T, I]) Enqueue(elem T, priority I) {
pq.elem = append(pq.elem, PQElem[T, I]{elem, priority})
sort.Sort(pq.elem)
}
func (pq *PriorityQueue[T, I]) IsEmpty() bool {
return len(pq.elem) == 0
}
func (pq *PriorityQueue[T, I]) Dequeue() (T, bool) {
var elem T
if pq.IsEmpty() { if pq.IsEmpty() {
return elem return elem, false
} }
sort.Slice(pq.elems, func(i, j int) bool { return pq.less(pq.elems[j], pq.elems[i]) }) elem, pq.elem = pq.elem[0].Value, pq.elem[1:]
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. type Vertex[V comparable, I integer] struct {
func ManhattanDistance[T integer](a, b Point[T]) T { to V
return ABS(a[0]-b[0]) + ABS(a[1]-b[1]) score I
}
type graph[V comparable, I uinteger] struct {
adj map[V][]Vertex[V, I]
} }
type pather[C number, N comparable] interface { func Graph[V comparable, I uinteger](size int) *graph[V, I] {
// Neighbors returns all neighbors to node N that should be considered next. return &graph[V, I]{
Neighbors(N) []N adj: make(map[V][]Vertex[V, I], size),
// 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 (g *graph[V, I]) AddEdge(u, v V, w I) {
func (h *fibHeap[T]) Merge(a *fibHeap[T]) { g.adj[u] = append(g.adj[u], Vertex[V, I]{to: v, score: w})
h.trees = append(h.trees, a.trees...) g.adj[v] = append(g.adj[v], Vertex[V, I]{to: u, score: w})
h.count += a.count
if h.least == nil || a.least != nil && h.less(a.least.value, h.least.value) {
h.least = a.least
}
} }
func (g *graph[V, I]) Dijkstra(m interface{ Get() }, src V) map[V]I {
pq := PriorityQueue[V, I]{}
dist := make(map[V]I, len(g.adj))
visited := make(map[V]bool, len(g.adj))
var INF I
INF = ^INF
func (h *fibHeap[T]) find(fn func(*T) bool) *fibTree[T] { pq.Enqueue(src, 0)
var st []*fibTree[T] dist[src] = 0
st = append(st, h.trees...)
var tr *fibTree[T]
for len(st) > 0 { for !pq.IsEmpty() {
tr, st = st[0], st[1:] u, _ := pq.Dequeue()
ro := *tr.value
if fn(&ro) { if _, ok := visited[u]; ok {
break continue
} }
st = append(st, tr.child...) visited[u] = true
for _, v := range g.adj[u] {
_, ok := visited[v.to]
var du, dv I
if d, inf := dist[u]; !inf {
du = INF
} else {
du = d
}
if d, inf := dist[v.to]; !inf {
dv = INF
} else {
dv = d
} }
return tr if !ok && du+v.score < dv {
} dist[v.to] = du + v.score
pq.Enqueue(v.to, du+v.score)
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) return dist
h.cascadingCut(y.parent)
}
} }
-68
View File
@@ -1,68 +0,0 @@
package aoc
import "golang.org/x/exp/maps"
type set[T comparable] map[T]struct{}
func Set[T comparable](arr ...T) set[T] {
m := make(set[T], len(arr))
for _, a := range arr {
m[a] = struct{}{}
}
return m
}
func (m *set[T]) Add(a T) {
(*m)[a] = struct{}{}
}
func (m *set[T]) Items() []T {
return maps.Keys(*m)
}
func (m *set[T]) Has(a T) bool {
var ok bool
_, ok = (*m)[a]
return ok
}
type defaultMap[K comparable, V any] struct {
m map[K]V
d V
}
func DefaultMap[K comparable, V any](d V) *defaultMap[K, V] {
return &defaultMap[K, V]{
make(map[K]V),
d,
}
}
func (m *defaultMap[K, V]) Set(k K, v V) {
m.m[k] = v
}
func (m *defaultMap[K, V]) Get(k K) (V, bool) {
if v, ok := m.m[k]; ok {
return v, true
}
return m.d, false
}
type pair[K, V any] struct {
K K
V V
}
func (m *defaultMap[K, V]) Items() []pair[K, V] {
var items = make([]pair[K, V], 0, len(m.m))
for k, v := range m.m {
items = append(items, pair[K, V]{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
@@ -1,27 +0,0 @@
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})
}