Skip to content

Commit

Permalink
AoC days 18, 19, 20, 21, 22, 23 (#475)
Browse files Browse the repository at this point in the history
  • Loading branch information
Akuli authored Dec 23, 2023
1 parent 23a3252 commit 1b6cbd6
Show file tree
Hide file tree
Showing 25 changed files with 2,093 additions and 3 deletions.
1 change: 1 addition & 0 deletions examples/aoc2023/day10/part1.jou
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ def main() -> int:
grid = read_grid_from_file(f)
fclose(f)

assert grid.count('S') == 1
point = grid.find_first('S')

# take first step away from S
Expand Down
1 change: 1 addition & 0 deletions examples/aoc2023/day10/part2.jou
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ def main() -> int:
grid = read_grid_from_file(f)
fclose(f)

assert grid.count('S') == 1
point = grid.find_first('S')

loop: int[2]* = malloc(grid.width * grid.height * sizeof(loop[0]))
Expand Down
119 changes: 119 additions & 0 deletions examples/aoc2023/day18/part1.jou
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
import "stdlib/io.jou"
import "stdlib/str.jou"
import "stdlib/mem.jou"
import "../grid.jou"


def prepend_blank_row(grid: Grid*) -> None:
assert strlen(grid->data) == (grid->width + 1)*grid->height
grid->data = realloc(grid->data, grid->width + 1 + strlen(grid->data) + 1)
memmove(&grid->data[grid->width + 1], grid->data, strlen(grid->data) + 1)
memset(grid->data, '.', grid->width)
grid->data[grid->width] = '\n'
grid->height++
assert strlen(grid->data) == (grid->width + 1)*grid->height


def append_blank_row(grid: Grid*) -> None:
assert strlen(grid->data) == (grid->width + 1)*grid->height
grid->data = realloc(grid->data, grid->width + 1 + strlen(grid->data) + 1)
p = &grid->data[strlen(grid->data)]
memset(p, '.', grid->width)
p[grid->width] = '\n'
p[grid->width + 1] = '\0'
grid->height++
assert strlen(grid->data) == (grid->width + 1)*grid->height


def surround_with_blanks(grid: Grid*) -> None:
prepend_blank_row(grid)
append_blank_row(grid)
grid->transpose()
prepend_blank_row(grid)
append_blank_row(grid)
grid->transpose()


def read_input_to_grid(filename: byte*) -> Grid:
f = fopen(filename, "r")
assert f != NULL

direction_letter: byte
step_count: int
color: byte[7]

grid = Grid{width = 1, height = 1, data = strdup("#\n")}
x = 0
y = 0

while fscanf(f, "%c %d (#%6s)\n", &direction_letter, &step_count, color) == 3:
while step_count --> 0:
if direction_letter == 'U':
y--
elif direction_letter == 'D':
y++
elif direction_letter == 'L':
x--
elif direction_letter == 'R':
x++
else:
assert False

if y == -1:
prepend_blank_row(&grid)
y++
if y == grid.height:
append_blank_row(&grid)
if x == -1:
grid.transpose()
prepend_blank_row(&grid)
grid.transpose()
x++
if x == grid.width:
grid.transpose()
append_blank_row(&grid)
grid.transpose()

grid.set([x, y], '#')

fclose(f)
return grid


def fill_with_f(grid: Grid*) -> None:
todo: int[2]* = malloc(sizeof(todo[0]))
todo_len = 1
todo_alloc = 1
todo[0] = [0, 0]

while todo_len > 0:
point = todo[--todo_len]
if not grid->is_in_bounds(point) or grid->get(point) != '.':
continue

grid->set(point, 'f')

# Append neighbors to todo list
neighbors: int[2][4] = [
[point[0], point[1]-1],
[point[0], point[1]+1],
[point[0]-1, point[1]],
[point[0]+1, point[1]],
]
while todo_alloc < todo_len + 4:
todo_alloc *= 2
todo = realloc(todo, sizeof(todo[0]) * todo_alloc)
assert todo != NULL
memcpy(&todo[todo_len], &neighbors, sizeof(neighbors))
todo_len += 4

free(todo)


def main() -> int:
grid = read_input_to_grid("sampleinput.txt")
surround_with_blanks(&grid)
fill_with_f(&grid)
printf("%d\n", grid.width*grid.height - grid.count('f')) # Output: 62
free(grid.data)
return 0
95 changes: 95 additions & 0 deletions examples/aoc2023/day18/part2.jou
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import "stdlib/io.jou"
import "stdlib/str.jou"
import "stdlib/mem.jou"
import "stdlib/ascii.jou"
import "stdlib/math.jou"


# TODO: figure out better way
def parse_hex_string(s: byte*, len: int) -> int:
result = 0
for i = 0; i < len; i++:
result *= 16
if is_ascii_digit(s[i]):
result += s[i] - '0'
else:
assert 'a' <= s[i] and s[i] <= 'f'
result += 10 + (s[i] - 'a')
return result


# returned array is [-1, -1] terminated
def read_input_as_points(filename: byte*, result_len: int*) -> int[2]*:
result: int[2]* = malloc(sizeof(result[0]))
assert result != NULL
result[0] = [0, 0]
*result_len = 1

f = fopen(filename, "r")
assert f != NULL

direction_letter: byte
step_count: int
hex: byte[7]
x = 0
y = 0

while fscanf(f, "%c %d (#%6s)\n", &direction_letter, &step_count, hex) == 3:
assert strlen(hex) == 6
step_count = parse_hex_string(hex, 5)
if hex[5] == '0':
# right
x += step_count
elif hex[5] == '1':
# down
y += step_count
elif hex[5] == '2':
# left
x -= step_count
elif hex[5] == '3':
# up
y -= step_count
else:
assert False

result = realloc(result, sizeof(result[0]) * (*result_len + 1))
result[(*result_len)++] = [x, y]

fclose(f)

return result


# See day 10 part 2
def polygon_area(corners: int[2]*, ncorners: int) -> long:
double_area = 0L
for i = 0; i < ncorners; i++:
a: long = corners[i][0]
b: long = corners[i][1]
c: long = corners[(i+1) % ncorners][0]
d: long = corners[(i+1) % ncorners][1]
double_area += a*d - b*c
return llabs(double_area)/2


def main() -> int:
n: int
points = read_input_as_points("sampleinput.txt", &n)

# must end where it starts
assert n > 0
assert points[0][0] == 0
assert points[0][1] == 0
assert points[n-1][0] == 0
assert points[n-1][1] == 0

path_len = 0L
for i = 1; i < n; i++:
path_len += abs(points[i-1][0] - points[i][0])
path_len += abs(points[i-1][1] - points[i][1])

assert path_len % 2 == 0
printf("%lld\n", polygon_area(points, n-1) + 1 + path_len/2) # Output: 952408144115

free(points)
return 0
14 changes: 14 additions & 0 deletions examples/aoc2023/day18/sampleinput.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
R 6 (#70c710)
D 5 (#0dc571)
L 2 (#5713f0)
D 2 (#d2c081)
R 2 (#59c680)
D 2 (#411b91)
L 5 (#8ceee2)
U 2 (#caa173)
L 1 (#1b58a2)
U 2 (#caa171)
R 2 (#7807d2)
U 3 (#a77fa3)
L 2 (#015232)
U 2 (#7a21e3)
148 changes: 148 additions & 0 deletions examples/aoc2023/day19/part1.jou
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
import "stdlib/ascii.jou"
import "stdlib/io.jou"
import "stdlib/str.jou"
import "stdlib/mem.jou"


class XMAS:
x: int
m: int
a: int
s: int

def sum(self) -> int:
return self->x + self->m + self->a + self->s


class Expression:
var: byte
greater_than: bool # if False, this is a less than
value: int

def applies_to(self, xmas: XMAS) -> bool:
if self->var == 'x':
actual_value = xmas.x
elif self->var == 'm':
actual_value = xmas.m
elif self->var == 'a':
actual_value = xmas.a
elif self->var == 's':
actual_value = xmas.s
else:
assert False

if self->greater_than:
return actual_value > self->value
else:
return actual_value < self->value


class Workflow:
name: byte[10]
ifs: Expression*
thens: byte[10]*
n_ifs_and_thens: int
the_else: byte[10]

def run(self, xmas: XMAS) -> byte*:
for i = 0; i < self->n_ifs_and_thens; i++:
if self->ifs[i].applies_to(xmas):
return self->thens[i]
return self->the_else


def take_word(p: byte**) -> byte[10]:
result: byte[10]

i = 0
while is_ascii_letter(**p):
assert i < sizeof(result)
result[i++] = *(*p)++

assert i < sizeof(result)
result[i] = '\0'
return result


def parse_workflow(s: byte*) -> Workflow:
wf = Workflow{name = take_word(&s)}
assert *s++ == '{'

while True:
# Check for the special else word
p = s
possibly_the_else = take_word(&p)
if *p == '}':
assert p[1] == '\0'
wf.the_else = possibly_the_else
return wf

# "s>1188:ktb," --> var="s", op='>', num=1188, then="ktb"
var = take_word(&s)
op = *s++
num = atoi(s)
while is_ascii_digit(*s):
s++
assert *s++ == ':'
then = take_word(&s)
assert *s++ == ','

wf.ifs = realloc(wf.ifs, sizeof(wf.ifs[0]) * (wf.n_ifs_and_thens + 1))
wf.thens = realloc(wf.thens, sizeof(wf.thens[0]) * (wf.n_ifs_and_thens + 1))

assert strlen(var) == 1
assert op == '>' or op == '<'
wf.ifs[wf.n_ifs_and_thens] = Expression{var = var[0], greater_than = (op == '>'), value = num}
wf.thens[wf.n_ifs_and_thens] = then
wf.n_ifs_and_thens++


def find_workflow(workflows: Workflow*, nworkflows: int, name: byte*) -> Workflow*:
for i = 0; i < nworkflows; i++:
if strcmp(workflows[i].name, name) == 0:
return &workflows[i]
assert False


def run(workflows: Workflow*, nworkflows: int, xmas: XMAS) -> bool:
result = "in"

while True:
result = find_workflow(workflows, nworkflows, result)->run(xmas)
if strcmp(result, "A") == 0:
return True
if strcmp(result, "R") == 0:
return False


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

workflows: Workflow* = NULL
nworkflows = 0

line: byte[200]
while fgets(line, sizeof(line) as int, f) != NULL:
trim_ascii_whitespace(line)
if line[0] == '\0':
# end of workflows
break

workflows = realloc(workflows, sizeof(workflows[0]) * (nworkflows + 1))
workflows[nworkflows++] = parse_workflow(line)

xmas: XMAS
result = 0
while fscanf(f, "{x=%d,m=%d,a=%d,s=%d}\n", &xmas.x, &xmas.m, &xmas.a, &xmas.s) == 4:
if run(workflows, nworkflows, xmas):
result += xmas.sum()

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

for i = 0; i < nworkflows; i++:
free(workflows[i].ifs)
free(workflows[i].thens)
free(workflows)
fclose(f)
return 0
Loading

0 comments on commit 1b6cbd6

Please sign in to comment.