This repository has been archived by the owner on Nov 7, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathpuzzle11.fs
123 lines (104 loc) · 3.5 KB
/
puzzle11.fs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
//
// https://adventofcode.com/2020/day/11
//
#if !INTERACTIVE
module Puzzle11
#else
#load "common.fs"
#endif
open System.IO
open common
type Cell =
| Floor
| SeatEmpty
| SeatOccupied
type WaitingArea = WaitingArea of Cell[,]
let unwrap =
function
| WaitingArea cells -> cells
let create chars =
chars
|> Array2D.map (fun c -> match c with | '#' -> SeatOccupied | 'L' -> SeatEmpty | _ -> Floor)
|> WaitingArea
let copy (wa: WaitingArea) =
wa |> unwrap |> Array2D.copy |> WaitingArea
let input =
Path.Combine(__SOURCE_DIRECTORY__, "puzzle11.txt")
|> read2d
module Array2D =
let tryGet (ar:'a[,]) i j =
let x1 = Array2D.base1 ar
let x2 = Array2D.length1 ar
let y1 = Array2D.base2 ar
let y2 = Array2D.length2 ar
if (i >= x1 && i < x2 && j >= y1 && j < y2) then Some ar.[i,j]
else None
let rec evolve1 wa =
let waArray = unwrap wa
let resolve i j el =
let adjacentAndSelf = waArray.[i-1..i+1, j-1..j+1] |> Seq.cast<Cell>
match el with
| Floor -> Floor
| SeatEmpty ->
let toOccupy =
adjacentAndSelf
|> Seq.filter ((=) SeatOccupied)
|> Seq.isEmpty
if (toOccupy) then SeatOccupied else SeatEmpty
| SeatOccupied ->
let toFree =
adjacentAndSelf
|> Seq.filter ((=) SeatOccupied)
|> Seq.length
>= 5
if (toFree) then SeatEmpty else SeatOccupied
let newState = Array2D.mapi resolve waArray
if (Operators.compare newState waArray = 0)
then wa
else WaitingArea newState |> evolve1
let puzzle11_1 =
input |> create |> evolve1
|> unwrap |> Seq.cast<Cell>
|> Seq.filter ((=) SeatOccupied)
|> Seq.length
let allDirections = Seq.allPairs (seq {-1; 0; 1}) (seq {-1; 0; 1}) |> Seq.except (seq {0, 0})
|> Seq.toArray
let rec evolve2 wa =
let waArray = unwrap wa
let collectInDirection x y xDir yDir =
Seq.unfold (fun (xState, yState) ->
let newPoint = xState + xDir, yState + yDir
newPoint
||> Array2D.tryGet waArray
|> Option.map (fun el -> el, newPoint)
) (x, y)
let resolve i j el =
let visible() =
allDirections
|> Array.choose (fun (xDir, yDir) -> collectInDirection i j xDir yDir
|> Seq.filter ((<>)Floor)
|> Seq.tryHead)
match el with
| Floor -> Floor
| SeatEmpty ->
let toOccupy =
visible()
|> Seq.filter ((=) SeatOccupied)
|> Seq.isEmpty
if (toOccupy) then SeatOccupied else SeatEmpty
| SeatOccupied ->
let toFree =
visible()
|> Seq.filter ((=) SeatOccupied)
|> Seq.length
>= 5
if (toFree) then SeatEmpty else SeatOccupied
let newState = Array2D.mapi resolve waArray
if (Operators.compare newState waArray = 0)
then wa
else WaitingArea newState |> evolve2
let puzzle11_2 =
input |> create |> evolve2
|> unwrap |> Seq.cast<Cell>
|> Seq.filter ((=) SeatOccupied)
|> Seq.length