Compare commits
	
		
			2 Commits
		
	
	
		
			04bbac8559
			...
			0d652660f1
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 0d652660f1 | |||
| e046a6c06d | 
@ -10,7 +10,7 @@ import (
 | 
			
		||||
 | 
			
		||||
// var log = aoc.Log
 | 
			
		||||
 | 
			
		||||
func main() { aoc.MustResult(aoc.Runner(run)) }
 | 
			
		||||
func main() { aoc.MustResult(aoc.Runner(runner(64))) }
 | 
			
		||||
 | 
			
		||||
type result struct {
 | 
			
		||||
	valuePT1 int
 | 
			
		||||
@ -19,12 +19,81 @@ type result struct {
 | 
			
		||||
 | 
			
		||||
func (r result) String() string { return fmt.Sprintf("%#v", r) }
 | 
			
		||||
 | 
			
		||||
func run(scan *bufio.Scanner) (*result, error) {
 | 
			
		||||
func runner(rounds int) func(scan *bufio.Scanner) (*result, error) {
 | 
			
		||||
	return func(scan *bufio.Scanner) (*result, error) {
 | 
			
		||||
		var garden garden
 | 
			
		||||
 | 
			
		||||
	for scan.Scan() {
 | 
			
		||||
		_ = scan.Text()
 | 
			
		||||
		for scan.Scan() {
 | 
			
		||||
			txt := 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
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return &result{}, nil
 | 
			
		||||
	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)
 | 
			
		||||
	scan := bufio.NewScanner(bytes.NewReader(example))
 | 
			
		||||
 | 
			
		||||
	result, err := run(scan)
 | 
			
		||||
	result, err := runner(6)(scan)
 | 
			
		||||
	is.NoErr(err)
 | 
			
		||||
 | 
			
		||||
	t.Log(result)
 | 
			
		||||
	is.Equal(result.valuePT1, 0)
 | 
			
		||||
	is.Equal(result.valuePT1, 16)
 | 
			
		||||
	is.Equal(result.valuePT2, 0)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -32,10 +32,10 @@ func TestSolution(t *testing.T) {
 | 
			
		||||
	is := is.New(t)
 | 
			
		||||
	scan := bufio.NewScanner(bytes.NewReader(input))
 | 
			
		||||
 | 
			
		||||
	result, err := run(scan)
 | 
			
		||||
	result, err := runner(64)(scan)
 | 
			
		||||
	is.NoErr(err)
 | 
			
		||||
 | 
			
		||||
	t.Log(result)
 | 
			
		||||
	is.Equal(result.valuePT1, 0)
 | 
			
		||||
	is.Equal(result.valuePT1, 3709)
 | 
			
		||||
	is.Equal(result.valuePT2, 0)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										13
									
								
								aoc2023/day25/example.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								aoc2023/day25/example.txt
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,13 @@
 | 
			
		||||
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
 | 
			
		||||
							
								
								
									
										1261
									
								
								aoc2023/day25/input.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1261
									
								
								aoc2023/day25/input.txt
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										63
									
								
								aoc2023/day25/main.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								aoc2023/day25/main.go
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,63 @@
 | 
			
		||||
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++
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}	
 | 
			
		||||
							
								
								
									
										41
									
								
								aoc2023/day25/main_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								aoc2023/day25/main_test.go
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,41 @@
 | 
			
		||||
package main
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bufio"
 | 
			
		||||
	"bytes"
 | 
			
		||||
	"testing"
 | 
			
		||||
 | 
			
		||||
	_ "embed"
 | 
			
		||||
 | 
			
		||||
	"github.com/matryer/is"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
//go:embed example.txt
 | 
			
		||||
var example []byte
 | 
			
		||||
 | 
			
		||||
//go:embed input.txt
 | 
			
		||||
var input []byte
 | 
			
		||||
 | 
			
		||||
func TestExample(t *testing.T) {
 | 
			
		||||
	is := is.New(t)
 | 
			
		||||
	scan := bufio.NewScanner(bytes.NewReader(example))
 | 
			
		||||
 | 
			
		||||
	result, err := run(scan)
 | 
			
		||||
	is.NoErr(err)
 | 
			
		||||
 | 
			
		||||
	t.Log(result)
 | 
			
		||||
	is.Equal(result.valuePT1, 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,7 +9,6 @@ import (
 | 
			
		||||
	aoc "go.sour.is/advent-of-code"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
func TestList(t *testing.T) {
 | 
			
		||||
	is := is.New(t)
 | 
			
		||||
 | 
			
		||||
@ -56,7 +55,6 @@ func TestPriorityQueue(t *testing.T) {
 | 
			
		||||
	is.True(v == nil)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
func ExamplePriorityQueue() {
 | 
			
		||||
	type memo struct {
 | 
			
		||||
		pt    int
 | 
			
		||||
@ -74,7 +72,7 @@ func ExamplePriorityQueue() {
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	pq := aoc.PriorityQueue(less)
 | 
			
		||||
	visited := aoc.Set([]int{}...)
 | 
			
		||||
	visited := aoc.NewSet([]int{}...)
 | 
			
		||||
	dist := aoc.DefaultMap[int](int(^uint(0) >> 1))
 | 
			
		||||
 | 
			
		||||
	dist.Set(0, 0)
 | 
			
		||||
@ -117,25 +115,7 @@ func ExamplePriorityQueue() {
 | 
			
		||||
	// point 5 is 22 steps away.
 | 
			
		||||
	// point 6 is 19 steps away.
 | 
			
		||||
}
 | 
			
		||||
func TestGraph(t *testing.T) {
 | 
			
		||||
	is := is.New(t)
 | 
			
		||||
 | 
			
		||||
	var adjacencyList = map[int][]int{
 | 
			
		||||
		2: {3, 5, 1},
 | 
			
		||||
		1: {2, 4},
 | 
			
		||||
		3: {6, 2},
 | 
			
		||||
		4: {1, 5, 7},
 | 
			
		||||
		5: {2, 6, 8, 4},
 | 
			
		||||
		6: {3, 0, 9, 5},
 | 
			
		||||
		7: {4, 8},
 | 
			
		||||
		8: {5, 9, 7},
 | 
			
		||||
		9: {6, 0, 8},
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	g := aoc.Graph(aoc.WithAdjacencyList[int, int](adjacencyList))
 | 
			
		||||
	is.Equal(g.Neighbors(1), []int{2, 4})
 | 
			
		||||
	is.Equal(map[int][]int(g.AdjacencyList()), adjacencyList)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func ExampleFibHeap() {
 | 
			
		||||
	type memo struct {
 | 
			
		||||
@ -154,7 +134,7 @@ func ExampleFibHeap() {
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	pq := aoc.FibHeap(less)
 | 
			
		||||
	visited := aoc.Set([]int{}...)
 | 
			
		||||
	visited := aoc.NewSet([]int{}...)
 | 
			
		||||
	dist := aoc.DefaultMap[int](int(^uint(0) >> 1))
 | 
			
		||||
 | 
			
		||||
	dist.Set(0, 0)
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										85
									
								
								grids.go
									
									
									
									
									
								
							
							
						
						
									
										85
									
								
								grids.go
									
									
									
									
									
								
							@ -3,6 +3,7 @@ package aoc
 | 
			
		||||
import (
 | 
			
		||||
	"cmp"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"iter"
 | 
			
		||||
	"sort"
 | 
			
		||||
	"strings"
 | 
			
		||||
 | 
			
		||||
@ -156,10 +157,10 @@ func CompressMap[C number, N comparable](p pather[C, N], start N) pather[C, N] {
 | 
			
		||||
	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 {
 | 
			
		||||
type adjacencyList[V comparable] map[V][]V
 | 
			
		||||
type graph[V comparable, W cmp.Ordered] map[V]*vertex[V, W]
 | 
			
		||||
type graphOption[V comparable, W cmp.Ordered] func(g *graph[V, W])
 | 
			
		||||
type vertex[V comparable, W cmp.Ordered] struct {
 | 
			
		||||
	Value V
 | 
			
		||||
	Edges edges[V, W]
 | 
			
		||||
}
 | 
			
		||||
@ -173,48 +174,48 @@ func (v *vertex[V, W]) Neighbors() []V {
 | 
			
		||||
	return nbs
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type edge[V any, W cmp.Ordered] struct {
 | 
			
		||||
type edge[V comparable, W cmp.Ordered] struct {
 | 
			
		||||
	Vertex *vertex[V, W]
 | 
			
		||||
	Weight W
 | 
			
		||||
}
 | 
			
		||||
type edges[V any, W cmp.Ordered] []edge[V, W]
 | 
			
		||||
type edges[V comparable, 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])
 | 
			
		||||
func Graph[V comparable, W cmp.Ordered](opts ...graphOption[V, W]) *graph[V, W] {
 | 
			
		||||
	g := make(graph[V, W])
 | 
			
		||||
	for _, opt := range opts {
 | 
			
		||||
		opt(&g)
 | 
			
		||||
	}
 | 
			
		||||
	return &g
 | 
			
		||||
}
 | 
			
		||||
func (g *graph[V, W, C]) AddVertex(id C, value V) {
 | 
			
		||||
func (g *graph[V, W]) AddVertex(id V, value V) {
 | 
			
		||||
	(*g)[id] = &vertex[V, W]{Value: value}
 | 
			
		||||
}
 | 
			
		||||
func (g *graph[V, W, C]) AddEdge(from, to C, w W) {
 | 
			
		||||
func (g *graph[V, W]) AddEdge(from, to V, w W) {
 | 
			
		||||
	if g == nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	if _, ok := (*g)[from]; !ok {
 | 
			
		||||
		return
 | 
			
		||||
		g.AddVertex(from, from)
 | 
			
		||||
	}
 | 
			
		||||
	if _, ok := (*g)[to]; !ok {
 | 
			
		||||
		return
 | 
			
		||||
		g.AddVertex(to, to)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	(*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]) Neighbors(v V) []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)
 | 
			
		||||
func (g *graph[V, W]) AdjacencyList() adjacencyList[V] {
 | 
			
		||||
	m := make(map[V][]V)
 | 
			
		||||
	for id, v := range *g {
 | 
			
		||||
		if len(v.Edges) == 0 {
 | 
			
		||||
			continue
 | 
			
		||||
@ -224,9 +225,9 @@ func (g *graph[V, W, C]) AdjacencyList() adjacencyList[V, C] {
 | 
			
		||||
	return m
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func WithAdjacencyList[W cmp.Ordered, C comparable](list adjacencyList[C, C]) graphOption[C, W, C] {
 | 
			
		||||
func WithAdjacencyList[W cmp.Ordered, V comparable](list adjacencyList[V]) graphOption[V, W] {
 | 
			
		||||
	var zeroW W
 | 
			
		||||
	return func(g *graph[C, W, C]) {
 | 
			
		||||
	return func(g *graph[V, W]) {
 | 
			
		||||
		for vertex, edges := range list {
 | 
			
		||||
			if _, ok := (*g)[vertex]; !ok {
 | 
			
		||||
				g.AddVertex(vertex, vertex)
 | 
			
		||||
@ -244,3 +245,53 @@ func WithAdjacencyList[W cmp.Ordered, C comparable](list adjacencyList[C, C]) gr
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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)
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										75
									
								
								grids_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										75
									
								
								grids_test.go
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,75 @@
 | 
			
		||||
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,3 +42,16 @@ 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,3 +31,21 @@ func TestABS(t *testing.T) {
 | 
			
		||||
	is.Equal(aoc.ABS(0), 0)
 | 
			
		||||
	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"
 | 
			
		||||
 | 
			
		||||
type set[T comparable] map[T]struct{}
 | 
			
		||||
type Set[T comparable] map[T]struct{}
 | 
			
		||||
 | 
			
		||||
func Set[T comparable](arr ...T) set[T] {
 | 
			
		||||
	m := make(set[T], len(arr))
 | 
			
		||||
func NewSet[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) {
 | 
			
		||||
func (m *Set[T]) Add(a T) {
 | 
			
		||||
	(*m)[a] = struct{}{}
 | 
			
		||||
}
 | 
			
		||||
func (m *set[T]) Items() []T {
 | 
			
		||||
func (m *Set[T]) Items() []T {
 | 
			
		||||
	return maps.Keys(*m)
 | 
			
		||||
}
 | 
			
		||||
func (m *set[T]) Has(a T) bool {
 | 
			
		||||
func (m *Set[T]) Has(a T) bool {
 | 
			
		||||
	var ok bool
 | 
			
		||||
	_, ok = (*m)[a]
 | 
			
		||||
	return ok
 | 
			
		||||
 | 
			
		||||
@ -11,7 +11,7 @@ import (
 | 
			
		||||
func TestSet(t *testing.T) {
 | 
			
		||||
	is := is.New(t)
 | 
			
		||||
 | 
			
		||||
	s := aoc.Set(1, 2, 3)
 | 
			
		||||
	s := aoc.NewSet(1, 2, 3)
 | 
			
		||||
	is.True(!s.Has(0))
 | 
			
		||||
	is.True(s.Has(1))
 | 
			
		||||
	is.True(s.Has(2))
 | 
			
		||||
@ -24,4 +24,6 @@ func TestSet(t *testing.T) {
 | 
			
		||||
	items := s.Items()
 | 
			
		||||
	sort.Ints(items)
 | 
			
		||||
	is.Equal(items, []int{1, 2, 3, 4})
 | 
			
		||||
	is.True(aoc.In(4, items...))
 | 
			
		||||
	is.True(!aoc.In(99, items...))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										64
									
								
								stack.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										64
									
								
								stack.go
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,64 @@
 | 
			
		||||
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…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user