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"