package day_08
import "core:log"
import "core:os"
import "core:sort"
import "core:strconv"
import "core:strings"
Input :: struct {
fuse_boxes: [][3]int,
}
Result1 :: int
Result2 :: 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)
lines, err := strings.split_lines(strings.trim_space(string(raw_data)))
if err != .None {
panic("oh no, failed splitting into lines")
}
defer delete(lines)
input.fuse_boxes = make([][3]int, len(lines))
for line, i in lines {
nums := strings.split(line, ",")
defer delete(nums)
input.fuse_boxes[i] = {
strconv.parse_int(nums[0]) or_else 0,
strconv.parse_int(nums[1]) or_else 0,
strconv.parse_int(nums[2]) or_else 0,
}
}
return input
}
free_input :: proc(input: ^Input) {
delete(input.fuse_boxes)
}
// --- Input --- //
// --- Helpers --- //
// --- Helpers --- //
// --- Task 1 --- //
Edge :: struct {
a, b: int,
dist: int,
}
Disjoint_Set :: struct {
parent: []int,
size: []int,
}
disjoint_set_init :: proc(ds: ^Disjoint_Set, count: int) {
ds.parent = make([]int, count)
ds.size = make([]int, count)
for i in 0 ..< count {
ds.parent[i] = i
ds.size[i] = 1
}
}
disjoint_set_destroy :: proc(ds: ^Disjoint_Set) {
delete(ds.parent)
ds.parent = nil
delete(ds.size)
ds.size = nil
}
disjoint_set_find :: proc(ds: ^Disjoint_Set, x: int) -> int {
if ds.parent[x] != x {
ds.parent[x] = disjoint_set_find(ds, ds.parent[x])
}
return ds.parent[x]
}
disjoint_set_union :: proc(ds: ^Disjoint_Set, a, b: int) {
sa := disjoint_set_find(ds, a)
sb := disjoint_set_find(ds, b)
if sa == sb {
return
}
if ds.size[sa] < ds.size[sb] {
sa, sb = sb, sa
}
ds.parent[sb] = sa
ds.size[sa] += ds.size[sb]
}
run_task1 :: proc(input: Input, iteration_count: int = 1000) -> Result1 {
result: Result1
edges := make([dynamic]Edge, 0, len(input.fuse_boxes))
defer delete(edges)
for i in 0 ..< len(input.fuse_boxes) {
for j in i + 1 ..< len(input.fuse_boxes) {
a := input.fuse_boxes[i]
b := input.fuse_boxes[j]
c := a - b
c *= c
append(&edges, Edge{a = i, b = j, dist = c[0] + c[1] + c[2]})
}
}
sort.quick_sort_proc(edges[:], proc(a, b: Edge) -> int {
return a.dist - b.dist
})
ds: Disjoint_Set
disjoint_set_init(&ds, len(input.fuse_boxes))
defer disjoint_set_destroy(&ds)
steps := 0
for e in edges {
disjoint_set_union(&ds, e.a, e.b)
steps += 1
if steps >= iteration_count {
break
}
}
component_sizes := make([dynamic]int, 0, len(ds.size))
defer delete(component_sizes)
for i in 0 ..< len(input.fuse_boxes) {
if ds.parent[i] == i {
append(&component_sizes, ds.size[i])
}
}
sort.quick_sort(component_sizes[:])
top_3 := component_sizes[len(component_sizes) - 3:]
result += top_3[0] * top_3[1] * top_3[2]
return result
}
print_result1 :: proc(result: Result1) {
log.infof("Task 1: %d", result)
}
// --- Task 1 --- //
// --- Task 2 --- //
run_task2 :: proc(input: Input) -> Result2 {
result: Result2
edges := make([dynamic]Edge, 0, len(input.fuse_boxes))
defer delete(edges)
for i in 0 ..< len(input.fuse_boxes) {
for j in i + 1 ..< len(input.fuse_boxes) {
a := input.fuse_boxes[i]
b := input.fuse_boxes[j]
c := a - b
c *= c
append(&edges, Edge{a = i, b = j, dist = c[0] + c[1] + c[2]})
}
}
sort.quick_sort_proc(edges[:], proc(a, b: Edge) -> int {
return a.dist - b.dist
})
ds: Disjoint_Set
disjoint_set_init(&ds, len(input.fuse_boxes))
defer disjoint_set_destroy(&ds)
components := len(input.fuse_boxes)
last_edge: Edge
for e in edges {
sa := disjoint_set_find(&ds, e.a)
sb := disjoint_set_find(&ds, e.b)
if sa != sb {
disjoint_set_union(&ds, e.a, e.b)
components -= 1
last_edge = e
if components == 1 {
break
}
}
}
log.debugf("%v", last_edge)
log.debugf("%v - %v", input.fuse_boxes[last_edge.a], input.fuse_boxes[last_edge.b])
result = input.fuse_boxes[last_edge.a][0] * input.fuse_boxes[last_edge.b][0]
return result
}
print_result2 :: proc(result: Result2) {
log.infof("Task 2: %d", result)
}
// --- Task 2 --- //
run :: proc() {
input := parse_input_file("input/day_08.txt")
defer free_input(&input)
result1 := run_task1(input)
print_result1(result1)
result2 := run_task2(input)
print_result2(result2)
}