-
Notifications
You must be signed in to change notification settings - Fork 10
/
Day03.cs
101 lines (90 loc) · 3.6 KB
/
Day03.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
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
using System;
using System.Buffers.Binary;
using System.Runtime.CompilerServices;
using AdventOfCode.CSharp.Common;
namespace AdventOfCode.CSharp.Y2024.Solvers;
public class Day03 : ISolver
{
public static void Solve(ReadOnlySpan<byte> input, Solution solution)
{
int part1 = 0;
int part2 = 0;
const uint mulBytes = 0x286C756DU; // "mul(" as a little endian uint
const uint doBytes = 0x29286F64U; // "do()" as a little endian uint
const ulong dontBytes = 0x292874276E6F64UL; // "don't()" as a little endian ulong
const ulong dontMask = 0xFFFFFFFFFFFFFFUL; // mask to check for "don't()" in a ulong
bool isEnabled = true;
while (input.Length != 0)
{
int candidateIndex = input.IndexOfAny((byte)'d', (byte)'m');
if (candidateIndex < 0)
break;
input = input.Slice(candidateIndex);
if (input[0] == 'm') // check for mul(a,b)
{
if (input.Length >= 8) // "mul(a,b)" is 8 characters long
{
uint mulCandidate = BinaryPrimitives.ReadUInt32LittleEndian(input);
if (mulCandidate == mulBytes)
{
int i = 4;
int a = ParseNumber(input, ref i, out byte separator);
if (separator == (byte)',')
{
int b = ParseNumber(input, ref i, out separator);
if (separator == (byte)')')
{
int mul = a * b;
part1 += mul;
if (isEnabled)
part2 += mul;
input = input.Slice(i);
continue;
}
}
input = input.Slice(i - 1); // subtract 1 because the separator might be the start of another instruction
continue;
}
}
}
else if (isEnabled) // check for don't()
{
if (input.Length >= 8) // even though "don't()" is 7 digits long, file always ends in newline so can safely load 8 bytes
{
ulong dontCandidate = BinaryPrimitives.ReadUInt64LittleEndian(input);
if ((dontCandidate & dontMask) == dontBytes)
{
isEnabled = false;
input = input.Slice(7);
continue;
}
}
}
else // check for do()
{
if (input.Length >= 4) // "do()" is 4 digits long
{
uint doCandidate = BinaryPrimitives.ReadUInt32LittleEndian(input);
if (doCandidate == doBytes)
{
isEnabled = true;
input = input.Slice(4);
continue;
}
}
}
input = input.Slice(1);
}
solution.SubmitPart1(part1);
solution.SubmitPart2(part2);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static int ParseNumber(ReadOnlySpan<byte> input, ref int i, out byte c)
{
c = 0;
int a = 0;
while (i < input.Length && (c = input[i++]) is >= (byte)'0' and <= (byte)'9')
a = a * 10 + c - '0';
return a;
}
}