Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Aoc day 7 #431

Merged
merged 5 commits into from
Dec 8, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion examples/aoc2023/day02/part1.jou
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion examples/aoc2023/day02/part2.jou
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
148 changes: 148 additions & 0 deletions examples/aoc2023/day07/part1.jou
Original file line number Diff line number Diff line change
@@ -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
184 changes: 184 additions & 0 deletions examples/aoc2023/day07/part2.jou
Original file line number Diff line number Diff line change
@@ -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
5 changes: 5 additions & 0 deletions examples/aoc2023/day07/sampleinput.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
32T3K 765
T55J5 684
KK677 28
KTJJT 220
QQQJA 483
2 changes: 1 addition & 1 deletion valgrind-suppressions.sup
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
{
<llvm functions>
Memcheck:Leak
match-leak-kinds: reachable
match-leak-kinds: reachable,possible
...
obj:*/libLLVM*.so.*
...
Expand Down