chore(aos): add compress graph
This commit is contained in:
parent
328a0f3eb3
commit
951c2c298a
97
aoc_test.go
97
aoc_test.go
|
@ -9,66 +9,6 @@ import (
|
||||||
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)
|
||||||
|
@ -116,23 +56,6 @@ func TestPriorityQueue(t *testing.T) {
|
||||||
is.True(v == nil)
|
is.True(v == nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSet(t *testing.T) {
|
|
||||||
is := is.New(t)
|
|
||||||
|
|
||||||
s := aoc.Set(1, 2, 3)
|
|
||||||
is.True(!s.Has(0))
|
|
||||||
is.True(s.Has(1))
|
|
||||||
is.True(s.Has(2))
|
|
||||||
is.True(s.Has(3))
|
|
||||||
is.True(!s.Has(4))
|
|
||||||
|
|
||||||
s.Add(4)
|
|
||||||
is.True(s.Has(4))
|
|
||||||
|
|
||||||
items := s.Items()
|
|
||||||
sort.Ints(items)
|
|
||||||
is.Equal(items, []int{1, 2, 3, 4})
|
|
||||||
}
|
|
||||||
|
|
||||||
func ExamplePriorityQueue() {
|
func ExamplePriorityQueue() {
|
||||||
type memo struct {
|
type memo struct {
|
||||||
|
@ -194,26 +117,6 @@ 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 TestStack(t *testing.T) {
|
|
||||||
is := is.New(t)
|
|
||||||
|
|
||||||
s := aoc.Stack(1, 2, 3, 4)
|
|
||||||
is.True(!s.IsEmpty())
|
|
||||||
is.Equal(s.Pop(), 4)
|
|
||||||
is.Equal(s.Pop(), 3)
|
|
||||||
is.Equal(s.Pop(), 2)
|
|
||||||
is.Equal(s.Pop(), 1)
|
|
||||||
is.True(s.IsEmpty())
|
|
||||||
s.Push(4, 3, 2, 1)
|
|
||||||
is.True(!s.IsEmpty())
|
|
||||||
is.Equal(s.Pop(), 1)
|
|
||||||
is.Equal(s.Pop(), 2)
|
|
||||||
is.Equal(s.Pop(), 3)
|
|
||||||
is.Equal(s.Pop(), 4)
|
|
||||||
is.True(s.IsEmpty())
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestGraph(t *testing.T) {
|
func TestGraph(t *testing.T) {
|
||||||
is := is.New(t)
|
is := is.New(t)
|
||||||
|
|
||||||
|
|
78
grids.go
78
grids.go
|
@ -3,6 +3,8 @@ package aoc
|
||||||
import (
|
import (
|
||||||
"cmp"
|
"cmp"
|
||||||
"sort"
|
"sort"
|
||||||
|
|
||||||
|
"golang.org/x/exp/maps"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Vector struct {
|
type Vector struct {
|
||||||
|
@ -82,6 +84,76 @@ func (m *Map[I, T]) Valid(p Point[I]) bool {
|
||||||
return p[0] >= 0 && p[0] < rows && p[1] >= 0 && p[1] < cols
|
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, v := range nbs {
|
||||||
|
fmt.Fprintln(b, " ", to, k)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 adjacencyList[V any, C comparable] map[C][]V
|
||||||
type graph[V any, W cmp.Ordered, C comparable] map[C]*vertex[V, W]
|
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 graphOption[V any, W cmp.Ordered, C comparable] func(g *graph[V, W, C])
|
||||||
|
@ -117,7 +189,7 @@ func Graph[V any, W cmp.Ordered, C comparable](opts ...graphOption[V, W, C]) *gr
|
||||||
return &g
|
return &g
|
||||||
}
|
}
|
||||||
func (g *graph[V, W, C]) AddVertex(id C, 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, C]) AddEdge(from, to C, w W) {
|
func (g *graph[V, W, C]) AddEdge(from, to C, w W) {
|
||||||
if g == nil {
|
if g == nil {
|
||||||
|
@ -130,7 +202,7 @@ func (g *graph[V, W, C]) AddEdge(from, to C, w W) {
|
||||||
return
|
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, C]) Neighbors(v C) []V {
|
func (g *graph[V, W, C]) Neighbors(v C) []V {
|
||||||
if g == nil {
|
if g == nil {
|
||||||
|
@ -170,5 +242,3 @@ func WithAdjacencyList[W cmp.Ordered, C comparable](list adjacencyList[C, C]) gr
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// func GraphFromMap()
|
|
||||||
|
|
47
itertools_test.go
Normal file
47
itertools_test.go
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
package aoc_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"sort"
|
||||||
|
"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},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
27
math_test.go
Normal file
27
math_test.go
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
package aoc_test
|
||||||
|
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
24
search.go
24
search.go
|
@ -42,30 +42,6 @@ func (pq *priorityQueue[T]) ExtractMin() *T {
|
||||||
return elem
|
return elem
|
||||||
}
|
}
|
||||||
|
|
||||||
type stack[T any] []T
|
|
||||||
|
|
||||||
func Stack[T any](a ...T) *stack[T] {
|
|
||||||
var s stack[T] = a
|
|
||||||
return &s
|
|
||||||
}
|
|
||||||
func (s *stack[T]) Push(a ...T) {
|
|
||||||
if s == nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
*s = append(*s, a...)
|
|
||||||
}
|
|
||||||
func (s *stack[T]) IsEmpty() bool {
|
|
||||||
return s == nil || len(*s) == 0
|
|
||||||
}
|
|
||||||
func (s *stack[T]) Pop() T {
|
|
||||||
var a T
|
|
||||||
if s.IsEmpty() {
|
|
||||||
return a
|
|
||||||
}
|
|
||||||
a, *s = (*s)[len(*s)-1], (*s)[:len(*s)-1]
|
|
||||||
return a
|
|
||||||
}
|
|
||||||
|
|
||||||
// ManhattanDistance the distance between two points measured along axes at right angles.
|
// ManhattanDistance the distance between two points measured along axes at right angles.
|
||||||
func ManhattanDistance[T integer](a, b Point[T]) T {
|
func ManhattanDistance[T integer](a, b Point[T]) T {
|
||||||
return ABS(a[0]-b[0]) + ABS(a[1]-b[1])
|
return ABS(a[0]-b[0]) + ABS(a[1]-b[1])
|
||||||
|
|
20
set_test.go
Normal file
20
set_test.go
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
package aoc_test
|
||||||
|
|
||||||
|
|
||||||
|
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})
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user