Compare commits
No commits in common. "0d652660f1ba2c6d3fd593774e8a9f0c19a4d16c" and "04bbac85592156fbcf1ab5b6fb230dd97e29b996" have entirely different histories.
0d652660f1
...
04bbac8559
|
@ -10,7 +10,7 @@ import (
|
||||||
|
|
||||||
// var log = aoc.Log
|
// var log = aoc.Log
|
||||||
|
|
||||||
func main() { aoc.MustResult(aoc.Runner(runner(64))) }
|
func main() { aoc.MustResult(aoc.Runner(run)) }
|
||||||
|
|
||||||
type result struct {
|
type result struct {
|
||||||
valuePT1 int
|
valuePT1 int
|
||||||
|
@ -19,81 +19,12 @@ type result struct {
|
||||||
|
|
||||||
func (r result) String() string { return fmt.Sprintf("%#v", r) }
|
func (r result) String() string { return fmt.Sprintf("%#v", r) }
|
||||||
|
|
||||||
func runner(rounds int) func(scan *bufio.Scanner) (*result, error) {
|
func run(scan *bufio.Scanner) (*result, error) {
|
||||||
return func(scan *bufio.Scanner) (*result, error) {
|
|
||||||
var garden garden
|
|
||||||
|
|
||||||
for scan.Scan() {
|
for scan.Scan() {
|
||||||
txt := scan.Text()
|
_ = scan.Text()
|
||||||
garden.m = append(garden.m, []rune(txt))
|
|
||||||
|
|
||||||
for i, c := range txt {
|
|
||||||
if c == 'S' {
|
|
||||||
garden.start[0] = len(garden.m) - 1
|
|
||||||
garden.start[1] = i
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
garden.Step(rounds)
|
|
||||||
return &result{
|
|
||||||
valuePT1: len(garden.steps[len(garden.steps)-1]),
|
|
||||||
}, nil
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
return &result{}, nil
|
||||||
type garden struct {
|
|
||||||
start aoc.Point[int]
|
|
||||||
m [][]rune
|
|
||||||
steps []aoc.Set[aoc.Point[int]]
|
|
||||||
}
|
|
||||||
|
|
||||||
func (g *garden) Neighbors(p aoc.Point[int]) []aoc.Point[int] {
|
|
||||||
var neighbors []aoc.Point[int]
|
|
||||||
for _, n := range []aoc.Point[int]{
|
|
||||||
{p[0] - 1, p[1]},
|
|
||||||
{p[0] + 1, p[1]},
|
|
||||||
{p[0], p[1] - 1},
|
|
||||||
{p[0], p[1] + 1},
|
|
||||||
} {
|
|
||||||
if n[0] >= 0 && n[0] < len(g.m) && n[1] >= 0 && n[1] < len(g.m[0]) && g.m[n[0]][n[1]] != '#' {
|
|
||||||
neighbors = append(neighbors, n)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return neighbors
|
|
||||||
}
|
|
||||||
|
|
||||||
func (g *garden) Step(n int) {
|
|
||||||
if len(g.steps) == 0 {
|
|
||||||
g.steps = append(g.steps, aoc.NewSet(g.start))
|
|
||||||
}
|
|
||||||
|
|
||||||
for step := range(n) {
|
|
||||||
g.steps = append(g.steps, aoc.NewSet[aoc.Point[int]]())
|
|
||||||
for p := range g.steps[step] {
|
|
||||||
for _, n := range g.Neighbors(p) {
|
|
||||||
g.steps[step+1].Add(n)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (g garden) String() string {
|
|
||||||
var b []rune
|
|
||||||
for i, line := range g.m {
|
|
||||||
if i == g.start[0] {
|
|
||||||
line[g.start[1]] = 'X'
|
|
||||||
}
|
|
||||||
|
|
||||||
if steps := len(g.steps) - 1; steps > 0 {
|
|
||||||
for p := range g.steps[len(g.steps)-1] {
|
|
||||||
if p[0] == i {
|
|
||||||
line[p[1]] = 'O'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
b = append(b, line...)
|
|
||||||
b = append(b, '\n')
|
|
||||||
}
|
|
||||||
return string(b)
|
|
||||||
}
|
}
|
|
@ -20,11 +20,11 @@ func TestExample(t *testing.T) {
|
||||||
is := is.New(t)
|
is := is.New(t)
|
||||||
scan := bufio.NewScanner(bytes.NewReader(example))
|
scan := bufio.NewScanner(bytes.NewReader(example))
|
||||||
|
|
||||||
result, err := runner(6)(scan)
|
result, err := run(scan)
|
||||||
is.NoErr(err)
|
is.NoErr(err)
|
||||||
|
|
||||||
t.Log(result)
|
t.Log(result)
|
||||||
is.Equal(result.valuePT1, 16)
|
is.Equal(result.valuePT1, 0)
|
||||||
is.Equal(result.valuePT2, 0)
|
is.Equal(result.valuePT2, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -32,10 +32,10 @@ func TestSolution(t *testing.T) {
|
||||||
is := is.New(t)
|
is := is.New(t)
|
||||||
scan := bufio.NewScanner(bytes.NewReader(input))
|
scan := bufio.NewScanner(bytes.NewReader(input))
|
||||||
|
|
||||||
result, err := runner(64)(scan)
|
result, err := run(scan)
|
||||||
is.NoErr(err)
|
is.NoErr(err)
|
||||||
|
|
||||||
t.Log(result)
|
t.Log(result)
|
||||||
is.Equal(result.valuePT1, 3709)
|
is.Equal(result.valuePT1, 0)
|
||||||
is.Equal(result.valuePT2, 0)
|
is.Equal(result.valuePT2, 0)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +0,0 @@
|
||||||
jqt: rhn xhk nvd
|
|
||||||
rsh: frs pzl lsr
|
|
||||||
xhk: hfx
|
|
||||||
cmg: qnr nvd lhk bvb
|
|
||||||
rhn: xhk bvb hfx
|
|
||||||
bvb: xhk hfx
|
|
||||||
pzl: lsr hfx nvd
|
|
||||||
qnr: nvd
|
|
||||||
ntq: jqt hfx bvb xhk
|
|
||||||
nvd: lhk
|
|
||||||
lsr: lhk
|
|
||||||
rzs: qnr cmg lsr rsh
|
|
||||||
frs: qnr lhk lsr
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,63 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bufio"
|
|
||||||
_ "embed"
|
|
||||||
"fmt"
|
|
||||||
"iter"
|
|
||||||
"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 int
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r result) String() string { return fmt.Sprintf("%#v", r) }
|
|
||||||
|
|
||||||
func run(scan *bufio.Scanner) (*result, error) {
|
|
||||||
g := aoc.Graph[string, int]()
|
|
||||||
var root string
|
|
||||||
|
|
||||||
for scan.Scan() {
|
|
||||||
line := scan.Text()
|
|
||||||
v, lis, ok := strings.Cut(line, ": ")
|
|
||||||
if !ok {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if root == "" {
|
|
||||||
root = v
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, l := range strings.Split(lis, " ") {
|
|
||||||
g.AddEdge(v, l, 1)
|
|
||||||
g.AddEdge(l, v, 1)
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for i, v := range enumerate(g.BFS(root)) {
|
|
||||||
fmt.Println(i, v)
|
|
||||||
}
|
|
||||||
|
|
||||||
return &result{}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func enumerate[T any](vs iter.Seq[T]) iter.Seq2[int, T] {
|
|
||||||
i := 0
|
|
||||||
return func(yield func(int, T) bool) {
|
|
||||||
for v := range vs {
|
|
||||||
if !yield(i, v) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
i++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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, 50)
|
|
||||||
is.Equal(result.valuePT2, 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
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, 0)
|
|
||||||
is.Equal(result.valuePT2, 0)
|
|
||||||
}
|
|
24
aoc_test.go
24
aoc_test.go
|
@ -9,6 +9,7 @@ import (
|
||||||
aoc "go.sour.is/advent-of-code"
|
aoc "go.sour.is/advent-of-code"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
func TestList(t *testing.T) {
|
func TestList(t *testing.T) {
|
||||||
is := is.New(t)
|
is := is.New(t)
|
||||||
|
|
||||||
|
@ -55,6 +56,7 @@ func TestPriorityQueue(t *testing.T) {
|
||||||
is.True(v == nil)
|
is.True(v == nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func ExamplePriorityQueue() {
|
func ExamplePriorityQueue() {
|
||||||
type memo struct {
|
type memo struct {
|
||||||
pt int
|
pt int
|
||||||
|
@ -72,7 +74,7 @@ func ExamplePriorityQueue() {
|
||||||
}
|
}
|
||||||
|
|
||||||
pq := aoc.PriorityQueue(less)
|
pq := aoc.PriorityQueue(less)
|
||||||
visited := aoc.NewSet([]int{}...)
|
visited := aoc.Set([]int{}...)
|
||||||
dist := aoc.DefaultMap[int](int(^uint(0) >> 1))
|
dist := aoc.DefaultMap[int](int(^uint(0) >> 1))
|
||||||
|
|
||||||
dist.Set(0, 0)
|
dist.Set(0, 0)
|
||||||
|
@ -115,7 +117,25 @@ func ExamplePriorityQueue() {
|
||||||
// point 5 is 22 steps away.
|
// point 5 is 22 steps away.
|
||||||
// point 6 is 19 steps away.
|
// point 6 is 19 steps away.
|
||||||
}
|
}
|
||||||
|
func TestGraph(t *testing.T) {
|
||||||
|
is := is.New(t)
|
||||||
|
|
||||||
|
var adjacencyList = map[int][]int{
|
||||||
|
2: {3, 5, 1},
|
||||||
|
1: {2, 4},
|
||||||
|
3: {6, 2},
|
||||||
|
4: {1, 5, 7},
|
||||||
|
5: {2, 6, 8, 4},
|
||||||
|
6: {3, 0, 9, 5},
|
||||||
|
7: {4, 8},
|
||||||
|
8: {5, 9, 7},
|
||||||
|
9: {6, 0, 8},
|
||||||
|
}
|
||||||
|
|
||||||
|
g := aoc.Graph(aoc.WithAdjacencyList[int, int](adjacencyList))
|
||||||
|
is.Equal(g.Neighbors(1), []int{2, 4})
|
||||||
|
is.Equal(map[int][]int(g.AdjacencyList()), adjacencyList)
|
||||||
|
}
|
||||||
|
|
||||||
func ExampleFibHeap() {
|
func ExampleFibHeap() {
|
||||||
type memo struct {
|
type memo struct {
|
||||||
|
@ -134,7 +154,7 @@ func ExampleFibHeap() {
|
||||||
}
|
}
|
||||||
|
|
||||||
pq := aoc.FibHeap(less)
|
pq := aoc.FibHeap(less)
|
||||||
visited := aoc.NewSet([]int{}...)
|
visited := aoc.Set([]int{}...)
|
||||||
dist := aoc.DefaultMap[int](int(^uint(0) >> 1))
|
dist := aoc.DefaultMap[int](int(^uint(0) >> 1))
|
||||||
|
|
||||||
dist.Set(0, 0)
|
dist.Set(0, 0)
|
||||||
|
|
85
grids.go
85
grids.go
|
@ -3,7 +3,6 @@ package aoc
|
||||||
import (
|
import (
|
||||||
"cmp"
|
"cmp"
|
||||||
"fmt"
|
"fmt"
|
||||||
"iter"
|
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
@ -157,10 +156,10 @@ func CompressMap[C number, N comparable](p pather[C, N], start N) pather[C, N] {
|
||||||
return &cmap[C, N]{base: p, neighbors: visited}
|
return &cmap[C, N]{base: p, neighbors: visited}
|
||||||
}
|
}
|
||||||
|
|
||||||
type adjacencyList[V comparable] map[V][]V
|
type adjacencyList[V any, C comparable] map[C][]V
|
||||||
type graph[V comparable, W cmp.Ordered] map[V]*vertex[V, W]
|
type graph[V any, W cmp.Ordered, C comparable] map[C]*vertex[V, W]
|
||||||
type graphOption[V comparable, W cmp.Ordered] func(g *graph[V, W])
|
type graphOption[V any, W cmp.Ordered, C comparable] func(g *graph[V, W, C])
|
||||||
type vertex[V comparable, W cmp.Ordered] struct {
|
type vertex[V any, W cmp.Ordered] struct {
|
||||||
Value V
|
Value V
|
||||||
Edges edges[V, W]
|
Edges edges[V, W]
|
||||||
}
|
}
|
||||||
|
@ -174,48 +173,48 @@ func (v *vertex[V, W]) Neighbors() []V {
|
||||||
return nbs
|
return nbs
|
||||||
}
|
}
|
||||||
|
|
||||||
type edge[V comparable, W cmp.Ordered] struct {
|
type edge[V any, W cmp.Ordered] struct {
|
||||||
Vertex *vertex[V, W]
|
Vertex *vertex[V, W]
|
||||||
Weight W
|
Weight W
|
||||||
}
|
}
|
||||||
type edges[V comparable, W cmp.Ordered] []edge[V, 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]) 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]) 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 (e edges[V, W]) Swap(i, j int) { e[i], e[j] = e[j], e[i] }
|
||||||
|
|
||||||
func Graph[V comparable, W cmp.Ordered](opts ...graphOption[V, W]) *graph[V, W] {
|
func Graph[V any, W cmp.Ordered, C comparable](opts ...graphOption[V, W, C]) *graph[V, W, C] {
|
||||||
g := make(graph[V, W])
|
g := make(graph[V, W, C])
|
||||||
for _, opt := range opts {
|
for _, opt := range opts {
|
||||||
opt(&g)
|
opt(&g)
|
||||||
}
|
}
|
||||||
return &g
|
return &g
|
||||||
}
|
}
|
||||||
func (g *graph[V, W]) AddVertex(id V, value V) {
|
func (g *graph[V, W, C]) AddVertex(id C, value V) {
|
||||||
(*g)[id] = &vertex[V, W]{Value: value}
|
(*g)[id] = &vertex[V, W]{Value: value}
|
||||||
}
|
}
|
||||||
func (g *graph[V, W]) AddEdge(from, to V, w W) {
|
func (g *graph[V, W, C]) AddEdge(from, to C, w W) {
|
||||||
if g == nil {
|
if g == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if _, ok := (*g)[from]; !ok {
|
if _, ok := (*g)[from]; !ok {
|
||||||
g.AddVertex(from, from)
|
return
|
||||||
}
|
}
|
||||||
if _, ok := (*g)[to]; !ok {
|
if _, ok := (*g)[to]; !ok {
|
||||||
g.AddVertex(to, to)
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
(*g)[from].Edges = append((*g)[from].Edges, edge[V, W]{(*g)[to], w})
|
(*g)[from].Edges = append((*g)[from].Edges, edge[V, W]{(*g)[to], w})
|
||||||
}
|
}
|
||||||
func (g *graph[V, W]) Neighbors(v V) []V {
|
func (g *graph[V, W, C]) Neighbors(v C) []V {
|
||||||
if g == nil {
|
if g == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return (*g)[v].Neighbors()
|
return (*g)[v].Neighbors()
|
||||||
}
|
}
|
||||||
func (g *graph[V, W]) AdjacencyList() adjacencyList[V] {
|
func (g *graph[V, W, C]) AdjacencyList() adjacencyList[V, C] {
|
||||||
m := make(map[V][]V)
|
m := make(map[C][]V)
|
||||||
for id, v := range *g {
|
for id, v := range *g {
|
||||||
if len(v.Edges) == 0 {
|
if len(v.Edges) == 0 {
|
||||||
continue
|
continue
|
||||||
|
@ -225,9 +224,9 @@ func (g *graph[V, W]) AdjacencyList() adjacencyList[V] {
|
||||||
return m
|
return m
|
||||||
}
|
}
|
||||||
|
|
||||||
func WithAdjacencyList[W cmp.Ordered, V comparable](list adjacencyList[V]) graphOption[V, W] {
|
func WithAdjacencyList[W cmp.Ordered, C comparable](list adjacencyList[C, C]) graphOption[C, W, C] {
|
||||||
var zeroW W
|
var zeroW W
|
||||||
return func(g *graph[V, W]) {
|
return func(g *graph[C, W, C]) {
|
||||||
for vertex, edges := range list {
|
for vertex, edges := range list {
|
||||||
if _, ok := (*g)[vertex]; !ok {
|
if _, ok := (*g)[vertex]; !ok {
|
||||||
g.AddVertex(vertex, vertex)
|
g.AddVertex(vertex, vertex)
|
||||||
|
@ -245,53 +244,3 @@ func WithAdjacencyList[W cmp.Ordered, V comparable](list adjacencyList[V]) graph
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *graph[V, W]) BFS(start V) iter.Seq[V] {
|
|
||||||
visited := make(map[V]bool)
|
|
||||||
stack := NewStack(start)
|
|
||||||
|
|
||||||
return func(yield func(V) bool) {
|
|
||||||
for !stack.IsEmpty() {
|
|
||||||
current := stack.Pull()
|
|
||||||
if visited[current] {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
visited[current] = true
|
|
||||||
if !yield(current) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
neighbors := g.Neighbors(current)
|
|
||||||
for _, n := range neighbors {
|
|
||||||
if !visited[n] {
|
|
||||||
stack.Push(n)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// DFS returns a sequence of vertices in depth-first order, starting at the
|
|
||||||
// given vertex.
|
|
||||||
func (g *graph[V, W]) DFS(start V) iter.Seq[V] {
|
|
||||||
visited := make(map[V]bool)
|
|
||||||
stack := NewStack(start)
|
|
||||||
|
|
||||||
return func(yield func(V) bool) {
|
|
||||||
for !stack.IsEmpty() {
|
|
||||||
current := stack.Pop()
|
|
||||||
if visited[current] {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
visited[current] = true
|
|
||||||
if !yield(current) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
for _, n := range Reverse(g.Neighbors(current)) {
|
|
||||||
if !visited[n] {
|
|
||||||
stack.Push(n)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,75 +0,0 @@
|
||||||
package aoc_test
|
|
||||||
|
|
||||||
import (
|
|
||||||
"iter"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/matryer/is"
|
|
||||||
aoc "go.sour.is/advent-of-code"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestGraph(t *testing.T) {
|
|
||||||
is := is.New(t)
|
|
||||||
|
|
||||||
var adjacencyList = map[int][]int{
|
|
||||||
2: {3, 5, 1},
|
|
||||||
1: {2, 4},
|
|
||||||
3: {6, 2},
|
|
||||||
4: {1, 5, 7},
|
|
||||||
5: {2, 6, 8, 4},
|
|
||||||
6: {3, 0, 9, 5},
|
|
||||||
7: {4, 8},
|
|
||||||
8: {5, 9, 7},
|
|
||||||
9: {6, 0, 8},
|
|
||||||
}
|
|
||||||
|
|
||||||
g := aoc.Graph(aoc.WithAdjacencyList[int](adjacencyList))
|
|
||||||
is.Equal(g.Neighbors(1), []int{2, 4})
|
|
||||||
is.Equal(map[int][]int(g.AdjacencyList()), adjacencyList)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestGraphDFS(t *testing.T) {
|
|
||||||
is := is.New(t)
|
|
||||||
|
|
||||||
var adjacencyList = map[int][]int{
|
|
||||||
2: {3, 5, 1},
|
|
||||||
1: {2, 4},
|
|
||||||
3: {6, 2},
|
|
||||||
4: {1, 5, 7},
|
|
||||||
5: {2, 6, 8, 4},
|
|
||||||
6: {3, 0, 9, 5},
|
|
||||||
7: {4, 8},
|
|
||||||
8: {5, 9, 7},
|
|
||||||
9: {6, 0, 8},
|
|
||||||
}
|
|
||||||
|
|
||||||
g := aoc.Graph(aoc.WithAdjacencyList[int](adjacencyList))
|
|
||||||
is.Equal(toList(g.DFS(6)), []int{6, 3, 2, 5, 8, 9, 0, 7, 4, 1})
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestGraphBFS(t *testing.T) {
|
|
||||||
is := is.New(t)
|
|
||||||
|
|
||||||
var adjacencyList = map[int][]int{
|
|
||||||
2: {3, 5, 1},
|
|
||||||
1: {2, 4},
|
|
||||||
3: {6, 2},
|
|
||||||
4: {1, 5, 7},
|
|
||||||
5: {2, 6, 8, 4},
|
|
||||||
6: {3, 0, 9, 5},
|
|
||||||
7: {4, 8},
|
|
||||||
8: {5, 9, 7},
|
|
||||||
9: {6, 0, 8},
|
|
||||||
}
|
|
||||||
|
|
||||||
g := aoc.Graph(aoc.WithAdjacencyList[int](adjacencyList))
|
|
||||||
is.Equal(toList(g.BFS(6)), []int{6, 3, 0, 9, 5, 2, 8, 4, 1, 7})
|
|
||||||
}
|
|
||||||
|
|
||||||
func toList[T any](seq iter.Seq[T]) []T {
|
|
||||||
var list []T
|
|
||||||
for v := range seq {
|
|
||||||
list = append(list, v)
|
|
||||||
}
|
|
||||||
return list
|
|
||||||
}
|
|
|
@ -42,16 +42,3 @@ func TestTranspose(t *testing.T) {
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestPairwise(t *testing.T) {
|
|
||||||
is := is.New(t)
|
|
||||||
|
|
||||||
is.Equal(
|
|
||||||
aoc.Pairwise([]int{1, 2, 3, 4}),
|
|
||||||
[][2]int{
|
|
||||||
{1, 2},
|
|
||||||
{2, 3},
|
|
||||||
{3, 4},
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
18
math_test.go
18
math_test.go
|
@ -31,21 +31,3 @@ func TestABS(t *testing.T) {
|
||||||
is.Equal(aoc.ABS(0), 0)
|
is.Equal(aoc.ABS(0), 0)
|
||||||
is.Equal(aoc.ABS(-1), 1)
|
is.Equal(aoc.ABS(-1), 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMin(t *testing.T) {
|
|
||||||
is := is.New(t)
|
|
||||||
|
|
||||||
is.Equal(aoc.Min(10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10), 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestMax(t *testing.T) {
|
|
||||||
is := is.New(t)
|
|
||||||
|
|
||||||
is.Equal(aoc.Max(1, 10, 2, 3, 4, 5, 6, 7, 8, 9, 1), 10)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestSum(t *testing.T) {
|
|
||||||
is := is.New(t)
|
|
||||||
|
|
||||||
is.Equal(aoc.Sum(1, 2, 3, 4, 5, 6, 7, 8, 9, 10), 55)
|
|
||||||
}
|
|
12
set.go
12
set.go
|
@ -2,22 +2,22 @@ package aoc
|
||||||
|
|
||||||
import "golang.org/x/exp/maps"
|
import "golang.org/x/exp/maps"
|
||||||
|
|
||||||
type Set[T comparable] map[T]struct{}
|
type set[T comparable] map[T]struct{}
|
||||||
|
|
||||||
func NewSet[T comparable](arr ...T) Set[T] {
|
func Set[T comparable](arr ...T) set[T] {
|
||||||
m := make(Set[T], len(arr))
|
m := make(set[T], len(arr))
|
||||||
for _, a := range arr {
|
for _, a := range arr {
|
||||||
m[a] = struct{}{}
|
m[a] = struct{}{}
|
||||||
}
|
}
|
||||||
return m
|
return m
|
||||||
}
|
}
|
||||||
func (m *Set[T]) Add(a T) {
|
func (m *set[T]) Add(a T) {
|
||||||
(*m)[a] = struct{}{}
|
(*m)[a] = struct{}{}
|
||||||
}
|
}
|
||||||
func (m *Set[T]) Items() []T {
|
func (m *set[T]) Items() []T {
|
||||||
return maps.Keys(*m)
|
return maps.Keys(*m)
|
||||||
}
|
}
|
||||||
func (m *Set[T]) Has(a T) bool {
|
func (m *set[T]) Has(a T) bool {
|
||||||
var ok bool
|
var ok bool
|
||||||
_, ok = (*m)[a]
|
_, ok = (*m)[a]
|
||||||
return ok
|
return ok
|
||||||
|
|
|
@ -11,7 +11,7 @@ import (
|
||||||
func TestSet(t *testing.T) {
|
func TestSet(t *testing.T) {
|
||||||
is := is.New(t)
|
is := is.New(t)
|
||||||
|
|
||||||
s := aoc.NewSet(1, 2, 3)
|
s := aoc.Set(1, 2, 3)
|
||||||
is.True(!s.Has(0))
|
is.True(!s.Has(0))
|
||||||
is.True(s.Has(1))
|
is.True(s.Has(1))
|
||||||
is.True(s.Has(2))
|
is.True(s.Has(2))
|
||||||
|
@ -24,6 +24,4 @@ func TestSet(t *testing.T) {
|
||||||
items := s.Items()
|
items := s.Items()
|
||||||
sort.Ints(items)
|
sort.Ints(items)
|
||||||
is.Equal(items, []int{1, 2, 3, 4})
|
is.Equal(items, []int{1, 2, 3, 4})
|
||||||
is.True(aoc.In(4, items...))
|
|
||||||
is.True(!aoc.In(99, items...))
|
|
||||||
}
|
}
|
||||||
|
|
64
stack.go
64
stack.go
|
@ -1,64 +0,0 @@
|
||||||
package aoc
|
|
||||||
|
|
||||||
type stack[T any] []T
|
|
||||||
|
|
||||||
func NewStack[T any](items ...T) *stack[T] {
|
|
||||||
s := make(stack[T], len(items))
|
|
||||||
copy(s, items)
|
|
||||||
return &s
|
|
||||||
}
|
|
||||||
|
|
||||||
// Push adds an element to the top of the stack.
|
|
||||||
func (s *stack[T]) Push(v T) {
|
|
||||||
*s = append(*s, v)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Pop removes the top element from the stack and returns it.
|
|
||||||
// If the stack is empty, it panics.
|
|
||||||
func (s *stack[T]) Pop() T {
|
|
||||||
if s.IsEmpty() {
|
|
||||||
var zero T
|
|
||||||
return zero
|
|
||||||
}
|
|
||||||
|
|
||||||
v := (*s)[len(*s)-1]
|
|
||||||
*s = (*s)[:len(*s)-1]
|
|
||||||
return v
|
|
||||||
}
|
|
||||||
|
|
||||||
// Peek returns the top element from the stack without removing it.
|
|
||||||
// If the stack is empty, it panics.
|
|
||||||
func (s *stack[T]) Peek() T {
|
|
||||||
if s.IsEmpty() {
|
|
||||||
var zero T
|
|
||||||
return zero
|
|
||||||
}
|
|
||||||
|
|
||||||
return (*s)[len(*s)-1]
|
|
||||||
}
|
|
||||||
|
|
||||||
// Len returns the number of elements in the stack.
|
|
||||||
func (s *stack[T]) Len() int {
|
|
||||||
return len(*s)
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsEmpty returns true if the stack is empty and false otherwise.
|
|
||||||
func (s *stack[T]) IsEmpty() bool {
|
|
||||||
return s == nil || len(*s) == 0
|
|
||||||
}
|
|
||||||
|
|
||||||
// Clear removes all elements from the stack, returning it to its initial state.
|
|
||||||
func (s *stack[T]) Clear() {
|
|
||||||
*s = (*s)[:0]
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *stack[T]) Pull() T {
|
|
||||||
if s.IsEmpty() {
|
|
||||||
var zero T
|
|
||||||
return zero
|
|
||||||
}
|
|
||||||
v := (*s)[0]
|
|
||||||
*s = (*s)[1:]
|
|
||||||
return v
|
|
||||||
}
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user