#import "Basic";
#import "File";
#import "String";
#import "Hash_Table";

solve_day8 :: (test: bool) {
    contents := read_entire_file("inputs/day8.txt");
    lines := split(contents, "\n");

    instructions: [..]u8;
    node_to_id_table: Table(string, u32);
    node_list: [..]Walk_Node;
    node_links: [..]Node_Link;

    for char_it: 0..lines[0].count - 1{
        c := lines[0][char_it];
        if c == {
            case #char "R";
                array_add(*instructions, 1);
            case #char "L";
                array_add(*instructions, 0);
            case;
                print("Unknown instruction: %\n", c);
        }
    }

    for line: array_view(lines, 1, lines.count) {
        if line.count == 0  continue;

        node_name       := slice(line, 0, 3);
        left_node_name  := slice(line, 7, 3);
        right_node_name := slice(line, 12, 3);

        table_add(*node_to_id_table, node_name, xx node_list.count);

        array_add(*node_links, .{
            name = node_name,
            left = left_node_name,
            right = right_node_name,
        });

        array_add(*node_list, .{
            name = node_name,
            left = 0,
            right = 0,
        });
    }

    for 0..node_links.count - 1 {
        node_list[it].left  = table_find_pointer(*node_to_id_table, node_links[it].left).*;
        node_list[it].right = table_find_pointer(*node_to_id_table, node_links[it].right).*;
    }

    part1 := 0;

    start_node_i,_ := table_find(*node_to_id_table, "AAA");
    end_node_i,_   := table_find(*node_to_id_table, "ZZZ");

    current_node := node_list[start_node_i];

    while outer:= part1 < 1_000_000 {
        for instruction: instructions {
            part1 += 1;

            if instruction == 0 {
                if current_node.left == end_node_i break outer;

                current_node = node_list[current_node.left];
            } else {
                if current_node.right == end_node_i break outer;

                current_node = node_list[current_node.right];
            }
        }
    }

    part2 := 0;    

    nodes_to_walk: [..]u64;

    for node_list {
        if it.name[2] == #char "A" {
            node := it;
            steps: u64 = 0;

            while outer:= steps < 1_000_000 {
                for instruction: instructions {
                    steps += 1;
                    if instruction == 0 {
                        if node_list[node.left].name[2] == #char "Z" {
                            break outer;
                        }
                        node = node_list[node.left];
                    } else {
                        if node_list[node.right].name[2] == #char "Z" {
                            break outer;
                        }
                        node = node_list[node.right];
                    }

                }
            }

            array_add(*nodes_to_walk, steps);
        }
    }

    part2 = 1;

    for nodes_to_walk {
        part2 = lcm(part2, xx it);
    }

    print("Part 1: %\n", part1);
    print("Part 2: %\n", part2);
}

Walk_Node :: struct {
    name:  string;
    left:  u64;
    right: u64;
}

Node_Link :: struct {
    name:  string;
    left:  string;
    right: string;
}