-
Notifications
You must be signed in to change notification settings - Fork 10
/
Day06.cs
71 lines (57 loc) · 2.17 KB
/
Day06.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
using System;
using AdventOfCode.CSharp.Common;
namespace AdventOfCode.CSharp.Y2023.Solvers;
public class Day06 : ISolver
{
public static void Solve(ReadOnlySpan<byte> input, Solution solution)
{
int timesLineEnd = input.IndexOf((byte)'\n');
ReadOnlySpan<byte> timesLine = input.Slice(0, timesLineEnd);
ReadOnlySpan<byte> distanceLine = input.Slice(timesLineEnd + 1, input.Length - timesLineEnd - 2);
long part1 = 1;
long part2Time = 0;
long part2Dist = 0;
while (timesLine.Length > 0)
{
long time = ParseNum(ref timesLine, ref part2Time);
long distance = ParseNum(ref distanceLine, ref part2Dist);
part1 *= NumWaysToWin(time, distance);
}
solution.SubmitPart1(part1);
long part2 = NumWaysToWin(part2Time, part2Dist);
solution.SubmitPart2(part2);
}
private static long ParseNum(ref ReadOnlySpan<byte> line, ref long part2Var)
{
byte c;
int nextStart = line.IndexOfAnyInRange((byte)'0', (byte)'9');
line = line.Slice(nextStart);
long time = 0;
int i = 0;
while (i < line.Length && (c = line[i]) != ' ')
{
time = time * 10 + c - '0';
part2Var = part2Var * 10 + c - '0';
i++;
}
line = line.Slice(i);
return time;
}
static long NumWaysToWin(long time, long distance)
{
// solve for distance = (time - x) * x
// x = (time +- sqrt(time^2 - 4 * distance)) / 2
// time^2 overflows the long on part 2, so we can rewrite it as follows:
// x = (time +- sqrt(time - 2 * sqrt(distance)) * sqrt(time + 2 * sqrt(distance))) / 2
double sqrtDist = Math.Sqrt(distance);
double sqrt = Math.Sqrt(time - 2 * sqrtDist) * Math.Sqrt(time + 2 * sqrtDist);
long low = Convert.ToInt64(Math.Ceiling((time - sqrt) / 2));
long high = Convert.ToInt64(Math.Floor((time + sqrt) / 2));
// handle ties or precision issues
if ((time - low) * low <= distance)
low++;
if ((time - high) * high <= distance)
high--;
return high - low + 1;
}
}