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 days 15, 16, 17 #465

Merged
merged 7 commits into from
Dec 18, 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
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