diff --git a/src/Utils.kt b/src/Utils.kt index 87aec90..23dfa16 100644 --- a/src/Utils.kt +++ b/src/Utils.kt @@ -17,6 +17,14 @@ fun readInputAsCommaSeparatedInts(day: Int, name: String) = openFile(day, name) .split(",") .map { it.toInt() } +fun readGraph(day: Int, name: String) = readInput(day, name).fold(mapOf>()) { currentGraph, edge -> + val (fromVertex, toVertex) = edge.split("-") + val fromNeighbours = currentGraph.getOrDefault(fromVertex, emptySet()) + toVertex + val toNeighbours = currentGraph.getOrDefault(toVertex, emptySet()) + fromVertex + + currentGraph + mapOf(fromVertex to fromNeighbours, toVertex to toNeighbours) +}.toMap() + /** * Converts string to md5 hash. */ diff --git a/src/year2021/day12/Day12.kt b/src/year2021/day12/Day12.kt new file mode 100644 index 0000000..d46e215 --- /dev/null +++ b/src/year2021/day12/Day12.kt @@ -0,0 +1,61 @@ +package year2021.day12 + +import readGraph + +fun findAllPaths(graph: Map>, path: List, visited: Set): Set { + if (path.last() == "end") { + return setOf(path.joinToString("-")) + } + + val neighbours = graph + .getOrDefault(path.last(), emptySet()) + .filter { it == it.uppercase() || !visited.contains(it) } + + return neighbours.map { neighbour -> + findAllPaths(graph, path + neighbour, visited + neighbour) + }.fold(emptySet()) { acc, it -> acc + it } +} + +fun part1(input: Map>): Int = + findAllPaths(input, listOf("start"), setOf("start")).size + +fun findAllPaths( + graph: Map>, + path: List, + visited: Set, + twiceVisited: Boolean +): Set { + if (path.last() == "end") { + return setOf(path.joinToString("-")) + } + + val neighbours = graph + .getOrDefault(path.last(), emptySet()) + .filter { it == it.uppercase() || (!twiceVisited && it != "start") || !visited.contains(it) } + + return neighbours.map { neighbour -> + if (neighbour == neighbour.lowercase() && visited.contains(neighbour)) + findAllPaths(graph, path + neighbour, visited, true) + else + findAllPaths(graph, path + neighbour, visited + neighbour, twiceVisited) + }.fold(emptySet()) { acc, it -> acc + it } +} + +fun part2(input: Map>): Int = findAllPaths(input, listOf("start"), setOf("start"), false).size + +fun main() { + val sample = readGraph(12, "sample") + val slightlyLargerSample = readGraph(12, "slightly_larger_sample") + val evenLargerExample = readGraph(12, "even_larger_sample") + val input = readGraph(12, "input") + + check(part1(sample) == 10) + check(part1(slightlyLargerSample) == 19) + check(part1(evenLargerExample) == 226) + println(part1(input)) + + check(part2(sample) == 36) + check(part2(slightlyLargerSample) == 103) + check(part2(evenLargerExample) == 3509) + println(part2(input)) +} diff --git a/src/year2021/day12/even_larger_sample.txt b/src/year2021/day12/even_larger_sample.txt new file mode 100644 index 0000000..da6e083 --- /dev/null +++ b/src/year2021/day12/even_larger_sample.txt @@ -0,0 +1,18 @@ +fs-end +he-DX +fs-he +start-DX +pj-DX +end-zg +zg-sl +zg-pj +pj-he +RW-he +fs-DX +pj-RW +zg-RW +start-pj +he-WI +zg-he +pj-fs +start-RW \ No newline at end of file diff --git a/src/year2021/day12/sample.txt b/src/year2021/day12/sample.txt new file mode 100644 index 0000000..898cd56 --- /dev/null +++ b/src/year2021/day12/sample.txt @@ -0,0 +1,7 @@ +start-A +start-b +A-c +A-b +b-d +A-end +b-end \ No newline at end of file diff --git a/src/year2021/day12/slightly_larger_sample.txt b/src/year2021/day12/slightly_larger_sample.txt new file mode 100644 index 0000000..ef30b81 --- /dev/null +++ b/src/year2021/day12/slightly_larger_sample.txt @@ -0,0 +1,10 @@ +dc-end +HN-start +start-kj +dc-start +dc-HN +LN-dc +HN-end +kj-sa +kj-HN +kj-dc \ No newline at end of file