mirror of
https://github.com/fredrikr79/advent_of_code.git
synced 2026-01-19 15:28:22 +01:00
142 lines
3.5 KiB
Odin
142 lines
3.5 KiB
Odin
package day3
|
|
|
|
import "core:fmt"
|
|
import "core:mem"
|
|
import "core:os"
|
|
import "core:strings"
|
|
import "core:time"
|
|
|
|
PUZZLE_INPUT :: `
|
|
987654321111111
|
|
811111111111119
|
|
234234234234278
|
|
818181911112111
|
|
`
|
|
|
|
Data_Is_Empty_Error :: distinct struct{}
|
|
|
|
Data_Is_Ragged_Error :: distinct struct {
|
|
line: int,
|
|
}
|
|
|
|
Illegal_Token_Error :: distinct struct {
|
|
line, col: int,
|
|
token: rune,
|
|
}
|
|
|
|
Parsing_Error :: union {
|
|
mem.Allocator_Error,
|
|
Illegal_Token_Error,
|
|
Data_Is_Ragged_Error,
|
|
Data_Is_Empty_Error,
|
|
}
|
|
|
|
Grid :: struct {
|
|
data: []int,
|
|
rows, cols: int,
|
|
}
|
|
|
|
parse :: proc(input: string, allocator := context.allocator) -> (grid: Grid, err: Parsing_Error) {
|
|
context.allocator = context.temp_allocator
|
|
defer context.allocator = allocator
|
|
|
|
lines := strings.split_lines(strings.trim_space(input)) or_return
|
|
if lines[0] == "" do return {}, Data_Is_Empty_Error{}
|
|
|
|
rows := len(lines)
|
|
cols := len(strings.trim_space(lines[0]))
|
|
|
|
data := make([dynamic]int, 0, rows * cols, allocator) or_return
|
|
|
|
for line, row in lines {
|
|
clean_line := strings.trim_space(line)
|
|
if len(clean_line) != cols do return {}, Data_Is_Ragged_Error{row}
|
|
|
|
for char, col in clean_line {
|
|
digit := int(char - '0')
|
|
if digit < 0 || digit > 9 do return {}, Illegal_Token_Error{row, col, char}
|
|
append(&data, digit) or_return
|
|
}
|
|
}
|
|
|
|
return Grid{data[:], rows, cols}, nil
|
|
}
|
|
|
|
remove_digits :: proc(
|
|
row: []int,
|
|
k: int,
|
|
allocator := context.allocator,
|
|
) -> (
|
|
output: []int,
|
|
err: mem.Allocator_Error,
|
|
) {
|
|
stack := make([dynamic]int, 0, len(row) - k, allocator) or_return
|
|
dels := k
|
|
for digit in row {
|
|
for len(stack) > 0 && digit > stack[len(stack) - 1] && dels > 0 {
|
|
pop(&stack)
|
|
dels -= 1
|
|
}
|
|
append(&stack, digit) or_return
|
|
}
|
|
return stack[:], .None
|
|
}
|
|
|
|
process :: proc(row: []int, n: int) -> (output: int, err: mem.Allocator_Error) {
|
|
digits := remove_digits(row, len(row) - n) or_return
|
|
for digit in digits[:n] {
|
|
output = 10 * output + digit
|
|
}
|
|
return
|
|
}
|
|
|
|
solve :: proc(grid: Grid, n: int) -> (solution: int, err: mem.Allocator_Error) {
|
|
context.allocator = context.temp_allocator
|
|
|
|
bank_solutions := make([]int, grid.rows) or_return
|
|
|
|
for row in 0 ..< grid.rows {
|
|
row_data := grid.data[row * grid.cols:(row + 1) * grid.cols]
|
|
bank_solutions[row] = process(row_data, n) or_return
|
|
}
|
|
|
|
for bank in bank_solutions do solution += bank
|
|
return
|
|
}
|
|
|
|
part_1 :: proc(grid: Grid) -> (solution: int, err: mem.Allocator_Error) {
|
|
return solve(grid, 2)
|
|
}
|
|
|
|
part_2 :: proc(grid: Grid) -> (solution: int, err: mem.Allocator_Error) {
|
|
return solve(grid, 12)
|
|
}
|
|
|
|
main :: proc() {
|
|
time_start := time.now()
|
|
input := string(os.read_entire_file("input") or_else panic("failed to read input"))
|
|
time_read := time.since(time_start)
|
|
|
|
data, parsing_error := parse(input, context.temp_allocator)
|
|
defer free_all(context.temp_allocator)
|
|
if parsing_error != nil do fmt.panicf("failed to parse: %v\n", parsing_error)
|
|
|
|
time_parse := time.since(time_start) - time_read
|
|
fmt.println("part 1: ", part_1(data) or_else panic("part 1 failed"))
|
|
time_solve_1 := time.since(time_start) - time_read - time_parse
|
|
fmt.println("part 2: ", part_2(data) or_else panic("part 2 failed"))
|
|
time_solve_2 := time.since(time_start) - time_read - time_parse - time_solve_1
|
|
time_total := time.since(time_start)
|
|
|
|
fmt.println("performance benchmarks [ms]:")
|
|
fmt.println("total\tread\tparse\tpart 1\tpart 2")
|
|
fmt.printf(
|
|
"%.3f\t%.3f\t%.3f\t%.3f\t%.3f\n",
|
|
time.duration_milliseconds(time_total),
|
|
time.duration_milliseconds(time_read),
|
|
time.duration_milliseconds(time_parse),
|
|
time.duration_milliseconds(time_solve_1),
|
|
time.duration_milliseconds(time_solve_2),
|
|
)
|
|
}
|