diff --git a/2021/11p1.odin b/2021/11p1.odin new file mode 100644 index 0000000..c591f04 --- /dev/null +++ b/2021/11p1.odin @@ -0,0 +1,95 @@ +package main + +import "core:fmt" +import "core:strconv" +import "core:strings" +import "utils" + +D11P1 :: proc() { + lines, backing := utils.read_lines("./inputs/11.txt") + defer delete(lines) + defer delete(backing) + + flash_total := get_octopi_energy_flashes(lines, 100) + fmt.printfln("Total flashes after 100 steps: %v", flash_total) +} + +get_octopi_energy_flashes :: proc(lines: []string, steps: int) -> int { + energy_levels := parse_octopi_energy_levels(lines) + flashes := 0 + for _ in 0 ..< steps { + flashes += simulate_octopus_step(&energy_levels) + } + return flashes +} + +parse_octopi_energy_levels :: proc(lines: []string) -> (energy_levels: [10][10]int) { + for line, i in lines { + energy_strings := strings.split(line, "", context.temp_allocator) + for str, j in energy_strings { + energy_levels[i][j] = strconv.atoi(str) + } + } + return +} + +simulate_octopus_step :: proc(energy_levels: ^[10][10]int) -> (flashes_in_step: int) { + peak_energy_indexes: [dynamic]Vec2 + defer delete(peak_energy_indexes) + + for i in 0 ..< 10 { + for j in 0 ..< 10 { + energy_levels[i][j] += 1 + if energy_levels[i][j] > 9 { + append(&peak_energy_indexes, Vec2{i, j}) + } + } + } + + flashes_in_step = simulate_octopus_energy_flash(energy_levels, &peak_energy_indexes) + return +} + +simulate_octopus_energy_flash :: proc( + energy_levels: ^[10][10]int, + peak_energy_indexes: ^[dynamic]Vec2, +) -> ( + flashes: int, +) { + for len(peak_energy_indexes) > 0 { + current := pop(peak_energy_indexes) + if energy_levels[current.x][current.y] == 0 { + continue + } + + energy_levels[current.x][current.y] = 0 + flashes += 1 + + neighbors := []Vec2 { + {current.x - 1, current.y}, + {current.x + 1, current.y}, + {current.x, current.y - 1}, + {current.x, current.y + 1}, + {current.x - 1, current.y - 1}, + {current.x - 1, current.y + 1}, + {current.x + 1, current.y - 1}, + {current.x + 1, current.y + 1}, + } + + for neighbor in neighbors { + // check if neighbor is within bounds + if neighbor.x >= 0 && neighbor.x < 10 && neighbor.y >= 0 && neighbor.y < 10 { + if energy_levels[neighbor.x][neighbor.y] == 0 { + continue + } + + energy_levels[neighbor.x][neighbor.y] += 1 + if energy_levels[neighbor.x][neighbor.y] > 9 { + append(peak_energy_indexes, neighbor) + } + } + } + } + + return +} diff --git a/2021/11p2.odin b/2021/11p2.odin new file mode 100644 index 0000000..74c3d02 --- /dev/null +++ b/2021/11p2.odin @@ -0,0 +1,24 @@ +package main + +import "core:fmt" +import "utils" + +D11P2 :: proc() { + lines, backing := utils.read_lines("./inputs/11.txt") + defer delete(lines) + defer delete(backing) + + all_flash_at_step := get_all_octopi_flash_step(lines) + fmt.printfln("All Octopi flash at step: %v", all_flash_at_step) +} + +get_all_octopi_flash_step :: proc(lines: []string) -> int { + energy_levels := parse_octopi_energy_levels(lines) + flashes := 0 + steps := 0 + for flashes != 100 { + flashes = simulate_octopus_step(&energy_levels) + steps += 1 + } + return steps +} diff --git a/2021/inputs/11.txt b/2021/inputs/11.txt new file mode 100644 index 0000000..378eb6b --- /dev/null +++ b/2021/inputs/11.txt @@ -0,0 +1,10 @@ +2478668324 +4283474125 +1663463374 +1738271323 +4285744861 +3551311515 +8574335438 +7843525826 +1366237577 +3554687226 diff --git a/2021/main.odin b/2021/main.odin index d3f40a9..54cfac6 100644 --- a/2021/main.odin +++ b/2021/main.odin @@ -31,6 +31,8 @@ solutions: map[string]proc() = { "09P2:Smoke Basin" = D09P2, "10P1:Syntax Scoring" = D10P1, "10P2:Autocomplete Scoring" = D10P2, + "11P1:Dumbo Octopus" = D11P1, + "11P2:Dumbo Octopus" = D11P2, } main :: proc() { diff --git a/2021/tests/11_test.odin b/2021/tests/11_test.odin new file mode 100644 index 0000000..4b8b546 --- /dev/null +++ b/2021/tests/11_test.odin @@ -0,0 +1,111 @@ +package main + +import "core:fmt" +import "core:testing" + +octopi_engery_levels :: []string { + "5483143223", + "2745854711", + "5264556173", + "6141336146", + "6357385478", + "4167524645", + "2176841721", + "6882881134", + "4846848554", + "5283751526", +} + +@(test) +d11p1 :: proc(t: ^testing.T) { + want := 1656 + got := get_octopi_energy_flashes(octopi_engery_levels, 100) + testing.expect(t, got == want, fmt.tprintf("Got: %v | Want: %v", got, want)) +} + +@(test) +d11p2 :: proc(t: ^testing.T) { + want := 195 + got := get_all_octopi_flash_step(octopi_engery_levels) + testing.expect(t, got == want, fmt.tprintf("Got: %v | Want: %v", got, want)) +} + +@(test) +test_parse_octopi_enegy_levels :: proc(t: ^testing.T) { + want_map := map[Vec2]int { + {0, 5} = 4, + {3, 0} = 6, + {6, 9} = 1, + {9, 2} = 8, + } + + got := parse_octopi_energy_levels(octopi_engery_levels) + for key, value in want_map { + testing.expect( + t, + got[key.x][key.y] == value, + fmt.tprintf("Incorect value at %v: Got: %v | Want: %v", key, got[key.x][key.y], value), + ) + } + + free_all() +} + +@(test) +test_octopi_state_at_step :: proc(t: ^testing.T) { + energy_levels := parse_octopi_energy_levels(octopi_engery_levels) + want_flashes := 0 + got_flashes := simulate_octopus_step(&energy_levels) + + want_map := map[Vec2]int { + {0, 2} = 9, + {4, 3} = 8, + } + for key, value in want_map { + testing.expect( + t, + energy_levels[key.x][key.y] == value, + fmt.tprintf( + "Incorect value at %v: Got: %v | Want: %v", + key, + energy_levels[key.x][key.y], + value, + ), + ) + } + + testing.expect( + t, + got_flashes == want_flashes, + fmt.tprintf("Got: %v | Want: %v", got_flashes, want_flashes), + ) + + // add another step + want_flashes = 35 + got_flashes = simulate_octopus_step(&energy_levels) + + want_map = map[Vec2]int { + {0, 2} = 0, + {4, 3} = 0, + } + for key, value in want_map { + testing.expect( + t, + energy_levels[key.x][key.y] == value, + fmt.tprintf( + "Incorect value at %v: Got: %v | Want: %v", + key, + energy_levels[key.x][key.y], + value, + ), + ) + } + + testing.expect( + t, + got_flashes == want_flashes, + fmt.tprintf("Got: %v | Want: %v", got_flashes, want_flashes), + ) + + free_all() +}