๐Ÿ“ฆ sleepyfran / duets

๐Ÿ“„ Blackjack.Tests.fs ยท 357 lines
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
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357module Duets.Simulation.Tests.MiniGames.Blackjack

open NUnit.Framework
open FsUnit
open Test.Common
open Test.Common.Generators

open Aether
open Duets.Common
open Duets.Entities
open Duets.Entities.SituationTypes
open Duets.Simulation
open Duets.Simulation.MiniGames

let private dummyPlayingGame = MiniGame.Blackjack.create 100m<dd>

(* -------- Before the game. ------- *)

[<Test>]
let ``startGame sets the situation to betting`` () =
    Blackjack.startGame
    |> should equal (SituationChanged(PlayingMiniGame(Blackjack(Betting))))

(* -------- Betting. -------- *)

[<Test>]
let ``betting is not allowed when not in the Betting state`` () =
    Blackjack.bet dummyState (Playing dummyPlayingGame) 50m<dd>
    |> Result.unwrapError
    |> should equal Blackjack.BettingNotAllowed

[<Test>]
let ``betting is not allowed when the bet is less than 0`` () =
    Blackjack.bet dummyState Betting 0m<dd>
    |> Result.unwrapError
    |> should equal Blackjack.InvalidBet

[<Test>]
let ``betting is not allowed when the bet is more than 100`` () =
    Blackjack.bet dummyState Betting 101m<dd>
    |> Result.unwrapError
    |> should equal Blackjack.InvalidBet

[<Test>]
let ``betting is not allowed when player does not have enough balance`` () =
    let playerAccount = dummyState |> Queries.Bank.playableCharacterAccount

    let state =
        dummyState
        |> State.Bank.setBalance playerAccount (Incoming(0m<dd>, 50m<dd>))

    Blackjack.bet state Betting 80m<dd>
    |> Result.unwrapError
    |> should equal Blackjack.NotEnoughFunds

[<Test>]
let ``betting with enough balance and an allowed amount sets the situation to playing``
    ()
    =
    let effect = Blackjack.bet dummyState Betting 50m<dd> |> Result.unwrap

    match effect with
    | SituationChanged(PlayingMiniGame(Blackjack(Playing _))) -> ()
    | _ -> failwith "Unexpected effect"

(* -------- Playing. -------- *)

let private game =
    let effect = Blackjack.bet dummyState Betting 50m<dd> |> Result.unwrap

    match effect with
    | SituationChanged(PlayingMiniGame(Blackjack(Playing game))) -> game
    | _ -> failwith "Unexpected effect"

[<Test>]
let ``hitting when not playing is not allowed`` () =
    Blackjack.hit dummyState Betting
    |> Result.unwrapError
    |> should equal Blackjack.NotAllowed

[<Test>]
let ``hitting and getting less than 22 returns a Continue and updated situation effects``
    ()
    =
    let hitAllowedGame =
        { game with
            PlayerHand =
                { Cards =
                    [ { Suit = Suit.Clubs; Rank = Rank.Two }
                      { Suit = Suit.Diamonds
                        Rank = Rank.Two } ]
                  Score = ScoreType.Single 4 } }

    let result =
        Blackjack.hit dummyState (Playing hitAllowedGame) |> Result.unwrap

    match result with
    | Blackjack.Continue effects ->
        let situationEffect = effects |> List.head

        match situationEffect with
        | SituationChanged(PlayingMiniGame(Blackjack(Playing gameState))) ->
            gameState.PlayerHand.Score
            |> Blackjack.scoreValue
            |> should be (greaterThanOrEqualTo 4)
        | _ -> failwith "Unexpected effect"
    | _ -> failwith "Unexpected result"

[<Test>]
let ``hitting and getting over 21 results in busted and money is taken from the player``
    ()
    =
    (* Will deal a 10 card. *)
    use _ = changeToStaticRandom 9

    let bustGame =
        { game with
            PlayerHand =
                { Cards =
                    [ { Suit = Suit.Clubs; Rank = Rank.King }
                      { Suit = Suit.Diamonds
                        Rank = Rank.King } ]
                  Score = ScoreType.Single 10 } }

    let result = Blackjack.hit dummyState (Playing bustGame) |> Result.unwrap

    match result with
    | Blackjack.Bust(game, effects) ->
        game.PlayerHand.Score
        |> Blackjack.scoreValue
        |> should be (greaterThanOrEqualTo 22)

        effects |> List.head |> should be (ofCase (<@ SituationChanged @>))
        effects |> List.item 1 |> should be (ofCase (<@ MoneyTransferred @>))
    | _ -> failwith "Unexpected result"

[<Test>]
let ``standing when both player and dealer have the same hand value results in push``
    ()
    =
    let pushGame =
        { game with
            PlayerHand =
                { Cards =
                    [ { Suit = Suit.Clubs; Rank = Rank.King }
                      { Suit = Suit.Diamonds
                        Rank = Rank.King } ]
                  Score = ScoreType.Single 20 }
            DealerHand =
                { Cards =
                    [ { Suit = Suit.Clubs; Rank = Rank.King }
                      { Suit = Suit.Diamonds
                        Rank = Rank.King } ]
                  Score = ScoreType.Single 20 } }

    let result = Blackjack.stand dummyState (Playing pushGame) |> Result.unwrap

    match result with
    | Blackjack.Push(game, effects) ->
        game.PlayerHand.Score |> Blackjack.scoreValue |> should be (equal 20)

        game.DealerHand.Score |> Blackjack.scoreValue |> should be (equal 20)

        effects |> List.head |> should be (ofCase (<@ SituationChanged @>))
    | _ -> failwith "Unexpected result"

[<Test>]
let ``standing when both player and dealer have 21 results in push`` () =
    let pushGame =
        { game with
            PlayerHand =
                { Cards =
                    [ { Suit = Suit.Clubs; Rank = Rank.King }
                      { Suit = Suit.Diamonds
                        Rank = Rank.Ace } ]
                  Score = ScoreType.Multiple(11, 21) }
            DealerHand =
                { Cards =
                    [ { Suit = Suit.Clubs; Rank = Rank.King }
                      { Suit = Suit.Diamonds
                        Rank = Rank.Ace } ]
                  Score = ScoreType.Multiple(11, 21) } }

    let result = Blackjack.stand dummyState (Playing pushGame) |> Result.unwrap

    match result with
    | Blackjack.Push(game, effects) ->
        game.PlayerHand.Score |> Blackjack.scoreValue |> should be (equal 21)

        game.DealerHand.Score |> Blackjack.scoreValue |> should be (equal 21)

        effects |> List.head |> should be (ofCase (<@ SituationChanged @>))
    | _ -> failwith "Unexpected result"

[<Test>]
let ``standing when player has 21 and dealer does not results in blackjack for player``
    ()
    =
    let blackjackGame =
        { PlayerHand =
            { Cards =
                [ { Suit = Suit.Clubs; Rank = Rank.King }
                  { Suit = Suit.Diamonds
                    Rank = Rank.Ace } ]
              Score = ScoreType.Multiple(11, 21) }
          DealerHand =
            { Cards =
                [ { Suit = Suit.Clubs; Rank = Rank.King }
                  { Suit = Suit.Diamonds
                    Rank = Rank.Seven } ]
              Score = ScoreType.Single 17 }
          Bet = 50m<dd> }

    let result =
        Blackjack.stand dummyState (Playing blackjackGame) |> Result.unwrap

    match result with
    | Blackjack.PlayerBlackjack(game, amount, effects) ->
        game.PlayerHand.Score |> Blackjack.scoreValue |> should be (equal 21)
        game.DealerHand.Score |> Blackjack.scoreValue |> should be (equal 17)

        amount |> should equal 75m<dd>

        effects |> List.head |> should be (ofCase (<@ MoneyEarned @>))
        effects |> List.item 1 |> should be (ofCase (<@ SituationChanged @>))
    | _ -> failwith "Unexpected result"

[<Test>]
let ``standing when player has less than 21 and dealer busts results in win for player``
    ()
    =
    let dealerBustGame =
        { PlayerHand =
            { Cards =
                [ { Suit = Suit.Clubs; Rank = Rank.King }
                  { Suit = Suit.Diamonds
                    Rank = Rank.Seven } ]
              Score = ScoreType.Single 17 }
          DealerHand =
            { Cards =
                [ { Suit = Suit.Clubs; Rank = Rank.King }
                  { Suit = Suit.Diamonds
                    Rank = Rank.King }
                  { Suit = Suit.Hearts
                    Rank = Rank.Three } ]
              Score = ScoreType.Single 23 }
          Bet = 50m<dd> }

    let result =
        Blackjack.stand dummyState (Playing dealerBustGame) |> Result.unwrap

    match result with
    | Blackjack.DealerBusted(game, effects) ->
        game.PlayerHand.Score |> Blackjack.scoreValue |> should be (equal 17)
        game.DealerHand.Score |> Blackjack.scoreValue |> should be (equal 23)

        effects |> List.head |> should be (ofCase (<@ MoneyEarned @>))
        effects |> List.item 1 |> should be (ofCase (<@ SituationChanged @>))
    | _ -> failwith "Unexpected result"

[<Test>]
let ``standing when player has more than dealer results in win for player`` () =
    let winGame =
        { PlayerHand =
            { Cards =
                [ { Suit = Suit.Clubs; Rank = Rank.King }
                  { Suit = Suit.Diamonds
                    Rank = Rank.Nine } ]
              Score = ScoreType.Single 19 }
          DealerHand =
            { Cards =
                [ { Suit = Suit.Clubs; Rank = Rank.King }
                  { Suit = Suit.Diamonds
                    Rank = Rank.Seven } ]
              Score = ScoreType.Single 17 }
          Bet = 50m<dd> }

    let result = Blackjack.stand dummyState (Playing winGame) |> Result.unwrap

    match result with
    | Blackjack.PlayerWin(game, effects) ->
        game.PlayerHand.Score |> Blackjack.scoreValue |> should be (equal 19)
        game.DealerHand.Score |> Blackjack.scoreValue |> should be (equal 17)

        effects |> List.head |> should be (ofCase (<@ MoneyEarned @>))
        effects |> List.item 1 |> should be (ofCase (<@ SituationChanged @>))
    | _ -> failwith "Unexpected result"

[<Test>]
let ``standing when player has less than dealer results in loss for player``
    ()
    =
    let lossGame =
        { PlayerHand =
            { Cards =
                [ { Suit = Suit.Clubs; Rank = Rank.King }
                  { Suit = Suit.Diamonds
                    Rank = Rank.Seven } ]
              Score = ScoreType.Single 17 }
          DealerHand =
            { Cards =
                [ { Suit = Suit.Clubs; Rank = Rank.King }
                  { Suit = Suit.Diamonds
                    Rank = Rank.King } ]
              Score = ScoreType.Single 20 }
          Bet = 50m<dd> }

    let result = Blackjack.stand dummyState (Playing lossGame) |> Result.unwrap

    match result with
    | Blackjack.DealerWin(game, effects) ->
        game.PlayerHand.Score |> Blackjack.scoreValue |> should be (equal 17)
        game.DealerHand.Score |> Blackjack.scoreValue |> should be (equal 20)

        effects |> List.head |> should be (ofCase (<@ MoneyTransferred @>))
        effects |> List.item 1 |> should be (ofCase (<@ SituationChanged @>))
    | _ -> failwith "Unexpected result"

[<Test>]
let ``standing when the dealer has less than 17 triggers a turn for the dealer``
    ()
    =
    use _ = changeToStaticRandom 2 (* Will deal a Three. *)

    let nonFinishedGame =
        { PlayerHand =
            { Cards =
                [ { Suit = Suit.Clubs; Rank = Rank.King }
                  { Suit = Suit.Diamonds
                    Rank = Rank.Seven } ]
              Score = ScoreType.Single 17 }
          DealerHand =
            { Cards =
                [ { Suit = Suit.Clubs; Rank = Rank.King }
                  { Suit = Suit.Diamonds
                    Rank = Rank.Six } ]
              Score = ScoreType.Single 16 }
          Bet = 50m<dd> }

    let result =
        Blackjack.stand dummyState (Playing nonFinishedGame) |> Result.unwrap

    match result with
    | Blackjack.DealerWin(game, _) ->
        game.PlayerHand.Score |> Blackjack.scoreValue |> should be (equal 17)
        game.DealerHand.Score |> Blackjack.scoreValue |> should be (equal 19)
    | _ -> failwith "Unexpected result"

(* -------- After the game. -------- *)

[<Test>]
let ``leaving sets the situation back to free roam and increase time`` () =
    let effects = Blackjack.leave Betting |> Result.unwrap

    effects |> List.head |> should be (ofCase (<@ SituationChanged @>))
    effects |> List.item 1 |> should be (ofCase (<@ MiniGamePlayed @>))