-
Notifications
You must be signed in to change notification settings - Fork 10
/
Copy pathDay07.fs
92 lines (77 loc) · 2.7 KB
/
Day07.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
module Year2015Day07
open AdventOfCode.FSharp.Common
// TODO: Replace with Union-Find
type Value =
| Wire of string
| Signal of int
let parseValue v =
try
int v |> Signal
with _ ->
Wire v
type Operation =
| Set of Value * string
| And of Value * Value * string
| LeftShift of Value * Value * string
| Not of Value * string
| Or of Value * Value * string
| RightShift of Value * Value * string
let parseOp (op : string) =
let args = splitBy " " id op
if args.[0] = "NOT" then Not (parseValue args.[1], args.[3])
elif args.[1] = "LSHIFT" then LeftShift (parseValue args.[0], parseValue args.[2], args.[4])
elif args.[1] = "AND" then And (parseValue args.[0], parseValue args.[2], args.[4])
elif args.[1] = "OR" then Or (parseValue args.[0], parseValue args.[2], args.[4])
elif args.[1] = "RSHIFT" then RightShift (parseValue args.[0], parseValue args.[2], args.[4])
elif args.Length = 3 then Set (parseValue args.[0], args.[2])
else failwithf "%s" op
let parse = parseEachLine parseOp >> Seq.toArray
let applyOp (vals : Map<string, int>) op =
let getVal v : int option =
match v with
| Signal v' -> Some v'
| Wire w -> Map.tryFind w vals
match op with
| Set (v1, v2) ->
match getVal v1 with
| Some v1' -> Map.add v2 v1' vals
| None -> vals
| And (v1, v2, v3) ->
match (getVal v1, getVal v2) with
| Some v1', Some v2' -> Map.add v3 (v1' &&& v2') vals
| _ -> vals
| Or (v1, v2, v3) ->
match (getVal v1, getVal v2) with
| Some v1', Some v2' -> Map.add v3 (v1' ||| v2') vals
| _ -> vals
| Not (v1, v2) ->
match getVal v1 with
| Some v1' -> Map.add v2 (~~~ v1') vals
| _ -> vals
| LeftShift (v1, v2, v3) ->
match (getVal v1, getVal v2) with
| Some v1', Some v2' -> Map.add v3 (v1' <<< v2') vals
| _ -> vals
| RightShift (v1, v2, v3) ->
match (getVal v1, getVal v2) with
| Some v1', Some v2' -> Map.add v3 (v1' >>> v2') vals
| _ -> vals
let solvePart1 input =
let rec keepTrying vals =
if Map.containsKey "a" vals then vals.["a"]
else
input
|> Seq.fold applyOp vals
|> keepTrying
keepTrying Map.empty
let solvePart2 input =
let newB = solvePart1 input
let newInput = Array.append input [| Set (Signal newB, "b")|]
let rec keepTrying vals =
if Map.containsKey "a" vals then vals.["a"]
else
newInput
|> Seq.fold applyOp vals
|> keepTrying
keepTrying Map.empty
let solver = { parse = parse; part1 = solvePart1; part2 = solvePart2 }