Skip to content

Commit

Permalink
Aoc 2023 solutions, days 1-3 (#401)
Browse files Browse the repository at this point in the history
  • Loading branch information
Akuli authored Dec 3, 2023
1 parent a39dd39 commit 32bb790
Show file tree
Hide file tree
Showing 16 changed files with 420 additions and 15 deletions.
6 changes: 3 additions & 3 deletions .github/workflows/linux.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ jobs:
- uses: actions/checkout@v3
- run: sudo apt install -y llvm-${{ matrix.llvm-version }}-dev clang-${{ matrix.llvm-version }} make valgrind
- run: LLVM_CONFIG=llvm-config-${{ matrix.llvm-version }} make
- run: ./runtests.sh --verbose './jou ${{ matrix.opt-level }} %s'
- run: ./runtests.sh --verbose './jou ${{ matrix.opt-level }} --verbose %s'
- run: ./runtests.sh --verbose 'jou ${{ matrix.opt-level }} %s'
- run: ./runtests.sh --verbose 'jou ${{ matrix.opt-level }} --verbose %s'
# Valgrinding is slow. Do it only when this file or something in the compiler has been modified.
- name: Figure out if we need to run tests with valgrind
id: check-need-valgrind
Expand All @@ -35,7 +35,7 @@ jobs:
echo doit=no >> $GITHUB_OUTPUT
fi
- if: ${{ steps.check-need-valgrind.outputs.doit == 'yes' }}
run: ./runtests.sh --verbose --valgrind './jou ${{ matrix.opt-level }} %s'
run: ./runtests.sh --verbose --valgrind 'jou ${{ matrix.opt-level }} %s'
# valgrind+verbose isn't meaningful: test script would ignore valgrind output
- run: make clean
- name: Check that "make clean" deleted all files not committed to Git
Expand Down
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,8 @@ jou_compiled

# ide stuff
/.vscode/

# Advent of Code input files https://adventofcode.com/
# These are large text files, and each AoC user gets different input files.
# Tests use sampleinput.txt files, copied from problem descriptions
/examples/aoc2023/day*/input.txt
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ def main() -> int:

See the [examples](./examples/) and [tests](./tests/) directories for more example programs.

So far, Jou is usable enough to do [Advent of Code 2023](https://adventofcode.com/).
We'll see whether I get 50 stars with Jou this year.
See [examples/aoc2023](./examples/aoc2023/) for the code.

Goals:
- Minimalistic feel of C + simple Python-style syntax
- Possible target audiences:
Expand Down
3 changes: 2 additions & 1 deletion compare_compilers.sh
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ for arg in "$@"; do
done

if [ ${#files[@]} = 0 ]; then
mapfile -t files < <( find stdlib examples tests -name '*.jou' | sort )
# TODO: do not skip Advent Of Code files
mapfile -t files < <( find stdlib examples tests -name '*.jou' | grep -v aoc2023 | sort )
fi
if [ ${#actions[@]} = 0 ]; then
actions=(tokenize parse run)
Expand Down
24 changes: 24 additions & 0 deletions examples/aoc2023/day01/corner-cases.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
eight3fiveninefivemtxm9eightwot
x1vzgnpdjtwonert
t3sixtwonedmj
9qzbqxmqonefiveknrnzpxoneightrq
4btqghfcqx25fivetwo95oneightxf
48sevensixfoureightwodx
15qhpvsevensixoneightt
7fiveeightoneightvs
fivesevenfour9jslninesevenjtttt7oneightssr
fivefour852eightwosx
4ssskfrfqhz9eightfour37oneightjm
25sixjrjqgl5fivekhtxstwovgxzfpvzfmoneightb
65rdlfdxjeightwox
ninercxgj4txpflzvhgtwoneqh
49seven7threeeightwokr
onetwonine4noneightvk
3eightfive88eightwor
6q9pjsdzponerfnqt6eightwob
1eightworg
8onecctzfxreighteightwoq
ptwo2fivedqxthreesdmbvdcdxrtwonegt
hdfdltsrtwoseventbqr7pckgcqtcgh8onetwonez
62xvvkpbhhbthreetwooneeightwozr
ninesevensrzxkzpmgz8kcjxsbdftwoner
27 changes: 27 additions & 0 deletions examples/aoc2023/day01/part1.jou
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import "stdlib/str.jou"
import "stdlib/io.jou"
import "stdlib/ascii.jou"


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

result = 0
line: byte[1000]
while fgets(line, sizeof(line) as int, f) != NULL:
first: byte* = line
while *first != '\0' and not is_ascii_digit(*first):
first++

last = &line[strlen(line) - 1]
while last > &line[0] and not is_ascii_digit(*last):
last--

result += 10*(*first - '0')
result += *last - '0'

fclose(f)

printf("%d\n", result) # Output: 142
return 0
39 changes: 39 additions & 0 deletions examples/aoc2023/day01/part2.jou
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import "stdlib/str.jou"
import "stdlib/io.jou"
import "stdlib/ascii.jou"


def parse_prefix_digit(s: byte*) -> int:
if is_ascii_digit(s[0]):
return s[0] - '0'

strings = ["", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine"]
for i = 1; i <= 9; i++:
if starts_with(s, strings[i]):
return i

return -1


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

result = 0
line: byte[1000]
while fgets(line, sizeof(line) as int, f) != NULL:
first: byte* = line
while *first != '\0' and parse_prefix_digit(first) == -1:
first++

last = &line[strlen(line) - 1]
while last > &line[0] and parse_prefix_digit(last) == -1:
last--

result += 10*parse_prefix_digit(first)
result += parse_prefix_digit(last)

fclose(f)

printf("%d\n", result) # Output: 281
return 0
4 changes: 4 additions & 0 deletions examples/aoc2023/day01/sampleinput.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
1abc2
pqr3stu8vwx
a1b2c3d4e5f
treb7uchet
7 changes: 7 additions & 0 deletions examples/aoc2023/day01/sampleinput2.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
two1nine
eightwothree
abcone2threexyz
xtwone3four
4nineeightseven2
zoneight234
7pqrstsixteen
53 changes: 53 additions & 0 deletions examples/aoc2023/day02/part1.jou
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import "stdlib/str.jou"
import "stdlib/io.jou"
import "stdlib/ascii.jou"


def game_is_possible(game_data: byte*) -> bool:
# loop in ; or , separated chunks
while *game_data != '\0':
chunk_len = strcspn(game_data, ";,")
chunk = game_data

# \0 terminate the chunk and skip it
game_data = &game_data[chunk_len]
if *game_data != '\0': # check needed to avoid overflow at end of string
*game_data = '\0'
game_data++

trim_ascii_whitespace(chunk)

n: int
color: byte[10]
assert sscanf(chunk, "%d %10s", &n, color) == 2

if strcmp(color, "red") == 0 and n > 12:
return False
if strcmp(color, "green") == 0 and n > 13:
return False
if strcmp(color, "blue") == 0 and n > 14:
return False

return True


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

result = 0
line: byte[1000]
while fgets(line, sizeof(line) as int, f) != NULL:
assert starts_with(line, "Game ")
game_id = atoi(&line[5])

id_end = strchr(line, ':')
assert id_end != NULL

if game_is_possible(&id_end[1]):
result += game_id

fclose(f)

printf("%d\n", result) # Output: 8
return 0
62 changes: 62 additions & 0 deletions examples/aoc2023/day02/part2.jou
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import "stdlib/str.jou"
import "stdlib/io.jou"
import "stdlib/ascii.jou"


class Game:
red: int
green: int
blue: int

def update(self, text: byte*) -> void:
n: int
color: byte[10]
assert sscanf(text, "%d %10s", &n, color) == 2

if strcmp(color, "red") == 0 and n > self->red:
self->red = n
if strcmp(color, "green") == 0 and n > self->green:
self->green = n
if strcmp(color, "blue") == 0 and n > self->blue:
self->blue = n

def get_power(self) -> int:
return self->red * self->green * self->blue


def parse_game(game_data: byte*) -> Game:
result = Game{}

# loop in ; or , separated chunks
while *game_data != '\0':
chunk_len = strcspn(game_data, ";,")
chunk = game_data

# \0 terminate the chunk and skip it
game_data = &game_data[chunk_len]
if *game_data != '\0': # check needed to avoid overflow at end of string
*game_data = '\0'
game_data++

trim_ascii_whitespace(chunk)
result.update(chunk)

return result


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

result = 0
line: byte[1000]
while fgets(line, sizeof(line) as int, f) != NULL:
id_end = strchr(line, ':')
assert id_end != NULL
game = parse_game(&id_end[1])
result += game.get_power()

fclose(f)

printf("%d\n", result) # Output: 2286
return 0
5 changes: 5 additions & 0 deletions examples/aoc2023/day02/sampleinput.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
Game 1: 3 blue, 4 red; 1 red, 2 green, 6 blue; 2 green
Game 2: 1 blue, 2 green; 3 green, 4 blue, 1 red; 1 green, 1 blue
Game 3: 8 green, 6 blue, 20 red; 5 blue, 4 red, 13 green; 5 green, 1 red
Game 4: 1 green, 3 red, 6 blue; 3 green, 6 red; 3 green, 15 blue, 14 red
Game 5: 6 red, 1 blue, 3 green; 2 blue, 1 red, 2 green
69 changes: 69 additions & 0 deletions examples/aoc2023/day03/part1.jou
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import "stdlib/ascii.jou"
import "stdlib/io.jou"
import "stdlib/mem.jou"
import "stdlib/str.jou"


def read_file(filename: byte*) -> byte*:
huge = 1000*1000

result: byte* = malloc(huge)
assert result != NULL
memset(result, 0, huge)

f = fopen(filename, "r")
assert f != NULL
fread(result, 1, huge, f)
fclose(f)

assert result[huge-1] == '\0' # check if full
return result


# Check if there is a part number between start and end.
# Start and end should be pointers into input.
def is_part_number(input: byte*, start: byte*, end: byte*) -> bool:
if start >= end:
# empty range
return False

for p = start; p < end; p++:
if not is_ascii_digit(*p):
return False

line_size = strcspn(input, "\n") + 1

for dy = -1; dy <= 1; dy++:
y_offset = line_size * dy
check_start = &start[y_offset - 1]
check_end = &end[y_offset + 1]

# stay within input
if check_start < input:
check_start = input
if check_end > &input[strlen(input)]:
check_end = &input[strlen(input)]

for p = check_start; p < check_end; p++:
if *p != '.' and is_ascii_punctuation(*p):
return True

return False


def main() -> int:
input = read_file("sampleinput.txt")
sum = 0

for start = input; *start != '\0'; start++:
end = start
while *end != '\0' and is_ascii_digit(*end):
end++

if is_part_number(input, start, end):
sum += atoi(start)
start = end # skip rest of number

free(input)
printf("%d\n", sum) # Output: 4361
return 0
Loading

0 comments on commit 32bb790

Please sign in to comment.