-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathday12_part01.fs
82 lines (72 loc) · 3.92 KB
/
day12_part01.fs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
module day12_part01
open System.IO
open CustomDataTypes
let path = "day12_input.txt"
//let path = "test_input00.txt"
//let path = "test_input01.txt"
//let path = "test_input02.txt"
let cavePaths =
File.ReadLines(__SOURCE_DIRECTORY__ + @"../../" + path) |> Seq.toList
let isLowerCase(value: string) =
let values = value.ToCharArray() |> Array.map int
values |> Array.forall(fun v -> [97..122] |> List.contains v)
let getCaveType(value: string) =
match value with
| "start" -> CaveType.START
| "end" -> CaveType.END
| _ -> if isLowerCase value then CaveType.SMALL else CaveType.BIG
//| _ -> if ([97..122] |> List.contains(value.ToCharArray().[0] |> int)) then CaveType.SMALL else CaveType.BIG
let createCave(definition: string) =
let caveParts = definition.Split('-')
let connection = { Name = caveParts.[1]; Size = getCaveType(caveParts.[1]); Connections = [] }
let cave = { Name = caveParts.[0]; Size = getCaveType(caveParts.[0]); Connections = [] }
(cave, connection)
let rec generateCaves (paths: string list, listOfCaves: Cave list) =
match paths with
| [] -> listOfCaves
| x::xs ->
let tmpCaves = createCave(x)
let oldCaveInit = listOfCaves |> List.filter(fun c -> c.Name = (fst tmpCaves).Name)
let oldCaveEnd = listOfCaves |> List.filter(fun c -> c.Name = (snd tmpCaves).Name)
if oldCaveInit.IsEmpty then
if oldCaveEnd.IsEmpty then
generateCaves (xs, listOfCaves @
[{ Name = (fst tmpCaves).Name; Size = (fst tmpCaves).Size; Connections = [snd tmpCaves] };
{ Name = (snd tmpCaves).Name; Size = (snd tmpCaves).Size; Connections = [] }])
else
generateCaves (xs, listOfCaves @ [{ Name = (fst tmpCaves).Name; Size = (fst tmpCaves).Size; Connections = [snd tmpCaves] }])
else
if oldCaveEnd.IsEmpty then
generateCaves (xs,
(listOfCaves |> List.except(oldCaveInit)) @ [{ Name = (fst tmpCaves).Name; Size = (fst tmpCaves).Size; Connections = oldCaveInit.Head.Connections @ [snd tmpCaves] };
{ Name = (snd tmpCaves).Name; Size = (snd tmpCaves).Size; Connections = [] }])
else
generateCaves (xs, (listOfCaves |> List.except(oldCaveInit)) @ [{ Name = (fst tmpCaves).Name; Size = (fst tmpCaves).Size; Connections = oldCaveInit.Head.Connections @ [snd tmpCaves] }])
let rec buildPath (from: Cave, paths: Cave list, visited: Cave list) =
let origin = paths |> List.filter(fun c -> c.Name = from.Name)
let result = seq {
match origin with
| [x] ->
let availableConnections = x.Connections @
(paths |>
List.filter(fun p -> p.Size <> CaveType.START && (p.Connections |>
List.map(fun pp -> pp.Name)) |> List.contains(x.Name)))
let filteredConnections = availableConnections |>
List.filter(fun p -> p.Size <> CaveType.START && p.Size <> CaveType.SMALL || not ((visited |> List.map(fun pp -> pp.Name)) |> List.contains(p.Name)))
let newVisited = visited @ origin
for con in filteredConnections do
match con.Name with
| "end" -> newVisited @ [con]
| _ -> yield! buildPath(con, paths, newVisited)
| _ -> []
}
result
let pathIsValid(path: Cave list) =
let smallCaves = path |> List.filter(fun c -> c.Size = CaveType.SMALL)
let groupedCaves = smallCaves |> List.groupBy(fun c -> c.Name)
groupedCaves |> List.forall(fun gc -> (snd gc).Length = 1)
let execute =
let listOfCaves = generateCaves(cavePaths, [])
let origin = listOfCaves |> List.find(fun c -> c.Name = "start")
let allPaths = buildPath(origin, listOfCaves, [])
allPaths |> Seq.toList |> List.length