Compare commits
2 Commits
e9068fdf78
...
1891be35f2
Author | SHA1 | Date | |
---|---|---|---|
1891be35f2 | |||
f10418bc60 |
4
day01/example1.txt
Normal file
4
day01/example1.txt
Normal file
|
@ -0,0 +1,4 @@
|
|||
1abc2
|
||||
pqr3stu8vwx
|
||||
a1b2c3d4e5f
|
||||
treb7uchet
|
7
day01/example2.txt
Normal file
7
day01/example2.txt
Normal file
|
@ -0,0 +1,7 @@
|
|||
two1nine
|
||||
eightwothree
|
||||
abcone2threexyz
|
||||
xtwone3four
|
||||
4nineeightseven2
|
||||
zoneight234
|
||||
7pqrstsixteen
|
160
day01/main.go
160
day01/main.go
|
@ -2,25 +2,41 @@ package main
|
|||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
_ "embed"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
aoc "go.sour.is/advent-of-code-2023"
|
||||
)
|
||||
|
||||
//go:embed input.txt
|
||||
var input []byte
|
||||
|
||||
func main() {
|
||||
buf := bytes.NewReader(input)
|
||||
scan := bufio.NewScanner(buf)
|
||||
result, err := aoc.Runner(run)
|
||||
if err != nil {
|
||||
fmt.Println("ERR", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
fmt.Println(result)
|
||||
}
|
||||
|
||||
type result struct {
|
||||
sum int
|
||||
sum2 int
|
||||
}
|
||||
|
||||
func (r result) String() string {
|
||||
return fmt.Sprintln("result pt1:", r.sum, "\nresult pt2:", r.sum2)
|
||||
}
|
||||
|
||||
var numbers = []string{"zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine"}
|
||||
|
||||
func run(scan *bufio.Scanner) (*result, error) {
|
||||
result := &result{}
|
||||
|
||||
sum := 0
|
||||
for scan.Scan() {
|
||||
var first, last int
|
||||
|
||||
orig := scan.Text()
|
||||
_ = orig
|
||||
var first2, last2 int
|
||||
|
||||
text := scan.Text()
|
||||
|
||||
|
@ -30,110 +46,66 @@ func main() {
|
|||
|
||||
switch {
|
||||
case slice[0] >= '0' && slice[0] <= '9':
|
||||
if first == 0 {
|
||||
first = int(slice[0] - '0')
|
||||
case strings.HasPrefix(string(slice), "one"):
|
||||
first = 1
|
||||
case strings.HasPrefix(string(slice), "two"):
|
||||
first = 2
|
||||
case strings.HasPrefix(string(slice), "three"):
|
||||
first = 3
|
||||
case strings.HasPrefix(string(slice), "four"):
|
||||
first = 4
|
||||
case strings.HasPrefix(string(slice), "five"):
|
||||
first = 5
|
||||
case strings.HasPrefix(string(slice), "six"):
|
||||
first = 6
|
||||
case strings.HasPrefix(string(slice), "seven"):
|
||||
first = 7
|
||||
case strings.HasPrefix(string(slice), "eight"):
|
||||
first = 8
|
||||
case strings.HasPrefix(string(slice), "nine"):
|
||||
first = 9
|
||||
|
||||
}
|
||||
if first != 0 {
|
||||
if first2 == 0 {
|
||||
first2 = int(slice[0] - '0')
|
||||
}
|
||||
default:
|
||||
if first2 != 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
for i, s := range numbers {
|
||||
if strings.HasPrefix(string(slice), s) {
|
||||
first2 = i
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
if first != 0 && first2 != 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
text = string(reverse([]rune(text)))
|
||||
text = string(aoc.Reverse([]rune(text)))
|
||||
|
||||
for i := range text {
|
||||
copy(slice, []rune(text[i:]))
|
||||
slice = reverse(slice)
|
||||
slice = aoc.Reverse(slice)
|
||||
|
||||
switch {
|
||||
case slice[4] >= '0' && slice[4] <= '9':
|
||||
if last == 0 {
|
||||
last = int(slice[4] - '0')
|
||||
case strings.HasSuffix(string(slice), "one"):
|
||||
last = 1
|
||||
case strings.HasSuffix(string(slice), "two"):
|
||||
last = 2
|
||||
case strings.HasSuffix(string(slice), "three"):
|
||||
last = 3
|
||||
case strings.HasSuffix(string(slice), "four"):
|
||||
last = 4
|
||||
case strings.HasSuffix(string(slice), "five"):
|
||||
last = 5
|
||||
case strings.HasSuffix(string(slice), "six"):
|
||||
last = 6
|
||||
case strings.HasSuffix(string(slice), "seven"):
|
||||
last = 7
|
||||
case strings.HasSuffix(string(slice), "eight"):
|
||||
last = 8
|
||||
case strings.HasSuffix(string(slice), "nine"):
|
||||
last = 9
|
||||
|
||||
}
|
||||
if last != 0 {
|
||||
if last2 == 0 {
|
||||
last2 = int(slice[4] - '0')
|
||||
}
|
||||
default:
|
||||
if last2 != 0 {
|
||||
continue
|
||||
}
|
||||
for i, s := range numbers {
|
||||
if strings.HasSuffix(string(slice), s) {
|
||||
last2 = i
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
sum += first*10 + last
|
||||
}
|
||||
if last != 0 && last2 != 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
result.sum += first*10 + last
|
||||
result.sum2 += first2*10 + last2
|
||||
}
|
||||
if err := scan.Err(); err != nil {
|
||||
panic(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
fmt.Println(sum)
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func reverse[T any](arr []T) []T{
|
||||
for i := 0; i < len(arr)/2; i++ {
|
||||
arr[i], arr[len(arr)-i-1] = arr[len(arr)-i-1], arr[i]
|
||||
}
|
||||
return arr
|
||||
}
|
||||
|
||||
|
||||
// type sorter[T rune | int] []T
|
||||
|
||||
// func (s sorter[T]) Less(i, j int) bool { return s[i] < s[j] }
|
||||
// func (s sorter[T]) Len() int { return len(s) }
|
||||
// func (s sorter[T]) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
|
||||
|
||||
/*
|
||||
0
|
||||
1
|
||||
2
|
||||
3
|
||||
4
|
||||
5
|
||||
6
|
||||
7
|
||||
8
|
||||
9
|
||||
one
|
||||
two
|
||||
three
|
||||
four
|
||||
five
|
||||
six
|
||||
seven
|
||||
eight
|
||||
nine
|
||||
ten
|
||||
|
||||
|
||||
*/
|
||||
|
|
54
day01/main_test.go
Normal file
54
day01/main_test.go
Normal file
|
@ -0,0 +1,54 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"testing"
|
||||
|
||||
_ "embed"
|
||||
|
||||
"github.com/matryer/is"
|
||||
)
|
||||
|
||||
//go:embed example1.txt
|
||||
var example1 []byte
|
||||
|
||||
//go:embed example2.txt
|
||||
var example2 []byte
|
||||
|
||||
//go:embed input.txt
|
||||
var input []byte
|
||||
|
||||
func TestExample1(t *testing.T) {
|
||||
is := is.New(t)
|
||||
scan := bufio.NewScanner(bytes.NewReader(example1))
|
||||
|
||||
result, err := run(scan)
|
||||
is.NoErr(err)
|
||||
|
||||
t.Log(result)
|
||||
is.Equal(result.sum, 142)
|
||||
}
|
||||
|
||||
|
||||
func TestExample2(t *testing.T) {
|
||||
is := is.New(t)
|
||||
scan := bufio.NewScanner(bytes.NewReader(example2))
|
||||
|
||||
result, err := run(scan)
|
||||
is.NoErr(err)
|
||||
|
||||
t.Log(result)
|
||||
is.Equal(result.sum2, 281)
|
||||
}
|
||||
func TestInput(t *testing.T) {
|
||||
is := is.New(t)
|
||||
scan := bufio.NewScanner(bytes.NewReader(input))
|
||||
|
||||
result, err := run(scan)
|
||||
is.NoErr(err)
|
||||
|
||||
t.Log(result)
|
||||
is.Equal(result.sum, 54573)
|
||||
is.Equal(result.sum2, 54591)
|
||||
}
|
163
day08/main.go
163
day08/main.go
|
@ -5,21 +5,12 @@ import (
|
|||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
aoc "go.sour.is/advent-of-code-2023"
|
||||
)
|
||||
|
||||
func main() {
|
||||
if len(os.Args) != 2 {
|
||||
fmt.Fprintln(os.Stderr, "Usage: day08 FILE")
|
||||
}
|
||||
|
||||
input, err := os.Open(os.Args[1])
|
||||
if err != nil {
|
||||
fmt.Fprintln(os.Stderr, err)
|
||||
}
|
||||
|
||||
scan := bufio.NewScanner(input)
|
||||
|
||||
result, err := run(scan)
|
||||
result, err := aoc.Runner(run)
|
||||
if err != nil {
|
||||
fmt.Println("ERR", err)
|
||||
os.Exit(1)
|
||||
|
@ -29,10 +20,14 @@ func main() {
|
|||
}
|
||||
|
||||
type result struct {
|
||||
stepsPT1 int
|
||||
stepsPT1 uint64
|
||||
stepsPT2 uint64
|
||||
}
|
||||
|
||||
func (r result) String() string {
|
||||
return fmt.Sprintf("solution 1: %v\nsolution 2: %v\n", r.stepsPT1, r.stepsPT2)
|
||||
}
|
||||
|
||||
func run(scan *bufio.Scanner) (*result, error) {
|
||||
var path []rune
|
||||
m := make(nodeMap)
|
||||
|
@ -64,8 +59,8 @@ func run(scan *bufio.Scanner) (*result, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
steps1 := SolutionPT1(m, path)
|
||||
steps2 := SolutionPT2(m, path)
|
||||
steps1 := m.SolvePT1(path)
|
||||
steps2 := m.SolvePT2(path)
|
||||
|
||||
return &result{steps1, steps2}, nil
|
||||
}
|
||||
|
@ -96,26 +91,25 @@ func (m nodeMap) mapNodes() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func SolutionPT1(m nodeMap, path []rune) int {
|
||||
fmt.Println("---- PART 1 BEGIN ----")
|
||||
position, ok := m["AAA"]
|
||||
func (m nodeMap) solver(start string, isEnd func(string) bool, path []rune) uint64 {
|
||||
position, ok := m[start]
|
||||
if !ok {
|
||||
return 0
|
||||
}
|
||||
var i int
|
||||
var steps int
|
||||
var steps uint64
|
||||
|
||||
for steps < 100000 {
|
||||
for steps < ^uint64(0) {
|
||||
steps++
|
||||
if path[i] == 'R' {
|
||||
fmt.Println("step", steps, position.value, "R->", position.rvalue)
|
||||
// fmt.Println("step", steps, position.value, "R->", position.rvalue)
|
||||
position = position.right
|
||||
} else {
|
||||
fmt.Println("step", steps, position.value, "L->", position.lvalue)
|
||||
// fmt.Println("step", steps, position.value, "L->", position.lvalue)
|
||||
position = position.left
|
||||
}
|
||||
|
||||
if position.value == "ZZZ" {
|
||||
if isEnd(position.value) {
|
||||
break
|
||||
}
|
||||
|
||||
|
@ -124,126 +118,33 @@ func SolutionPT1(m nodeMap, path []rune) int {
|
|||
i = 0
|
||||
}
|
||||
}
|
||||
fmt.Println("---- PART 1 END ----")
|
||||
return steps
|
||||
}
|
||||
|
||||
func SolutionPT2(m nodeMap, path []rune) uint64 {
|
||||
fmt.Println("---- PART 2 BEGIN ----")
|
||||
func (m nodeMap) SolvePT1(path []rune) uint64 {
|
||||
fmt.Println("---- PART 1 BEGIN ----")
|
||||
defer fmt.Println("---- PART 1 END ----")
|
||||
|
||||
type loop struct {
|
||||
start, position, end *node
|
||||
steps uint64
|
||||
return m.solver("AAA", func(s string) bool { return s == "ZZZ" }, path)
|
||||
}
|
||||
loops := make(map[*node]loop)
|
||||
|
||||
endpoints := make(map[*node]struct{})
|
||||
func (m nodeMap) SolvePT2(path []rune) uint64 {
|
||||
fmt.Println("---- PART 2 BEGIN ----")
|
||||
defer fmt.Println("---- PART 2 END ----")
|
||||
|
||||
var starts []*node
|
||||
|
||||
for k, n := range m {
|
||||
if strings.HasSuffix(k, "A") {
|
||||
fmt.Println("start", k)
|
||||
loops[n] = loop{start: n, position: n}
|
||||
}
|
||||
|
||||
if strings.HasSuffix(k, "Z") {
|
||||
fmt.Println("stop", k)
|
||||
endpoints[n] = struct{}{}
|
||||
starts = append(starts, n)
|
||||
}
|
||||
}
|
||||
|
||||
var i int
|
||||
var steps uint64
|
||||
var stops int
|
||||
maxUint := ^uint64(0)
|
||||
loopsFound := 0
|
||||
|
||||
for steps < maxUint {
|
||||
steps++
|
||||
if path[i] == 'R' {
|
||||
for k, loop := range loops {
|
||||
// fmt.Println("step", steps, position.value, "R->", position.rvalue)
|
||||
loop.position = loop.position.right
|
||||
loops[k] = loop
|
||||
}
|
||||
} else {
|
||||
for k, loop := range loops {
|
||||
// fmt.Println("step", steps, position.value, "L->", position.lvalue)
|
||||
loop.position = loop.position.left
|
||||
loops[k] = loop
|
||||
loops := make([]uint64, len(starts))
|
||||
for i, n := range starts {
|
||||
loops[i] = m.solver(n.value, func(s string) bool { return strings.HasSuffix(s, "Z") }, path)
|
||||
}
|
||||
return aoc.LCM(loops...)
|
||||
}
|
||||
|
||||
done := true
|
||||
s := 0
|
||||
for k, loop := range loops {
|
||||
if _, ok := endpoints[loop.position]; !ok {
|
||||
// fmt.Println("no stop", i, position.value)
|
||||
done = false
|
||||
// break
|
||||
} else {
|
||||
// fmt.Println("stop", i, position.value)
|
||||
if loop.end == nil {
|
||||
loop.end = loop.position
|
||||
loop.steps = steps
|
||||
fmt.Println("loop found", loop.position.value, "steps", steps)
|
||||
loops[k] = loop
|
||||
loopsFound++
|
||||
}
|
||||
s++
|
||||
}
|
||||
}
|
||||
|
||||
if loopsFound == len(loops) {
|
||||
var values []uint64
|
||||
for _, loop := range loops {
|
||||
values = append(values, loop.steps)
|
||||
}
|
||||
return LCM(values...)
|
||||
}
|
||||
|
||||
if s > stops {
|
||||
stops = s
|
||||
fmt.Println("stops", stops, "steps", steps)
|
||||
}
|
||||
|
||||
if done {
|
||||
break
|
||||
}
|
||||
|
||||
i++
|
||||
if i > len(path)-1 {
|
||||
i = 0
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Println("---- PART 2 END ----")
|
||||
return steps
|
||||
}
|
||||
|
||||
// greatest common divisor (GCD) via Euclidean algorithm
|
||||
func GCD(a, b uint64) uint64 {
|
||||
for b != 0 {
|
||||
t := b
|
||||
b = a % b
|
||||
a = t
|
||||
}
|
||||
return a
|
||||
}
|
||||
|
||||
// find Least Common Multiple (LCM) via GCD
|
||||
func LCM(integers ...uint64) uint64 {
|
||||
if len(integers) == 0 {
|
||||
return 0
|
||||
}
|
||||
if len(integers) == 1 {
|
||||
return integers[0]
|
||||
}
|
||||
|
||||
a, b := integers[0], integers[1]
|
||||
result := a * b / GCD(a, b)
|
||||
|
||||
for _, c := range integers[2:] {
|
||||
result = LCM(result, c)
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
|
|
@ -30,7 +30,7 @@ func TestExample1(t *testing.T) {
|
|||
is.NoErr(err)
|
||||
|
||||
t.Log(result.stepsPT1)
|
||||
is.Equal(result.stepsPT1, 2)
|
||||
is.Equal(result.stepsPT1, uint64(2))
|
||||
}
|
||||
|
||||
func TestExample2(t *testing.T) {
|
||||
|
@ -41,7 +41,7 @@ func TestExample2(t *testing.T) {
|
|||
is.NoErr(err)
|
||||
|
||||
t.Log(result.stepsPT1)
|
||||
is.Equal(result.stepsPT1, 6)
|
||||
is.Equal(result.stepsPT1, uint64(6))
|
||||
}
|
||||
|
||||
func TestExample3(t *testing.T) {
|
||||
|
@ -63,10 +63,18 @@ func TestInput(t *testing.T) {
|
|||
is.NoErr(err)
|
||||
|
||||
t.Log("part1 solution", result.stepsPT1)
|
||||
is.Equal(result.stepsPT1, 14429)
|
||||
is.Equal(result.stepsPT1, uint64(14429))
|
||||
|
||||
t.Log("part2 solution", result.stepsPT2)
|
||||
is.Equal(result.stepsPT2, uint64(10921547990923))
|
||||
}
|
||||
|
||||
// first: 14429
|
||||
// second: 10921547990923
|
||||
|
||||
// Brüt
|
||||
// stops 1 steps 13201
|
||||
// stops 2 steps 620447
|
||||
// stops 3 steps 36606373
|
||||
// stops 4 steps 2232988753
|
||||
// stops 5 steps 149610246451
|
||||
|
|
58
tools.go
Normal file
58
tools.go
Normal file
|
@ -0,0 +1,58 @@
|
|||
package aoc
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"os"
|
||||
)
|
||||
|
||||
func Runner[R any, F func(*bufio.Scanner) (R, error)](run F) (R, error) {
|
||||
if len(os.Args) != 2 {
|
||||
fmt.Fprintln(os.Stderr, "Usage:", os.Args[0] , "FILE")
|
||||
}
|
||||
|
||||
input, err := os.Open(os.Args[1])
|
||||
if err != nil {
|
||||
fmt.Fprintln(os.Stderr, err)
|
||||
}
|
||||
|
||||
scan := bufio.NewScanner(input)
|
||||
return run(scan)
|
||||
}
|
||||
|
||||
func Reverse[T any](arr []T) []T {
|
||||
for i := 0; i < len(arr)/2; i++ {
|
||||
arr[i], arr[len(arr)-i-1] = arr[len(arr)-i-1], arr[i]
|
||||
}
|
||||
return arr
|
||||
}
|
||||
|
||||
|
||||
// greatest common divisor (GCD) via Euclidean algorithm
|
||||
func GCD(a, b uint64) uint64 {
|
||||
for b != 0 {
|
||||
t := b
|
||||
b = a % b
|
||||
a = t
|
||||
}
|
||||
return a
|
||||
}
|
||||
|
||||
// find Least Common Multiple (LCM) via GCD
|
||||
func LCM(integers ...uint64) uint64 {
|
||||
if len(integers) == 0 {
|
||||
return 0
|
||||
}
|
||||
if len(integers) == 1 {
|
||||
return integers[0]
|
||||
}
|
||||
|
||||
a, b := integers[0], integers[1]
|
||||
result := a * b / GCD(a, b)
|
||||
|
||||
for _, c := range integers[2:] {
|
||||
result = LCM(result, c)
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
Loading…
Reference in New Issue
Block a user