#import "File";
#import "Basic";
#import "String";
ONE :: #run to_u128(cast(u8)1);
ZERO :: #run to_u128(cast(u8)0);
solve_day4 :: (test: bool) {
contents := read_entire_file(ifx test then "inputs/day4_test.txt" else "inputs/day4.txt");
sections := split(contents, "\n\n");
draws := parse_draws(sections[0]);
defer array_free(draws);
bingo_cards: [..]Bingo_Card;
for 1..sections.count - 1 {
array_add(*bingo_cards, parse_bingo_card(sections[it]));
}
part1 := 0;
part2 := 0;
cards_won := 0;
drawn := ZERO;
for draw, d_i: draws {
drawn = drawn | (ONE << draw);
for *card: bingo_cards {
if !card.won && has_won(drawn, card) {
part2 = xx (draw * sum_of_marked(drawn, card));
if part1 == 0 {
part1 = part2;
}
card.won = true;
}
}
}
print("Part 1: %\n", part1);
print("Part 2: %\n", part2);
}
#scope_file
has_won :: (drawn: U128, card: Bingo_Card) -> bool {
for row: card.rows {
if (row & drawn) == row return true;
}
for column: card.columns {
if (column & drawn) == column return true;
}
return false;
}
sum_of_marked :: (drawn: U128, card: Bingo_Card) -> u64 {
f := ZERO;
result: u64 = 0;
for row: card.rows {
f = f | ((~drawn) & row);
}
for 0..127 {
if (f >> xx it) & ONE == ONE {
result += xx it;
}
}
return result;
}
parse_draws :: (line: string) -> []u8 {
numbers := split(line, ",");
result := NewArray(numbers.count, u8);
for numbers {
result[it_index] = string_to_int(it, 10, u8);
}
return result;
}
parse_bingo_card :: (card_section: string) -> Bingo_Card {
lines := split(card_section, "\n");
card: Bingo_Card;
for line, line_i: lines {
numbers := split(line, " ");
number_i := 0;
for number: numbers {
if number.count > 0 {
defer number_i += 1;
n := string_to_int(number, 10, u8);
number_bit := ONE << n;
card.rows[line_i] = card.rows[line_i] | number_bit;
card.columns[number_i] = card.columns[number_i] | number_bit;
}
}
}
return card;
}
Bingo_Card :: struct {
rows: [5]U128;
columns: [5]U128;
won: bool = false;
}
operator | :: (a: U128, b: U128) -> U128 {
return .{
low = a.low | b.low,
high = a.high | b.high,
};
}
operator & :: (a: U128, b: U128) -> U128 {
return .{
low = a.low & b.low,
high = a.high & b.high,
};
}
operator ~ :: (a: U128) -> U128 {
return .{ high = ~a.high, low = ~a.low };
}