Treetop Tree House
Description: https://adventofcode.com/2022/day/8
open System.IO
open System
type Index(x: int, y: int) =
member _.X = x
member _.Y = y
type Tree(index: Index, height: int) =
let index = index
let height = height
member _.Index = index
member _.Height = height
member val visibleLeft = false with get, set
member val visibleRight = false with get, set
member val visibleUp = false with get, set
member val visibleDown = false with get, set
member this.visible() =
this.visibleLeft || this.visibleRight || this.visibleUp || this.visibleDown
type Forest() =
let mutable trees: Tree[][] = Array.empty
let mutable down: Tree[][] = Array.empty
let mutable up: Tree[][] = Array.empty
let mutable right: Tree[][] = Array.empty
let mutable left: Tree[][] = Array.empty
let addHorizontal (tree: Tree) =
if Array.isEmpty left[tree.Index.Y] then
left[tree.Index.Y] <- Array.append left[tree.Index.Y] [| tree |]
tree.visibleLeft <- true
else if (Array.last left[tree.Index.Y]).Height < tree.Height then
left[tree.Index.Y] <- Array.append left[tree.Index.Y] [| tree |]
tree.visibleLeft <- true
Array.ForEach(right[tree.Index.Y], (fun (x: Tree) -> x.visibleRight <- false))
right[tree.Index.Y] <- Array.empty<Tree>
else if Array.isEmpty right[tree.Index.Y] then
right[tree.Index.Y] <- Array.append right[tree.Index.Y] [| tree |]
tree.visibleRight <- true
else
Array.ForEach(right[tree.Index.Y], (fun (x: Tree) -> x.visibleRight <- false))
right[tree.Index.Y] <-
(right[tree.Index.Y] |> (Array.filter (fun x -> x.Height > tree.Height)), [| tree |])
||> Array.append
Array.ForEach(right[tree.Index.Y], (fun (x: Tree) -> x.visibleRight <- true))
let addVertical (tree: Tree) =
if tree.Index.X > down.Length - 1 then
down <- Array.append down [| [| tree |] |]
tree.visibleDown <- true
up <- Array.append up [| [||] |]
else if (Array.last down[tree.Index.X]).Height < tree.Height then
down[tree.Index.X] <- Array.append down[tree.Index.X] [| tree |]
tree.visibleDown <- true
Array.ForEach(up[tree.Index.X], (fun (x: Tree) -> x.visibleUp <- false))
up[tree.Index.X] <- Array.empty<Tree>
else if Array.isEmpty up[tree.Index.X] then
up[tree.Index.X] <- Array.append up[tree.Index.X] [| tree |]
tree.visibleUp <- true
else
Array.ForEach(up[tree.Index.X], (fun (x: Tree) -> x.visibleUp <- false))
up[tree.Index.X] <-
(up[tree.Index.X] |> Array.filter (fun x -> x.Height > tree.Height), [| tree |])
||> Array.append
Array.ForEach(up[tree.Index.X], (fun (x: Tree) -> x.visibleUp <- true))
member _.Visible =
Array.fold (fun (acc: Tree[]) (x: Tree[]) -> Array.append acc x) Array.empty trees
|> Array.filter (fun x -> x.visible ())
member this.VisibleCount = this.Visible |> Array.length
member _.NewRow() =
left <- Array.append left [| [||] |]
right <- Array.append right [| [||] |]
trees <- Array.append trees [| [||] |]
member _.Add (index: Index) (height: int) =
let tree = new Tree(index, height)
trees[tree.Index.Y] <- Array.append trees[tree.Index.Y] [| tree |]
addHorizontal tree
addVertical tree
member this.Score() =
let lowerIndex (axis: Index -> int) (trees: Tree[]) =
if Array.isEmpty trees then
0
else
Array.last trees |> fun x -> x.Index |> axis
let higherIndex (maxIndex: int) (axis: Index -> int) (trees: Tree[]) =
if Array.isEmpty trees then
maxIndex
else
trees[0] |> fun x -> x.Index |> axis
let higherOrEqualHeight (height: int) (trees: Tree[]) =
trees |> Array.filter (fun x -> x.Height >= height)
let mutable maxScore = 0
for tree in this.Visible do
let filter (selector: (Index -> int)) (comparer: int -> int -> bool) (trees: Tree[]) =
Array.filter (fun (x: Tree) -> (x.Index |> selector, tree.Index |> selector) ||> comparer) trees
let vertical = trees |> Array.map (fun x -> x[tree.Index.X])
let horizontal = trees[tree.Index.Y]
let upScore =
vertical
|> filter (fun x -> x.Y) (<)
|> higherOrEqualHeight tree.Height
|> lowerIndex (fun x -> x.Y)
|> fun x -> tree.Index.Y - x
let downScore =
vertical
|> filter (fun x -> x.Y) (>)
|> higherOrEqualHeight tree.Height
|> higherIndex (trees.Length - 1) (fun x -> x.Y)
|> fun x -> x - tree.Index.Y
let leftScore =
horizontal
|> filter (fun x -> x.X) (<)
|> higherOrEqualHeight tree.Height
|> lowerIndex (fun x -> x.X)
|> fun x -> tree.Index.X - x
let rightScore =
horizontal
|> filter (fun x -> x.X) (>)
|> higherOrEqualHeight tree.Height
|> higherIndex (trees[0].Length - 1) (fun x -> x.X)
|> fun x -> x - tree.Index.X
let score = downScore * upScore * leftScore * rightScore
if (score > maxScore) then
maxScore <- score
maxScore
type Input() =
member _.Compute(part: int) =
use stream = new StreamReader "./input.txt"
let mutable endOfFile = false
let tree = new Forest()
let mutable index: Index = new Index(0, 0)
while (not endOfFile) do
let line = stream.ReadLine()
if (line = null) then
endOfFile <- true
else
index <- new Index(0, index.Y)
tree.NewRow()
for x in line do
let num: int = (int) x - (int) '0'
tree.Add index num
index <- new Index(index.X + 1, index.Y)
index <- new Index(index.X, index.Y + 1)
if part = 1 then tree.VisibleCount else tree.Score()
let input = Input()
let part = (Environment.GetCommandLineArgs()[1]) |> int
printfn "%d" (input.Compute(part))