-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
3 changed files
with
306 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |