Skip to content

Commit

Permalink
Aoc day 7 (#431)
Browse files Browse the repository at this point in the history
  • Loading branch information
Akuli authored Dec 8, 2023
1 parent 9c73195 commit 44e6505
Show file tree
Hide file tree
Showing 6 changed files with 340 additions and 3 deletions.
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

0 comments on commit 44e6505

Please sign in to comment.