Really slow day 12 part 2 solution
This commit is contained in:
parent
a9e5391187
commit
8b63de7df5
1 changed files with 35 additions and 19 deletions
|
@ -1,29 +1,45 @@
|
|||
import ./common, std/[sequtils, algorithm, sugar, sets, strformat, strutils, tables]
|
||||
|
||||
proc toGraph(lines: seq[string]): Table[string, HashSet[string]] =
|
||||
result = initTable[string, HashSet[string]]()
|
||||
for l in lines:
|
||||
let nodes = l.split("-")
|
||||
if result.hasKey(nodes[0]): result[nodes[0]].incl(nodes[1])
|
||||
else: result[nodes[0]] = toHashSet([nodes[1]])
|
||||
if result.hasKey(nodes[1]): result[nodes[1]].incl(nodes[0])
|
||||
else: result[nodes[1]] = toHashSet([nodes[0]])
|
||||
type
|
||||
Lines = seq[string]
|
||||
Path = seq[string]
|
||||
NodeSet = HashSet[string]
|
||||
Graph = Table[string, NodeSet]
|
||||
|
||||
proc visit(curNode: string, graph: Table[string, HashSet[string]], visitedNodes: HashSet[string], hasVisitedSmallCaveTwice = true): int =
|
||||
if curNode == "end": return 1
|
||||
echo visitedNodes, curNode, " (", hasVisitedSmallCaveTwice, ")"
|
||||
var isBig = curNode == curNode.toUpper()
|
||||
if not isBig and not hasVisitedSmallCaveTwice and curNode != "start":
|
||||
for node in (graph[curNode] - visitedNodes): result += visit(node, graph, visitedNodes, true)
|
||||
var newVisitedNodes = visitedNodes
|
||||
if not isBig: newVisitedNodes.incl(curNode)
|
||||
for node in (graph[curNode] - visitedNodes): result += visit(node, graph, newVisitedNodes, hasVisitedSmallCaveTwice)
|
||||
proc toGraph(lines: Lines): Graph =
|
||||
for l in lines:
|
||||
let nodes = l.split "-"
|
||||
if result.hasKey nodes[0]: result[nodes[0]].incl nodes[1]
|
||||
else: result[nodes[0]] = toHashSet [nodes[1]]
|
||||
if result.hasKey nodes[1]: result[nodes[1]].incl nodes[0]
|
||||
else: result[nodes[1]] = toHashSet [nodes[0]]
|
||||
|
||||
proc basicIneligibleNodes(path: Path): NodeSet =
|
||||
for n in path:
|
||||
if n in ["start", "end"] or n.toUpper != n:
|
||||
result.incl n
|
||||
|
||||
proc part2IneligibleNodes(path: Path): NodeSet =
|
||||
# determine if we've double visited any small caves yet
|
||||
var hasVisitedSingleSmallCaveTwice: bool = path.filterIt(not (it in ["start", "end"]) and it != it.toUpper).toCountTable.values.toSeq.anyIt(it >= 2)
|
||||
for n in path:
|
||||
let isStartOrEnd = n == "start" or n == "end"
|
||||
let isSmall = n.toUpper != n
|
||||
if isStartOrEnd or (isSmall and hasVisitedSingleSmallCaveTwice): result.incl n
|
||||
|
||||
# TODO: tail-call optimization?
|
||||
proc visit(node: string, graph: Graph, ineligibleNodesReducer: (Path) -> NodeSet, path: Path = @[]): int =
|
||||
if node == "end": return 1
|
||||
let newPath = path & @[node]
|
||||
let forbiddenNodes = newPath.ineligibleNodesReducer()
|
||||
let toVisit = graph[node] - forbiddenNodes
|
||||
for n in toVisit: result += visit(n, graph, ineligibleNodesReducer, newPath)
|
||||
|
||||
proc pathing(input: seq[string]): int =
|
||||
visit("start", input.toGraph, toHashSet[string]([]))
|
||||
visit("start", input.toGraph, basicIneligibleNodes)
|
||||
|
||||
proc pathing2(input: seq[string]): int =
|
||||
visit("start", input.toGraph, toHashSet[string]([]), false)
|
||||
visit("start", input.toGraph, part2IneligibleNodes)
|
||||
|
||||
const smallTestInput = @[
|
||||
"start-A",
|
||||
|
|
Loading…
Reference in a new issue