Skip to content

Commit

Permalink
AoC days 15, 16, 17 (#465)
Browse files Browse the repository at this point in the history
  • Loading branch information
Akuli authored Dec 18, 2023
1 parent 36d955a commit 0509fe6
Show file tree
Hide file tree
Showing 9 changed files with 648 additions and 0 deletions.
31 changes: 31 additions & 0 deletions examples/aoc2023/day15/part1.jou
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import "stdlib/io.jou"
import "stdlib/mem.jou"


def main() -> int:
f = fopen("sampleinput.txt", "r")
assert f != NULL

huge = 100000
s: byte* = malloc(huge)
assert s != NULL
assert fgets(s, huge, f) != NULL
fclose(f)

h = 0 as byte
result = 0

for p = s; *p != '\0' and *p != '\n'; p++:
if *p == ',':
result += h
h = 0 as byte
else:
h += *p
h *= 17 as byte

result += h
printf("%d\n", result) # Output: 1320

free(s)

return 0
88 changes: 88 additions & 0 deletions examples/aoc2023/day15/part2.jou
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
import "stdlib/ascii.jou"
import "stdlib/io.jou"
import "stdlib/mem.jou"
import "stdlib/str.jou"


class Lens:
label: byte[50]
value: int


class Box:
lenses: Lens[100]
nlenses: int

def set(self, label: byte*, value: int) -> None:
for i = 0; i < self->nlenses; i++:
if strcmp(self->lenses[i].label, label) == 0:
self->lenses[i].value = value
return

lens = Lens{value=value}
assert strlen(label) < sizeof(lens.label)
strcpy(lens.label, label)

assert self->nlenses < sizeof(self->lenses)/sizeof(self->lenses[0])
self->lenses[self->nlenses++] = lens

def remove_by_label(self, label: byte*) -> None:
for i = 0; i < self->nlenses; i++:
if strcmp(self->lenses[i].label, label) == 0:
memmove(&self->lenses[i], &self->lenses[i+1], (--self->nlenses - i) * sizeof(self->lenses[0]))
break


def hash(s: byte*) -> byte:
result = 0 as byte
for p = s; *p != '\0'; p++:
result += *p
result *= 17 as byte
return result


def main() -> int:
f = fopen("sampleinput.txt", "r")
assert f != NULL

huge = 100000
s: byte* = malloc(huge)
assert s != NULL
assert fgets(s, huge, f) != NULL
fclose(f)

for p = s; *p != '\0'; p++:
if *p == ',':
*p = ' '
commands = split_by_ascii_whitespace(s)

boxes: Box[256]* = malloc(sizeof(*boxes))
assert boxes != NULL
memset(boxes, 0, sizeof(*boxes))

for commandptr = commands; *commandptr != NULL; commandptr++:
command = *commandptr

if ends_with(command, "-"):
command[strlen(command)-1] = '\0'
box = &(*boxes)[hash(command)]
box->remove_by_label(command)
else:
eq = strchr(command, '=')
assert eq != NULL
*eq = '\0'
box = &(*boxes)[hash(command)]
box->set(command, atoi(&eq[1]))

free(commands)
free(s)

result = 0
for box_num = 0; box_num < 256; box_num++:
box = &(*boxes)[box_num]
for slot_num = 0; slot_num < box->nlenses; slot_num++:
result += (box_num + 1) * (slot_num + 1) * box->lenses[slot_num].value

printf("%d\n", result) # Output: 145
free(boxes)
return 0
1 change: 1 addition & 0 deletions examples/aoc2023/day15/sampleinput.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
rn=1,cm-,qp=3,cm=2,qp-,pc=4,ot=9,ab=5,pc-,pc=6,ot=7
111 changes: 111 additions & 0 deletions examples/aoc2023/day16/part1.jou
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
import "stdlib/math.jou"
import "stdlib/io.jou"
import "stdlib/mem.jou"
import "../grid.jou"


# Returns same direction twice, if there is only one direction where to go
def get_new_directions(old_dir: int[2], character: byte) -> int[2][2]:
dx = old_dir[0]
dy = old_dir[1]

assert (abs(dx) == 1 and dy == 0) or (abs(dy) == 1 and dx == 0)

if character == '.' or (character == '|' and dx == 0) or (character == '-' and dy == 0):
return [old_dir, old_dir]

# Reflect across line y=x: from high school math, we know this swaps x and y coordinates
if character == '\\':
return [[dy, dx], [dy, dx]]

# Reflect across line y=-x: can swap x and y, and then rotate 180deg.
# This is because rotating the mirror 90deg rotates light 180deg.
if character == '/':
return [[-dy, -dx], [-dy, -dx]]

# split
if character == '|' and dy == 0:
return [[0, -1], [0, 1]]
if character == '-' and dx == 0:
return [[-1, 0], [1, 0]]

assert False


class LightBeam:
location: int[2]
direction: int[2]


def direction_to_int(d: int[2]) -> int:
if d[0] == 0 and d[1] == -1:
return 0
if d[0] == 0 and d[1] == 1:
return 1
if d[0] == -1 and d[1] == 0:
return 2
if d[0] == 1 and d[1] == 0:
return 3
assert False


# How return value works:
# (*returnvalue)[x][y][direction_to_int(dir)] = True, if there was beam at (x,y) going in direction.
def run_beam(grid: Grid*, start_beam: LightBeam) -> bool[4][200][200]*:
assert grid->width < 200
assert grid->height < 200
result: bool[4][200][200]* = calloc(1, sizeof(*result))
assert result != NULL

todo: LightBeam* = malloc(sizeof(todo[0]))
todo[0] = start_beam
todo_len = 1
todo_alloc = 1

while todo_len > 0:
# Make sure there is room for another beam
if todo_alloc == todo_len:
todo_alloc *= 2
todo = realloc(todo, sizeof(todo[0]) * todo_alloc)
assert todo != NULL

beam = todo[--todo_len]
x = beam.location[0]
y = beam.location[1]
ptr = &(*result)[x][y][direction_to_int(beam.direction)]
if *ptr:
# we have already handled this beam --> prevent getting stuck in loop
continue
*ptr = True

next_dirs = get_new_directions(beam.direction, grid->get([x, y]))
for i = 0; i < 2; i++:
dir = next_dirs[i]
location = [beam.location[0] + dir[0], beam.location[1] + dir[1]]
if grid->is_in_bounds(location):
todo[todo_len++] = LightBeam{location = location, direction = dir}

free(todo)
return result


def main() -> int:
f = fopen("sampleinput.txt", "r")
assert f != NULL
grid = read_grid_from_file(f)
fclose(f)

visited = run_beam(&grid, LightBeam{location = [0,0], direction = [1,0]})

n = 0
for x = 0; x < 200; x++:
for y = 0; y < 200; y++:
for i = 0; i < 4; i++:
if (*visited)[x][y][i]:
n++
break
printf("%d\n", n) # Output: 46

free(grid.data)
free(visited)
return 0
129 changes: 129 additions & 0 deletions examples/aoc2023/day16/part2.jou
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
import "stdlib/math.jou"
import "stdlib/io.jou"
import "stdlib/mem.jou"
import "../grid.jou"


# Returns same direction twice, if there is only one direction where to go
def get_new_directions(old_dir: int[2], character: byte) -> int[2][2]:
dx = old_dir[0]
dy = old_dir[1]

assert (abs(dx) == 1 and dy == 0) or (abs(dy) == 1 and dx == 0)

if character == '.' or (character == '|' and dx == 0) or (character == '-' and dy == 0):
return [old_dir, old_dir]

# Reflect across line y=x: from high school math, we know this swaps x and y coordinates
if character == '\\':
return [[dy, dx], [dy, dx]]

# Reflect across line y=-x: can swap x and y, and then rotate 180deg.
# This is because rotating the mirror 90deg rotates light 180deg.
if character == '/':
return [[-dy, -dx], [-dy, -dx]]

# split
if character == '|' and dy == 0:
return [[0, -1], [0, 1]]
if character == '-' and dx == 0:
return [[-1, 0], [1, 0]]

assert False


class LightBeam:
location: int[2]
direction: int[2]


def direction_to_int(d: int[2]) -> int:
if d[0] == 0 and d[1] == -1:
return 0
if d[0] == 0 and d[1] == 1:
return 1
if d[0] == -1 and d[1] == 0:
return 2
if d[0] == 1 and d[1] == 0:
return 3
assert False


def run_beam(grid: Grid*, start_beam: LightBeam) -> int:
assert grid->width < 200
assert grid->height < 200

# How visited array works:
# (*visited)[x][y][direction_to_int(dir)] = True, if there was beam at (x,y) going in direction.
visited: bool[4][200][200]* = calloc(1, sizeof(*visited))
assert visited != NULL

todo: LightBeam* = malloc(sizeof(todo[0]))
todo[0] = start_beam
todo_len = 1
todo_alloc = 1

while todo_len > 0:
# Make sure there is room for another beam
if todo_alloc == todo_len:
todo_alloc *= 2
todo = realloc(todo, sizeof(todo[0]) * todo_alloc)
assert todo != NULL

beam = todo[--todo_len]
x = beam.location[0]
y = beam.location[1]
ptr = &(*visited)[x][y][direction_to_int(beam.direction)]
if *ptr:
# we have already handled this beam --> prevent getting stuck in loop
continue
*ptr = True

next_dirs = get_new_directions(beam.direction, grid->get([x, y]))
for i = 0; i < 2; i++:
dir = next_dirs[i]
location = [beam.location[0] + dir[0], beam.location[1] + dir[1]]
if grid->is_in_bounds(location):
todo[todo_len++] = LightBeam{location = location, direction = dir}

free(todo)

n = 0
for x = 0; x < 200; x++:
for y = 0; y < 200; y++:
for i = 0; i < 4; i++:
if (*visited)[x][y][i]:
n++
break

free(visited)
return n


def main() -> int:
f = fopen("sampleinput.txt", "r")
assert f != NULL
grid = read_grid_from_file(f)
fclose(f)

best = 0

for x = 0; x < grid.width; x++:
n = run_beam(&grid, LightBeam{location = [x, 0], direction = [0, 1]})
if n > best:
best = n
n = run_beam(&grid, LightBeam{location = [x, grid.height - 1], direction = [0, -1]})
if n > best:
best = n

for y = 0; y < grid.height; y++:
n = run_beam(&grid, LightBeam{location = [0, y], direction = [1, 0]})
if n > best:
best = n
n = run_beam(&grid, LightBeam{location = [grid.width - 1, y], direction = [-1, 0]})
if n > best:
best = n

printf("%d\n", best) # Output: 51
free(grid.data)
return 0
10 changes: 10 additions & 0 deletions examples/aoc2023/day16/sampleinput.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
.|...\....
|.-.\.....
.....|-...
........|.
..........
.........\
..../.\\..
.-.-/..|..
.|....-|.\
..//.|....
Loading

0 comments on commit 0509fe6

Please sign in to comment.