Skip to content

Commit 93e6915

Browse files
committed
add part6
1 parent b31126c commit 93e6915

File tree

4 files changed

+164
-0
lines changed

4 files changed

+164
-0
lines changed
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
source https://www.nuget.org/api/v2
2+
framework: net461
3+
nuget Hopac
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
RESTRICTION: == net461
2+
NUGET
3+
remote: https://www.nuget.org/api/v2
4+
FSharp.Core (4.3.4)
5+
Hopac (0.3.23)
6+
FSharp.Core (>= 3.1.2.5)
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
#r "packages/Hopac/lib/net45/Hopac.Core.dll"
2+
#r "packages/Hopac/lib/net45/Hopac.Platform.dll"
3+
#r "packages/Hopac/lib/net45/Hopac.dll"
4+
5+
open Hopac
6+
open Hopac.Infixes
7+
open System
8+
9+
type Ticker (timeSpan : TimeSpan) =
10+
let tickCh = Ch<DateTimeOffset>()
11+
let cancelled = IVar()
12+
13+
let tick () =
14+
Ch.give tickCh DateTimeOffset.Now
15+
16+
let rec loop () =
17+
let tickerLoop =
18+
timeOut timeSpan
19+
|> Alt.afterJob tick
20+
|> Alt.afterJob loop
21+
tickerLoop <|> IVar.read cancelled
22+
23+
do start (loop())
24+
25+
member __.Stop() =
26+
IVar.tryFill cancelled () |> start
27+
member __.C
28+
with get() = tickCh
Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
#load "ticker.fsx"
2+
open System
3+
open Ticker
4+
open Hopac
5+
6+
type Reason =
7+
| Exploded
8+
| Defused
9+
10+
type Status =
11+
| NotActivated
12+
| Alive
13+
| Dead of Reason
14+
15+
16+
type TimeBomb () =
17+
18+
let reason = IVar<Reason>()
19+
let activated = IVar()
20+
let secondsRemainingCh = Ch<int>()
21+
let inCh = Ch<char>()
22+
let rec onTick (ticker : Ticker) secondsRemaining =
23+
ticker.C
24+
|> Alt.afterJob (fun _ -> Ch.send secondsRemainingCh secondsRemaining)
25+
|> Alt.afterJob (fun _ -> onTick ticker (secondsRemaining - 1))
26+
27+
let startTicker seconds =
28+
let ticker = new Ticker(TimeSpan.FromSeconds 1.)
29+
onTick ticker (seconds - 1) |> start
30+
ticker
31+
32+
let startTimeOut seconds =
33+
let timeOutAlt =
34+
seconds
35+
|> float
36+
|> TimeSpan.FromSeconds
37+
|> timeOut
38+
39+
timeOutAlt
40+
|> Alt.afterJob (fun _ ->
41+
IVar.tryFill reason Exploded)
42+
|> start
43+
44+
let rec inputLoop defuseChar =
45+
inCh
46+
|> Alt.afterJob (fun c ->
47+
if c = defuseChar then
48+
IVar.tryFill reason Defused
49+
else
50+
inputLoop defuseChar :> Job<unit>
51+
)
52+
let activate seconds defuseChar =
53+
let ticker = startTicker seconds
54+
startTimeOut seconds
55+
IVar.tryFill activated () |> start
56+
inputLoop defuseChar |> start
57+
IVar.read reason
58+
|> Alt.afterFun (fun _ -> ticker.Stop())
59+
60+
member __.Status () =
61+
let deadReasonAlt =
62+
IVar.read reason
63+
|> Alt.afterFun Dead
64+
65+
let activatedAlt =
66+
IVar.read activated
67+
|> Alt.afterFun (fun _ -> Alive)
68+
69+
let notActivatedAlt =
70+
Alt.always NotActivated
71+
72+
Alt.choose [
73+
deadReasonAlt
74+
activatedAlt
75+
notActivatedAlt
76+
] |> run
77+
78+
member this.Activate (seconds : int, defuseChar : char) =
79+
match this.Status() with
80+
| NotActivated ->
81+
activate seconds defuseChar |> start
82+
| _ -> ()
83+
84+
member this.TryDefuse(defuseChar) =
85+
match this.Status() with
86+
| Alive ->
87+
Ch.give inCh defuseChar
88+
|> start
89+
| _ -> ()
90+
91+
member __.SecondsRemainingCh
92+
with get() = secondsRemainingCh
93+
94+
member __.DeadStatusAlt
95+
with get() = IVar.read reason
96+
97+
98+
let printSecondsRemaining (t : TimeBomb) =
99+
t.SecondsRemainingCh
100+
|> Alt.afterFun (printfn "Seconds Remaining: %d")
101+
|> Job.foreverServer |> start
102+
103+
let simulateExplosion () =
104+
let seconds = 5
105+
let t = TimeBomb()
106+
t.Status() |> printfn "Status: %A"
107+
t.Activate(seconds, 'a')
108+
printSecondsRemaining t
109+
t.Status() |> printfn "Status: %A"
110+
t.DeadStatusAlt
111+
|> Alt.afterFun (printfn "Status: %A")
112+
|> run
113+
114+
let simulateDefusal char =
115+
let seconds = 5
116+
let t = TimeBomb()
117+
t.Status() |> printfn "Status: %A"
118+
t.Activate(seconds, 'a')
119+
printSecondsRemaining t
120+
t.Status() |> printfn "Status: %A"
121+
122+
TimeSpan.FromSeconds 3.
123+
|> timeOut
124+
|> Alt.afterFun (fun _ -> t.TryDefuse(char))
125+
|> Alt.afterJob (fun _ -> t.DeadStatusAlt)
126+
|> Alt.afterFun (printfn "Status: %A")
127+
|> run

0 commit comments

Comments
 (0)