package main
import "core:bytes"
import "core:fmt"
import "core:io"
import "core:os"
import "core:strconv"
import "core:strings"
Color :: enum {
Red,
Green,
Blue,
}
Combination :: struct {
num: int,
col: Color,
}
Set :: [dynamic]Combination
Game :: struct {
id: int,
sets: [dynamic]Set,
}
Input :: struct {
games: [dynamic]Game,
}
Result1 :: distinct int
Result2 :: distinct int
// --- 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")
}
buf: bytes.Buffer
bytes.buffer_init(&buf, raw_data)
defer bytes.buffer_destroy(&buf)
input.games = make([dynamic]Game, 0, 10)
line: string
err: io.Error
for ; err != .EOF; line, err = bytes.buffer_read_string(&buf, '\n') {
if line == "" || line == "\n" {
continue
}
line = line[:len(line) - 1]
game_and_sets := strings.split(line, ": ")
current_game := strings.split(game_and_sets[0], " ")
sets := strings.split(game_and_sets[1], "; ")
game: Game
game.id = strconv.atoi(current_game[1])
game.sets = make([dynamic]Set, 0, 10)
for set in sets {
parsed_set := make([dynamic]Combination, 0, 10)
combinations := strings.split(set, ", ")
for combination in combinations {
number_and_color := strings.split(combination, " ")
col: Color
switch number_and_color[1] {
case "red":
col = .Red
case "green":
col = .Green
case "blue":
col = .Blue
}
append(&parsed_set, Combination{num = strconv.atoi(number_and_color[0]), col = col})
}
append(&game.sets, parsed_set)
}
append(&input.games, game)
}
return input
}
free_input :: proc(input: ^Input) {
for game in input.games {
for set in game.sets {
delete(set)
}
delete(game.sets)
}
delete(input.games)
}
// --- Input --- //
// --- Task 1 --- //
task1_rules := map[Color]int {
.Red = 12,
.Green = 13,
.Blue = 14,
}
run_task1 :: proc(input: ^Input, debug: bool) -> Result1 {
result: Result1
if debug {
fmt.printf("input: %#v\n", input)
}
for game in input.games {
ok := true
for set in game.sets {
for combination in set {
if task1_rules[combination.col] < combination.num {
ok = false
break
}
}
}
if ok {
if debug {
fmt.printf("Possible game: %d\n", game.id)
}
result += Result1(game.id)
}
}
return result
}
print_result1 :: proc(result: ^Result1) {
fmt.printf("Task 1: %d\n", result^)
}
// --- Task 1 --- //
// --- Task 2 --- //
run_task2 :: proc(input: ^Input, debug: bool) -> Result2 {
result: Result2
if debug {
fmt.printf("input: %#v\n", input)
}
for game in input.games {
fewest_cubes_necessary := map[Color]int {
.Red = 0,
.Green = 0,
.Blue = 0,
}
for set in game.sets {
for combination in set {
if num, _ := fewest_cubes_necessary[combination.col]; combination.num > num {
fewest_cubes_necessary[combination.col] = combination.num
}
}
}
power := fewest_cubes_necessary[.Red] * fewest_cubes_necessary[.Green] * fewest_cubes_necessary[.Blue]
if debug {
fmt.printf("Possible game: %d\n", game.id)
fmt.printf("Fewest cubes necessary: %#v -> %d\n", fewest_cubes_necessary, power)
}
result += Result2(power)
}
return result
}
print_result2 :: proc(result: ^Result2) {
fmt.printf("Task 2: %d\n", result^)
}
// --- Task 2 --- //