Compare commits
9
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a5ebbe25d0
|
||
|
|
50af2114d4
|
||
|
|
f8fa61672f
|
||
|
|
951c2c298a
|
||
|
|
328a0f3eb3
|
||
|
|
7d7402f054
|
||
|
|
7585526634
|
||
|
|
924c8d74f3
|
||
|
|
22184ed9c7
|
No files matched your search
@@ -0,0 +1,6 @@
|
||||
-----BEGIN SSH SIGNATURE-----
|
||||
U1NIU0lHAAAAAQAAADMAAAALc3NoLWVkMjU1MTkAAAAgZ+OuJYdd3UiUbyBuO1RlsQR20a
|
||||
Qm5mKneuMxRjGo3zkAAAAEZmlsZQAAAAAAAAAGc2hhNTEyAAAAUwAAAAtzc2gtZWQyNTUx
|
||||
OQAAAED8T4C6WILXYZ1KxqDIlVhlrAEjr1Vc+tn8ypcVM3bN7iOexVvuUuvm90nr8eEwKU
|
||||
acrdDxmq2S+oysQbK+pMUE
|
||||
-----END SSH SIGNATURE-----
|
||||
+185
-102
@@ -9,66 +9,6 @@ import (
|
||||
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) {
|
||||
is := is.New(t)
|
||||
@@ -85,62 +25,44 @@ func TestPriorityQueue(t *testing.T) {
|
||||
is := is.New(t)
|
||||
|
||||
type elem [2]int
|
||||
less := func(a, b elem) bool {
|
||||
return a[0] < b[0]
|
||||
less := func(b, a *elem) bool {
|
||||
return (*a)[0] < (*b)[0]
|
||||
}
|
||||
|
||||
pq := aoc.PriorityQueue(less)
|
||||
|
||||
pq.Enqueue(elem{1, 4})
|
||||
pq.Enqueue(elem{3, 2})
|
||||
pq.Enqueue(elem{2, 3})
|
||||
pq.Enqueue(elem{4, 1})
|
||||
pq.Insert(&elem{1, 4})
|
||||
pq.Insert(&elem{3, 2})
|
||||
pq.Insert(&elem{2, 3})
|
||||
pq.Insert(&elem{4, 1})
|
||||
|
||||
v, ok := pq.Dequeue()
|
||||
is.True(ok)
|
||||
is.Equal(v, elem{4, 1})
|
||||
v := pq.ExtractMin()
|
||||
is.True(v != nil)
|
||||
is.Equal(v, &elem{4, 1})
|
||||
|
||||
v, ok = pq.Dequeue()
|
||||
is.True(ok)
|
||||
is.Equal(v, elem{3, 2})
|
||||
v = pq.ExtractMin()
|
||||
is.True(v != nil)
|
||||
is.Equal(v, &elem{3, 2})
|
||||
|
||||
v, ok = pq.Dequeue()
|
||||
is.True(ok)
|
||||
is.Equal(v, elem{2, 3})
|
||||
v = pq.ExtractMin()
|
||||
is.True(v != nil)
|
||||
is.Equal(v, &elem{2, 3})
|
||||
|
||||
v, ok = pq.Dequeue()
|
||||
is.True(ok)
|
||||
is.Equal(v, elem{1, 4})
|
||||
v = pq.ExtractMin()
|
||||
is.True(v != nil)
|
||||
is.Equal(v, &elem{1, 4})
|
||||
|
||||
v, ok = pq.Dequeue()
|
||||
is.True(!ok)
|
||||
is.Equal(v, elem{})
|
||||
v = pq.ExtractMin()
|
||||
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() {
|
||||
type memo struct {
|
||||
pt int
|
||||
score int
|
||||
}
|
||||
less := func(a, b memo) bool { return b.score < a.score }
|
||||
less := func(a, b *memo) bool { return a.score < b.score }
|
||||
|
||||
adj := map[int][][2]int{
|
||||
0: {{1, 2}, {2, 6}},
|
||||
@@ -156,10 +78,10 @@ func ExamplePriorityQueue() {
|
||||
dist := aoc.DefaultMap[int](int(^uint(0) >> 1))
|
||||
|
||||
dist.Set(0, 0)
|
||||
pq.Enqueue(memo{0, 0})
|
||||
pq.Insert(&memo{0, 0})
|
||||
|
||||
for !pq.IsEmpty() {
|
||||
m, _ := pq.Dequeue()
|
||||
m := pq.ExtractMin()
|
||||
|
||||
u := m.pt
|
||||
if visited.Has(u) {
|
||||
@@ -175,7 +97,7 @@ func ExamplePriorityQueue() {
|
||||
|
||||
if !visited.Has(v) && du+w < dv {
|
||||
dist.Set(v, du+w)
|
||||
pq.Enqueue(memo{v, du + w})
|
||||
pq.Insert(&memo{v, du + w})
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -195,3 +117,164 @@ 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 {
|
||||
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})
|
||||
}
|
||||
+61
-26
@@ -29,10 +29,10 @@ func run(scan *bufio.Scanner) (*result, error) {
|
||||
log("start day 17")
|
||||
|
||||
result := result{}
|
||||
result.valuePT1 = search(m, 1, 3)
|
||||
result.valuePT1 = search(m, 1, 3, seenFn)
|
||||
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
|
||||
@@ -90,6 +90,7 @@ type graph struct {
|
||||
m Map
|
||||
target Point
|
||||
reads int
|
||||
seenFn func(a position) position
|
||||
}
|
||||
|
||||
// Neighbors returns valid steps from given position. if at target returns none.
|
||||
@@ -118,6 +119,7 @@ func (g *graph) Neighbors(current position) []position {
|
||||
if forward := current.step(); current.steps < g.max && g.m.Valid(forward.loc) {
|
||||
nbs = append(nbs, forward)
|
||||
}
|
||||
|
||||
return nbs
|
||||
}
|
||||
|
||||
@@ -129,12 +131,13 @@ func (g *graph) Cost(a, b position) int16 {
|
||||
}
|
||||
|
||||
// Potential calculates distance to target
|
||||
func (g *graph) Potential(a, b position) int16 {
|
||||
return aoc.ManhattanDistance(a.loc, b.loc)
|
||||
}
|
||||
// func (g *graph) Potential(a position) int16 {
|
||||
// return aoc.ManhattanDistance(a.loc, g.target)
|
||||
// }
|
||||
|
||||
func (g *graph) Target(a position) bool {
|
||||
if a.loc == g.target && a.steps >= g.min {
|
||||
// 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
|
||||
@@ -142,47 +145,79 @@ func (g *graph) Target(a position) bool {
|
||||
|
||||
// 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 a.direction == U {
|
||||
// a.direction = D
|
||||
// }
|
||||
// if a.direction == L {
|
||||
// a.direction = R
|
||||
// }
|
||||
// a.steps = 0
|
||||
// return a
|
||||
// }
|
||||
func (g *graph) Seen(a position) position {
|
||||
if g.seenFn != nil {
|
||||
return g.seenFn(a)
|
||||
}
|
||||
return a
|
||||
}
|
||||
|
||||
func search(m Map, minSteps, maxSteps int8) int {
|
||||
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()
|
||||
start := Point{}
|
||||
target := Point{rows - 1, cols - 1}
|
||||
|
||||
g := graph{min: minSteps, max: maxSteps, m: m, target: target}
|
||||
cost, path := aoc.FindPath[int16, position](&g, position{loc: start}, position{loc: target})
|
||||
g := graph{min: minSteps, max: maxSteps, m: m, target: target, seenFn: seenFn}
|
||||
|
||||
log("total map reads = ", g.reads)
|
||||
printGraph(m, path)
|
||||
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 overlay
|
||||
func printGraph(m Map, path []position) {
|
||||
// printGraph with the path/cost overlay
|
||||
func printGraph(m Map, path []position, closed map[position]int16, seenFn func(a position) position) {
|
||||
pts := make(map[Point]position, len(path))
|
||||
for _, pt := range path {
|
||||
pts[pt.loc] = pt
|
||||
}
|
||||
|
||||
clpt := make(map[position]position, len(closed))
|
||||
for pt := range closed {
|
||||
clpt[position{loc: pt.loc, steps: pt.steps}] = pt
|
||||
}
|
||||
|
||||
for r, row := range m {
|
||||
// if r == 0 {
|
||||
// for c := range row {
|
||||
// if c == 0 {
|
||||
// fmt.Print(" ")
|
||||
// }
|
||||
// fmt.Printf("% 5d", c)
|
||||
// }
|
||||
// fmt.Println("")
|
||||
// }
|
||||
for c := range row {
|
||||
if _, ok := pts[Point{int16(r), int16(c)}]; ok {
|
||||
// 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("*")
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
fmt.Print(".")
|
||||
// fmt.Print(" ....")
|
||||
fmt.Print(" ")
|
||||
}
|
||||
fmt.Println("")
|
||||
}
|
||||
|
||||
+9
-9
@@ -28,14 +28,14 @@ func TestExample(t *testing.T) {
|
||||
is.Equal(result.valuePT2, 94)
|
||||
}
|
||||
|
||||
// func TestSolution(t *testing.T) {
|
||||
// is := is.New(t)
|
||||
// scan := bufio.NewScanner(bytes.NewReader(input))
|
||||
func TestSolution(t *testing.T) {
|
||||
is := is.New(t)
|
||||
scan := bufio.NewScanner(bytes.NewReader(input))
|
||||
|
||||
// result, err := run(scan)
|
||||
// is.NoErr(err)
|
||||
result, err := run(scan)
|
||||
is.NoErr(err)
|
||||
|
||||
// t.Log(result)
|
||||
// is.Equal(result.valuePT1, 843)
|
||||
// is.Equal(result.valuePT2, 1017)
|
||||
// }
|
||||
t.Log(result)
|
||||
is.Equal(result.valuePT1, 843)
|
||||
is.Equal(result.valuePT2, 1017)
|
||||
}
|
||||
+6
-6
@@ -186,8 +186,8 @@ func solveWorkflow(parts []part, workflows map[string][]rule) int {
|
||||
|
||||
func solveRanges(workflows map[string][]rule) uint {
|
||||
|
||||
pq := aoc.PriorityQueue(func(a, b queue) bool { return false })
|
||||
pq.Enqueue(queue{
|
||||
pq := aoc.PriorityQueue(func(a, b *queue) bool { return false })
|
||||
pq.Insert(&queue{
|
||||
"in",
|
||||
block{
|
||||
ranger{1, 4000},
|
||||
@@ -200,9 +200,9 @@ func solveRanges(workflows map[string][]rule) uint {
|
||||
// var rejected []block
|
||||
|
||||
for !pq.IsEmpty() {
|
||||
current, _ := pq.Dequeue()
|
||||
current := pq.ExtractMin()
|
||||
for _, rule := range workflows[current.name] {
|
||||
next := queue{name: rule.queue, block: current.block}
|
||||
next := &queue{name: rule.queue, block: current.block}
|
||||
|
||||
switch rule.match {
|
||||
case "x":
|
||||
@@ -223,14 +223,14 @@ func solveRanges(workflows map[string][]rule) uint {
|
||||
accepted = append(accepted, next.block)
|
||||
|
||||
default:
|
||||
pq.Enqueue(next)
|
||||
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))
|
||||
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
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
#.#####################
|
||||
#.......#########...###
|
||||
#######.#########.#.###
|
||||
###.....#.>.>.###.#.###
|
||||
###v#####.#v#.###.#.###
|
||||
###.>...#.#.#.....#...#
|
||||
###v###.#.#.#########.#
|
||||
###...#.#.#.......#...#
|
||||
#####.#.#.#######.#.###
|
||||
#.....#.#.#.......#...#
|
||||
#.#####.#.#.#########v#
|
||||
#.#...#...#...###...>.#
|
||||
#.#.#v#######v###.###v#
|
||||
#...#.>.#...>.>.#.###.#
|
||||
#####v#.#.###v#.#.###.#
|
||||
#.....#...#...#.#.#...#
|
||||
#.#########.###.#.#.###
|
||||
#...###...#...#...#.###
|
||||
###.###.#.###v#####v###
|
||||
#...#...#.#.>.>.#.>.###
|
||||
#.###.###.#.###.#.#v###
|
||||
#.....###...###...#...#
|
||||
#####################.#
|
||||
-141
@@ -1,141 +0,0 @@
|
||||
#.###########################################################################################################################################
|
||||
#.#...#.......#...#.....#...#...#######...###...#...#.......#...#...#...#...#...#...#...###...###...###...............#.....#...#######...###
|
||||
#.#.#.#.#####.#.#.#.###.#.#.#.#.#######.#.###.#.#.#.#.#####.#.#.#.#.#.#.#.#.#.#.#.#.#.#.###.#.###.#.###.#############.#.###.#.#.#######.#.###
|
||||
#.#.#.#.#.....#.#.#...#.#.#...#...#.....#...#.#.#.#.#.....#...#.#.#.#.#.#.#.#.#...#...#.....#.#...#...#.............#.#...#...#.......#.#...#
|
||||
#.#.#.#.#.#####.#.###.#.#.#######.#.#######.#.#.#.#.#####.#####.#.#.#.#.#.#.#.###############.#.#####.#############.#.###.###########.#.###.#
|
||||
#...#...#.....#.#.###.#.#.#.......#.....#...#.#.#.#.#.>.>.#.....#.#.#.#.#.#.#...#.............#.#.....#...#.......#.#.....#...........#.#...#
|
||||
#############.#.#v###.#.#.#.###########.#.###.#.#.#.#.#v###.#####.#.#.#.#.#.###.#.#############.#.#####.#.#.#####.#.#######.###########.#.###
|
||||
#...###...###...#.>.#.#.#.#.#...###.....#.....#.#.#...#...#.#...#.#.#.#.#.#.###.#.#####...###...#...#...#.#...#...#.....#...#...###...#.#.###
|
||||
#.#.###.#.#######v#.#.#.#.#.#.#.###.###########.#.#######.#.#.#.#.#.#.#.#.#.###.#.#####.#.###.#####.#.###.###.#.#######.#.###.#.###.#.#.#.###
|
||||
#.#.#...#.#.....#.#.#.#.#.#...#...#.........#...#.###.....#.#.#.#.#.#.#.#.#.>.>.#.......#.#...#.....#...#.#...#.#.......#...#.#.....#.#.#.###
|
||||
#.#.#.###.#.###.#.#.#.#.#.#######.#########.#.###.###.#####.#.#.#.#.#.#.#.###v###########.#.###.#######.#.#.###.#.#########.#.#######.#.#.###
|
||||
#.#.#...#.#...#.#.#.#.#.#...#.....#...#...#.#...#...#.....#.#.#.#.#.#.#...###.#...........#...#.....#...#.#...#.#.........#.#.#.......#.#.###
|
||||
#.#.###.#.###.#.#.#.#.#.###.#.#####.#.#.#.#.###.###.#####.#.#.#.#.#.#.#######.#.#############.#####.#.###.###.#.#########.#.#.#.#######.#.###
|
||||
#.#.....#.#...#.#.#.#.#.#...#.....#.#...#.#...#.#...#.....#...#...#.#.#.......#.#.....#.....#.#.....#...#.###.#.#...#.....#...#.#...###.#.###
|
||||
#.#######.#.###.#.#.#.#.#.#######.#.#####.###.#.#.###.#############.#.#.#######.#.###.#.###.#.#.#######.#.###.#.#.#.#.#########.#.#.###.#.###
|
||||
#.#...###...###.#.#...#.#...#.....#.#...#...#.#.#...#...........###...#.......#.#.#...#...#.#.#.#...###.#.###.#.#.#.#.....#.....#.#.#...#...#
|
||||
#.#.#.#########.#.#####.###.#.#####.#.#.###.#.#.###.###########.#############.#.#.#.#####.#.#.#.#.#.###.#.###.#.#.#.#####.#.#####.#.#.#####.#
|
||||
#.#.#.........#...#.....#...#.#...#...#...#...#.....#####.......#...###.......#.#.#.#.....#.#.#.#.#.#...#.>.>.#.#.#.#.....#...#...#...###...#
|
||||
#.#.#########.#####.#####.###.#.#.#######.###############.#######.#.###.#######.#.#.#.#####.#.#.#.#.#.#####v###.#.#.#.#######.#.#########.###
|
||||
#...#.......#.#...#...#...###.#.#.>.>...#...#...#...###...###...#.#...#.......#.#.#...###...#.#.#.#.#...#...###...#...###.....#.###.......###
|
||||
#####.#####.#.#.#.###.#.#####.#.###v###.###.#.#.#.#.###.#####.#.#.###.#######.#.#.#######.###.#.#.#.###.#.###############.#####.###.#########
|
||||
#...#.....#...#.#.###...#####...#...###.....#.#.#.#.#...#...#.#...#...#.......#.#.#.....#.....#.#.#.....#...#...........#.#...#...#...#.....#
|
||||
#.#.#####.#####.#.###############.###########.#.#.#.#.###.#.#.#####.###.#######.#.#.###.#######.#.#########.#.#########.#.#.#.###.###.#.###.#
|
||||
#.#.......#...#.#.#...#...###...#.....#.......#.#.#...#...#...#.....###.......#...#...#.#.....#.#...#...###...#.........#...#.#...###...#...#
|
||||
#.#########.#.#.#.#.#.#.#.###.#.#####.#.#######.#.#####.#######.#############.#######.#.#.###.#.###.#.#.#######.#############.#.#########.###
|
||||
#.........#.#.#.#.#.#.#.#...#.#.......#.#.......#.......###.....#...#.........###...#.#.#.#...#.....#.#.#...###.............#...#...#...#...#
|
||||
#########.#.#.#.#.#.#.#.###.#.#########.#.#################.#####.#.#.###########.#.#.#.#.#.#########.#.#.#.###############.#####.#.#.#.###.#
|
||||
#.........#.#.#.#.#.#.#...#.#.......###.#.#...#...#...#...#.....#.#.#.......#...#.#...#.#.#...#.......#.#.#...#.............#...#.#...#.....#
|
||||
#.#########.#.#.#.#.#.###.#.#######v###.#.#.#.#.#.#.#.#.#.#####v#.#.#######.#.#.#.#####.#.###.#.#######.#.###.#.#############.#.#.###########
|
||||
#...........#.#.#...#.#...#...#...>.>.#.#...#.#.#...#.#.#...#.>.>.#.#...###.#.#.#.....#.#.#...#.......#.#...#.#...#...#...###.#.#...........#
|
||||
#############.#.#####.#.#####.#.###v#.#.#####.#.#####.#.###.#.#v###.#.#.###v#.#.#####.#.#.#.#########.#.###.#.###v#.#.#.#.###.#.###########.#
|
||||
#...#...#.....#.....#.#.#.....#.#...#.#.....#.#...###...#...#.#...#.#.#.#.>.>.#.#...#.#.#.#...#.......#...#.#.#.>.>.#...#...#.#...#.........#
|
||||
#.#.#.#.#.#########.#.#.#.#####.#.###.#####.#.###.#######.###.###.#.#.#.#.#v###.#.#.#.#.#.###.#.#########.#.#.#.#v#########.#.###.#.#########
|
||||
#.#...#.#.#####...#.#.#.#.#.....#...#...#...#.#...#.....#...#...#.#...#...#.###...#...#...#...#.......###...#...#.#...#...#.#.#...#...#...###
|
||||
#.#####.#.#####.#.#.#.#.#.#.#######.###.#.###.#.###.###.###.###.#.#########.###############.#########.###########.#.#.#.#.#.#.#.#####.#.#.###
|
||||
#.....#...###...#.#.#...#...#.....#...#.#.#...#.....#...###.....#.....#.....#...#...#...###...#.......#...#...###.#.#...#...#.#...###...#...#
|
||||
#####.#######.###.#.#########.###.###.#.#.#.#########.###############.#.#####.#.#.#.#.#.#####.#.#######.#.#.#.###.#.#########.###.#########.#
|
||||
#.....#...#...###...#...#.....###...#.#.#.#.#...#...#...#.............#...#...#...#...#.....#.#.....#...#...#...#.#.###...###...#.#...#.....#
|
||||
#.#####.#.#.#########.#.#.#########.#.#.#.#.#.#.#.#.###.#.###############.#.###############.#.#####.#.#########.#.#.###.#.#####.#.#.#.#.#####
|
||||
#.....#.#...#####.....#.#.........#...#.#.#.#.#...#.#...#...............#...#...............#.#.....#.#.....#...#.#.#...#.#...#.#.#.#.#...###
|
||||
#####.#.#########.#####.#########.#####.#.#.#.#####.#.#################.#####.###############.#.#####.#.###.#.###.#.#.###.#.#.#.#.#.#.###v###
|
||||
#...#.#.........#.#...#...........#...#...#.#.....#.#.#.................#.....#.....#.......#.#.....#...#...#.....#.#.###.#.#.#.#.#.#.#.>.###
|
||||
#.#.#v#########.#.#.#.#############.#.#####.#####.#.#.#.#################.#####.###.#.#####.#.#####.#####.#########.#.###.#.#.#.#.#.#.#.#v###
|
||||
#.#.#.>...#.....#...#...............#.....#.#...#.#...#.#...#...........#.#.....###...#.....#.......#...#.........#.#...#.#.#...#.#.#...#...#
|
||||
#.#.#v###.#.#############################.#.#.#.#.#####.#.#.#.#########.#.#.###########.#############.#.#########.#.###.#.#.#####.#.#######.#
|
||||
#.#.#...#.#.......#.......................#...#...#...#...#...#...#.....#.#.#...........#...#...###...#...........#.#...#.#.#.....#.#.......#
|
||||
#.#.###.#.#######.#.###############################.#.#########.#.#.#####.#.#.###########.#.#.#.###.###############.#.###.#.#.#####.#.#######
|
||||
#.#.....#.........#...#...#.........###...#...#...#.#.#.........#...#...#...#.#...........#.#.#...#.........#.....#...###.#.#.#.....#.#.....#
|
||||
#.###################.#.#.#.#######.###.#.#.#.#.#.#.#.#.#############.#.#####.#.###########.#.###.#########.#.###.#######.#.#.#.#####.#.###.#
|
||||
#...#...###.....#...#...#.#.#.......#...#...#.#.#.#.#.#.............#.#.....#...#...........#.#...#.........#...#.....###...#...#...#...#...#
|
||||
###.#.#.###.###.#.#.#####.#.#.#######.#######.#.#.#.#.#############.#.#####.#####.###########.#.###.###########.#####.###########.#.#####.###
|
||||
#...#.#...#...#.#.#.#.....#.#.....###.#.......#.#...#...#...#...###...#.....#...#.......#...#.#.###.......###...#.....#...#.....#.#...###...#
|
||||
#.###.###.###.#.#.#.#.#####.#####.###.#.#######.#######.#.#.#.#.#######.#####.#.#######.#.#.#.#.#########v###.###.#####.#.#.###.#.###.#####.#
|
||||
#.....###.....#.#.#.#.......#...#...#.#.....###.......#.#.#...#.#.......#####.#.........#.#.#.#...#.....>.>.#...#.#...#.#.#.#...#...#.###...#
|
||||
###############.#.#.#########.#.###.#.#####.#########.#.#.#####.#.###########.###########.#.#.###.#.#####v#.###.#.#.#.#.#.#.#.#####.#.###v###
|
||||
#...............#.#.#.......#.#.....#.#.....#...#...#.#.#.....#.#...........#...#...#...#.#.#.#...#.....#.#.....#.#.#.#.#.#.#...#...#...>.###
|
||||
#.###############.#.#.#####.#.#######.#.#####.#.#.#.#.#.#####.#.###########.###.#.#.#.#.#.#.#.#.#######.#.#######.#.#.#.#.#.###.#.#######v###
|
||||
#...#.....#...###.#.#.....#.#.#...###.#.#...#.#.#.#.#.#.#...#.#.###.........###...#...#.#.#...#...#.....#.....#...#.#...#.#...#.#.#.....#.###
|
||||
###.#.###.#.#.###.#.#####.#.#.#.#.###.#.#.#.#.#.#.#.#.#.#.#.#.#.###v###################.#.#######.#.#########.#.###.#####.###.#.#.#.###.#.###
|
||||
###...###.#.#.#...#.#.....#...#.#.#...#.#.#.#.#.#.#.#.#.#.#...#...>.>.........#...#.....#.....#...#...#.......#.....#.....#...#...#...#...###
|
||||
#########v#.#.#.###.#.#########.#.#.###.#.#.#.#.#.#.#.#.#.#########v#########.#.#.#.#########.#.#####.#.#############.#####.#########.#######
|
||||
#...#...#.>.#.#...#.#.........#.#.#.#...#.#.#.#.#.#.#.#.#.#.........###.......#.#.#.....#.....#.....#.#...#.........#...#...#.........#...###
|
||||
#.#.#.#.#v###.###.#.#########.#.#.#.#.###.#.#.#.#.#.#.#.#.#.###########.#######.#.#####.#.#########.#.###.#.#######.###.#.###.#########.#.###
|
||||
#.#...#...###.....#.#...#.....#.#...#...#.#.#.#.#.#...#...#...#.....#...#.....#.#.#.....#.......###.#.###...#...#...#...#...#.#...#.....#...#
|
||||
#.#################.#.#.#.#####.#######.#.#.#.#.#.###########.#.###.#.###.###.#.#.#.###########.###.#.#######.#.#.###.#####.#.#.#.#.#######.#
|
||||
#.............#.....#.#.#.....#.....###...#.#.#.#.###...#...#...#...#...#.#...#.#.#.#.....#...#...#.#.#.......#...###...#...#...#...#.......#
|
||||
#############.#.#####.#.#####v#####.#######.#.#.#.###.#.#.#.#####.#####.#.#.###.#.#v#.###.#.#.###.#.#.#.###############.#.###########.#######
|
||||
#.............#.#...#.#...#.>.>.....#.....#.#.#.#.#...#...#.......#####.#.#.....#.>.>.###.#.#.....#.#.#.......#.....###.#...#.......#.......#
|
||||
#.#############.#.#.#.###.#.#v#######.###.#.#.#.#.#.###################.#.#########v#####.#.#######.#.#######.#.###.###.###.#.#####.#######.#
|
||||
#.........#...#...#.#.###.#.#.........#...#...#...#.......#.........#...#...#.......#...#...#...###.#.#.....#...#...#...#...#.....#.........#
|
||||
#########.#.#.#####.#.###.#.###########.#################.#.#######.#.#####.#.#######.#.#####.#.###.#.#.###.#####.###.###.#######.###########
|
||||
#.........#.#.#...#...###...#.........#.#...#...#.......#...#...#...#.#.....#.......#.#.......#...#...#...#.#...#...#.....#...###...........#
|
||||
#.#########.#.#.#.###########.#######.#.#.#.#.#.#.#####.#####.#.#.###.#.###########.#.###########.#######.#.#.#.###.#######.#.#############.#
|
||||
#...#...#...#.#.#.#...#.......#...###...#.#.#.#.#.....#...#...#...###...#...###...#.#.#...........#...#...#...#.....#...###.#.#...#.......#.#
|
||||
###.#.#.#.###.#.#v#.#.#.#######.#.#######.#.#.#.#####.###.#.#############.#.###.#.#.#.#.###########.#.#.#############.#.###.#.#.#.#.#####.#.#
|
||||
#...#.#.#.#...#.#.>.#.#.....#...#...#...#.#.#.#.#...#.#...#.......#...#...#.#...#.#...#.....#.....#.#...#.....###...#.#.#...#.#.#.#...###...#
|
||||
#.###.#.#.#.###.#v###.#####.#.#####.#.#.#.#.#.#.#.#.#.#.#########.#.#.#.###.#.###.#########.#.###.#.#####.###.###.#.#.#.#.###.#.#.###v#######
|
||||
#.....#.#.#...#.#.#...#...#...###...#.#.#.#.#.#.#.#...#.#.......#.#.#.#...#.#...#.###...#...#.#...#...#...###...#.#...#.#...#.#.#...>.###...#
|
||||
#######.#.###.#.#.#.###.#.#######.###.#.#.#.#.#.#.#####.#.#####.#.#.#.###.#.###.#.###.#.#v###.#.#####.#.#######.#.#####.###.#.#.#####v###.#.#
|
||||
#...###...###...#.#...#.#...#...#.###.#.#.#.#.#.#.....#.#.#.....#.#.#.#...#...#.#.#...#.>.>.#.#.....#...#.......#.#.....#...#.#...#...###.#.#
|
||||
#.#.#############.###.#.###.#.#.#v###.#.#.#.#.#.#####.#.#.#.#####v#.#.#.#####.#.#.#.#####v#.#.#####.#####.#######.#.#####.###.###.#.#####.#.#
|
||||
#.#.#...#.....#...###.#.#...#.#.>.>.#.#.#.#.#.#...#...#.#.#.#...>.>.#.#.....#.#.#.#.#.....#...#.....#...#.....#...#.....#...#.#...#.......#.#
|
||||
#.#.#.#.#.###.#.#####.#.#.###.###v#.#.#.#.#.#.###.#.###.#.#.#.###v###.#####.#.#.#.#.#.#########.#####.#.#####.#.#######.###.#.#.###########.#
|
||||
#.#.#.#.#...#.#...#...#.#...#.#...#...#.#.#.#.###...#...#.#.#.#...###...#...#.#.#.#.#.......#...###...#...###.#.......#.#...#.#.#.....#...#.#
|
||||
#.#.#.#.###.#.###.#.###.###.#.#.#######.#.#.#.#######.###.#.#.#.#######.#.###.#.#.#.#######.#.#####.#####.###.#######.#.#.###.#.#.###.#.#.#.#
|
||||
#.#...#.#...#.#...#...#...#...#.......#.#.#.#...#.....#...#...#.......#.#...#...#...#...#...#.......#.....#...#...#...#.#.###...#...#...#...#
|
||||
#.#####.#.###.#.#####.###.###########.#.#.#.###.#.#####.#############.#.###.#########.#.#.###########.#####.###.#.#.###.#.#########.#########
|
||||
#.#...#...###...#.....#...#...........#...#.....#...#...#...#...#...#.#.#...#...#...#.#.#...#.........#...#...#.#.#...#...#####...#.........#
|
||||
#.#.#.###########.#####.###.#######################.#.###.#.#.#.#.#.#.#.#.###.#.#.#.#.#.###.#.#########.#.###v#.#.###.#########.#.#########.#
|
||||
#...#.........###.....#...#.......###...#.........#...#...#...#...#.#.#...#...#...#...#.....#.....#...#.#.#.>.>.#...#.#.........#...........#
|
||||
#############.#######.###.#######.###.#.#.#######.#####.###########.#.#####.#####################.#.#.#.#.#.#v#####.#.#.#####################
|
||||
#.............#...###.....#.....#.....#...#...#...#.....#.......#...#.#...#.................#.....#.#...#...#...###...#.#...#...#.......#...#
|
||||
#.#############.#.#########.###.###########.#.#.###.#####.#####.#.###.#.#.#################.#.#####.###########.#######.#.#.#.#.#.#####.#.#.#
|
||||
#.#.....#...###.#.....#...#...#...........#.#...###.......#...#.#...#.#.#.#.........#...#...#...#...#.......#...#...###...#...#...#...#...#.#
|
||||
#.#.###.#.#.###.#####.#.#.###.###########.#.###############.#.#.###.#.#.#.#.#######.#.#.#.#####.#.###.#####.#.###.#.###############.#.#####.#
|
||||
#...###...#...#...#...#.#.###.........#...#.......#.........#.#.#...#.#.#.#.......#.#.#.#.#...#...###.....#.#.....#...#.............#.....#.#
|
||||
#############.###.#.###.#.###########.#.#########.#.#########.#.#.###.#.#.#######.#.#.#.#.#.#.###########.#.#########.#.#################.#.#
|
||||
#...###.......#...#...#.#.#...........#.....#.....#.........#...#.....#.#.........#.#.#.#.#.#.............#...#.......#.................#.#.#
|
||||
#.#.###v#######.#####.#.#.#.###############.#.#############.###########.###########.#.#.#.#.#################.#.#######################.#.#.#
|
||||
#.#...#.>.#.....#.....#.#.#...............#.#...#...#######.....#...###...........#.#.#.#.#.#.......#...#####...###.....#...#...###.....#.#.#
|
||||
#.###.#v#.#.#####.#####.#.###############.#.###.#.#.###########.#.#.#############.#.#.#.#.#.#.#####.#.#.###########.###.#.#.#.#.###.#####.#.#
|
||||
#...#...#...#.....#...#.#...#.............#.#...#.#.###.........#.#.#...###.......#...#...#...###...#.#...#...#...#...#.#.#.#.#...#.....#...#
|
||||
###.#########.#####.#.#.###.#.#############.#.###.#.###.#########.#.#.#.###.#####################.###.###.#.#.#.#.###.#.#.#.#.###.#####.#####
|
||||
#...#.......#.....#.#.#.#...#.....#...#...#...###.#...#.......#...#...#...#.........#...#...#...#.....#...#.#.#.#.###.#.#.#.#.#...#.....#...#
|
||||
#.###.#####.#####.#.#.#.#.#######.#.#.#.#.#######.###.#######.#.#########.#########.#.#.#.#.#.#.#######.###.#.#.#.###.#.#.#.#.#.###v#####.#.#
|
||||
#.....#.....#...#...#...#...#.....#.#...#.#.......#...#.......#...#.......#.........#.#.#.#.#.#.#...###.###.#.#.#.#...#.#.#.#.#.#.>.###...#.#
|
||||
#######.#####.#.###########.#.#####.#####.#.#######.###.#########.#.#######.#########.#.#.#.#.#.#.#.###v###.#.#.#.#.###.#.#.#.#.#.#v###.###.#
|
||||
#.......#.....#.#...#.......#.......#.....#.......#.###.....#...#.#...#...#.....###...#.#.#.#.#.#.#.#.>.>...#.#.#...###.#.#.#.#...#...#.#...#
|
||||
#.#######.#####.#.#.#.###############.###########.#.#######.#.#.#.###.#.#.#####.###.###.#.#.#.#.#.#.#.#v#####.#.#######.#.#.#.#######.#.#.###
|
||||
#.......#.#.....#.#.#.....#.....#.....#...#...#...#...#...#.#.#.#.#...#.#.#...#.#...###.#.#...#.#.#...#.....#.#.......#.#.#.#...#.....#.#...#
|
||||
#######.#.#.#####.#.#####.#.###.#.#####.#.#.#.#.#####.#.#.#.#.#.#.#.###.#.#.#.#v#.#####.#.#####.#.#########.#.#######.#.#.#.###.#.#####.###.#
|
||||
#.......#.#...#...#...#...#...#.#.#...#.#.#.#.#...#...#.#.#.#.#.#.#...#.#.#.#.>.>.###...#.....#.#.###.......#.#.......#.#.#.#...#.......#...#
|
||||
#.#######.###.#.#####.#.#####.#.#v#.#.#.#.#.#.###.#.###.#.#v#.#.#.###.#.#.#.###v#####.#######.#.#.###.#######.#.#######.#.#.#.###########.###
|
||||
#...#...#...#.#.#.....#.#...#.#.>.>.#.#.#...#.#...#...#.#.>.>.#.#.#...#.#...###.....#...#...#.#.#.#...#.....#.#.....###...#.#...#.........###
|
||||
###.#.#.###.#.#.#.#####.#.#.#.###v###.#.#####.#.#####.#.###v###.#.#.###.###########.###.#.#.#.#.#.#.###.###.#.#####.#######.###.#.###########
|
||||
###.#.#.#...#...#.....#...#...###.#...#.....#...#.....#.###...#...#.....#...#...#...#...#.#.#.#.#.#...#.#...#...#...#...###.....#...........#
|
||||
###.#.#.#.###########.###########.#.#######.#####.#####.#####.###########.#.#.#.#.###.###.#.#.#.#.###.#.#.#####.#.###.#.###################.#
|
||||
#...#.#.#.#...........###...#.....#...#...#.....#.#.....#####.......#.....#...#.#...#.#...#...#...###...#.....#.#.###.#.#...#...#...........#
|
||||
#.###.#.#.#.#############.#.#.#######.#.#.#####.#.#.###############.#.#########.###.#.#.#####################.#.#.###.#.#.#.#.#.#.###########
|
||||
#...#.#.#.#.#...........#.#.#.#.....#.#.#.#.....#...#...............#...#...###.....#.#...#.................#.#.#.#...#...#.#.#.#.........###
|
||||
###.#.#.#.#.#.#########.#.#.#.#.###.#.#.#.#.#########.#################.#.#.#########.###.#.###############.#.#.#.#.#######.#.#.#########.###
|
||||
###.#.#.#.#.#.#.......#...#.#...#...#.#.#.#...#...#...#...#.......#...#...#.........#.....#...............#...#...#...#.....#.#.#...#...#...#
|
||||
###.#.#.#.#.#.#.#####.#####.#####.###.#.#.###.#.#.#.###.#.#.#####.#.#.#############.#####################.###########.#.#####.#.#.#.#v#.###.#
|
||||
###.#.#.#.#...#.....#.#...#.#...#.###...#.....#.#.#...#.#...#.....#.#.#.............###...#...#.....#...#.#.......#...#...#...#.#.#.>.#.....#
|
||||
###.#.#.#.#########.#.#.#.#.#.#.#.#############.#.###.#.#####.#####.#.#.###############.#.#.#.#.###.#.#.#.#.#####.#.#####.#.###.#.###v#######
|
||||
###...#...#.....#...#...#...#.#.#...........###.#.###...#.....###...#.#.......#.......#.#.#.#.#...#...#.#.#.....#...###...#...#...#...#...###
|
||||
###########.###.#.###########.#.###########.###.#.#######.#######.###.#######.#.#####.#.#.#.#.###.#####.#.#####.#######.#####.#####.###.#.###
|
||||
#.......###...#...#...###.....#.............#...#.......#.......#.#...#...#...#.#.....#.#.#.#.###.....#...#...#.......#.......#...#.....#...#
|
||||
#.#####.#####.#####.#.###.###################.#########.#######.#.#.###.#.#.###.#.#####.#.#.#.#######.#####.#.#######.#########.#.#########.#
|
||||
#.....#.......#...#.#...#.........#...###...#...#.......#...#...#.#...#.#...#...#.#...#.#.#.#.#...#...#...#.#.###...#...###.....#...........#
|
||||
#####.#########.#.#.###.#########v#.#.###.#.###.#.#######.#.#.###.###.#.#####.###.#.#.#.#.#.#.#.#.#.###.#.#.#.###.#.###.###.#################
|
||||
#.....#.......#.#.#.###...#...#.>.>.#...#.#.#...#...#.....#...###...#.#.....#.#...#.#.#.#.#.#.#.#.#...#.#.#.#.#...#.....#...#.....#.....#####
|
||||
#.#####.#####.#.#.#.#####.#.#.#.#######.#.#.#.#####.#.#############.#.#####v#.#.###.#.#.#.#.#.#.#.###v#.#.#.#.#.#########.###.###.#.###.#####
|
||||
#.....#.#.....#.#.#.#####.#.#...#.......#.#.#...#...#.........###...#.#...>.>.#.#...#.#.#...#.#.#...>.>.#.#.#.#.........#...#.#...#.###...###
|
||||
#####.#.#.#####.#.#.#####.#.#####.#######.#.###.#.###########v###.###.#.#######.#.###.#.#####.#.#########.#.#.#########.###.#.#.###.#####.###
|
||||
#####...#.....#.#...#.....#.....#.......#.#...#.#...#...#...>.>.#.###.#.....###.#.###.#.###...#.......#...#.#.#.......#.#...#.#.....#...#...#
|
||||
#############.#.#####.#########.#######.#.###.#.###.#.#.#.#####.#.###.#####.###.#.###.#.###.#########.#.###.#.#.#####.#.#.###.#######.#.###.#
|
||||
#.............#...#...#...#.....#.......#.#...#...#.#.#.#.....#.#.#...#.....#...#...#.#...#.....#.....#...#.#.#.....#.#.#...#.#.......#.....#
|
||||
#.###############.#.###.#.#.#####.#######.#.#####.#.#.#.#####.#.#.#.###.#####.#####.#.###.#####.#.#######.#.#.#####.#.#.###.#.#.#############
|
||||
#.................#.....#...#####.........#.......#...#.......#...#.....#####.......#.....#####...#######...#.......#...###...#.............#
|
||||
###########################################################################################################################################.#
|
||||
-237
@@ -1,237 +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 int
|
||||
}
|
||||
|
||||
func (r result) String() string { return fmt.Sprintf("%#v", r) }
|
||||
|
||||
func run(scan *bufio.Scanner) (*result, error) {
|
||||
var m aoc.Map[int16, rune]
|
||||
|
||||
start := Point{0, 0}
|
||||
target := Point{0, 0}
|
||||
var text string
|
||||
for scan.Scan() {
|
||||
text = scan.Text()
|
||||
if start == target {
|
||||
start[1] = int16(strings.IndexRune(text, '.'))
|
||||
}
|
||||
m = append(m, []rune(text))
|
||||
}
|
||||
target[0] = int16(len(m) - 1)
|
||||
target[1] = int16(strings.IndexRune(text, '.'))
|
||||
|
||||
result := &result{}
|
||||
|
||||
result.valuePT1 = search(&graph{m: m, start: start, target: target, neighbors: part1nbs})
|
||||
result.valuePT2 = search(&graph{m: m, start: start, target: target, neighbors: part2nbs})
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
type Point = aoc.Point[int16]
|
||||
type Map = aoc.Map[int16, rune]
|
||||
|
||||
// diretion of path steps
|
||||
type direction int8
|
||||
|
||||
var (
|
||||
U = Point{-1, 0}
|
||||
R = Point{0, 1}
|
||||
D = Point{1, 0}
|
||||
L = Point{0, -1}
|
||||
)
|
||||
|
||||
var directions = []Point{U, R, D, L}
|
||||
|
||||
var dirIDX = func() map[Point]direction {
|
||||
m := make(map[Point]direction, len(directions))
|
||||
for k, v := range directions {
|
||||
m[v] = direction(k)
|
||||
}
|
||||
return m
|
||||
}()
|
||||
|
||||
var arrows = []rune{'^', '>', 'v', '<'}
|
||||
|
||||
var arrowIDX = func() map[rune]Point {
|
||||
m := make(map[rune]Point, len(arrows))
|
||||
for k, v := range arrows {
|
||||
m[v] = directions[k]
|
||||
}
|
||||
return m
|
||||
}()
|
||||
|
||||
// position on the map
|
||||
type position struct {
|
||||
loc Point
|
||||
direction Point
|
||||
}
|
||||
|
||||
func (p position) step(to Point) position {
|
||||
return position{p.loc.Add(to), to}
|
||||
}
|
||||
|
||||
// implements FindPath graph interface
|
||||
type graph struct {
|
||||
m Map
|
||||
start Point
|
||||
target Point
|
||||
|
||||
neighbors func(g *graph, current position) []position
|
||||
}
|
||||
|
||||
// Neighbors returns valid steps from given position. if at target returns none.
|
||||
func (g *graph) Neighbors(current position) []position {
|
||||
return g.neighbors(g, current)
|
||||
}
|
||||
|
||||
// Cost calculates heat cost to neighbor from map
|
||||
func (g *graph) Cost(a, b position) int16 {
|
||||
return 1
|
||||
}
|
||||
|
||||
// Potential calculates distance to target
|
||||
func (g *graph) Potential(a, b position) int16 {
|
||||
return aoc.ManhattanDistance(a.loc, b.loc)
|
||||
}
|
||||
|
||||
func (g *graph) Seen(a position) position {
|
||||
a.direction = Point{}
|
||||
return a
|
||||
}
|
||||
|
||||
func match[T comparable](match T, lis ...T) bool {
|
||||
for _, b := range lis {
|
||||
if b == match {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func search(g *graph) int {
|
||||
costs, paths := aoc.FindPaths[int16, position](g, position{loc: g.start}, position{loc: g.target})
|
||||
|
||||
for i, path := range paths {
|
||||
log("path length = ", costs[i])
|
||||
printGraph(g.m, path)
|
||||
}
|
||||
|
||||
return int(aoc.Max(0, costs...))
|
||||
}
|
||||
|
||||
// printGraph with the path overlay
|
||||
func printGraph(m Map, path []position) {
|
||||
pts := make(map[Point]position, len(path))
|
||||
for _, pt := range path {
|
||||
pts[pt.loc] = pt
|
||||
}
|
||||
|
||||
for r, row := range m {
|
||||
for c, x := range row {
|
||||
if _, ok := pts[Point{int16(r), int16(c)}]; ok {
|
||||
if x == '.' {
|
||||
fmt.Print("*")
|
||||
} else {
|
||||
fmt.Print(string(x))
|
||||
}
|
||||
continue
|
||||
}
|
||||
fmt.Print(".")
|
||||
_ = x
|
||||
// fmt.Print(string(x))
|
||||
}
|
||||
fmt.Println("")
|
||||
}
|
||||
fmt.Println("")
|
||||
}
|
||||
|
||||
func opposite(d Point) Point {
|
||||
return directions[(dirIDX[d]+2)%4]
|
||||
}
|
||||
|
||||
|
||||
func part1nbs(g *graph, current position) []position {
|
||||
var nbs []position
|
||||
|
||||
if current.loc == g.start {
|
||||
return []position{
|
||||
{current.loc.Add(D), D},
|
||||
}
|
||||
}
|
||||
|
||||
if current.loc == g.target {
|
||||
return nil
|
||||
}
|
||||
|
||||
// only one direction on arrow.
|
||||
_, r, _ := g.m.Get(current.loc)
|
||||
if match(r, arrows...) {
|
||||
to := arrowIDX[r]
|
||||
if next := current.step(to); g.m.Valid(next.loc) {
|
||||
_, r, _ := g.m.Get(next.loc)
|
||||
d := arrows[(dirIDX[to]+2)%4] // flow from opposite direction
|
||||
if !match(r, rune(d), '#') {
|
||||
nbs = append(nbs, next)
|
||||
}
|
||||
}
|
||||
return nbs
|
||||
}
|
||||
|
||||
for _, to := range directions {
|
||||
if next := current.step(to); g.m.Valid(next.loc) {
|
||||
_, r, _ := g.m.Get(next.loc)
|
||||
d := arrows[(dirIDX[to]+2)%4] // flow from opposite direction
|
||||
if !match(r, rune(d), '#') {
|
||||
nbs = append(nbs, next)
|
||||
}
|
||||
}
|
||||
}
|
||||
return nbs
|
||||
}
|
||||
|
||||
func part2nbs(g *graph, current position) []position {
|
||||
var nbs []position
|
||||
|
||||
if current.loc == g.start {
|
||||
return []position{
|
||||
{current.loc.Add(D), D},
|
||||
}
|
||||
}
|
||||
|
||||
if current.loc == g.target {
|
||||
return nil
|
||||
}
|
||||
|
||||
for _, to := range directions {
|
||||
if next := current.step(to); g.m.Valid(next.loc) {
|
||||
if next.direction == opposite(current.direction) {
|
||||
continue
|
||||
}
|
||||
_, r, _ := g.m.Get(next.loc)
|
||||
if r == '#' {
|
||||
continue
|
||||
}
|
||||
|
||||
nbs = append(nbs, next)
|
||||
}
|
||||
}
|
||||
return nbs
|
||||
}
|
||||
@@ -1,42 +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, 94)
|
||||
is.Equal(result.valuePT2, 154)
|
||||
}
|
||||
|
||||
// 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.True(result.valuePT1 > 1918)
|
||||
// is.Equal(result.valuePT1, 2074)
|
||||
// is.Equal(result.valuePT2, 0)
|
||||
// }
|
||||
@@ -1,8 +1,6 @@
|
||||
module go.sour.is/advent-of-code
|
||||
|
||||
go 1.21.4
|
||||
|
||||
toolchain go1.21.5
|
||||
go 1.22.0
|
||||
|
||||
require (
|
||||
github.com/matryer/is v1.4.1
|
||||
|
||||
@@ -1,5 +1,14 @@
|
||||
package aoc
|
||||
|
||||
import (
|
||||
"cmp"
|
||||
"fmt"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/exp/maps"
|
||||
)
|
||||
|
||||
type Vector struct {
|
||||
Offset Point[int]
|
||||
Scale int
|
||||
@@ -58,7 +67,7 @@ func NumPoints(outline []Point[int], borderLength int) int {
|
||||
|
||||
type Map[I integer, T any] [][]T
|
||||
|
||||
func (m *Map[I,T]) Get(p Point[I]) (Point[I], T, bool) {
|
||||
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
|
||||
@@ -66,13 +75,172 @@ func (m *Map[I,T]) Get(p Point[I]) (Point[I], T, bool) {
|
||||
|
||||
return p, (*m)[p[0]][p[1]], true
|
||||
}
|
||||
func (m *Map[I,T]) Size() (I, I) {
|
||||
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 {
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
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) {}
|
||||
@@ -0,0 +1,109 @@
|
||||
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)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
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
|
||||
@@ -0,0 +1,2 @@
|
||||
8 90
|
||||
13 47 74 12 89 74 18 38
|
||||
Whitespace-only changes.
@@ -0,0 +1,44 @@
|
||||
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},
|
||||
},
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
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)
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package main
|
||||
|
||||
|
||||
func countChan(n int) <-chan int {
|
||||
ch := make(chan int)
|
||||
|
||||
go func() {
|
||||
for i := range n {
|
||||
ch <- i
|
||||
}
|
||||
close(ch)
|
||||
}()
|
||||
|
||||
return ch
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
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
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,193 @@
|
||||
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})
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
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,26 +2,70 @@ package aoc
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"flag"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"runtime/pprof"
|
||||
"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) {
|
||||
if len(os.Args) != 2 {
|
||||
if len(os.Args) < 2 {
|
||||
Log("Usage:", filepath.Base(os.Args[0]), "FILE")
|
||||
os.Exit(22)
|
||||
}
|
||||
|
||||
input, err := os.Open(os.Args[1])
|
||||
inputFilename := 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 {
|
||||
Log(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
scan := bufio.NewScanner(input)
|
||||
|
||||
return run(scan)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
package aoc
|
||||
|
||||
import (
|
||||
"maps"
|
||||
"math/bits"
|
||||
"sort"
|
||||
)
|
||||
|
||||
type priorityQueue[T any] struct {
|
||||
elems []T
|
||||
less func(a, b T) bool
|
||||
elems []*T
|
||||
less func(a, b *T) bool
|
||||
maxDepth int
|
||||
totalEnqueue int
|
||||
totalDequeue int
|
||||
@@ -17,10 +17,10 @@ type priorityQueue[T any] struct {
|
||||
// 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] {
|
||||
func PriorityQueue[T any](less func(a, b *T) bool) *priorityQueue[T] {
|
||||
return &priorityQueue[T]{less: less}
|
||||
}
|
||||
func (pq *priorityQueue[T]) Enqueue(elem T) {
|
||||
func (pq *priorityQueue[T]) Insert(elem *T) {
|
||||
pq.totalEnqueue++
|
||||
|
||||
pq.elems = append(pq.elems, elem)
|
||||
@@ -29,35 +29,41 @@ func (pq *priorityQueue[T]) Enqueue(elem T) {
|
||||
func (pq *priorityQueue[T]) IsEmpty() bool {
|
||||
return len(pq.elems) == 0
|
||||
}
|
||||
func (pq *priorityQueue[T]) Dequeue() (T, bool) {
|
||||
func (pq *priorityQueue[T]) ExtractMin() *T {
|
||||
pq.totalDequeue++
|
||||
|
||||
var elem T
|
||||
var elem *T
|
||||
if pq.IsEmpty() {
|
||||
return elem, false
|
||||
return elem
|
||||
}
|
||||
|
||||
sort.Slice(pq.elems, func(i, j int) bool { return pq.less(pq.elems[i], pq.elems[j]) })
|
||||
sort.Slice(pq.elems, func(i, j int) bool { return pq.less(pq.elems[j], pq.elems[i]) })
|
||||
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.
|
||||
func ManhattanDistance[T integer](a, b Point[T]) T {
|
||||
return ABS(a[1]-b[1]) + ABS(a[0]-b[0])
|
||||
return ABS(a[0]-b[0]) + ABS(a[1]-b[1])
|
||||
}
|
||||
|
||||
type pather[C number, N comparable] interface {
|
||||
// Neighbors returns all neighbors to node N that should be considered next.
|
||||
Neighbors(N) []N
|
||||
|
||||
// Cost returns
|
||||
Cost(a, b N) C
|
||||
Potential(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
|
||||
|
||||
// Target returns true if target reached.
|
||||
// Target(N) bool
|
||||
}
|
||||
|
||||
// FindPath uses the A* path finding algorithem.
|
||||
@@ -68,9 +74,18 @@ type pather[C number, N comparable] interface {
|
||||
//
|
||||
// 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) {
|
||||
func FindPath[C integer, N comparable](g pather[C, N], start, end N) (C, []N, map[N]C) {
|
||||
var zero C
|
||||
closed := make(map[N]bool)
|
||||
|
||||
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
|
||||
@@ -79,7 +94,7 @@ func FindPath[C integer, N comparable](g pather[C, N], start, end N) (C, []N) {
|
||||
position N
|
||||
}
|
||||
|
||||
NewPath := func(n *node) []N {
|
||||
newPath := func(n *node) []N {
|
||||
var path []N
|
||||
for n.parent != nil {
|
||||
path = append(path, n.position)
|
||||
@@ -91,158 +106,219 @@ func FindPath[C integer, N comparable](g pather[C, N], start, end N) (C, []N) {
|
||||
return path
|
||||
}
|
||||
|
||||
less := func(a, b node) bool {
|
||||
return b.cost+b.potential < a.cost+a.potential
|
||||
less := func(a, b *node) bool {
|
||||
return a.cost+a.potential < b.cost+b.potential
|
||||
}
|
||||
|
||||
pq := PriorityQueue(less)
|
||||
pq.Enqueue(node{position: start})
|
||||
closed[start] = false
|
||||
closed := make(map[N]C)
|
||||
open := FibHeap(less)
|
||||
|
||||
defer func() {
|
||||
Log("queue max depth = ", pq.maxDepth, "total enqueue = ", pq.totalEnqueue, "total dequeue = ", pq.totalDequeue)
|
||||
}()
|
||||
open.Insert(&node{position: start, potential: potentialFn(start)})
|
||||
closed[start] = zero
|
||||
|
||||
var seenFn = func(a N) N { return a }
|
||||
if s, ok := g.(interface{ Seen(N) N }); ok {
|
||||
seenFn = s.Seen
|
||||
}
|
||||
|
||||
var targetFn = func(a N) bool { return true }
|
||||
if s, ok := g.(interface{ Target(N) bool }); ok {
|
||||
targetFn = s.Target
|
||||
}
|
||||
|
||||
for !pq.IsEmpty() {
|
||||
current, _ := pq.Dequeue()
|
||||
cost, potential, n := current.cost, current.potential, current.position
|
||||
|
||||
seen := seenFn(n)
|
||||
if closed[seen] {
|
||||
continue
|
||||
}
|
||||
closed[seen] = true
|
||||
|
||||
if cost > 0 && potential == zero && targetFn(current.position) {
|
||||
return cost, NewPath(¤t)
|
||||
}
|
||||
|
||||
for _, nb := range g.Neighbors(n) {
|
||||
seen := seenFn(nb)
|
||||
if closed[seen] {
|
||||
continue
|
||||
}
|
||||
|
||||
cost := g.Cost(n, nb) + current.cost
|
||||
nextPath := node{
|
||||
for !open.IsEmpty() {
|
||||
current := open.ExtractMin()
|
||||
for _, nb := range g.Neighbors(current.position) {
|
||||
next := &node{
|
||||
position: nb,
|
||||
parent: ¤t,
|
||||
cost: cost,
|
||||
potential: g.Potential(nb, end),
|
||||
parent: current,
|
||||
cost: g.Cost(current.position, nb) + current.cost,
|
||||
potential: potentialFn(nb),
|
||||
}
|
||||
// check if path is in open list
|
||||
if _, open := closed[seen]; !open {
|
||||
pq.Enqueue(nextPath)
|
||||
closed[seen] = false // add to open list
|
||||
|
||||
seen := seenFn(nb)
|
||||
cost, ok := closed[seen]
|
||||
if !ok || next.cost < cost {
|
||||
open.Insert(next)
|
||||
closed[seen] = next.cost
|
||||
}
|
||||
|
||||
if next.potential == zero && g.Target(next.position, next.cost) {
|
||||
return next.cost, newPath(next), closed
|
||||
}
|
||||
}
|
||||
}
|
||||
return zero, nil
|
||||
return zero, nil, closed
|
||||
}
|
||||
|
||||
// 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 FindPaths[C integer, N comparable](g pather[C, N], start, end N) ([]C, [][]N) {
|
||||
var zero C
|
||||
// closed := make(map[N]bool)
|
||||
|
||||
type node struct {
|
||||
cost C
|
||||
potential C
|
||||
parent *node
|
||||
position N
|
||||
closed map[N]bool
|
||||
type fibTree[T any] struct {
|
||||
value *T
|
||||
parent *fibTree[T]
|
||||
child []*fibTree[T]
|
||||
mark bool
|
||||
}
|
||||
|
||||
func (t *fibTree[T]) Value() *T { return t.value }
|
||||
func (t *fibTree[T]) addAtEnd(n *fibTree[T]) {
|
||||
n.parent = t
|
||||
t.child = append(t.child, n)
|
||||
}
|
||||
|
||||
type fibHeap[T any] struct {
|
||||
trees []*fibTree[T]
|
||||
least *fibTree[T]
|
||||
count uint
|
||||
less func(a, b *T) bool
|
||||
}
|
||||
|
||||
func FibHeap[T any](less func(a, b *T) bool) *fibHeap[T] {
|
||||
return &fibHeap[T]{less: less}
|
||||
}
|
||||
|
||||
func (h *fibHeap[T]) GetMin() *T {
|
||||
return h.least.value
|
||||
}
|
||||
|
||||
func (h *fibHeap[T]) IsEmpty() bool { return h.least == nil }
|
||||
|
||||
func (h *fibHeap[T]) Insert(v *T) {
|
||||
ntree := &fibTree[T]{value: v}
|
||||
h.trees = append(h.trees, ntree)
|
||||
if h.least == nil || h.less(v, h.least.value) {
|
||||
h.least = ntree
|
||||
}
|
||||
h.count++
|
||||
}
|
||||
|
||||
func (h *fibHeap[T]) ExtractMin() *T {
|
||||
smallest := h.least
|
||||
if smallest != nil {
|
||||
// Remove smallest from root trees.
|
||||
for i := range h.trees {
|
||||
pos := h.trees[i]
|
||||
if pos == smallest {
|
||||
h.trees[i] = h.trees[len(h.trees)-1]
|
||||
h.trees = h.trees[:len(h.trees)-1]
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// Add children to root
|
||||
h.trees = append(h.trees, smallest.child...)
|
||||
smallest.child = smallest.child[:0]
|
||||
|
||||
NewPath := func(n *node) []N {
|
||||
var path []N
|
||||
for n.parent != nil {
|
||||
path = append(path, n.position)
|
||||
n = n.parent
|
||||
h.least = nil
|
||||
if len(h.trees) > 0 {
|
||||
h.consolidate()
|
||||
}
|
||||
path = append(path, n.position)
|
||||
|
||||
Reverse(path)
|
||||
return path
|
||||
h.count--
|
||||
return smallest.value
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
less := func(b, a node) bool {
|
||||
return b.cost+b.potential < a.cost+a.potential
|
||||
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
|
||||
}
|
||||
|
||||
pq := PriorityQueue(less)
|
||||
pq.Enqueue(node{position: start, closed: make(map[N]bool)})
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
defer func() {
|
||||
Log("queue max depth = ", pq.maxDepth, "total enqueue = ", pq.totalEnqueue, "total dequeue = ", pq.totalDequeue)
|
||||
}()
|
||||
func (h *fibHeap[T]) Merge(a *fibHeap[T]) {
|
||||
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]
|
||||
|
||||
var seenFn = func(a N) N { return a }
|
||||
if s, ok := g.(interface{ Seen(N) N }); ok {
|
||||
seenFn = s.Seen
|
||||
for len(st) > 0 {
|
||||
tr, st = st[0], st[1:]
|
||||
ro := *tr.value
|
||||
if fn(&ro) {
|
||||
break
|
||||
}
|
||||
st = append(st, tr.child...)
|
||||
}
|
||||
|
||||
return tr
|
||||
}
|
||||
|
||||
var targetFn = func(a N) bool { return true }
|
||||
if s, ok := g.(interface{ Target(N) bool }); ok {
|
||||
targetFn = s.Target
|
||||
func (h *fibHeap[T]) Find(fn func(*T) bool) *T {
|
||||
if needle := h.find(fn); needle != nil {
|
||||
return needle.value
|
||||
}
|
||||
|
||||
var paths [][]N
|
||||
var costs []C
|
||||
return nil
|
||||
}
|
||||
|
||||
for !pq.IsEmpty() {
|
||||
current, _ := pq.Dequeue()
|
||||
cost, potential, n := current.cost, current.potential, current.position
|
||||
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
|
||||
}
|
||||
|
||||
seen := seenFn(n)
|
||||
if current.closed[seen] {
|
||||
continue
|
||||
if parent := needle.parent; parent != nil {
|
||||
if h.less(needle.value, parent.value) {
|
||||
h.cut(needle)
|
||||
h.cascadingCut(parent)
|
||||
}
|
||||
current.closed[seen] = true
|
||||
}
|
||||
}
|
||||
|
||||
if cost > 0 && potential == zero && cost > Max(0, costs...) && targetFn(current.position) {
|
||||
paths = append([][]N(nil), NewPath(¤t))
|
||||
costs = append([]C(nil), cost)
|
||||
Log("new record = ", cost)
|
||||
continue
|
||||
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)
|
||||
|
||||
for _, nb := range g.Neighbors(n) {
|
||||
seen := seenFn(nb)
|
||||
if current.closed[seen] {
|
||||
continue
|
||||
}
|
||||
if h.less(x.value, h.least.value) {
|
||||
h.least = x
|
||||
}
|
||||
}
|
||||
|
||||
cost := g.Cost(n, nb) + current.cost
|
||||
next := node{
|
||||
position: nb,
|
||||
parent: ¤t,
|
||||
cost: cost,
|
||||
potential: g.Potential(nb, end),
|
||||
closed: maps.Clone(current.closed),
|
||||
}
|
||||
// check if path is in open list
|
||||
if _, open := current.closed[seen]; !open {
|
||||
next.closed[seen] = false // add to open list
|
||||
pq.Enqueue(next)
|
||||
}
|
||||
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)
|
||||
}
|
||||
return costs, paths
|
||||
}
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
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