const std = @import("std");
const path = "../data/day08/input.txt";
const RetType = u20;
const DigitType = u7;
const pattern_pieces = 10;
const output_pieces = 4;
const input_lines = 200;
const InputLine = struct {
// patterns
patterns: [pattern_pieces]DigitType = [_]DigitType{0} ** pattern_pieces,
// output
outputs: [output_pieces]DigitType = [_]DigitType{0} ** output_pieces,
// 2, 3, 5
five_len: [3]DigitType = [_]DigitType{0} ** 3,
// 0, 6, 9
six_len: [3]DigitType = [_]DigitType{0} ** 3,
};
const FullInput = [input_lines]InputLine;
pub fn parseInput() anyerror!FullInput {
const input = @embedFile(path);
var lines = std.mem.tokenize(u8, input, "\n");
// This does not run the InputLine initialization
var inl: FullInput = undefined;
var i: usize = 0;
while (lines.next()) |line| : (i += 1) {
inl[i] = InputLine{};
var pattern_output = std.mem.tokenize(u8, line, "|");
var patts = std.mem.tokenize(u8, pattern_output.next().?, " ");
var outs = std.mem.tokenize(u8, pattern_output.next().?, " ");
// collect outs
var idx: usize = 0;
while (outs.next()) |out| : (idx += 1) {
for (out) |ch| {
inl[i].outputs[idx] |= @as(DigitType, 1) << @intCast(u3, ch - 'a');
}
}
// collect patterns
var five: usize = 0;
var six: usize = 0;
while (patts.next()) |patt| {
var curr: *u7 = undefined;
switch (patt.len) {
2 => curr = &inl[i].patterns[1],
4 => curr = &inl[i].patterns[4],
3 => curr = &inl[i].patterns[7],
7 => {
inl[i].patterns[8] = 0b1111111;
continue;
},
5 => {
curr = &inl[i].five_len[five];
five += 1;
},
6 => {
curr = &inl[i].six_len[six];
six += 1;
},
else => {
unreachable;
},
}
for (patt) |ch| {
curr.* |= @as(DigitType, 1) << @intCast(u3, ch - 'a');
}
}
}
return inl;
}
pub fn second() anyerror!RetType {
var input = try parseInput();
var sum: RetType = 0;
for (input) |*line| {
// 1. deduct 3 from 1
for (line.five_len) |five| {
if (five & line.patterns[1] == line.patterns[1]) {
line.patterns[3] = five;
break;
}
}
// 2. deduct 9 from 4
for (line.six_len) |six| {
if (six & line.patterns[4] == line.patterns[4]) {
line.patterns[9] = six;
break;
}
}
// 3. from six_len (discard 9!) the matching with 1 is 0, the other is 6
for (line.six_len) |six| {
if (six == line.patterns[9]) continue;
if (six & line.patterns[1] == line.patterns[1]) {
line.patterns[0] = six;
} else {
line.patterns[6] = six;
}
}
// 4. from five_len (discard 3!) the matching with 9 is 5, the other is 2
for (line.five_len) |five| {
if (five == line.patterns[3]) continue;
if (five & line.patterns[9] == five) {
line.patterns[5] = five;
} else {
line.patterns[2] = five;
}
}
// decode output
var ret: RetType = 0;
for (line.outputs) |out, idx| {
for (line.patterns) |patt, i| {
if (out == patt) {
ret += @intCast(RetType, i) *
try std.math.powi(RetType, 10, @intCast(RetType, 3 - idx));
break;
}
}
}
sum += ret;
}
return sum;
}
pub fn main() anyerror!void {
var timer = try std.time.Timer.start();
const ret = try second();
const s = timer.lap() / 1000;
try std.testing.expectEqual(ret, @as(RetType, 1023686));
std.debug.print("Day 8 \tsecond part result: {d} \ttime: {d}µs\n", .{ ret, s });
}
test "day08b" {
try std.testing.expectEqual(@as(RetType, 1023686), try second());
}