diff --git a/examples/aoc2023/day02/part1.jou b/examples/aoc2023/day02/part1.jou index 5e44a301..e6ad8ec8 100644 --- a/examples/aoc2023/day02/part1.jou +++ b/examples/aoc2023/day02/part1.jou @@ -19,7 +19,7 @@ def game_is_possible(game_data: byte*) -> bool: n: int color: byte[10] - assert sscanf(chunk, "%d %10s", &n, color) == 2 + assert sscanf(chunk, "%d %9s", &n, color) == 2 if strcmp(color, "red") == 0 and n > 12: return False diff --git a/examples/aoc2023/day02/part2.jou b/examples/aoc2023/day02/part2.jou index 4517320e..37bb5c11 100644 --- a/examples/aoc2023/day02/part2.jou +++ b/examples/aoc2023/day02/part2.jou @@ -11,7 +11,7 @@ class Game: def update(self, text: byte*) -> void: n: int color: byte[10] - assert sscanf(text, "%d %10s", &n, color) == 2 + assert sscanf(text, "%d %9s", &n, color) == 2 if strcmp(color, "red") == 0 and n > self->red: self->red = n diff --git a/examples/aoc2023/day07/part1.jou b/examples/aoc2023/day07/part1.jou new file mode 100644 index 00000000..147b52ec --- /dev/null +++ b/examples/aoc2023/day07/part1.jou @@ -0,0 +1,148 @@ +import "stdlib/io.jou" +import "stdlib/str.jou" + +class Hand: + letters: byte[6] + bid: int + + def count(self, letter: byte) -> int: + n = 0 + for i = 0; i < 5; i++: + if self->letters[i] == letter: + n++ + return n + + def all_same(self) -> bool: + return self->count(self->letters[0]) == 5 + + def all_but_one_same(self) -> bool: + return self->count(self->letters[0]) == 4 or self->count(self->letters[1]) == 4 + + def three_same_and_two_same(self) -> bool: + # ensure that every count is either 3 or 2 + for i = 0; i < 5; i++: + n = self->count(self->letters[i]) + if n != 3 and n != 2: + return False + return True + + def three_same_two_distinct(self) -> bool: + # ensure that every count is either 3 or 1, and count 3 appears + found3 = False + for i = 0; i < 5; i++: + n = self->count(self->letters[i]) + if n != 3 and n != 1: + return False + if n == 3: + found3 = True + return found3 + + def two_pairs_one_distinct(self) -> bool: + # ensure that every count is either 2 or 1, and count 1 appears only once + count1 = 0 + for i = 0; i < 5; i++: + n = self->count(self->letters[i]) + if n != 2 and n != 1: + return False + if n == 1: + count1++ + return count1 == 1 + + def one_pair(self) -> bool: + # ensure that every count is either 2 or 1, and exactly 2 cards have count 2 + count2 = 0 + for i = 0; i < 5; i++: + n = self->count(self->letters[i]) + if n != 2 and n != 1: + return False + if n == 2: + count2++ + return count2 == 2 + + def all_distinct(self) -> bool: + for i = 0; i < 5; i++: + if self->count(self->letters[i]) != 1: + return False + return True + + def hand_type_strength(self) -> int: + # check that i did this right, exactly one should be true + # return index of true in list + bools = [ + self->all_distinct(), + self->one_pair(), + self->two_pairs_one_distinct(), + self->three_same_two_distinct(), + self->three_same_and_two_same(), + self->all_but_one_same(), + self->all_same(), + ] + + result = -1 + for i = 0; i < sizeof(bools)/sizeof(bools[0]); i++: + if bools[i]: + assert result == -1 + result = i + + assert result != -1 + return result + + # Return value: + # +1 if self > other + # 0 if self == other + # -1 if self < other + def compare(self, other: Hand*) -> int: + if self->hand_type_strength() > other->hand_type_strength(): + return 1 + if self->hand_type_strength() < other->hand_type_strength(): + return -1 + + for i = 0; i < 5; i++: + s = "23456789TJQKA" + self_idx_ptr = strchr(s, self->letters[i]) + other_idx_ptr = strchr(s, other->letters[i]) + assert self_idx_ptr != NULL and other_idx_ptr != NULL + if self_idx_ptr > other_idx_ptr: + return 1 + if self_idx_ptr < other_idx_ptr: + return -1 + + return 0 + + +def swap(h1: Hand*, h2: Hand*) -> void: + temp = *h1 + *h1 = *h2 + *h2 = temp + + +def sort(hands: Hand*, nhands: int) -> void: + # bubble sort go brrr + for sorted_part_len = 1; sorted_part_len < nhands; sorted_part_len++: + i = sorted_part_len + while i > 0 and hands[i-1].compare(&hands[i]) == 1: + swap(&hands[i-1], &hands[i]) + i-- + + +def main() -> int: + hands: Hand[2000] + nhands = 0 + + f = fopen("sampleinput.txt", "r") + assert f != NULL + + while fscanf(f, "%5s %d\n", &hands[nhands].letters, &hands[nhands].bid) == 2: + nhands++ + assert nhands < sizeof(hands)/sizeof(hands[0]) + + fclose(f) + + sort(hands, nhands) + + sum = 0 + for i = 0; i < nhands; i++: + sum += (i+1) * hands[i].bid + printf("%d\n", sum) # Output: 6440 + + return 0 diff --git a/examples/aoc2023/day07/part2.jou b/examples/aoc2023/day07/part2.jou new file mode 100644 index 00000000..7b69eb59 --- /dev/null +++ b/examples/aoc2023/day07/part2.jou @@ -0,0 +1,184 @@ +import "stdlib/io.jou" +import "stdlib/str.jou" +import "stdlib/mem.jou" + +class Hand: + letters: byte[6] + bid: int + + # optimization to speed up sorting + cached_hand_type_strength: int + + def count(self, letter: byte) -> int: + n = 0 + for i = 0; i < 5; i++: + if self->letters[i] == letter: + n++ + return n + + def all_same(self) -> bool: + return self->count(self->letters[0]) == 5 + + def all_but_one_same(self) -> bool: + return self->count(self->letters[0]) == 4 or self->count(self->letters[1]) == 4 + + def three_same_and_two_same(self) -> bool: + # ensure that every count is either 3 or 2 + for i = 0; i < 5; i++: + n = self->count(self->letters[i]) + if n != 3 and n != 2: + return False + return True + + def three_same_two_distinct(self) -> bool: + # ensure that every count is either 3 or 1, and count 3 appears + found3 = False + for i = 0; i < 5; i++: + n = self->count(self->letters[i]) + if n != 3 and n != 1: + return False + if n == 3: + found3 = True + return found3 + + def two_pairs_one_distinct(self) -> bool: + # ensure that every count is either 2 or 1, and count 1 appears only once + count1 = 0 + for i = 0; i < 5; i++: + n = self->count(self->letters[i]) + if n != 2 and n != 1: + return False + if n == 1: + count1++ + return count1 == 1 + + def one_pair(self) -> bool: + # ensure that every count is either 2 or 1, and exactly 2 cards have count 2 + count2 = 0 + for i = 0; i < 5; i++: + n = self->count(self->letters[i]) + if n != 2 and n != 1: + return False + if n == 2: + count2++ + return count2 == 2 + + def all_distinct(self) -> bool: + for i = 0; i < 5; i++: + if self->count(self->letters[i]) != 1: + return False + return True + + def hand_type_strength_without_J_special_casing(self) -> int: + # check that i did this right, exactly one should be true + # return index of true in list + bools = [ + self->all_distinct(), + self->one_pair(), + self->two_pairs_one_distinct(), + self->three_same_two_distinct(), + self->three_same_and_two_same(), + self->all_but_one_same(), + self->all_same(), + ] + + result = -1 + for i = 0; i < sizeof(bools)/sizeof(bools[0]); i++: + if bools[i]: + assert result == -1 + result = i + + assert result != -1 + return result + + def hand_type_strength(self) -> int: + if self->cached_hand_type_strength != -1: + return self->cached_hand_type_strength + + variations: Hand* = malloc(sizeof(variations[0])) + variations[0] = *self + nvariations = 1 + + for i = 0; i < 5; i++: + if self->letters[i] == 'J': + # Duplicate each existing variation 13 times + nvariations *= 13 + variations = realloc(variations, sizeof(variations)[0] * nvariations) + for isrc = nvariations/13 - 1; isrc >= 0; isrc--: + for idest = 13*isrc; idest < 13*(isrc+1); idest++: + variations[idest] = variations[isrc] + + # Replace i'th letter in every possible way + for k = 0; k < nvariations; k++: + variations[k].letters[i] = "J23456789TQKA"[k % 13] + + best = -1 + for i = 0; i < nvariations; i++: + value = variations[i].hand_type_strength_without_J_special_casing() + if value > best: + best = value + + free(variations) + self->cached_hand_type_strength = best + return best + + # Return value: + # +1 if self > other + # 0 if self == other + # -1 if self < other + def compare(self, other: Hand*) -> int: + if self->hand_type_strength() > other->hand_type_strength(): + return 1 + if self->hand_type_strength() < other->hand_type_strength(): + return -1 + + for i = 0; i < 5; i++: + s = "J23456789TQKA" + self_idx_ptr = strchr(s, self->letters[i]) + other_idx_ptr = strchr(s, other->letters[i]) + assert self_idx_ptr != NULL and other_idx_ptr != NULL + if self_idx_ptr > other_idx_ptr: + return 1 + if self_idx_ptr < other_idx_ptr: + return -1 + + return 0 + + +def swap(h1: Hand*, h2: Hand*) -> void: + temp = *h1 + *h1 = *h2 + *h2 = temp + + +def sort(hands: Hand*, nhands: int) -> void: + # bubble sort go brrr + for sorted_part_len = 1; sorted_part_len < nhands; sorted_part_len++: + i = sorted_part_len + while i > 0 and hands[i-1].compare(&hands[i]) == 1: + swap(&hands[i-1], &hands[i]) + i-- + + +def main() -> int: + hands: Hand[2000] + nhands = 0 + + f = fopen("sampleinput.txt", "r") + assert f != NULL + + while fscanf(f, "%5s %d\n", &hands[nhands].letters, &hands[nhands].bid) == 2: + hands[nhands].cached_hand_type_strength = -1 + nhands++ + assert nhands < sizeof(hands)/sizeof(hands[0]) + + fclose(f) + + sort(hands, nhands) + + sum = 0 + for i = 0; i < nhands; i++: + sum += (i+1) * hands[i].bid + printf("%d\n", sum) # Output: 5905 + + return 0 diff --git a/examples/aoc2023/day07/sampleinput.txt b/examples/aoc2023/day07/sampleinput.txt new file mode 100644 index 00000000..e3500c3b --- /dev/null +++ b/examples/aoc2023/day07/sampleinput.txt @@ -0,0 +1,5 @@ +32T3K 765 +T55J5 684 +KK677 28 +KTJJT 220 +QQQJA 483 diff --git a/valgrind-suppressions.sup b/valgrind-suppressions.sup index 4ca6162c..e189cd5e 100644 --- a/valgrind-suppressions.sup +++ b/valgrind-suppressions.sup @@ -20,7 +20,7 @@ { Memcheck:Leak - match-leak-kinds: reachable + match-leak-kinds: reachable,possible ... obj:*/libLLVM*.so.* ...