summary refs log blame commit diff stats
path: root/day24.fsx
blob: 47c76d2b80a9d5831ba4f2dcbfbea1f0da0e8444 (plain) (tree)

















































































                                                                                
open System.IO
open System.Collections.Generic

let input = File.ReadAllLines "day24.txt"

type Tile = Wall | Space | Number of int

let width, height = input.[0].Length, input.Length
let grid = Array2D.init width height (fun x y -> 
  match input.[y].[x] with
  | '#' -> Wall
  | '.' -> Space
  | num -> num |> string |> int |> Number)


let findShortestPath start target =
  let cache = new HashSet<int*int>([start])
  [| (start, 0) |]
  |> Seq.unfold (fun paths ->
    paths
    |> Seq.collect (fun ((x, y), moves) -> 
      [ x-1, y; x+1, y; x, y-1; x, y+1 ]
      |> Seq.filter (fun (x', y') -> grid.[x', y'] <> Wall && cache.Add(x', y'))
      |> Seq.map (fun (x', y') -> (x', y'), moves+1))
    |> Seq.toArray
    |> function
      | [||] -> None
      | newStates -> Some(newStates, newStates)
  )
  |> Seq.collect id
  |> Seq.pick (fun (pos, moves) -> if pos = target then Some moves else None)

let numbers = 
  [|
    for y = 0 to height-1 do
      for x = 0 to width-1 do
        match grid.[x, y] with
        | Number n -> yield n, (x, y)
        | _ -> ()
  |]
  |> Map.ofArray

let pairDistances =
  [|
    for src = 0 to 6 do
      for dest = src + 1 to 7 do
        let distance = findShortestPath numbers.[src] numbers.[dest]
        yield (src, dest), distance
        yield (dest, src), distance
  |]
  |> Map.ofArray

let part1 = 
  let rec traverse current (nodes : Set<int>) acc =
    if nodes.Count = 0 then acc
    else
      nodes
      |> Seq.map (fun next -> 
        let left = nodes.Remove next
        let dist = pairDistances.[current, next]

        traverse next left (acc + dist))
      |> Seq.min

  traverse 0 (set [1..7]) 0

let part2 = 
  let rec traverse current (nodes : Set<int>) finalDest acc =
    if nodes.Count = 0 then acc + pairDistances.[current, finalDest]
    else
      nodes
      |> Seq.map (fun next -> 
        let left = nodes.Remove next
        let dist = pairDistances.[current, next]

        traverse next left finalDest (acc + dist))
      |> Seq.min
      
  traverse 0 (set [1..7]) 0 0

part1 |> printfn "%d"
part2 |> printfn "%d"