package main import "core:bytes" import "core:fmt" import "core:io" import "core:os" import "core:strconv" parse_input_file :: proc(filepath: string) -> []u8 { data, ok := os.read_entire_file_from_filename(filepath) if !ok { panic("oh no, could not read file") } return data } Node :: struct { size: int, children: Node_Map, } Node_Map :: map[string]Node parse_filesystem :: proc(buf: ^bytes.Buffer, parsed: ^Node_Map, current_directory: string = "") { line: []u8 err: io.Error for ; err != .EOF; line, err = bytes.buffer_read_bytes(buf, '\n') { if len(line) == 0 { continue } line = line[:len(line) - 1] cmd := string(line[2:4]) if cmd == "cd" { target := string(line[5:]) if target == ".." { break } if !(target in parsed) { parsed[target] = { size = 0, children = make(Node_Map), } } dir := &parsed[target] parse_filesystem(buf, &dir.children, target) } else if cmd == "ls" { continue } else { split: int for c, i in line { if c == ' ' { split = i } } size_part := string(line[:split]) name_part := string(line[split + 1:]) if !(name_part in parsed) { if size_part == "dir" { parsed[name_part] = { size = 0, children = make(Node_Map), } } else { parsed[name_part] = { size = strconv.atoi(size_part), children = nil, } } } } } } update_dir_size :: proc(parsed_filesystem: ^Node_Map) -> int { size: int for _, node in parsed_filesystem { if node.size == 0 { node.size = update_dir_size(&node.children) } size += node.size } return size } find_total_of_max_size :: proc(parsed_filesystem: ^Node_Map, max_size: int) -> int { size: int for _, node in parsed_filesystem { if node.children != nil { if node.size <= 100000 { size += node.size } size += find_total_of_max_size(&node.children, max_size) } } return size } find_size_to_save :: proc(parsed_filesystem: ^Node_Map, total_size, target_size: int) -> int { min_size := 70000000 for _, node in parsed_filesystem { if node.children != nil { if total_size - node.size <= target_size { if node.size < min_size { min_size = node.size } } size := find_size_to_save(&node.children, total_size, target_size) if size < min_size { min_size = size } } } return min_size } task1 :: proc(filesystem: []u8) -> int { buf: bytes.Buffer bytes.buffer_init(&buf, filesystem) defer bytes.buffer_destroy(&buf) parsed_filesystem := make(Node_Map) defer delete(parsed_filesystem) parse_filesystem(&buf, &parsed_filesystem) update_dir_size(&parsed_filesystem) return find_total_of_max_size(&parsed_filesystem, 100000) } task2 :: proc(filesystem: []u8) -> int { buf: bytes.Buffer bytes.buffer_init(&buf, filesystem) defer bytes.buffer_destroy(&buf) parsed_filesystem := make(Node_Map) defer delete(parsed_filesystem) parse_filesystem(&buf, &parsed_filesystem) update_dir_size(&parsed_filesystem) return find_size_to_save(&parsed_filesystem, parsed_filesystem["/"].size, 40000000) } main :: proc() { filesystem := parse_input_file("input.txt") defer delete(filesystem) result1 := task1(filesystem) fmt.printf("Task 1 result: %d\n", result1) result2 := task2(filesystem) fmt.printf("Task 2 result: %d\n", result2) }