aoc20/d04/main.odin
2025-10-04 23:46:56 +02:00

161 lines
4.1 KiB
Odin

package main
import "core:math"
import "core:slice"
import "core:strconv"
import "core:strings"
import "core:bytes"
import "core:fmt"
import "core:os"
import "../util"
map_batch :: proc(batch: []string) -> map[string]string {
batch_map := make(map[string]string)
for line in batch {
parts := strings.split(line, " ")
for part in parts {
entry := strings.split(part, ":")
batch_map[entry[0]] = entry[1]
}
}
return batch_map
}
EXPECTED_FIELDS :: []string{
"byr",
"iyr",
"eyr",
"hgt",
"hcl",
"ecl",
"pid",
}
part_1 :: proc(lines: []string) {
result := 0
batches := make([dynamic]map[string]string)
batch: []string
batch_idx := 0
for line, idx in lines {
if len(line) == 0 {
batch := lines[batch_idx:idx]
append(&batches, map_batch(batch))
batch_idx = idx + 1
}
}
batch_loop: for batch in batches {
for field in EXPECTED_FIELDS {
_, ok := batch[field]
if !ok do continue batch_loop
}
result += 1
}
fmt.printfln("Part 1: %d", result)
}
part_2 :: proc(lines: []string) {
result := 0
batches := make([dynamic]map[string]string)
batch: []string
batch_idx := 0
for line, idx in lines {
if len(line) == 0 {
batch := lines[batch_idx:idx]
append(&batches, map_batch(batch))
batch_idx = idx + 1
}
}
batch_loop: for batch in batches {
for field in EXPECTED_FIELDS {
val, ok := batch[field]
if !ok do continue batch_loop
switch field {
case "byr":
if len(val) != 4 do continue batch_loop
year, ok := strconv.parse_int(val); assert(ok)
if year < 1920 || year > 2002 do continue batch_loop
case "iyr":
if len(val) != 4 do continue batch_loop
year, ok := strconv.parse_int(val); assert(ok)
if year < 2010 || year > 2020 do continue batch_loop
case "eyr":
if len(val) != 4 do continue batch_loop
year, ok := strconv.parse_int(val); assert(ok)
if year < 2020 || year > 2030 do continue batch_loop
case "hgt":
if len(val) < 3 do continue batch_loop
unit := val[len(val)-2:]
length, ok := strconv.parse_int(val[:len(val)-2]); assert(ok)
switch unit {
case "cm":
if length < 150 || length > 193 do continue batch_loop
case "in":
if length < 59 || length > 76 do continue batch_loop
case: continue batch_loop
}
case "hcl":
if len(val) != 7 do continue batch_loop
if val[0] != '#' do continue batch_loop
for letter in val[1:] {
switch letter {
case '0'..='9': continue
case 'a'..='f': continue
case: continue batch_loop
}
}
case "ecl":
EXPECTED_COLORS :: []string{
"amb",
"blu",
"brn",
"gry",
"grn",
"hzl",
"oth",
}
if !slice.contains(EXPECTED_COLORS, val) do continue batch_loop
case "pid":
if len(val) != 9 do continue batch_loop
for letter in val {
switch letter {
case '0'..='9': continue
case: continue batch_loop
}
}
}
}
result += 1
}
fmt.printfln("Part 2: %d", result)
}
main :: proc() {
context.allocator = context.temp_allocator
defer free_all(context.temp_allocator)
INPUT :: #load("input.txt", string)
lines := strings.split(INPUT, "\n")
lines = lines[:len(lines)-1]
part_1(lines)
part_2(lines)
}