Skip to content

Commit 3b0544e

Browse files
authored
Merge pull request #78 from Avokadoen/main
Solved day04 & day05 in zig
2 parents 6659217 + c3f070a commit 3b0544e

File tree

5 files changed

+270
-2
lines changed

5 files changed

+270
-2
lines changed

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@ Welcome to this community project, where we collaboratively solve the 2020 editi
1212
| sml | **8** | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | | ||||||||||||||||
1313
| deno.ts | **8** | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | | ||||||||||||||||
1414
| c | **6** | 1 | 1 | 1 | 1 | 1 | 1 | | | | ||||||||||||||||
15+
| zig | **5** | 1 | 1 | 1 | 1 | 1 | | | | | ||||||||||||||||
1516
| node.js | **4** | 1 | | | 1 | | 1 | 1 | | | ||||||||||||||||
16-
| zig | **3** | 1 | 1 | 1 | | | | | | | ||||||||||||||||
1717
| c++ | **2** | 1 | 1 | | | | | | | | ||||||||||||||||
1818
| ruby | **2** | 1 | | | 1 | | | | | | ||||||||||||||||
1919
| rust | **1** | 1 | | | | | | | | | ||||||||||||||||
@@ -22,7 +22,7 @@ Welcome to this community project, where we collaboratively solve the 2020 editi
2222
| php | **0** | | | | | | | | | | ||||||||||||||||
2323
| **Total** | **65** |**12**|**8**|**9**|**10**|**9**|**9**|**5**|**3**| | ||||||||||||||||
2424

25-
*Last updated: 2020-12-08 22:40:00Z*
25+
*Last updated: 2020-12-09 18:56:00Z*
2626

2727
See all languages we support in our [Dockerfile](./Dockerfile).
2828

days/day-04/solutions/day04.zig

Lines changed: 171 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
1+
const std = @import("std");
2+
const mem = std.mem;
3+
const io = std.io;
4+
5+
const MAX_FILE_SIZE = 25_000;
6+
7+
const PassportField = enum(u8) {
8+
invalid = 0b00000000,
9+
cid = 0b00000001,
10+
byr = 0b00000010,
11+
iyr = 0b00000100,
12+
eyr = 0b00001000,
13+
hgt = 0b00010000,
14+
hcl = 0b00100000,
15+
ecl = 0b01000000,
16+
pid = 0b10000000,
17+
required = 0b11111110,
18+
19+
inline fn fromString(str: []const u8) PassportField {
20+
21+
if (mem.eql(u8, str, "byr")) return PassportField.byr;
22+
if (mem.eql(u8, str, "iyr")) return PassportField.iyr;
23+
if (mem.eql(u8, str, "eyr")) return PassportField.eyr;
24+
if (mem.eql(u8, str, "hgt")) return PassportField.hgt;
25+
if (mem.eql(u8, str, "hcl")) return PassportField.hcl;
26+
if (mem.eql(u8, str, "ecl")) return PassportField.ecl;
27+
if (mem.eql(u8, str, "pid")) return PassportField.pid;
28+
if (mem.eql(u8, str, "cid")) return PassportField.cid;
29+
30+
return PassportField.invalid;
31+
}
32+
33+
fn validate(self: PassportField, field_value: []const u8) !bool {
34+
// TODO: investigate if zig has regex in std (would probably be slower though)
35+
36+
switch(self) {
37+
.byr, .iyr, .eyr => {
38+
const value: i32 = try std.fmt.parseInt(i32, field_value, 10);
39+
40+
switch(self) {
41+
.byr => return value >= 1920 and value <= 2002,
42+
.iyr => return value >= 2010 and value <= 2020,
43+
.eyr => return value >= 2020 and value <= 2030,
44+
else => unreachable,
45+
}
46+
},
47+
48+
.hgt => {
49+
const m_index = field_value.len - 2;
50+
51+
const measure = field_value[m_index..field_value.len];
52+
const value = try std.fmt.parseInt(i32, field_value[0..m_index], 10);
53+
54+
if (mem.eql(u8, measure, "cm")) {
55+
return value >= 150 and value <= 193;
56+
}
57+
58+
if (mem.eql(u8, measure, "in")) {
59+
return value >= 59 and value <= 76;
60+
}
61+
62+
return false;
63+
},
64+
65+
.hcl => {
66+
if (field_value[0] != '#') return false;
67+
68+
var i: usize = 1;
69+
while (i < field_value.len) : (i += 1) {
70+
if (i > 6) return false;
71+
72+
switch (field_value[i]) {
73+
'a'...'f', '0'...'9' => continue,
74+
else => return false,
75+
}
76+
}
77+
78+
return true;
79+
},
80+
81+
.ecl => {
82+
if (mem.eql(u8, field_value, "amb")
83+
or mem.eql(u8, field_value, "blu")
84+
or mem.eql(u8, field_value, "brn")
85+
or mem.eql(u8, field_value, "gry")
86+
or mem.eql(u8, field_value, "grn")
87+
or mem.eql(u8, field_value, "hzl")
88+
or mem.eql(u8, field_value, "oth")
89+
) return true;
90+
91+
return false;
92+
},
93+
94+
.pid => {
95+
if (field_value.len != 9) return false;
96+
97+
var i: usize = 0;
98+
while(i < field_value.len) : (i += 1) {
99+
switch (field_value[i]) {
100+
'0'...'9' => continue,
101+
else => return false,
102+
}
103+
}
104+
105+
return true;
106+
},
107+
108+
else => return true,
109+
}
110+
111+
unreachable;
112+
}
113+
};
114+
115+
116+
pub inline fn countValidPass(bytes: []u8) struct {naive: u32, improved: u32} {
117+
var maybe_valid_passports: u32 = 0;
118+
var valid_passports: u32 = 0;
119+
120+
var fields_found_map: u8 = 0;
121+
var fields_valid: bool = true;
122+
var lines = mem.split(bytes, "\n");
123+
124+
line_read: while (lines.next()) |line| {
125+
126+
if (line.len <= 2) {
127+
if (fields_found_map >= @enumToInt(PassportField.required)) {
128+
maybe_valid_passports += 1;
129+
valid_passports += @boolToInt(fields_valid);
130+
}
131+
132+
fields_valid = true;
133+
fields_found_map = @enumToInt(PassportField.invalid);
134+
continue;
135+
}
136+
137+
var words = mem.split(line, " ");
138+
while (words.next()) |word| {
139+
var i: usize = 0;
140+
while (i < word.len) : (i += 1) {
141+
if (word[i] == ':') break;
142+
}
143+
144+
const field = PassportField.fromString(word[0..i]);
145+
fields_found_map |= @enumToInt(field);
146+
147+
const field_value = word[i + 1..word.len];
148+
const valid: bool = field.validate(field_value) catch false;
149+
fields_valid = fields_valid and valid;
150+
}
151+
}
152+
153+
return .{
154+
.naive = maybe_valid_passports,
155+
.improved = valid_passports
156+
};
157+
}
158+
159+
160+
pub fn main() anyerror!void {
161+
const in = std.io.getStdIn().reader();
162+
const stdout = std.io.getStdOut().writer();
163+
164+
var bytes: [MAX_FILE_SIZE]u8 = undefined;
165+
const length = try in.readAll(&bytes);
166+
167+
var valid_count = countValidPass(bytes[0..length]);
168+
169+
try stdout.print("{}\n", .{valid_count.naive});
170+
try stdout.print("{}\n", .{valid_count.improved});
171+
}

days/day-04/test.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ D=$(dirname $(realpath $0))
66
echo
77
echo "--- Day 4: Passport Processing ---"
88
$D/../../languages/c.sh $D/input.txt $D/output.txt $D/solutions/day04.c
9+
$D/../../languages/zig.sh $D/input.txt $D/output.txt $D/solutions/day04.zig
910
$D/../../languages/sml.sh $D/input.txt $D/output.txt $D/solutions/day04.sml
1011
$D/../../languages/go.sh $D/input.txt $D/output.txt $D/solutions/day04.tholok97.go
1112
$D/../../languages/python.sh $D/input.txt $D/output.txt $D/solutions/day04.klyve.py

days/day-05/solutions/day05.zig

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
const std = @import("std");
2+
const mem = std.mem;
3+
const io = std.io;
4+
const Allocator = std.mem.Allocator;
5+
const ArrayList = std.ArrayList;
6+
7+
const MAX_FILE_SIZE = 15_000;
8+
9+
fn LineSegmentParser(comptime low_char: u8, comptime high_char: u8, comptime start_max: f32) type {
10+
return struct {
11+
fn parse(line: []const u8, from: usize, to: usize) u32 {
12+
var prev: f32 = 0;
13+
var min: f32 = 0;
14+
var max: f32 = start_max;
15+
var i: usize = from;
16+
17+
while (i < to) : (i += 1) {
18+
const is_not_last: bool = to - i > 1;
19+
20+
var delta: f32 = if (is_not_last) @ceil((max - min) / 2.0) else 0;
21+
22+
switch (line[i]) {
23+
low_char => {
24+
max -= delta;
25+
prev = min;
26+
},
27+
high_char => {
28+
min += delta;
29+
prev = max;
30+
},
31+
else => unreachable // TODO: error
32+
}
33+
34+
}
35+
36+
return @floatToInt(u32, prev);
37+
}
38+
};
39+
}
40+
41+
pub fn main() anyerror!void {
42+
var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
43+
defer arena.deinit();
44+
const allocator = &arena.allocator;
45+
46+
const in = std.io.getStdIn().reader();
47+
const stdout = std.io.getStdOut().writer();
48+
49+
var bytes: [MAX_FILE_SIZE]u8 = undefined;
50+
const length = try in.readAll(&bytes);
51+
52+
comptime const row_extractor = LineSegmentParser('F', 'B', 127);
53+
comptime const col_extractor = LineSegmentParser('L', 'R', 7);
54+
55+
var list = try ArrayList(u32).initCapacity(allocator, 1000);
56+
try list.append(0);
57+
defer list.deinit();
58+
59+
var highest_id: u32 = 0;
60+
var it = mem.split(bytes[0..length], "\n");
61+
while (it.next()) |raw_line| {
62+
const line = mem.trim(u8, raw_line, &std.ascii.spaces);
63+
if (line.len == 0) continue; // empty line
64+
65+
const row_start: usize = line.len - 3;
66+
const row = row_extractor.parse(line, 0, row_start);
67+
const col = col_extractor.parse(line, row_start, line.len);
68+
69+
const id: u32 = row * 8 + col;
70+
if (id > highest_id) highest_id = id;
71+
72+
// build sorted list
73+
var i: usize = list.items.len - 1;
74+
while (i >= 0) : (i -= 1) {
75+
if (id > list.items[i]) {
76+
try list.insert(i + 1, id);
77+
break;
78+
}
79+
}
80+
}
81+
82+
var i: usize = 1;
83+
var prev_id: u32 = 0;
84+
var my_id: u32 = 0;
85+
while (i < list.items.len) : (i += 1) {
86+
if (list.items[i + 1] - list.items[i] == 2) {
87+
my_id = list.items[i] + 1;
88+
break;
89+
}
90+
91+
prev_id = list.items[i];
92+
}
93+
94+
try stdout.print("{}\n{}\n", .{highest_id, my_id});
95+
}

days/day-05/test.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ echo "--- Day 5: Boarding pass ---"
88
$D/../../languages/c.sh $D/input.txt $D/output.txt $D/solutions/day05.c
99
$D/../../languages/go.sh $D/input.txt $D/output.txt $D/solutions/day05.stektpotet.go
1010
$D/../../languages/go.sh $D/input.txt $D/output.txt $D/solutions/tholok97.go
11+
$D/../../languages/zig.sh $D/input.txt $D/output.txt $D/solutions/day05.zig
1112
$D/../../languages/sml.sh $D/input.txt $D/output.txt $D/solutions/day05.sml
1213
$D/../../languages/python.sh $D/input.txt $D/output.txt $D/solutions/day05.stektpotet.py
1314
$D/../../languages/python.sh $D/input.txt $D/output.txt $D/solutions/day05.preng.py

0 commit comments

Comments
 (0)