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

Aoc2024 day 21 #542

Merged
merged 23 commits into from
Jan 4, 2025
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
187 changes: 187 additions & 0 deletions examples/aoc2024/day21/part1.jou
Original file line number Diff line number Diff line change
@@ -0,0 +1,187 @@
import "stdlib/io.jou"
import "stdlib/ascii.jou"
import "stdlib/math.jou"
import "stdlib/mem.jou"
import "stdlib/str.jou"


class List:
ptr: byte[100]*
length: int
alloc: int

def append(self, string: byte*) -> None:
if self->length == self->alloc:
if self->alloc == 0:
self->alloc = 4
else:
self->alloc *= 2
self->ptr = realloc(self->ptr, sizeof(self->ptr[0]) * self->alloc)
assert self->ptr != NULL

assert strlen(string) < sizeof(self->ptr[0])
strcpy(self->ptr[self->length++], string)

def dedup(self) -> None:
i = 0
while i < self->length:
exists_before = False
for k = 0; k < i; k++:
if strcmp(self->ptr[k], self->ptr[i]) == 0:
exists_before = True
break
if exists_before:
self->ptr[k] = self->ptr[--self->length]
else:
i++


class KeyPad:
rows: byte[3][4]

def find_button(self, button_label: byte) -> int[2]:
for x = 0; x < 3; x++:
for y = 0; y < 4; y++:
if self->rows[y][x] == button_label:
return [x, y]
assert False

def goes_to_blank(self, directions: byte*) -> bool:
pos = self->find_button('A')
x = pos[0]
y = pos[1]

for p = directions; *p != '\0'; p++:
if *p == '<':
x--
elif *p == '>':
x++
elif *p == '^':
y--
elif *p == 'v':
y++
else:
assert *p == 'A'
continue

assert 0 <= x and x < 3
assert 0 <= y and y < 4
if self->rows[y][x] == ' ':
return True

return False

def get_presses(self, what_to_write: byte*) -> List:
result = List{}
result.append("")

for p = &what_to_write[0]; *p != '\0'; p++:
if p == &what_to_write[0]:
prev = 'A'
else:
prev = p[-1]

pos1 = self->find_button(prev)
pos2 = self->find_button(*p)

dx = pos2[0] - pos1[0]
dy = pos2[1] - pos1[1]

h: byte[100] = ""
v: byte[100] = ""
if dx < 0:
memset(&h, '<', abs(dx))
else:
memset(&h, '>', dx)
if dy < 0:
memset(&v, '^', abs(dy))
else:
memset(&v, 'v', dy)

result2 = List{}
for i = 0; i < result.length; i++:
# Do horizontal and vertical moves in both possible orders. This
# may affect other robots, because their arms move less if we use
# consecutive presses in the same direction.
assert strlen(result.ptr[i]) + strlen(h) + strlen(v) + strlen("A") < 100

h_then_v: byte[100] = ""
strcat(h_then_v, result.ptr[i])
strcat(h_then_v, h)
strcat(h_then_v, v)
strcat(h_then_v, "A")

v_then_h: byte[100] = ""
strcat(v_then_h, result.ptr[i])
strcat(v_then_h, v)
strcat(v_then_h, h)
strcat(v_then_h, "A")

if not self->goes_to_blank(h_then_v):
result2.append(h_then_v)
if not self->goes_to_blank(v_then_h):
result2.append(v_then_h)

free(result.ptr)
result = result2
result.dedup() # must be done right away so we don't run out of memory

return result

def get_presses_for_each(self, things_we_could_write: List) -> List:
result = List{}
for i = 0; i < things_we_could_write.length; i++:
adding = self->get_presses(things_we_could_write.ptr[i])
for k = 0; k < adding.length; k++:
result.append(adding.ptr[k])
free(adding.ptr)

result.dedup()
return result


def main() -> int:
numeric_keypad = KeyPad{rows = [
['7', '8', '9'],
['4', '5', '6'],
['1', '2', '3'],
[' ', '0', 'A'],
]}

arrow_keypad = KeyPad{rows = [
[' ', '^', 'A'],
['<', 'v', '>'],
[' ', ' ', ' '],
[' ', ' ', ' '],
]}

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

result = 0

line: byte[20]
while fgets(line, sizeof(line) as int, f) != NULL:
trim_ascii_whitespace(line)

presses = numeric_keypad.get_presses(line)

repeat = 2
while repeat --> 0:
presses2 = arrow_keypad.get_presses_for_each(presses)
free(presses.ptr)
presses = presses2

assert presses.length != 0

shortest_len = strlen(presses.ptr[0]) as int
for i = 1; i < presses.length; i++:
shortest_len = min(shortest_len, strlen(presses.ptr[i]) as int)
free(presses.ptr)

result += shortest_len * atoi(line)

printf("%d\n", result) # Output: 126384

fclose(f)
return 0
Loading
Loading