Skip to content

Commit

Permalink
add day 12 solutions and tests
Browse files Browse the repository at this point in the history
  • Loading branch information
scottmckendry committed Nov 15, 2024
1 parent f147c00 commit 2f5437c
Show file tree
Hide file tree
Showing 5 changed files with 197 additions and 0 deletions.
96 changes: 96 additions & 0 deletions 2021/12p1.odin
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
package main

import "core:fmt"
import "core:strings"
import "utils"

cave :: struct {
large: bool,
connections: [dynamic]string,
}

D12P1 :: proc() {
lines, backing := utils.read_lines("./inputs/12.txt")
defer delete(lines)
defer delete(backing)

small_cave_path_total := traverse_caves(lines, true)
fmt.printfln("Paths through small caves: %v", small_cave_path_total)
}

traverse_caves :: proc(lines: []string, visited_twice: bool) -> int {
caves := parse_caves(lines)
visited := make(map[string]int)
defer {
for cave, _ in caves {
delete(caves[cave].connections)
}
delete(caves)
delete(visited)
}

return count_paths(caves, "start", &visited, visited_twice)
}

count_paths :: proc(
caves: map[string]cave,
current: string,
visited: ^map[string]int,
visited_twice: bool,
) -> int {
visited_twice_local := visited_twice
if current == "end" {
for cave, _ in caves {
if cave == "start" || cave == "end" {
continue
}
if !caves[cave].large && visited[cave] > 0 {
return 1
}
}
return 0
}

if current == "start" && visited[current] > 0 {
return 0
}

if !caves[current].large {
if visited[current] > 0 {
if visited_twice {
return 0
}
visited_twice_local = true
}
}

visited[current] += 1
defer {visited[current] -= 1}

total_paths := 0
for connection in caves[current].connections {
total_paths += count_paths(caves, connection, visited, visited_twice_local)
}

return total_paths
}


parse_caves :: proc(lines: []string) -> (caves: map[string]cave) {
for connection in lines {
connection_parts := strings.split(connection, "-", context.temp_allocator)
for part, i in &connection_parts {
mapped_cave, ok := &caves[part]
if !ok {
caves[part] = cave {
large = strings.to_upper(part, context.temp_allocator) == part,
connections = {connection_parts[(i + 1) % 2]},
}
} else {
append(&mapped_cave.connections, connection_parts[(i + 1) % 2])
}
}
}

return caves
}
13 changes: 13 additions & 0 deletions 2021/12p2.odin
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package main

import "core:fmt"
import "utils"

D12P2 :: proc() {
lines, backing := utils.read_lines("./inputs/12.txt")
defer delete(lines)
defer delete(backing)

small_cave_path_total := traverse_caves(lines, false)
fmt.printfln("Paths through small caves: %v", small_cave_path_total)
}
19 changes: 19 additions & 0 deletions 2021/inputs/12.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
lg-GW
pt-start
pt-uq
nx-lg
ve-GW
start-nx
GW-start
GW-nx
pt-SM
sx-GW
lg-end
nx-SM
lg-SM
pt-nx
end-ve
ve-SM
TG-uq
end-SM
SM-uq
2 changes: 2 additions & 0 deletions 2021/main.odin
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ solutions: map[string]proc() = {
"10P2:Autocomplete Scoring" = D10P2,
"11P1:Dumbo Octopus" = D11P1,
"11P2:Dumbo Octopus" = D11P2,
"12P1:Passage Pathfinding" = D12P1,
"12P2:Passage Pathfinding" = D12P2,
}

main :: proc() {
Expand Down
67 changes: 67 additions & 0 deletions 2021/tests/12_test.odin
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package main

import "core:fmt"
import "core:slice"
import "core:testing"

caves :: []string{"start-A", "start-b", "A-c", "A-b", "b-d", "A-end", "b-end"}

@(test)
d12p1 :: proc(t: ^testing.T) {
want := 9
got := traverse_caves(caves, true)
testing.expect(t, got == want, fmt.tprintf("Got: %v | Want: %v", got, want))
free_all()
}

@(test)
d12p2 :: proc(t: ^testing.T) {
want := 35
got := traverse_caves(caves, false)
testing.expect(t, got == want, fmt.tprintf("Got: %v | Want: %v", got, want))
free_all()
}

@(test)
test_parse_caves :: proc(t: ^testing.T) {
got := parse_caves(caves)
want_len := 6

testing.expect(t, len(got) == want_len, fmt.tprintf("Got: %v | Want: %v", len(got), want_len))

// test start
connections := got["start"].connections[:]
testing.expect(t, got["start"].large == false, "start should be small!")
testing.expect(
t,
slice.contains(connections, "A") && slice.contains(connections, "b"),
fmt.tprintf("start should connect to A and b, got: %v", got["start"].connections),
)

// test A
connections = got["A"].connections[:]
testing.expect(t, got["A"].large == true, "A should be large!")
testing.expect(
t,
slice.contains(connections, "start") &&
slice.contains(connections, "c") &&
slice.contains(connections, "b") &&
slice.contains(connections, "end"),
fmt.tprintf("A should connect to start, c, b, and end, got: %v", got["A"].connections),
)

// test d
connections = got["d"].connections[:]
testing.expect(t, got["d"].large == false, "d should be small!")
testing.expect(
t,
slice.contains(connections, "b"),
fmt.tprintf("d should connect to b! got: %v", got["d"].connections),
)

for cave in got {
delete(got[cave].connections)
}
clear(&got)
free_all()
}

0 comments on commit 2f5437c

Please sign in to comment.