const std = @import("std");
const path = "data/day03/input.txt";
const retSize = u24;
const lineSize = getLineSize();
fn first() anyerror!retSize {
const input = @embedFile(path);
var lines = std.mem.split(u8, input, "\n");
var ones: [lineSize]retSize = undefined;
var zeros: [lineSize]retSize = undefined;
while (lines.next()) |line| {
for (line) |bit, idx| {
if (bit == '0') {
zeros[idx] += 1;
} else {
ones[idx] += 1;
}
}
}
var gammaRate: [lineSize]u8 = undefined;
var epsilonRate: [lineSize]u8 = undefined;
for (ones) |val, i| {
if (val > zeros[i]) {
gammaRate[i] = '1';
epsilonRate[i] = '0';
} else {
gammaRate[i] = '0';
epsilonRate[i] = '1';
}
}
const gr = try std.fmt.parseUnsigned(retSize, &gammaRate, 2);
const er = try std.fmt.parseUnsigned(retSize, &epsilonRate, 2);
return gr * er;
}
fn second() anyerror!retSize {
const input = @embedFile(path);
var lines = std.mem.tokenize(u8, input, "\n");
var buffer: [1000 * lineSize * 100]u8 = undefined;
var fba = std.heap.FixedBufferAllocator.init(&buffer);
const allocator = fba.allocator();
var oxigen: std.BufSet = std.BufSet.init(allocator);
defer oxigen.deinit();
var co2: std.BufSet = std.BufSet.init(allocator);
defer co2.deinit();
while (lines.next()) |line| {
try oxigen.insert(line);
try co2.insert(line);
}
const ox = try getOxigenRating(&oxigen);
const co = try getCO2Rating(&co2);
return ox * co;
}
fn getOxigenRating(oxigen: *std.BufSet) anyerror!retSize {
var idx: usize = 0;
while (oxigen.count() > 1) : (idx += 1) {
var ones: retSize = 0;
var zeros: retSize = 0;
// count ones and zeros
var it = oxigen.iterator();
while (it.next()) |line| {
if (line.*[idx] == '1') {
ones += 1;
} else if (line.*[idx] == '0') {
zeros += 1;
} else unreachable;
}
it = oxigen.iterator(); // reset iterator
while (it.next()) |line| {
if (ones >= zeros) {
if (line.*[idx] != '1') {
oxigen.remove(line.*);
}
} else {
if (line.*[idx] != '0') {
oxigen.remove(line.*);
}
}
}
}
return try std.fmt.parseUnsigned(retSize, oxigen.iterator().next().?.*, 2);
}
fn getCO2Rating(co2: *std.BufSet) anyerror!retSize {
var idx: usize = 0;
while (co2.count() > 1) : (idx += 1) {
var ones: retSize = 0;
var zeros: retSize = 0;
// count ones and zeros
var it = co2.iterator();
while (it.next()) |line| {
if (line.*[idx] == '1') {
ones += 1;
} else if (line.*[idx] == '0') {
zeros += 1;
} else unreachable;
}
it = co2.iterator(); // reset iterator
while (it.next()) |line| {
if (zeros <= ones) {
if (line.*[idx] != '0') {
co2.remove(line.*);
}
} else {
if (line.*[idx] != '1') {
co2.remove(line.*);
}
}
}
}
return try std.fmt.parseUnsigned(retSize, co2.iterator().next().?.*, 2);
}
fn getLineSize() usize {
const input = @embedFile(path);
var ret: usize = 0;
for (input) |bit, idx| {
if (bit == '\n') {
ret = idx;
break;
}
}
return ret;
}
pub fn main() anyerror!void {
var timer = try std.time.Timer.start();
_ = try first();
const f = timer.lap() / 1000;
_ = try second();
const s = timer.lap() / 1000;
std.debug.print("Day 3 \t\tfirst: {d}us \t\tsecond: {d}us\n", .{ f, s });
}
test "first" {
try std.testing.expectEqual(@as(retSize, 3847100), try first(std.testing.allocator));
}
test "second" {
try std.testing.expectEqual(@as(retSize, 4105235), try second());
}