Skip to content

Instantly share code, notes, and snippets.

@object
Created December 11, 2020 06:46
Show Gist options
  • Select an option

  • Save object/9bce347fa411e1cbea0d12a035b5804a to your computer and use it in GitHub Desktop.

Select an option

Save object/9bce347fa411e1cbea0d12a035b5804a to your computer and use it in GitHub Desktop.
AdventOfCode 2020, December 11
type SeatStatus =
| Floor
| Empty
| Occupied
let parseStatus ch = match ch with | '.' -> Floor | 'L' -> Empty | _ -> Occupied
let input =
File.ReadAllLines("Data/input11.txt")
|> Array.filter (not << String.IsNullOrEmpty)
|> Array.map Seq.toArray
|> Array.map (fun line -> line |> Array.map (fun ch -> parseStatus ch))
let getNeighbours (area : SeatStatus array array) position =
let rows = area.Length
let cols = area.[0].Length
let row,col = position
[| (row-1,col-1); (row-1,col); (row-1,col+1); (row,col-1); (row,col+1); (row+1,col-1); (row+1,col); (row+1,col+1) |]
|> Array.filter (fun (row,col) -> row >= 0 && col >= 0 && row < rows && col < cols)
let rec findSeat (area : SeatStatus array array) currentSeat getNextSeat =
getNextSeat area currentSeat
|> Option.bind (fun nextSeat ->
let row, col = nextSeat
match area.[row].[col] with
| Empty | Occupied -> Some nextSeat
| Floor -> findSeat area nextSeat getNextSeat)
let getVisible (area : SeatStatus array array) position =
let rows = area.Length
let cols = area.[0].Length
[|
findSeat area position (fun _ position ->
let row,col = position
if row = 0 || col = 0 then None else Some (row-1,col-1))
findSeat area position (fun _ position ->
let row,col = position
if row = 0 then None else Some (row-1,col))
findSeat area position (fun _ position ->
let row,col = position
if row = 0 || col = cols-1 then None else Some (row-1,col+1))
findSeat area position (fun _ position ->
let row,col = position
if col = 0 then None else Some (row,col-1))
findSeat area position (fun _ position ->
let row,col = position
if col = cols-1 then None else Some (row,col+1))
findSeat area position (fun _ position ->
let row,col = position
if row = rows-1 || col = 0 then None else Some (row+1,col-1))
findSeat area position (fun _ position ->
let row,col = position
if row = rows-1 then None else Some (row+1,col))
findSeat area position (fun _ position ->
let row,col = position
if row = rows-1 || col = cols-1 then None else Some (row+1,col+1))
|]
|> Array.choose id
let countStatus (area : SeatStatus array array) seats status =
seats
|> Array.filter (fun (row,col) -> area.[row].[col] = status)
|> Array.length
let occupyRule1 area neighbours =
countStatus area neighbours Occupied = 0
let emptyRule1 area neighbours =
countStatus area neighbours Occupied >= 4
let occupyRule2 area visible =
countStatus area visible Occupied = 0
let emptyRule2 area visible =
countStatus area visible Occupied >= 5
let getNext getVisible occupyRule emptyRule area =
area |> Array.mapi (fun row seats ->
seats |> Array.mapi (fun col status ->
let neighbours = getVisible area (row,col)
match status with
| Empty -> if occupyRule area neighbours then Occupied else status
| Occupied -> if emptyRule area neighbours then Empty else status
| _ -> status))
let rec runUntilStop getVisible occupyRule emptyRule area =
let next = getNext getVisible occupyRule emptyRule area
if next = area then next else runUntilStop getVisible occupyRule emptyRule next
// Part 1
let result1 = runUntilStop getNeighbours occupyRule1 emptyRule1 input
result1
|> Array.sumBy (fun seats ->
seats |> Array.sumBy (fun seat -> if seat = Occupied then 1 else 0))
// Part 2
let result2 = runUntilStop getVisible occupyRule2 emptyRule2 input
result2
|> Array.sumBy (fun seats ->
seats |> Array.sumBy (fun seat -> if seat = Occupied then 1 else 0))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment