-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathday_4.fsx
99 lines (80 loc) · 2.5 KB
/
day_4.fsx
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
#load "common.fsx"
open System.IO
open System
open System.Text.RegularExpressions
open System.Collections.Generic
open System.Diagnostics
let winCache = Dictionary<int, int>()
type Card = {
CardNumber: int
WinningNumbers: int Set
MyNumbers: int Set
} with
member this.Wins =
match winCache.TryGetValue(this.CardNumber) with
| true, cacheValue ->
cacheValue
| false, _ ->
let wins = (Set.intersect this.WinningNumbers this.MyNumbers).Count
winCache.Add(this.CardNumber, wins)
wins
let readInput () = Input.readAllLines "input_4.txt"
let parseCard (line: string) =
let cardNbMatch = Regex.Match(line, "Card\s+(\d+):")
let cardNb = cardNbMatch.Groups[1].Value |> int
let splitCard = line |> String.splitTrim "|"
let winningNumbers =
splitCard[0]
|> String.splitTrim ":"
|> (fun x -> x[1].Trim())
|> String.splitTrim " "
|> Array.map int
|> Set.ofArray
let myNumbers =
splitCard[1]
|> String.splitTrim " "
|> Array.map int
|> Set.ofArray
{ CardNumber = cardNb; WinningNumbers = winningNumbers; MyNumbers = myNumbers }
let rec computeScoreRec matches score =
match matches with
| 0 -> score
| _ -> computeScoreRec (matches - 1) (score * 2)
let computeScore (card: Card) =
match card.Wins with
| 0 -> 0
| _ -> computeScoreRec (card.Wins - 1) 1
// Part 1
let cards =
readInput ()
|> Array.map parseCard
|> Array.toList
let total =
cards
|> List.map (fun x -> (x.CardNumber, computeScore x))
|> List.sumBy snd
printfn "Part1: %d" total
// Part 2
let processTotal () =
let counters = Dictionary<int, int>()
let cardNumbers = cards |> List.map _.CardNumber
let getWins (cardNb: int) = cards[cardNb - 1].Wins
for i in 1 .. cards.Length do
counters.Add(i, 0)
let rec processInternal head max =
if head < max then
counters[head] <- counters[head] + 1
let winnings = getWins head
if winnings > 0 then
processInternal (head + 1) (head + winnings + 1)
processInternal (head + 1) max
let first = List.head cardNumbers
let last = List.last cardNumbers + 1
processInternal first last
// for kvp in counters do
// printfn "%d: %d" kvp.Key kvp.Value
counters
|> Seq.map (fun x -> x.Value)
|> Seq.sum
processTotal ()
|> printfn "Part2: %d"