Skip to content

Commit

Permalink
Aoc 2023 day 5 (#424)
Browse files Browse the repository at this point in the history
  • Loading branch information
Akuli authored Dec 5, 2023
1 parent 27fe9b5 commit 36041c2
Show file tree
Hide file tree
Showing 3 changed files with 306 additions and 0 deletions.
84 changes: 84 additions & 0 deletions examples/aoc2023/day05/part1.jou
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
import "stdlib/io.jou"
import "stdlib/str.jou"
import "stdlib/ascii.jou"
import "stdlib/mem.jou"


class Map:
triples: long[3][50]
ntriples: int

def add_triple(self, s: byte*) -> void:
a: long
b: long
c: long
assert sscanf(s, "%lld %lld %lld", &a, &b, &c) == 3

assert self->ntriples < sizeof(self->triples)/sizeof(self->triples[0])
self->triples[self->ntriples++] = [a, b, c]

def map_number(self, n: long) -> long:
for i = 0; i < self->ntriples; i++:
dest_start = self->triples[i][0]
source_start = self->triples[i][1]
range_length = self->triples[i][2]
if source_start <= n and n < source_start+range_length:
return n - source_start + dest_start
return n


class Input:
seed_numbers: long[30]
n_seed_numbers: int

maps: Map[10]
nmaps: int

def add_seeds(self, line: byte*) -> void:
assert self->n_seed_numbers == 0
assert starts_with(line, "seeds: ")

words = split_by_ascii_whitespace(line)
for i = 1; words[i] != NULL; i++:
assert i < sizeof(self->seed_numbers) / sizeof(self->seed_numbers[0])
self->seed_numbers[i-1] = atoll(words[i])
self->n_seed_numbers++
free(words)


def main() -> int:
input: Input* = calloc(1, sizeof(*input))

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

line: byte[1000]

# Special-case first line
assert fgets(line, sizeof(line) as int, f) != NULL
input->add_seeds(line)

while fgets(line, sizeof(line) as int, f) != NULL:
if strstr(line, "map") != NULL:
# start of new map
assert input->nmaps < sizeof(input->maps)/sizeof(input->maps[0])
input->nmaps++
elif is_ascii_digit(line[0]):
# add numbers to existing map
assert input->nmaps > 0
input->maps[input->nmaps - 1].add_triple(line)

fclose(f)

smallest = -1 as long
for i = 0; i < input->n_seed_numbers; i++:
n = input->seed_numbers[i]
for k = 0; k < input->nmaps; k++:
n = input->maps[k].map_number(n)

if smallest == -1 or n < smallest:
smallest = n

free(input)
printf("%lld\n", smallest) # Output: 35
return 0
189 changes: 189 additions & 0 deletions examples/aoc2023/day05/part2.jou
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
import "stdlib/io.jou"
import "stdlib/str.jou"
import "stdlib/ascii.jou"
import "stdlib/mem.jou"


class List:
ptr: long*
len: int
alloc: int

def end(self) -> long*:
return &self->ptr[self->len]

def append(self, n: long) -> void:
if self->alloc == self->len:
if self->alloc == 0:
self->alloc = 4
else:
self->alloc *= 2

self->ptr = realloc(self->ptr, self->alloc * sizeof(self->ptr[0]))
assert self->ptr != NULL

self->ptr[self->len++] = n

def extend(self, other: List) -> void:
for v = other.ptr; v < other.end(); v++:
self->append(*v)

def remove_dupes(self) -> void:
for i = self->len-1; i >= 0; i--:
# delete i'th number if it occurs after index i
for k = i+1; k < self->len; k++:
if self->ptr[i] == self->ptr[k]:
self->ptr[i] = self->ptr[--self->len]
break


class Map:
triples: long[3][50]
ntriples: int

def add_triple(self, s: byte*) -> void:
a: long
b: long
c: long
assert sscanf(s, "%lld %lld %lld", &a, &b, &c) == 3

assert self->ntriples < sizeof(self->triples)/sizeof(self->triples[0])
self->triples[self->ntriples++] = [a, b, c]

def get_input_range_starts(self) -> List:
result = List{}
for i = 0; i < self->ntriples; i++:
result.append(self->triples[i][1])
return result

def map_number(self, n: long) -> long:
for i = 0; i < self->ntriples; i++:
dest_start = self->triples[i][0]
source_start = self->triples[i][1]
range_length = self->triples[i][2]
if source_start <= n and n < source_start+range_length:
return n - source_start + dest_start
return n

# Find all numbers n for which map_number(n) == output.
def inverse_image(self, output: long) -> List:
result = List{}

for i = 0; i < self->ntriples; i++:
dest_start = self->triples[i][0]
source_start = self->triples[i][1]
range_length = self->triples[i][2]

# Solve equation: output = n - source_start + dest_start
n = output + source_start - dest_start
if self->map_number(n) == output:
result.append(n)

if self->map_number(output) == output:
result.append(output)

return result

# Find all numbers n for which map_number(n) is in a list of outputs.
def inverse_image_of_list(self, outputs: List) -> List:
result = List{}
for p = outputs.ptr; p < outputs.end(); p++:
to_add = self->inverse_image(*p)
result.extend(to_add)
free(to_add.ptr)
return result


class Range:
start: long
end: long

def contains(self, n: long) -> bool:
return self->start <= n and n < self->end


class Input:
seed_ranges: Range[15]
n_seed_ranges: int

maps: Map[10]
nmaps: int

def add_seeds(self, line: byte*) -> void:
assert self->n_seed_ranges == 0
assert starts_with(line, "seeds: ")
line = &line[6]

words = split_by_ascii_whitespace(line)
for i = 0; words[i] != NULL and words[i+1] != NULL; i += 2:
assert i/2 < sizeof(self->seed_ranges) / sizeof(self->seed_ranges[0])
self->seed_ranges[i/2] = Range{
start = atoll(words[i]),
end = atoll(words[i]) + atoll(words[i+1]),
}
self->n_seed_ranges++
free(words)

def is_valid_seed(self, n: long) -> bool:
for i = 0; i < self->n_seed_ranges; i++:
if self->seed_ranges[i].contains(n):
return True
return False


def main() -> int:
input: Input* = calloc(1, sizeof(*input))

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

line: byte[1000]

# Special-case first line
assert fgets(line, sizeof(line) as int, f) != NULL
input->add_seeds(line)

while fgets(line, sizeof(line) as int, f) != NULL:
if strstr(line, "map") != NULL:
# start of new map
assert input->nmaps < sizeof(input->maps)/sizeof(input->maps[0])
input->nmaps++
elif is_ascii_digit(line[0]):
# add numbers to existing map
assert input->nmaps > 0
input->maps[input->nmaps - 1].add_triple(line)

fclose(f)

interesting_inputs = List{}
for i = 0; i < input->nmaps; i++:
# We get small values whenever the i'th map sees a start of its range.
values = input->maps[i].get_input_range_starts()

# Back the list of numbers through all previous maps.
for k = i-1; k >= 0; k--:
values2 = input->maps[k].inverse_image_of_list(values)
free(values.ptr)
values = values2

interesting_inputs.extend(values)
free(values.ptr)

# Let's also try start of each seed range
for i = 0; i < input->n_seed_ranges; i++:
interesting_inputs.append(input->seed_ranges[i].start)

smallest = -1 as long
for p = interesting_inputs.ptr; p < interesting_inputs.end(); p++:
if input->is_valid_seed(*p):
n = *p
for i = 0; i < input->nmaps; i++:
n = input->maps[i].map_number(n)
if smallest == -1 or n < smallest:
smallest = n

free(interesting_inputs.ptr)
free(input)

printf("%lld\n", smallest) # Output: 46
return 0
33 changes: 33 additions & 0 deletions examples/aoc2023/day05/sampleinput.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
seeds: 79 14 55 13

seed-to-soil map:
50 98 2
52 50 48

soil-to-fertilizer map:
0 15 37
37 52 2
39 0 15

fertilizer-to-water map:
49 53 8
0 11 42
42 0 7
57 7 4

water-to-light map:
88 18 7
18 25 70

light-to-temperature map:
45 77 23
81 45 19
68 64 13

temperature-to-humidity map:
0 69 1
1 0 69

humidity-to-location map:
60 56 37
56 93 4

0 comments on commit 36041c2

Please sign in to comment.