package main
import "core:log"
import "core:os"
import "core:slice"
import "core:strconv"
import "core:strings"
Rule :: struct {
before: [dynamic]int,
after: [dynamic]int,
}
Input :: struct {
rules: map[int]Rule,
updates: [dynamic][]int,
}
Result1 :: distinct int
Result2 :: distinct int
// --- Input --- //
print_input :: proc(input: ^Input) {
log.infof("%v", input)
}
parse_input_file :: proc(filepath: string) -> Input {
input: Input
raw_data, ok := os.read_entire_file_from_filename(filepath)
if !ok {
panic("oh no, could not read file")
}
defer delete(raw_data)
input.rules = map[int]Rule{}
input.updates = make([dynamic][]int, 0, 10)
rules_done: bool
string_data := string(raw_data)
for line in strings.split_lines_iterator(&string_data) {
if len(line) == 0 {
rules_done = true
continue
}
if !rules_done {
split := strings.index_rune(line, '|')
a := strconv.atoi(line[:split])
b := strconv.atoi(line[split + 1:])
if a not_in input.rules {
input.rules[a] = {
before = make([dynamic]int, 0, 10),
after = make([dynamic]int, 0, 10),
}
}
if b not_in input.rules {
input.rules[b] = {
before = make([dynamic]int, 0, 10),
after = make([dynamic]int, 0, 10),
}
}
rule_a := &input.rules[a]
rule_b := &input.rules[b]
append(&rule_a.before, b)
append(&rule_b.after, a)
} else {
raw_values := strings.split(line, ",")
defer delete(raw_values)
values := make([]int, len(raw_values))
for v, i in raw_values {
values[i] = strconv.atoi(v)
}
append(&input.updates, values)
}
}
return input
}
free_input :: proc(input: ^Input) {
for _, i in input.updates {
delete(input.updates[i])
}
delete(input.updates)
for k in input.rules {
delete(input.rules[k].before)
delete(input.rules[k].after)
}
delete(input.rules)
}
// --- Input --- //
// --- Helpers --- //
// --- Helpers --- //
// --- Task 1 --- //
run_task1 :: proc(input: ^Input, debug: bool) -> Result1 {
result: Result1
if debug {
print_input(input)
}
for values in input.updates {
valid := true
for v in values {
after: bool
for u in values {
if u == v {
after = true
continue
}
if (!after && !slice.contains(input.rules[v].after[:], u)) ||
(after && !slice.contains(input.rules[v].before[:], u)) {
valid = false
break
}
}
}
if valid {
log.debugf("%v VALID", values)
result += Result1(values[len(values) / 2])
} else {
log.debugf("%v INVALID", values)
}
}
return result
}
print_result1 :: proc(result: ^Result1) {
log.infof("Task 1: %d", result^)
}
// --- Task 1 --- //
// --- Task 2 --- //
run_task2 :: proc(input: ^Input, debug: bool) -> Result2 {
result: Result2
if debug {
print_input(input)
}
for values in input.updates {
valid := true
for v in values {
after: bool
for u in values {
if u == v {
after = true
continue
}
if (!after && !slice.contains(input.rules[v].after[:], u)) ||
(after && !slice.contains(input.rules[v].before[:], u)) {
valid = false
break
}
}
}
if !valid {
log.debugf("%v INVALID", values)
less :: proc(a, b: int) -> bool {
rules := cast(^map[int]Rule)context.user_ptr
return slice.contains(rules[a].before[:], b)
}
context.user_ptr = &input.rules
slice.sort_by(values, less)
result += Result2(values[len(values) / 2])
}
}
return result
}
print_result2 :: proc(result: ^Result2) {
log.infof("Task 2: %d", result^)
}
// --- Task 2 --- //