Skip to content

Commit

Permalink
aoc day 7
Browse files Browse the repository at this point in the history
  • Loading branch information
Akuli committed Dec 8, 2023
1 parent 7d0df65 commit 4b9598c
Show file tree
Hide file tree
Showing 2 changed files with 199 additions and 1 deletion.
2 changes: 1 addition & 1 deletion examples/aoc2023/day07/part1.jou
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ def main() -> int:
hands: Hand[2000]
nhands = 0

f = fopen("input.txt", "r")
f = fopen("sampleinput.txt", "r")
assert f != NULL

while fscanf(f, "%5s %d\n", &hands[nhands].letters, &hands[nhands].bid) == 2:
Expand Down
198 changes: 198 additions & 0 deletions examples/aoc2023/day07/part2.jou
Original file line number Diff line number Diff line change
@@ -0,0 +1,198 @@
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 find_distinct_letters(self, count: int*, distinct_letters: byte[5]*) -> void:
*count = 0

for i = 0; i < 5; i++:
seen = False
for k = 0; k < *count; k++:
if (*distinct_letters)[k] == self->letters[i]:
seen = True
break
if not seen:
(*distinct_letters)[(*count)++] = self->letters[i]

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++:
printf("sort: %d/%d\n", sorted_part_len, nhands)
fflush(stdout)
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("input.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)

return 0

0 comments on commit 4b9598c

Please sign in to comment.