-
Notifications
You must be signed in to change notification settings - Fork 1
/
day3.c3
140 lines (130 loc) · 3.11 KB
/
day3.c3
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
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
/*
* Advent of Code 2023 day 3
*/
import std::io;
import std::time;
import std::collections::list;
import std::ascii;
import std::math;
struct Gear
{
isz[<2>] location;
int counter;
long ratio;
}
def StringList = List(<String>);
def GearList = List(<Gear>);
GearList gear_list;
fn void main()
{
io::printn("Advent of code, day 3.");
@pool()
{
// Simple benchmarking with Clock, "mark" returns the last duration and resets the clock
Clock c = clock::now();
io::printfn("* Game 1 sum: %d - completed in %s", part1(), c.mark());
io::printfn("* Game 2 sum: %d - completed in %s", part2(), c.mark());
};
}
fn int part1()
{
gear_list.temp_init();
return scan_schematic();
}
fn long part2()
{
// We already collected all the gears, so now just
// add the gear ratios
long sum;
foreach (&gear : gear_list)
{
if (gear.counter == 2) sum += gear.ratio;
}
return sum;
}
fn int scan_schematic()
{
File f = file::open("day3.txt", "rb")!!;
defer (void)f.close();
StringList list;
list.temp_init();
// Read every line into a dynamic list.
while (try line = io::treadline(&f)) list.push(line);
// I prefer using the view, but the list can be used as
// well.
String[] schematic = list.array_view();
usz width = schematic[0].len;
usz height = schematic.len;
int sum;
// Scan for numbers
foreach (y, s : schematic)
{
for (usz i = 0; i < width; i++)
{
char c = s[i];
if (!c.is_digit()) continue;
// A number was found, find the end
usz start = i;
while (++i < width) if (!s[i].is_digit()) break;
usz len = i - start;
// Now scan the number and it's surroundings.
sum += scan_number(schematic, height, width, start, y, len);
}
}
return sum;
}
fn int scan_number(String[] list, isz height, isz width, isz x, isz y, isz len)
{
// Get the bountaries
isz start_y = math::max(y - 1, (isz)0);
isz end_y = math::min(y + 2, height);
isz start_x = math::max(x - 1, (isz)0);
isz end_x = math::min(x + len + 1, width);
// Scan everything around the digit for symbols
// for simplicity we unnecessarily also scan over the digit.
for (isz ys = start_y; ys < end_y; ys++)
{
String s = list[ys];
for (isz xs = start_x; xs < end_x; xs++)
{
switch (s[xs])
{
case '.':
case '0'..'9':
// We found space or digit, so we continue.
continue;
case '*':
// We found a gear, so we return the value *and*
// store the gear.
int value = list[y][x:len].to_int()!!;
multiply_gear({xs, ys}, value);
return value;
default:
// We found a non-gear, return the value.
return list[y][x:len].to_int()!!;;
}
}
}
// Nothing around this digit, return zero.
return 0;
}
fn void multiply_gear(isz[<2>] location, int value)
{
// Look throught the list of gears.
foreach (&gear : gear_list)
{
if (gear.location == location)
{
// The gear was found, increase the amount of surrounding digits.
gear.counter++;
if (gear.counter == 2)
{
// Multiply by the value if this is the second value.
gear.ratio *= value;
return;
}
}
}
// First time this gear is detected, store location, count and ratio.
gear_list.push({ location, 1, value });
}