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
|
open System
open System.Collections.Generic
open System.IO
open System.Text.RegularExpressions
let input = File.ReadAllLines "day10.txt"
type Target =
| Bot of int
| Output of int
let (|Regex|_|) pattern input =
let m = Regex.Match(input, pattern)
if m.Success then Some(List.tail [ for g in m.Groups -> g.Value ])
else None
let (|Int|) x = Int32.Parse x
let (|Target|) = function | "bot" -> Bot | _ -> Output
type Bot =
{
Number : int
Microchips : int list
LowTarget : Target
HiTarget : Target
}
let events =
let bots = new Dictionary<int, Bot>()
input
|> Array.sort
|> Array.iter (fun line ->
match line with
| Regex "bot (\d*) gives low to (bot|output) (\d*) and high to (bot|output) (\d*)"
[ Int botN; Target lowT; Int lowN; Target hiT; Int hiN ] ->
let bot =
{
Number = botN
Microchips = []
LowTarget = lowT lowN
HiTarget = hiT hiN
}
bots.Add(botN, bot)
| Regex "value (\d*) goes to bot (\d*)" [ Int value; Int botN ] ->
let bot = bots.[botN]
bots.[botN] <- { bot with Microchips = value::bot.Microchips }
| _ -> ())
let give value = function
| Bot botN ->
let bot = bots.[botN]
bots.[botN] <- { bot with Microchips = value::bot.Microchips }
| _ -> ()
let botsWithTwo =
bots
|> Seq.map (fun kvp -> kvp.Value)
|> Seq.filter (fun bot -> bot.Microchips.Length = 2)
seq {
while Seq.length botsWithTwo > 0 do
for bot in (Array.ofSeq botsWithTwo) do
let vals = bot.Microchips |> List.sort
let lowVal, hiVal = vals[0], vals[1]
bots.[bot.Number] <- { bot with Microchips = [] }
give lowVal bot.LowTarget
give hiVal bot.HiTarget
yield bot.Number, (bot.LowTarget, lowVal), (bot.HiTarget, hiVal)
}
let part1 =
events
|> Seq.pick (fun (botN, (_, lowVal), (_, hiVal)) ->
if lowVal = 17 && hiVal = 61 then Some botN else None)
let part2 =
let isOutput0To2 = function
| Output 0 | Output 1 | Output 2 -> true
| _ -> false
events
|> Seq.collect (fun (botN, (lowTarget, lowVal), (hiTarget, hiVal)) ->
seq {
if isOutput0To2 lowTarget then yield lowVal
if isOutput0To2 hiTarget then yield hiVal
})
|> Seq.take 3
|> Seq.reduce (*)
part1 |> printfn "%A"
part2 |> printfn "%A"
|