-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathday24_part02.fs
126 lines (108 loc) · 3.49 KB
/
day24_part02.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
124
125
126
module day24_part02
open AdventOfCode_2020.Modules
open AdventOfCode_Utilities
type Directions = NE | E | SE | SW | W | NW
type TileSide = White | Black
let parseContent (lines: string array) =
let parseLine line =
let initialDirection =
match Seq.head line with
| 'e' -> [E]
| 'w' -> [W]
| _ -> []
let otherDirections =
line
|> Seq.pairwise
|> Seq.choose (fun (lastChar, thisChar) ->
match (lastChar, thisChar) with
| ('n', 'e') -> Some NE
| ('s', 'e') -> Some SE
| (_, 'e') -> Some E
| ('n', 'w') -> Some NW
| ('s', 'w') -> Some SW
| (_, 'w') -> Some W
| (_, 'n') -> None
| (_, 's') -> None
| unrecognised -> failwithf "Unrecognised character pair %A" unrecognised
)
|> Seq.toList
initialDirection @ otherDirections
lines |> Seq.map parseLine
// Coordinates example:
// 0,0 2,0 4,0
// 1,1 3,1 5,1
// 0,2 2,2 4,2
let getVector direction =
match direction with
| NE -> 1, -1
| E -> 2, 0
| SE -> 1, 1
| SW -> -1, 1
| W -> -2, 0
| NW -> -1, -1
let followDirections directions =
directions
|> List.fold (fun position direction -> direction |> getVector |> add2d position) (0,0)
let flipTile (tileMap: Map<int*int, TileSide>) position =
tileMap
|> match tileMap |> Map.tryFind position with
| Some White -> Map.add position Black
| Some Black -> Map.add position White
| None -> Map.add position Black
let getTileMapFromDirections directions =
directions
|> Seq.fold (fun tileMap tileDirections ->
tileDirections
|> followDirections
|> flipTile tileMap
) Map.empty
let getNeighbours (posX, posY) =
[
posX + 1, posY - 1
posX + 2, posY
posX + 1, posY + 1
posX - 1, posY + 1
posX - 2, posY
posX - 1, posY - 1
]
let getTileColour tileMap position =
match tileMap |> Map.tryFind position with
| Some Black -> Black
| _ -> White
let countBlackNeighbours tileMap position =
position
|> getNeighbours
|> List.filter (getTileColour tileMap >> (=) Black)
|> List.length
let allTilesToConsider tileMap =
tileMap
|> Map.toList
|> List.collect (fun (pos, _) -> pos :: getNeighbours pos)
|> List.distinct
let getNextTileState tileMap position =
match (getTileColour tileMap position), (countBlackNeighbours tileMap position) with
| Black, blackNeighbours when blackNeighbours = 0 || blackNeighbours > 2 ->
White
| White, 2 ->
Black
| colour, _ ->
colour
let nextTileMap tileMap =
tileMap
|> allTilesToConsider
|> List.map (fun pos -> pos, getNextTileState tileMap pos)
|> Map.ofList
let blackTilesAfterDays directions =
let initialTileMap =
directions
|> getTileMapFromDirections
Seq.init 100 id
|> Seq.fold (fun tileMap _ -> nextTileMap tileMap) initialTileMap
|> Map.toList
|> List.filter (snd >> (=) Black)
|> List.length
let execute =
let path = "day24/day24_input.txt"
let content = LocalHelper.GetLinesFromFile path
let directions = parseContent content
blackTilesAfterDays directions