diff --git a/2019/01/01.go b/2019/01/01.go new file mode 100644 index 0000000..0a856db --- /dev/null +++ b/2019/01/01.go @@ -0,0 +1,33 @@ +package main + +import ( + "embed" + _ "embed" + "fmt" + + "github.com/dbut2/advent-of-code/pkg/sti" + "github.com/dbut2/advent-of-code/pkg/utils" +) + +//go:embed input.txt +var input string + +//go:embed test*.txt +var tests embed.FS + +func main() { + fmt.Println(solve(input)) +} + +func solve(input string) int { + s := utils.ParseInput(input) + + total := 0 + + for _, line := range sti.Stis(s) { + lv := (line / 3) - 2 + total += lv + } + + return total +} diff --git a/2019/01/02.go b/2019/01/02.go new file mode 100644 index 0000000..4bc2066 --- /dev/null +++ b/2019/01/02.go @@ -0,0 +1,40 @@ +package main + +import ( + "embed" + _ "embed" + "fmt" + + "github.com/dbut2/advent-of-code/pkg/sti" + "github.com/dbut2/advent-of-code/pkg/utils" +) + +//go:embed input.txt +var input string + +//go:embed test*.txt +var tests embed.FS + +func main() { + fmt.Println(solve(input)) +} + +func solve(input string) int { + s := utils.ParseInput(input) + + total := 0 + + for _, line := range sti.Stis(s) { + mass := line + for { + f := mass/3 - 2 + if f < 0 { + break + } + total += f + mass = f + } + } + + return total +} diff --git a/2019/01/input.txt b/2019/01/input.txt new file mode 100644 index 0000000..ba6fd5f --- /dev/null +++ b/2019/01/input.txt @@ -0,0 +1,100 @@ +141107 +119016 +145241 +72264 +116665 +81420 +88513 +128809 +145471 +81570 +124798 +75370 +84988 +71634 +135275 +96992 +53376 +62414 +148277 +135418 +82475 +137707 +105051 +83450 +102673 +88390 +100849 +94528 +135709 +63945 +126413 +70107 +84734 +119176 +85769 +115276 +137511 +61806 +92892 +121640 +93726 +146526 +95812 +132556 +103885 +78776 +55826 +120257 +61131 +79179 +130698 +97153 +121985 +61159 +103585 +148674 +84067 +110085 +138473 +105495 +112393 +144411 +73328 +125955 +58075 +136147 +124106 +81185 +138847 +69814 +127104 +86090 +67666 +102333 +99546 +98280 +99062 +129433 +125353 +77609 +71240 +71791 +146046 +113685 +121381 +122715 +147789 +53981 +140926 +81528 +121789 +106627 +73745 +67509 +144140 +119238 +82417 +129215 +75663 +106842 \ No newline at end of file diff --git a/2019/01/test1.txt b/2019/01/test1.txt new file mode 100644 index 0000000..e69de29 diff --git a/2019/01/test2.txt b/2019/01/test2.txt new file mode 100644 index 0000000..e69de29 diff --git a/2022/01/01.php b/2022/01/01.php new file mode 100644 index 0000000..faf0716 --- /dev/null +++ b/2022/01/01.php @@ -0,0 +1 @@ +array_sum(explode("\n",$s)),explode("\n\n",file_get_contents('input.txt')))); diff --git a/2022/12/02v2.go b/2022/12/02v2.go index 9e6679c..e6200b0 100644 --- a/2022/12/02v2.go +++ b/2022/12/02v2.go @@ -6,7 +6,9 @@ import ( "fmt" "strings" "sync" + "time" + "github.com/dbut2/advent-of-code/pkg/benchmark" "github.com/dbut2/advent-of-code/pkg/test" ) @@ -20,6 +22,9 @@ func main() { t := test.Register(tests, solve) t.Expect(1, 29) fmt.Println(solve(input)) + benchmark.Run(func() { + solve(input) + }, benchmark.Time(time.Second*10)) } func solve(input string) int { diff --git a/2022/13/input.txt b/2022/13/input.txt index f5c3f8c..7c1a966 100644 --- a/2022/13/input.txt +++ b/2022/13/input.txt @@ -446,4 +446,4 @@ [[[3,[],5],[5,[10,1,1,4]],[[7,3],[10,10,1,9,7],1,1],[5,[6,8,0,2]]],[[6,[0,7]],6,[10,[5,1]]],[],[],[[],[]]] [[9,5,8,7,[[9]]],[0,10,[6,10,[3,9,7,8]],[],3]] -[[7,7,[9,[9],[10,5,4,4,2],5]],[5,6,[10,8,0,[8,1,6,9],[1,1]]],[],[[],[1,4,[7,7,0]],[[9,7,1],[5,8,2,1],2,[4,7,7,6],2],[[9,1,6,10]],10]] \ No newline at end of file +[[7,7,[9,[9],[10,5,4,4,2],5]],[5,6,[10,8,0,[8,1,6,9],[1,1]]],[],[[],[1,4,[7,7,0]],[[9,7,1],[5,8,2,1],2,[4,7,7,6],2],[[9,1,6,10]],10]] diff --git a/2022/17/02.go b/2022/17/02.go new file mode 100644 index 0000000..09d4691 --- /dev/null +++ b/2022/17/02.go @@ -0,0 +1,228 @@ +package main + +import ( + "embed" + _ "embed" + "fmt" + "strings" + "time" + + "github.com/dbut2/advent-of-code/pkg/grid" + "github.com/dbut2/advent-of-code/pkg/test" + "github.com/dbut2/advent-of-code/pkg/utils" + "github.com/dbut2/advent-of-code/pkg/watch" +) + +//go:embed input.txt +var input string + +//go:embed test*.txt +var tests embed.FS + +var w = watch.Watch[int](time.Second) + +func main() { + t := test.Register(tests, solve) + t.Expect(1, 0) + fmt.Println(solve(input)) +} + +func solve(input string) int { + s := utils.ParseInput(input) + + var directions []int + + for _, d := range strings.Split(s[0], "") { + switch d { + case "<": + directions = append(directions, left) + case ">": + directions = append(directions, right) + default: + panic(d) + } + } + + g := grid.Grid[bool]{} + + m := -1 + lastHeight := 0 + + var regularGrowth int + var regularRounds int + var doneGrowth int + var doneRounds int + + _, _, _, _ = regularGrowth, regularRounds, doneGrowth, doneRounds + + rounds := 0 + for { + for n := 0; n < len(Rocks); n++ { + rounds++ + w.Update(rounds) + rock := Rocks[n%len(Rocks)] + i, j := findTop(g)+4, 2 + + for { + m++ + direction := directions[m%len(directions)] + + // can be blown + canBeBlown := true + for x, row := range rock { + x += i + for y, cell := range row { + y += j + + if !cell { + continue + } + newY := y + direction + + if newY < 0 || newY >= 7 { + canBeBlown = false + break + } + + if g.Get(x, newY) { + canBeBlown = false + break + } + } + } + + if canBeBlown { + j += direction + } + + // can move down + canMoveDown := true + for x, row := range rock { + x += i + for y, cell := range row { + y += j + + if !cell { + continue + } + + newX := x - 1 + + if newX < 0 { + canMoveDown = false + break + } + + if g.Get(newX, y) { + canMoveDown = false + break + } + } + } + + if canMoveDown { + i -= 1 + } + + if !canMoveDown { + break + } + } + + for x, row := range rock { + for y, cell := range row { + if cell { + g.Set(x+i, y+j, true) + } + } + } + } + + height := findTop(g) + growth := height - lastHeight + + // check when n and m have complete a round + if m%len(directions) == len(directions)-1 { + allMatches := true + for i := 0; i < growth; i++ { + for j := 0; j < 7; j++ { + if g.Get(lastHeight-i, j) != g.Get(lastHeight-i-growth, j) { + allMatches = false + } + } + } + + if allMatches { + regularGrowth = growth + regularRounds = len(Rocks) + doneGrowth = findTop(g) + doneRounds = rounds + break + } + + } + + lastHeight = height + } + + return findTop(g) + 1 +} + +func lcd(a, b int) int { + for i := 1; ; i++ { + if i%a == 0 && i%b == 0 { + return i + } + } +} + +// 0 1 2 +// >>><<><>><<<>><>>><<<>>><<<><<<>><>><<>> + +func findTop(g grid.Grid[bool]) int { + for i := 0; ; i++ { + rowHas := false + for j := 0; j < 7; j++ { + if g.Get(i, j) { + rowHas = true + } + } + if !rowHas { + return i - 1 + } + } +} + +const ( + left int = iota - 1 + _ + right +) + +type Rock [][]bool + +var Rocks = []Rock{ + { + {true, true, true, true}, + }, + { + {false, true, false}, + {true, true, true}, + {false, true, false}, + }, + { + {true, true, true}, + {false, false, true}, + {false, false, true}, + }, + { + {true}, + {true}, + {true}, + {true}, + }, + { + {true, true}, + {true, true}, + }, +} diff --git a/2022/18/01.go b/2022/18/01.go index 418a195..70df151 100644 --- a/2022/18/01.go +++ b/2022/18/01.go @@ -5,7 +5,9 @@ import ( _ "embed" "fmt" "strings" + "time" + "github.com/dbut2/advent-of-code/pkg/benchmark" "github.com/dbut2/advent-of-code/pkg/sets" "github.com/dbut2/advent-of-code/pkg/sti" "github.com/dbut2/advent-of-code/pkg/test" @@ -22,6 +24,9 @@ func main() { t := test.Register(tests, solve) t.Expect(1, 64) fmt.Println(solve(input)) + benchmark.Run(func() { + solve(input) + }, benchmark.Time(time.Second*10)) } func solve(input string) int { @@ -36,24 +41,21 @@ func solve(input string) int { total := 0 - for _, c := range cubes.Slice() { - sides := [6][3]int{ - {1, 0, 0}, - {0, 1, 0}, - {0, 0, 1}, - {-1, 0, 0}, - {0, -1, 0}, - {0, 0, -1}, - } + sides := [6][3]int{ + {1, 0, 0}, + {0, 1, 0}, + {0, 0, 1}, + {-1, 0, 0}, + {0, -1, 0}, + {0, 0, -1}, + } - count := 6 + for _, c := range cubes.Slice() { for _, d := range sides { - x, y, z := c[0]+d[0], c[1]+d[1], c[2]+d[2] - if cubes.Has([3]int{x, y, z}) { - count-- + if !cubes.Has([3]int{c[0] + d[0], c[1] + d[1], c[2] + d[2]}) { + total++ } } - total += count } return total diff --git a/2022/18/02.go b/2022/18/02.go index a655225..20e7f96 100644 --- a/2022/18/02.go +++ b/2022/18/02.go @@ -5,7 +5,9 @@ import ( _ "embed" "fmt" "strings" + "time" + "github.com/dbut2/advent-of-code/pkg/benchmark" "github.com/dbut2/advent-of-code/pkg/math" "github.com/dbut2/advent-of-code/pkg/sets" "github.com/dbut2/advent-of-code/pkg/sti" @@ -24,6 +26,9 @@ func main() { t.Expect(2, 10) t.Expect(1, 58) fmt.Println(solve(input)) + benchmark.Run(func() { + solve(input) + }, benchmark.Time(time.Second*10)) } func solve(input string) int { diff --git a/go.mod b/go.mod index e3abf01..4d9a215 100644 --- a/go.mod +++ b/go.mod @@ -1,3 +1,3 @@ module github.com/dbut2/advent-of-code -go 1.19 +go 1.21 diff --git a/pkg/grid/grid.go b/pkg/grid/grid.go index 1ccc383..b48ad3c 100644 --- a/pkg/grid/grid.go +++ b/pkg/grid/grid.go @@ -1,22 +1,19 @@ package grid -type Grid[T any] map[[2]int]T +type Grid[T any] map[[2]int]*T func (g Grid[T]) Set(x, y int, cell T) { - g.ensureGrid() - g[[2]int{x, y}] = cell + if g == nil { + g = make(Grid[T]) + } + g[[2]int{x, y}] = &cell } -func (g Grid[T]) Get(x, y int) T { - g.ensureGrid() +func (g Grid[T]) Get(x, y int) *T { if v, ok := g[[2]int{x, y}]; ok { return v } - return *new(T) -} - -func (g Grid[T]) ensureGrid() { - if g == nil { - g = make(Grid[T]) - } + cell := new(T) + g[[2]int{x, y}] = cell + return cell } diff --git a/pkg/lists/lists.go b/pkg/lists/lists.go index 72ccacd..70deca9 100644 --- a/pkg/lists/lists.go +++ b/pkg/lists/lists.go @@ -1,42 +1,42 @@ package lists import ( + "slices" + "github.com/dbut2/advent-of-code/pkg/math" ) func Intersection[T comparable](a, b []T) []T { var i []T for _, x := range a { - for _, y := range b { - if x == y { - i = append(i, x) - } + if slices.Contains(b, x) { + i = append(i, x) } } return i } func Range[N math.Number](a, b N) []N { - min := math.Min(a, b) - max := math.Max(a, b) + low := min(a, b) + high := max(a, b) - var l []N - for i := min; i <= max; i++ { + l := make([]N, 0, int(high-low+1)) + for i := low; i <= high; i++ { l = append(l, i) } return l } func Map[T, U any](s []T, f func(T) U) []U { - var l []U - for _, v := range s { - l = append(l, f(v)) + l := make([]U, len(s)) + for i, v := range s { + l[i] = f(v) } return l } func MapMap[T, U any, V, W comparable](s map[V]T, f func(V, T) (W, U)) map[W]U { - l := make(map[W]U) + l := make(map[W]U, len(s)) for k, v := range s { nk, nv := f(k, v) l[nk] = nv @@ -44,8 +44,8 @@ func MapMap[T, U any, V, W comparable](s map[V]T, f func(V, T) (W, U)) map[W]U { return l } -func MapToSlice[T comparable, U any](s map[T]U) []Pair[T, U] { - var l []Pair[T, U] +func MapToSlice[T comparable, U any](s map[T]U) Pairs[T, U] { + l := make(Pairs[T, U], 0, len(s)) for k, v := range s { l = append(l, Pair[T, U]{A: k, B: v}) } @@ -57,6 +57,24 @@ type Pair[T, U any] struct { B U } +type Pairs[T, U any] []Pair[T, U] + +func (p Pairs[T, U]) Keys() []T { + l := make([]T, len(p)) + for i := range p { + l[i] = p[i].A + } + return l +} + +func (p Pairs[T, U]) Vals() []U { + l := make([]U, len(p)) + for i := range p { + l[i] = p[i].B + } + return l +} + func Fill[T any](x int, def T) []T { a := make([]T, x) for i := 0; i < x; i++ { @@ -78,17 +96,11 @@ func Fill2D[T any](x, y int, def T) [][]T { } func Reverse[T any](s []T) []T { - for i, j := 0, len(s)-1; i < j; i, j = i+1, j-1 { - s[i], s[j] = s[j], s[i] - } - return s + r := slices.Clone(s) + slices.Reverse(r) + return r } func Contains[T comparable](s []T, i T) bool { - for _, item := range s { - if item == i { - return true - } - } - return false + return slices.Contains(s, i) } diff --git a/pkg/math/math.go b/pkg/math/math.go index 46c06a2..3e2f5eb 100644 --- a/pkg/math/math.go +++ b/pkg/math/math.go @@ -1,23 +1,5 @@ package math -import ( - "sort" -) - -func Max[N Number](a, b N) N { - if a > b { - return a - } - return b -} - -func Min[N Number](a, b N) N { - if a < b { - return a - } - return b -} - func Abs[N Number](a N) N { if a < 0 { return -a @@ -35,67 +17,6 @@ func Sign[N Snumber](a N) N { return 0 } -func Order[T Number](s []T, desc bool) []T { - t := s - sort.Slice(t, func(i, j int) bool { - return t[i] < t[j] - }) - if desc { - t = Reverse(t) - } - return t -} - -func OrderMap[T any](s []T, f func(T) int, desc bool) []T { - t := s - sort.Slice(s, func(i, j int) bool { - return f(t[i]) < f(t[j]) - }) - if desc { - t = Reverse(t) - } - return t -} - -func LargestN[N Number](s []N, n int) []N { - return Order(s, true)[:n] -} - -func Largest[N Number](s []N) N { - return LargestN(s, 1)[0] -} - -func LargestNMap[T any](s []T, f func(T) int, n int) []T { - return OrderMap(s, f, true)[:n] -} - -func LargestMap[T any](s []T, f func(T) int) T { - return LargestNMap(s, f, 1)[0] -} - -func SmallestN[N Number](s []N, n int) []N { - return Order(s, false)[:n] -} - -func Smallest[N Number](s []N) N { - return SmallestN(s, 1)[0] -} - -func SmallestNMap[T any](s []T, f func(T) int, n int) []T { - return OrderMap(s, f, false)[:n] -} - -func SmallestMap[T any](s []T, f func(T) int) T { - return SmallestNMap(s, f, 1)[0] -} - -func Reverse[T any](s []T) []T { - for i, j := 0, len(s)-1; i < j; i, j = i+1, j-1 { - s[i], s[j] = s[j], s[i] - } - return s -} - type Number interface { Sint | Uint | Float } @@ -158,7 +79,11 @@ func SumMapIf[T comparable](s map[T]int, predicate func(T) bool) int { return t } -func Pow[N Int, M Uint](x N, y M) N { +func Pow[N Number, M Int](x N, y M) N { + if y < 0 { + return 1 / Pow(x, -y) + } + result := N(1) for y > 0 { if y&1 == 1 { diff --git a/pkg/math/math_test.go b/pkg/math/math_test.go new file mode 100644 index 0000000..3a95496 --- /dev/null +++ b/pkg/math/math_test.go @@ -0,0 +1,18 @@ +package math + +import ( + "math" + "testing" +) + +func BenchmarkPow(b *testing.B) { + for i := 0; i < b.N; i++ { + Pow(100, 100) + } +} + +func BenchmarkOldPow(b *testing.B) { + for i := 0; i < b.N; i++ { + math.Pow(float64(100), float64(100)) + } +}