diff --git a/.gitignore b/.gitignore index bd12779..ccea2ef 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ *.bin *.txt +*.dSYM diff --git a/d11/main.odin b/d11/main.odin new file mode 100644 index 0000000..f042741 --- /dev/null +++ b/d11/main.odin @@ -0,0 +1,158 @@ +package main + +import "core:unicode/utf8" +import "core:math" +import "core:slice" +import "core:strconv" +import "core:strings" +import "core:bytes" +import "core:fmt" +import "core:os" + +import "../util" + +is_inside_boundries :: proc(row_idx, col_idx: int, layout: [][]rune) -> bool { + return col_idx >= 0 && col_idx < len(layout[0]) && row_idx >= 0 && row_idx < len(layout) +} + +get_adjacent_occupied :: proc(row_idx, col_idx: int, layout: [][]rune) -> i64 { + adjacent_occupied: i64 = 0 + + for adjacent_row_idx in -1..=1 { + for adjacent_col_idx in -1..=1 { + if adjacent_col_idx == 0 && adjacent_row_idx == 0 do continue + + neighbour_row_idx := row_idx + adjacent_row_idx + neighbour_col_idx := col_idx + adjacent_col_idx + + if is_inside_boundries(neighbour_row_idx, neighbour_col_idx, layout) && + layout[neighbour_row_idx][neighbour_col_idx] == '#' { + adjacent_occupied += 1 + } + } + } + + return adjacent_occupied +} + +get_adjacent_visible :: proc(row_idx, col_idx: int, layout: [][]rune) -> i64 { + visible_occupied: i64 = 0 + + directions := [8]struct{dr, dc: int}{ + {-1, -1}, {-1, 0}, {-1, 1}, + { 0, -1}, { 0, 1}, + { 1, -1}, { 1, 0}, { 1, 1}, + } + for dir in directions { + r, c := row_idx + dir.dr, col_idx + dir.dc + + for is_inside_boundries(r, c, layout) { + tile := layout[r][c] + + if tile == '#' { + visible_occupied += 1 + break + } else if tile == 'L' { + break + } + + r += dir.dr + c += dir.dc + } + } + + return visible_occupied +} + +part_1 :: proc(lines: []string) { + result: i64 = 0 + + layout := slice.mapper(lines, proc(line: string) -> []rune { + return utf8.string_to_runes(line) + }) + + changed := true + for changed { + new_layout := slice.clone(layout) + for row, row_idx in layout do new_layout[row_idx] = slice.clone(row) + changed = false + + for row, row_idx in layout { + for tile, col_idx in row { + if tile == '#' { + adjacent_occupied := get_adjacent_occupied(row_idx, col_idx, layout) + if adjacent_occupied >= 4 { + new_layout[row_idx][col_idx] = 'L' + changed = true + } + } else if tile == 'L' { + adjacent_occupied := get_adjacent_occupied(row_idx, col_idx, layout) + if adjacent_occupied == 0 { + new_layout[row_idx][col_idx] = '#' + changed = true + } + } + } + } + + layout = new_layout + } + + + result = slice.reduce(layout, i64(0), proc(res: i64, row: []rune) -> i64 { + return res + i64(slice.count(row, '#')) + }) + fmt.printfln("Part 1: %d", result) +} + +part_2 :: proc(lines: []string) { + result: i64 = 0 + + layout := slice.mapper(lines, proc(line: string) -> []rune { + return utf8.string_to_runes(line) + }) + + changed := true + for changed { + new_layout := slice.clone(layout) + for row, row_idx in layout do new_layout[row_idx] = slice.clone(row) + changed = false + + for row, row_idx in layout { + for tile, col_idx in row { + if tile == '#' { + adjacent_occupied := get_adjacent_visible(row_idx, col_idx, layout) + if adjacent_occupied >= 5 { + new_layout[row_idx][col_idx] = 'L' + changed = true + } + } else if tile == 'L' { + adjacent_occupied := get_adjacent_visible(row_idx, col_idx, layout) + if adjacent_occupied == 0 { + new_layout[row_idx][col_idx] = '#' + changed = true + } + } + } + } + + layout = new_layout + } + + result = slice.reduce(layout, i64(0), proc(res: i64, row: []rune) -> i64 { + return res + i64(slice.count(row, '#')) + }) + fmt.printfln("Part 2: %d", result) +} + +main :: proc() { + context.allocator = context.temp_allocator + defer free_all(context.temp_allocator) + + INPUT :: #load("input.txt", string) + lines := strings.split(INPUT, "\n") + lines = lines[:len(lines)-1] + + part_1(lines) + part_2(lines) +}