Compare commits
5
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ad4dca6919
|
||
|
|
2057a30420
|
||
|
|
bcd90a57f3
|
||
|
|
b6501e80c9
|
||
|
|
be110c4dea
|
No files matched your search
@@ -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 }}."
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
-----BEGIN SSH SIGNATURE-----
|
|
||||||
U1NIU0lHAAAAAQAAADMAAAALc3NoLWVkMjU1MTkAAAAgZ+OuJYdd3UiUbyBuO1RlsQR20a
|
|
||||||
Qm5mKneuMxRjGo3zkAAAAEZmlsZQAAAAAAAAAGc2hhNTEyAAAAUwAAAAtzc2gtZWQyNTUx
|
|
||||||
OQAAAED8T4C6WILXYZ1KxqDIlVhlrAEjr1Vc+tn8ypcVM3bN7iOexVvuUuvm90nr8eEwKU
|
|
||||||
acrdDxmq2S+oysQbK+pMUE
|
|
||||||
-----END SSH SIGNATURE-----
|
|
||||||
+70
-257
@@ -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})
|
|
||||||
}
|
}
|
||||||
@@ -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))
|
||||||
|
|||||||
@@ -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)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -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
|
||||||
|
|
||||||
|
|||||||
+152
-163
@@ -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
|
|
||||||
type position struct {
|
|
||||||
loc Point
|
|
||||||
direction Point
|
|
||||||
steps int8
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p position) step() position {
|
return p, int((*m)[p[0]][p[1]] - '0'), true
|
||||||
return position{p.loc.Add(p.direction), p.direction, p.steps + 1}
|
|
||||||
}
|
}
|
||||||
func (p position) rotateAndStep(towards rotate) position {
|
func (m *Map) GetNeighbor(p point, d point) (point, int, bool) {
|
||||||
d := directions[(int8(directionIDX[p.direction])+int8(towards)+4)%4]
|
return m.Get(p.add(d))
|
||||||
return position{p.loc.Add(d), d, 1}
|
|
||||||
}
|
}
|
||||||
|
func (m *Map) Size() (int, int) {
|
||||||
// implements FindPath graph interface
|
if m == nil || len(*m) == 0 {
|
||||||
type graph struct {
|
return 0, 0
|
||||||
min, max int8
|
|
||||||
m Map
|
|
||||||
target Point
|
|
||||||
reads int
|
|
||||||
seenFn func(a position) position
|
|
||||||
}
|
}
|
||||||
|
return len(*m), len((*m)[0])
|
||||||
// Neighbors returns valid steps from given position. if at target returns none.
|
}
|
||||||
func (g *graph) Neighbors(current position) []position {
|
func (m *Map) Neighbors(p point) []point {
|
||||||
var nbs []position
|
var lis []point
|
||||||
|
for _, d := range []point{UP, DN, LF, RT} {
|
||||||
if current.steps == 0 {
|
if p, _, ok := m.GetNeighbor(p, d); ok {
|
||||||
return []position{
|
lis = append(lis, p)
|
||||||
{R, R, 1},
|
|
||||||
{D, D, 1},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return lis
|
||||||
if current.loc == g.target {
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
func (m *Map) NeighborDirections(p point) []point {
|
||||||
if left := current.rotateAndStep(CCW); current.steps >= g.min && g.m.Valid(left.loc) {
|
var lis []point
|
||||||
nbs = append(nbs, left)
|
for _, d := range []point{UP, DN, LF, RT} {
|
||||||
|
if m.Valid(p.add(d)) {
|
||||||
|
lis = append(lis, d)
|
||||||
}
|
}
|
||||||
|
|
||||||
if right := current.rotateAndStep(CW); current.steps >= g.min && g.m.Valid(right.loc) {
|
|
||||||
nbs = append(nbs, right)
|
|
||||||
}
|
}
|
||||||
|
return lis
|
||||||
if forward := current.step(); current.steps < g.max && g.m.Valid(forward.loc) {
|
|
||||||
nbs = append(nbs, forward)
|
|
||||||
}
|
}
|
||||||
|
func (m *Map) Valid(p point) bool {
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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
|
||||||
}
|
}
|
||||||
|
|
||||||
clpt := make(map[position]position, len(closed))
|
func (memo) sort(a, b memo) bool {
|
||||||
for pt := range closed {
|
if a.h != b.h {
|
||||||
clpt[position{loc: pt.loc, steps: pt.steps}] = pt
|
return a.h < b.h
|
||||||
}
|
}
|
||||||
|
|
||||||
for r, row := range m {
|
if a.s != b.s {
|
||||||
// if r == 0 {
|
return a.s < b.s
|
||||||
// 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("*")
|
|
||||||
|
|
||||||
|
if a.p != b.p {
|
||||||
|
return a.p.less(b.p)
|
||||||
|
}
|
||||||
|
|
||||||
|
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
@@ -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)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -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
@@ -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
@@ -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}
|
|
||||||
}
|
|
||||||
@@ -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))
|
|
||||||
}
|
|
||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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) {}
|
|
||||||
@@ -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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
8 90
|
|
||||||
13 47 74 12 89 74 18 38
|
|
||||||
Whitespace-only changes.
@@ -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 {
|
||||||
|
|||||||
@@ -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},
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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)
|
|
||||||
}
|
|
||||||
@@ -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
|
|
||||||
}
|
|
||||||
@@ -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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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})
|
|
||||||
}
|
|
||||||
@@ -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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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...)
|
||||||
}
|
}
|
||||||
@@ -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
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
func (g *graph[V, I]) AddEdge(u, v V, w I) {
|
||||||
|
g.adj[u] = append(g.adj[u], Vertex[V, I]{to: v, score: w})
|
||||||
|
g.adj[v] = append(g.adj[v], Vertex[V, I]{to: u, score: w})
|
||||||
}
|
}
|
||||||
return zero, nil, closed
|
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
|
||||||
|
|
||||||
|
pq.Enqueue(src, 0)
|
||||||
|
dist[src] = 0
|
||||||
|
|
||||||
|
for !pq.IsEmpty() {
|
||||||
|
u, _ := pq.Dequeue()
|
||||||
|
|
||||||
|
if _, ok := visited[u]; ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
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
|
||||||
}
|
}
|
||||||
|
|
||||||
type fibTree[T any] struct {
|
if !ok && du+v.score < dv {
|
||||||
value *T
|
dist[v.to] = du + v.score
|
||||||
parent *fibTree[T]
|
pq.Enqueue(v.to, du+v.score)
|
||||||
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]) {
|
return dist
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -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
@@ -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})
|
|
||||||
}
|
|
||||||
Reference in new issue
Block a user