Hill Climbing Algorithm
Description: https://adventofcode.com/2022/day/12
open System.IO
open System
type Index = int * int
type Node = Index * char
let readInput =
seq {
use sr = new StreamReader("./input.txt")
while not sr.EndOfStream do
yield sr.ReadLine()
}
let nodes: Node list =
readInput
|> Seq.indexed
|> Seq.map (fun (y, xRow) -> xRow |> Seq.mapi (fun x value -> ((x, y), value)): seq<Index * char>)
|> Seq.fold (fun acc x -> Seq.append acc x) Seq.empty
|> Seq.toList
let start = nodes |> List.find (fun x -> (x |> snd) = 'S')
let finish = nodes |> List.find (fun x -> (x |> snd) = 'E')
let nodesList: Node list =
nodes
|> List.map (fun x ->
match x with
| i, 'S' -> (i, 'a')
| i, 'E' -> (i, 'z')
| _ -> x)
let getNode (i: Index) =
nodesList |> List.find (fun x -> fst x = i)
let neighbors (i: Index) (map: Node -> Node -> bool)=
let x, y = i
let iNode = getNode i
let mutable neighbors: Index list = []
if x - 1 >= 0 then
neighbors <- neighbors @ [(x - 1, y)]
if x + 1 <= 142 then
neighbors <- neighbors @ [(x + 1, y)]
if y - 1 >= 0 then
neighbors <- neighbors @ [(x, y - 1)]
if y + 1 <= 40 then
neighbors <- neighbors @ [(x, y + 1)]
neighbors
|> List.map (fun x -> getNode x)
|> List.filter (fun x -> ((map iNode x)))
let bfs (start: Node) (finish: Node -> bool) (map: Node -> Node -> bool) =
let rec find (queue: (int * Node) list) (visited: Node list) =
match queue with
| [] -> None
| (dist, node) :: tail ->
if (finish node) then
Some dist
else
let next =
neighbors (fst node) map
|> List.filter (fun x -> visited |> List.exists (fun n -> n = x) |> not)
|> List.filter (fun x -> tail |> List.exists (fun (_, n) -> n = x) |> not)
|> List.map (fun x -> (dist + 1, x))
let newQueue = tail @ next
let newVisited = visited @ [ node ]
find newQueue newVisited
find [ (0, start) ] [ start ]
let part = (Environment.GetCommandLineArgs()[1]) |> int
let mapData = (fun s e -> (e |> int) - 1 <= (s |> int))
match part with
| 1 ->
let start = (fst start, 'a')
let finishCheck (n: Node) = fst n = fst finish
let neighborsMap (s: Node) (e: Node) = mapData (snd s) (snd e)
(start, finishCheck, neighborsMap)
| _ ->
let start = (fst finish, 'z')
let finishCheck (n: Node) = snd n = 'a'
let neighborsMap (s: Node) (e: Node) = mapData (snd e) (snd s)
(start, finishCheck, neighborsMap)
|> (fun (s, f, n) -> bfs s f n) |> printfn "%A"