Skip to content

Commit ba547e5

Browse files
committed
2023 day06 optimised
1 parent ee047ea commit ba547e5

File tree

5 files changed

+115
-50
lines changed

5 files changed

+115
-50
lines changed

2023/day06/.bench

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
{"Lines":[{"Name":"Part 1","N":4518816,"NsPerOp":263.3,"AllocedBytesPerOp":0,"AllocsPerOp":0,"MBPerS":0,"Measured":1,"Ord":0},{"Name":"Part 2","N":434,"NsPerOp":2776692,"AllocedBytesPerOp":0,"AllocsPerOp":0,"MBPerS":0,"Measured":1,"Ord":0}],"Measured":1}
1+
{"Lines":[{"Name":"Part 1","N":152954395,"NsPerOp":7.729,"AllocedBytesPerOp":0,"AllocsPerOp":0,"MBPerS":0,"Measured":1,"Ord":0},{"Name":"Part 2","N":622866195,"NsPerOp":1.906,"AllocedBytesPerOp":0,"AllocsPerOp":0,"MBPerS":0,"Measured":1,"Ord":0}],"Measured":1}

2023/day06/main.go

Lines changed: 99 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@ package main
22

33
import (
44
_ "embed"
5+
"math"
56
"os"
7+
"strings"
68
)
79

810
//go:embed input.txt
@@ -11,36 +13,118 @@ var input string
1113
//go:embed input_test.txt
1214
var inputTest string
1315

16+
type Race struct {
17+
time, distance int
18+
}
19+
20+
var races []Race
21+
var bigRace Race
22+
1423
func main() {
1524
// Check argv if we use test input or not
1625
if len(os.Args) > 1 && os.Args[1] == "test" {
1726
input = inputTest
1827
}
1928

20-
answer := doPartOne(input)
29+
parseInput(input)
30+
31+
answer := doPartOne()
2132
println(answer)
2233

23-
answer = doPartTwo(input)
34+
answer = doPartTwo()
2435
println(answer)
2536
}
2637

27-
type Race struct {
28-
Time, Distance int
38+
func parseInput(input string) {
39+
lines := strings.Split(strings.TrimSpace(input), "\n")
40+
41+
// Parse times and distances
42+
times := parseNumbers(lines[0])
43+
distances := parseNumbers(lines[1])
44+
45+
// Part 1: individual races
46+
races = make([]Race, len(times))
47+
for i := range races {
48+
races[i] = Race{times[i], distances[i]}
49+
}
50+
51+
// Part 2: concatenated race
52+
bigRace = Race{concatenateNumbers(times), concatenateNumbers(distances)}
2953
}
3054

31-
func getWays(r Race) int {
32-
max := getVal(r, r.Time, -1)
33-
min := getVal(r, 0, 1)
34-
return max - min + 1
55+
func parseNumbers(line string) []int {
56+
var nums []int
57+
i := 0
58+
for i < len(line) {
59+
if line[i] >= '0' && line[i] <= '9' {
60+
num := 0
61+
for i < len(line) && line[i] >= '0' && line[i] <= '9' {
62+
num = num*10 + int(line[i]-'0')
63+
i++
64+
}
65+
nums = append(nums, num)
66+
} else {
67+
i++
68+
}
69+
}
70+
return nums
3571
}
3672

37-
func getVal(r Race, S, M int) int {
38-
for i := 0; i < r.Time; i++ {
39-
runtime := r.Time - (S + i*M)
40-
D := (S + i*M) * runtime
41-
if D > r.Distance {
42-
return (S + i*M)
73+
func concatenateNumbers(nums []int) int {
74+
result := 0
75+
for _, n := range nums {
76+
// Count digits in n
77+
temp := n
78+
multiplier := 1
79+
for temp > 0 {
80+
multiplier *= 10
81+
temp /= 10
4382
}
83+
result = result*multiplier + n
84+
}
85+
return result
86+
}
87+
88+
// Mathematical solution using quadratic formula
89+
// Distance d = h * (t - h) where h is hold time, t is total time
90+
// Need: h * (t - h) > record
91+
// Rearrange: -h² + t*h - record > 0
92+
// Solve: h² - t*h + record < 0
93+
// Using quadratic formula: h = (t ± sqrt(t² - 4*record)) / 2
94+
func getWays(r Race) int {
95+
t := float64(r.time)
96+
d := float64(r.distance)
97+
98+
// Discriminant
99+
disc := t*t - 4*d
100+
if disc < 0 {
101+
return 0
102+
}
103+
104+
sqrtDisc := math.Sqrt(disc)
105+
106+
// Two solutions from quadratic formula
107+
h1 := (t - sqrtDisc) / 2
108+
h2 := (t + sqrtDisc) / 2
109+
110+
// We need integer hold times strictly greater than the record
111+
// Round up h1, round down h2
112+
minHold := int(math.Floor(h1 + 1))
113+
maxHold := int(math.Ceil(h2 - 1))
114+
115+
// Edge case: if h1 is exactly an integer, we need strictly greater
116+
if h1 == math.Floor(h1) {
117+
minHold = int(h1) + 1
118+
}
119+
120+
// Edge case: if h2 is exactly an integer, we need strictly less
121+
if h2 == math.Ceil(h2) {
122+
maxHold = int(h2) - 1
44123
}
45-
return r.Time - S
124+
125+
if maxHold < minHold {
126+
return 0
127+
}
128+
129+
return maxHold - minHold + 1
46130
}

2023/day06/main_test.go

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,19 @@ package main
33
import "testing"
44

55
func BenchmarkPartOne(b *testing.B) {
6+
parseInput(input)
7+
b.ResetTimer()
8+
69
for n := 0; n < b.N; n++ {
7-
doPartOne(input)
10+
doPartOne()
811
}
912
}
1013

1114
func BenchmarkPartTwo(b *testing.B) {
15+
parseInput(input)
16+
b.ResetTimer()
17+
1218
for n := 0; n < b.N; n++ {
13-
doPartTwo(input)
19+
doPartTwo()
1420
}
1521
}

2023/day06/part1.go

Lines changed: 5 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,9 @@
11
package main
22

3-
import (
4-
"aocli/utils"
5-
"strings"
6-
)
7-
8-
func doPartOne(input string) int {
9-
lines := strings.Split(strings.TrimSpace(input), "\n")
10-
// Build up the races
11-
T := strings.Fields(lines[0])[1:]
12-
D := strings.Fields(lines[1])[1:]
13-
R := make([]Race, len(T))
14-
for i := range R {
15-
R[i] = Race{utils.Atoi(T[i]), utils.Atoi(D[i])}
16-
}
17-
18-
// Get the ways to win
19-
ways := make([]int, len(R))
20-
for i, r := range R {
21-
ways[i] = getWays(r)
3+
func doPartOne() int {
4+
result := 1
5+
for _, r := range races {
6+
result *= getWays(r)
227
}
23-
return utils.MultiplyArray(ways)
8+
return result
249
}

2023/day06/part2.go

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,5 @@
11
package main
22

3-
import (
4-
"aocli/utils"
5-
"strings"
6-
)
7-
8-
func doPartTwo(input string) int {
9-
lines := strings.Split(strings.TrimSpace(input), "\n")
10-
var R Race
11-
R.Time = utils.Atoi(strings.Join(strings.Fields(lines[0])[1:], ""))
12-
R.Distance = utils.Atoi(strings.Join(strings.Fields(lines[1])[1:], ""))
13-
14-
return getWays(R)
3+
func doPartTwo() int {
4+
return getWays(bigRace)
155
}

0 commit comments

Comments
 (0)