#import "Basic";
#import "Math";
#import "File";
#import "String";

solve_day13 :: (test: bool) {
    contents := read_entire_file(ifx test then "inputs/day13_test2.txt" else "inputs/day13.txt");

    section_split := split(contents, "\n\n");

    sections: [..]string;

    part1 := 0;
    part2 := 0;

    for section_split {
        builder: String_Builder;
        lines := split(it, "\n");

        section := Section.{
            width = lines[0].count,
            height = lines.count,
            lines = NewArray(50 * 50, u8),
        };

        rows := NewArray(50, u32);
        defer array_free(rows);

        for line,line_index: lines {
            for 0..line.count - 1 {
                if line[it] == #char "#" {
                    section.lines[line_index * 50 + it] = #char "1";
                } else if line[it] == #char "." {
                    section.lines[line_index * 50 + it] = #char "0";
                }
            }

            rows[line_index] = string_to_int(cast(string)array_view(section.lines, line_index * 50, line.count), 2, u32);
        }
        p1, p2 := find_symmetries(array_view(rows, 0, section.height));

        part1 += p1 * 100;
        part2 += p2 * 100;

        transpose(*section);

        for line_index: 0..section.height {
            rows[line_index] = string_to_int(cast(string)array_view(section.lines, line_index * 50, section.width), 2, u32);
        }

        p1, p2 = find_symmetries(array_view(rows, 0, section.height));

        part1 += p1;
        part2 += p2;
    }

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

}

transpose :: (section: *Section) {
    max_val := max(section.width, section.height);
    for row: 0..max_val - 1 {
        for column: row..max_val - 1 {
            section.lines[row * 50 + column], section.lines[column * 50 + row] = section.lines[column * 50 + row], section.lines[row * 50 + column];
        }
    }

    section.width, section.height = section.height, section.width;
}

is_pow_2 :: (val: u32) -> bool {
    return (val & (val - 1)) == 0 && val != 0;
}

find_symmetries :: (lines: []u32) -> (part1: u32, part2: u32) {
    errors: u32 = 0;
    error_val : u32 = 0;

    part1: u32 = 0;
    part2: u32 = 0;

    for row: 0..lines.count - 2 {
        errors = 0;

        j: u32 = 0;

        while errors < 2 && row >= j && j + row + 1 < lines.count {
            defer j += 1;

            if lines[row - j] != lines[row + j + 1] {
                errors += 1;
                error_val = lines[row - j] ^ lines[row + j + 1];
            }

        }

        if errors == 1 && is_pow_2(error_val) {
            part2 += xx (row + 1);
        }

        if errors == 0 {
            part1 += xx (row + 1);
        }
    }

    return part1, part2;
}

Section :: struct {
    width: s64;
    height: s64;
    lines: []u8;
}