Completed
Push — master ( 3a0fd5...719dbc )
by Rémi
02:36
created

Hangman::leaveGame()   B

Complexity

Conditions 5
Paths 5

Size

Total Lines 16
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 14
CRAP Score 5

Importance

Changes 4
Bugs 1 Features 1
Metric Value
c 4
b 1
f 1
dl 0
loc 16
ccs 14
cts 14
cp 1
rs 8.8571
cc 5
eloc 12
nc 5
nop 1
crap 5
1
<?php
2
3
namespace Hangman\Entity;
4
5
use Broadway\EventSourcing\EventSourcedAggregateRoot;
6
use Hangman\Event\HangmanBadLetterProposedEvent;
7
use Hangman\Event\HangmanGameCreatedEvent;
8
use Hangman\Event\HangmanGameFailedStartingEvent;
9
use Hangman\Event\HangmanGameLostEvent;
10
use Hangman\Event\HangmanGameStartedEvent;
11
use Hangman\Event\HangmanGoodLetterProposedEvent;
12
use Hangman\Event\HangmanPlayerCreatedEvent;
13
use Hangman\Event\HangmanPlayerFailedCreatingEvent;
14
use Hangman\Event\HangmanPlayerLostEvent;
15
use Hangman\Event\HangmanPlayerProposedInvalidAnswerEvent;
16
use Hangman\Event\HangmanPlayerTriedPlayingDuringAnotherPlayerTurnEvent;
17
use Hangman\Event\HangmanPlayerTriedPlayingInactiveGameEvent;
18
use Hangman\Event\HangmanPlayerTurnEvent;
19
use Hangman\Event\HangmanPlayerWinEvent;
20
use Hangman\Exception\HangmanException;
21
use Hangman\Exception\HangmanPlayerOptionsException;
22
use Hangman\Move\Answer;
23
use Hangman\Move\Proposition;
24
use Hangman\Options\HangmanPlayerOptions;
25
use Hangman\Result\HangmanBadProposition;
26
use Hangman\Result\HangmanGoodProposition;
27
use Hangman\Result\HangmanLost;
28
use Hangman\Result\HangmanWon;
29
use MiniGame\Entity\MiniGame;
30
use MiniGame\Entity\MiniGameId;
31
use MiniGame\Entity\Player;
32
use MiniGame\Entity\PlayerId;
33
use MiniGame\Entity\PlayTrait;
34
use MiniGame\GameResult;
35
use MiniGame\PlayerOptions;
36
37
class Hangman extends EventSourcedAggregateRoot implements MiniGame
38
{
39
    use PlayTrait;
40
41
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
42
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
43
    //////////////////////////////////////////////   CONSTANTS   ///////////////////////////////////////////////////
44
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
45
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
46
47
    const STATE_UNINITIALIZED = 'uninitialized';
48
    const STATE_READY = 'ready';
49
    const STATE_STARTED = 'started';
50
    const STATE_OVER = 'over';
51
52
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
53
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
54
    /////////////////////////////////////////////   PROPERTIES   ///////////////////////////////////////////////////
55
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
56
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
57
58
    /**
59
     * @var MiniGameId
60
     */
61
    private $id;
62
63
    /**
64
     * @var string
65
     */
66
    private $word;
67
68
    /**
69
     * @var HangmanPlayer[]
70
     **/
71
    private $players;
72
73
    /**
74
     * @var array
75
     */
76
    protected $gameOrder;
77
78
    /**
79
     * @var HangmanPlayer
80
     **/
81
    private $currentPlayer;
82
83
    /**
84
     * @var string
85
     */
86
    private $state;
87
88
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
89
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
90
    /////////////////////////////////////////   PRIVATE CONSTRUCTOR   //////////////////////////////////////////////
91
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
92
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
93
94
    /**
95
     * Constructor
96
     */
97 75
    private function __construct()
98
    {
99 75
        $this->state = self::STATE_UNINITIALIZED;
100 75
    }
101
102
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
103
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
104
    //////////////////////////////////////////////   ACCESSORS   ///////////////////////////////////////////////////
105
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
106
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
107
108
    /**
109
     * Returns the id of the game
110
     *
111
     * @return MiniGameId
112
     */
113 57
    public function getId()
114
    {
115 57
        return $this->id;
116
    }
117
118
    /**
119
     * Returns the aggregate id
120
     *
121
     * @return MiniGameId
122
     */
123 75
    public function getAggregateRootId()
124
    {
125 75
        return $this->id;
126
    }
127
128
    /**
129
     * Returns the name of the mini-game
130
     *
131
     * @return string
132
     */
133 3
    public static function getName()
134
    {
135 3
        return 'HANGMAN';
136
    }
137
138
    /**
139
     * Get the player identified by PlayerId
140
     *
141
     * @param  PlayerId $playerId
142
     * @return HangmanPlayer
143
     */
144 57
    public function getPlayer(PlayerId $playerId = null)
145
    {
146 57
        if ($playerId === null) {
147 3
            return null;
148
        }
149
150 54
        return isset($this->players[(string)$playerId]) ? $this->players[(string)$playerId] : null;
151
    }
152
153
    /**
154
     * Returns the player who can play
155
     *
156
     * @return Player
157
     */
158 3
    public function getCurrentPlayer()
159
    {
160 3
        return $this->currentPlayer;
161
    }
162
163
    /**
164
     * Get the players
165
     *
166
     * @return Player[]
167
     */
168 75
    public function getPlayers()
169
    {
170 75
        return $this->players;
171
    }
172
173
    /**
174
     * Is game started?
175
     *
176
     * @return bool
177
     */
178 36
    public function isGameStarted()
179
    {
180 36
        return $this->state === self::STATE_STARTED;
181
    }
182
183
    /**
184
     * Is it the player's turn?
185
     *
186
     * @param  PlayerId $playerId
187
     * @return bool
188
     */
189 36
    public function canPlayerPlay(PlayerId $playerId)
190
    {
191 36
        return $this->currentPlayer && $this->currentPlayer->getId()->equals($playerId);
192
    }
193
194
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
195
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
196
    ///////////////////////////////////////////   DOMAIN METHODS   /////////////////////////////////////////////////
197
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
198
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
199
200
    /**
201
     * Starts the game
202
     *
203
     * @param  PlayerId $playerId
204
     *
205
     * @return GameResult
206
     */
207 51
    public function startGame(PlayerId $playerId)
208
    {
209 51
        if ($this->state !== self::STATE_READY) {
210 3
            $event = new HangmanGameFailedStartingEvent(
211 3
                $this->id,
212 2
                $playerId,
213 1
                HangmanGameFailedStartingEvent::BAD_STATE
214 2
            );
215 3
            $this->apply($event);
216 3
            return $event;
217
        }
218
219 51
        if (count($this->players) === 0) {
220 3
            $event = new HangmanGameFailedStartingEvent(
221 3
                $this->id,
222 2
                $playerId,
223 1
                HangmanGameFailedStartingEvent::NO_PLAYER
224 2
            );
225 3
            $this->apply($event);
226 3
            return $event;
227
        }
228
229 48
        $event = new HangmanGameStartedEvent($this->id, $playerId);
230 48
        $this->apply($event);
231
232 48
        $this->setNextPlayer($playerId);
233
234 48
        return $event;
235
    }
236
237
    /**
238
     * Adds a player to the game
239
     *
240
     * @param  PlayerOptions $playerOptions
241
     * @throws HangmanPlayerOptionsException
242
     * @throws HangmanException
243
     * @return GameResult
244
     */
245 75
    public function addPlayerToGame(PlayerOptions $playerOptions)
246
    {
247 75
        if (! $playerOptions instanceof HangmanPlayerOptions) {
248 3
            throw new HangmanPlayerOptionsException(
249 3
                $playerOptions->getPlayerId(),
250 3
                $this->getId(),
251 1
                'Options are not recognized'
252 2
            );
253
        }
254
255 75
        if ($this->state !== self::STATE_READY) {
256 3
            $event = new HangmanPlayerFailedCreatingEvent(
257 3
                $this->id,
258 3
                $playerOptions->getPlayerId(),
259 3
                $playerOptions->getExternalReference()
260 2
            );
261 3
            $this->apply($event);
262 3
            return $event;
263
        }
264
265 75
        $event = new HangmanPlayerCreatedEvent(
266 75
            $this->id,
267 75
            $playerOptions->getPlayerId(),
268 75
            $playerOptions->getName(),
269 75
            $playerOptions->getLives(),
270 75
            $playerOptions->getExternalReference()
271 50
        );
272 75
        $this->apply($event);
273 75
        return $event;
274
    }
275
276
    /**
277
     * A player leaves the game
278
     *
279
     * @param  PlayerId $playerId
280
     * @return GameResult
281
     */
282 9
    public function leaveGame(PlayerId $playerId)
283
    {
284 9
        switch ($this->state) {
285 9
            case self::STATE_STARTED:
286 3
                $player = $this->getPlayer($playerId);
287 3
                return $player ? $this->playerLoses($player) : null;
288 6
            case self::STATE_OVER:
289 3
                break;
290 2
            default:
291 3
                if (isset($this->players[(string) $playerId])) {
292 3
                    unset($this->players[(string) $playerId]);
293 2
                }
294 3
                break;
295 4
        }
296 6
        return null;
297
    }
298
299
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
300
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
301
    //////////////////////////////////////////   PRIVATE METHODS   /////////////////////////////////////////////////
302
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
303
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
304
305
    /**
306
     * Initialize the game
307
     *
308
     * @param MiniGameId             $id
309
     * @param string                 $word
310
     */
311 75
    private function initialize(MiniGameId $id, $word)
312
    {
313 75
        $this->apply(new HangmanGameCreatedEvent($id, $word));
314 75
    }
315
316
    /**
317
     * Player proposes a letter
318
     *
319
     * @param  PlayerId $playerId
320
     * @param  Proposition $move
321
     * @return GameResult
322
     */
323 21
    private function playProposition(PlayerId $playerId, Proposition $move)
324
    {
325 21
        if ($errorEvent = $this->ensurePlayerCanPlay($playerId)) {
326 6
            $this->apply($errorEvent);
327 6
            return $errorEvent;
328
        }
329
330 15
        return $this->currentPlayerProposeLetter($move->getText());
331
    }
332
333
    /**
334
     * Player tries an answer
335
     *
336
     * @param  PlayerId $playerId
337
     * @param  Answer $move
338
     * @return GameResult
339
     */
340 15
    private function playAnswer(PlayerId $playerId, Answer $move)
341
    {
342 15
        if ($errorEvent = $this->ensurePlayerCanPlay($playerId)) {
343 3
            $this->apply($errorEvent);
344 3
            return $errorEvent;
345
        }
346
347
        try {
348 12
            return $this->currentPlayerProposeAnswer($move->getText());
349 3
        } catch (HangmanException $e) {
350 3
            $event = new HangmanPlayerProposedInvalidAnswerEvent(
351 3
                $this->getId(),
352 2
                $playerId,
353
                $move
354 2
            );
355 3
            $this->apply($event);
356 3
            return $event;
357
        }
358
    }
359
360
    /**
361
     * Returns an error event if player cannot play
362
     *
363
     * @param  PlayerId $playerId
364
     * @return GameResult
365
     */
366 36
    private function ensurePlayerCanPlay(PlayerId $playerId)
367
    {
368 36
        if (!$this->isGameStarted()) {
369 3
            $event = new HangmanPlayerTriedPlayingInactiveGameEvent(
370 3
                $this->getId(),
371
                $playerId
372 2
            );
373 3
            return $event;
374
        }
375
376 33
        if (!$this->canPlayerPlay($playerId)) {
377 6
            $event = new HangmanPlayerTriedPlayingDuringAnotherPlayerTurnEvent(
378 6
                $this->getId(),
379
                $playerId
380 4
            );
381 6
            return $event;
382
        }
383
384 27
        return null;
385
    }
386
387
    /**
388
     * Propose a letter
389
     *
390
     * @param  string   $letter
391
     * @return HangmanBadProposition|HangmanGoodProposition
392
     */
393 15
    private function currentPlayerProposeLetter($letter)
394
    {
395 15
        $capLetter = strtoupper($letter);
396 15
        $letterPresent = $this->wordContains($capLetter);
397
398 15
        $result =  (!$letterPresent)
399 13
                   ? $this->currentPlayerBadProposition($letter) // remove a life
400 15
                   : $this->currentPlayerGoodProposition($letter); // yay!
401
402 15
        return $result;
403
    }
404
405
    /**
406
     * Propose an answer
407
     *
408
     * @param  string   $answer
409
     * @return HangmanLost|HangmanWon
410
     */
411 12
    private function currentPlayerProposeAnswer($answer)
412
    {
413 12
        $this->checkAnswerIsValid($answer);
414
415 9
        if ($this->isTheAnswer(strtoupper($answer))) {
416 3
            return $this->playerWins($this->currentPlayer); // you win
417
        } else {
418 6
            return $this->playerLoses($this->currentPlayer); // you lose
419
        }
420
    }
421
422
    /**
423
     * Function to call when a bad proposition has been made
424
     *
425
     * @param  string $letter
426
     *
427
     * @return HangmanBadProposition
428
     */
429 9
    private function currentPlayerBadProposition($letter)
430
    {
431 9
        $capLetter = strtoupper($letter);
432 9
        $player = $this->currentPlayer;
433 9
        $playerId = $player->getId();
434
435 9
        $playedLetters = $this->getPlayedLettersForPlayer($playerId);
436 9
        $playedLetters[$capLetter] = $capLetter;
437 9
        $wordSoFar = $this->buildWord($playedLetters);
438 9
        $livesLost = 1;
439 9
        $remainingLives = $this->getRemainingLives($playerId) - $livesLost;
440 9
        $nextPlayerId = $this->getNextPlayerId();
441
442 9
        $event = new HangmanBadLetterProposedEvent(
443 9
            $this->id,
444 6
            $playerId,
445 6
            $capLetter,
446 6
            $playedLetters,
447 6
            $livesLost,
448 6
            $remainingLives,
449
            $wordSoFar
450 6
        );
451 9
        $this->apply($event);
452
453 9
        if ($remainingLives === 0) {
454 6
            return $this->playerLoses($player);
455
        }
456
457 3
        $this->setNextPlayer($nextPlayerId);
458
459 3
        return $event;
460
    }
461
462
    /**
463
     * Function to call after a good proposition of letter has been made
464
     *
465
     * @param  string $letter
466
     *
467
     * @return HangmanGoodProposition
468
     */
469 6
    private function currentPlayerGoodProposition($letter)
470
    {
471 6
        $capLetter = strtoupper($letter);
472 6
        $player = $this->currentPlayer;
473 6
        $playerId = $player->getId();
474
475 6
        $playedLetters = $this->getPlayedLettersForPlayer($playerId);
476 6
        $playedLetters[$capLetter] = $capLetter;
477 6
        $wordSoFar = $this->buildWord($playedLetters);
478 6
        $remainingLives = $this->getRemainingLives($playerId);
479 6
        $nextPlayerId = $this->getNextPlayerId();
480
481 6
        $event = new HangmanGoodLetterProposedEvent(
482 6
            $this->id,
483 4
            $playerId,
484 4
            $capLetter,
485 4
            $playedLetters,
486 4
            $remainingLives,
487
            $wordSoFar
488 4
        );
489 6
        $this->apply($event);
490
491 6
        if ($this->isAllLettersFoundForPlayer($player)) {
492 3
            return $this->playerWins($player);
493
        }
494
495 3
        $this->setNextPlayer($nextPlayerId);
496
497 3
        return $event;
498
    }
499
500
    /**
501
     * Function to call when game is won by a player
502
     *
503
     * @param  HangmanPlayer $player
504
     * @return HangmanWon
505
     */
506 6
    private function playerWins(HangmanPlayer $player)
507
    {
508 6
        $playerId = $player->getId();
509
510 6
        $playedLetters = $this->getPlayedLettersForPlayer($playerId);
511 6
        $remainingLives = $this->getRemainingLives($playerId);
512
513 6
        $event = new HangmanPlayerWinEvent(
514 6
            $this->id,
515 4
            $playerId,
516 4
            $playedLetters,
517 4
            $remainingLives,
518 6
            $this->word
519 4
        );
520 6
        $this->apply($event);
521
522 6
        foreach ($this->players as $otherPlayer) {
523 6
            if ($otherPlayer->equals($player) || $otherPlayer->hasLost()) {
524 6
                continue;
525
            }
526 6
            $this->makePlayerLose($otherPlayer);
527 4
        }
528
529 6
        return $event;
530
    }
531
532
    /**
533
     * Just make one player lose
534
     *
535
     * @param  HangmanPlayer $player
536
     * @return HangmanPlayerLostEvent
537
     */
538 21
    private function makePlayerLose(HangmanPlayer $player)
539
    {
540 21
        $playerId = $player->getId();
541
542 21
        $playedLetters = $this->getPlayedLettersForPlayer($playerId);
543 21
        $remainingLives = $this->getRemainingLives($playerId);
544
545 21
        $event = new HangmanPlayerLostEvent(
546 21
            $this->id,
547 14
            $playerId,
548 14
            $playedLetters,
549 14
            $remainingLives,
550 21
            $this->buildWord($playedLetters),
551 21
            $this->word
552 14
        );
553 21
        $this->apply($event);
554
555 21
        return $event;
556
    }
557
558
    /**
559
     * Function to call when game is lost by a player
560
     *
561
     * @param  HangmanPlayer $player
562
     * @return HangmanLost
563
     */
564 15
    private function playerLoses(HangmanPlayer $player)
565
    {
566 15
        $nextPlayerId = $this->getNextPlayerId();
567
568 15
        $event = $this->makePlayerLose($player);
569
570 15
        if (count($this->gameOrder) > 0 &&
571 15
            $this->currentPlayer &&
572 13
            $player->equals($this->currentPlayer)
573 10
        ) {
574 12
            $this->setNextPlayer($nextPlayerId);
575 12
            return $event;
576
        }
577
578 3
        $event = new HangmanGameLostEvent(
579 3
            $this->id,
580 3
            $player->getId(),
581 3
            $this->word
582 2
        );
583 3
        $this->apply($event);
584
585 3
        return $event;
586
    }
587
588
    /**
589
     * Sets the next player
590
     *
591
     * @param PlayerId $id
592
     */
593 48
    private function setNextPlayer(PlayerId $id = null)
594
    {
595 48
        if ($id === null || ($this->currentPlayer && $this->currentPlayer->getId()->equals($id))) {
596
            return;
597
        }
598
599 48
        $this->apply(
600 48
            new HangmanPlayerTurnEvent($this->getId(), $id)
601 32
        );
602 48
    }
603
604
    /**
605
     * Returns the next player in line
606
     *
607
     * @return PlayerId
608
     */
609 24
    private function getNextPlayerId()
610
    {
611 24
        if ($this->currentPlayer === null) {
612
            return null;
613
        }
614
615 24
        $nbPlayers = count($this->gameOrder);
616 24
        $currentPlayerId = (string)$this->currentPlayer->getId();
617 24
        $nextPlayerPosition = (array_search($currentPlayerId, $this->gameOrder) + 1) % $nbPlayers;
618
619 24
        $pos = $nextPlayerPosition;
620
        do {
621 24
            $id = PlayerId::create($this->gameOrder[$pos]);
622 24
            $player = $this->getPlayer($id);
623
624 24
            if ($player->getState() === HangmanPlayer::STATE_IN_GAME) {
625 24
                return $id;
626
            }
627
628
            $pos = ($pos + 1) % $nbPlayers;
629
        } while ($pos !== $nextPlayerPosition);
630
631
        return null;
632
    }
633
634
    /**
635
     * Returns the list of played letters
636
     *
637
     * @param  PlayerId $playerId
638
     * @return array
639
     */
640 27
    private function getPlayedLettersForPlayer(PlayerId $playerId)
641
    {
642 27
        return $this->getPlayer($playerId)->getPlayedLetters();
643
    }
644
645
    /**
646
     * Gets the remaining lives for the player
647
     *
648
     * @param  PlayerId $playerId
649
     * @return int
650
     */
651 27
    private function getRemainingLives(PlayerId $playerId)
652
    {
653 27
        return $this->getPlayer($playerId)->getRemainingLives();
654
    }
655
656
    /**
657
     * Returns the indexes of the letter in the word
658
     *
659
     * @param  string $letter
660
     * @return boolean
661
     */
662 15
    private function wordContains($letter)
663
    {
664 15
        return strpos(strtoupper($this->word), strtoupper($letter)) !== false;
665
    }
666
667
    /**
668
     * Get the letters of the word
669
     *
670
     * @return string[]
671
     */
672 27
    private function getLettersFromWord()
673
    {
674 27
        return array_unique(str_split(strtoupper($this->word)));
675
    }
676
677
    /**
678
     * Build the word from played letters
679
     *
680
     * @param  string[] $playedLetters
681
     * @return string
682
     */
683 27
    private function buildWord($playedLetters)
684
    {
685 27
        $wordLetters = $this->getLettersFromWord();
686
687 27
        $goodLetters = array_intersect($wordLetters, $playedLetters);
688
689 27
        $splitWord = str_split(strtoupper($this->word));
690 27
        $word = '';
691 27
        foreach ($splitWord as $letter) {
692 27
            $word .= (in_array($letter, $goodLetters) ? $letter : '_') . ' ';
693 18
        }
694
695 27
        return trim($word);
696
    }
697
698
    /**
699
     * Checks if all letters for the word have been found
700
     *
701
     * @param  HangmanPlayer $player
702
     * @return bool
703
     */
704 6
    private function isAllLettersFoundForPlayer(HangmanPlayer $player)
705
    {
706 6
        $wordLetters = $this->getLettersFromWord();
707 6
        $playerLetters = $player->getPlayedLetters();
708 6
        return count(array_intersect($wordLetters, $playerLetters)) == count($wordLetters);
709
    }
710
711
    /**
712
     * Checks if the answer is valid
713
     * If it's not, ends player turn and throws an HangmanException
714
     *
715
     * @param  string $answer
716
     * @throws HangmanException
717
     */
718 12
    private function checkAnswerIsValid($answer)
719
    {
720 12
        if (strlen($answer) !== strlen($this->word)) {
721 3
            throw new HangmanException(sprintf('"%s" is not a valid answer!', $answer));
722
        }
723 9
    }
724
725
    /**
726
     * Checks if the word is the same as the solution
727
     *
728
     * @param  string $word
729
     * @return bool
730
     */
731 9
    private function isTheAnswer($word)
732
    {
733 9
        return ($this->word === strtoupper($word));
734
    }
735
736
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
737
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
738
    ////////////////////////////////////////////   APPLY EVENTS   //////////////////////////////////////////////////
739
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
740
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
741
742
    /**
743
     * Apply the game created event
744
     *
745
     * @param  HangmanGameCreatedEvent $event
746
     * @return void
747
     */
748 75
    protected function applyHangmanGameCreatedEvent(HangmanGameCreatedEvent $event)
749
    {
750 75
        $this->id = $event->getGameId();
751 75
        $this->word = strtoupper($event->getWord());
752 75
        $this->players = [];
753 75
        $this->gameOrder = [];
754 75
        $this->state = self::STATE_READY;
755 75
    }
756
757
    /**
758
     * Apply the player created event
759
     *
760
     * @param  HangmanPlayerCreatedEvent $event
761
     * @return void
762
     */
763 75
    protected function applyHangmanPlayerCreatedEvent(HangmanPlayerCreatedEvent $event)
764
    {
765 75
        $player = new HangmanPlayer(
766 75
            $event->getPlayerId(),
767 75
            $event->getPlayerName(),
768 75
            $event->getLives(),
769 50
            $this,
770 75
            $event->getExternalReference()
771 50
        );
772
773 75
        $this->gameOrder[] = (string)$player->getId();
774 75
        $this->players[(string)$player->getId()] = $player;
775 75
    }
776
777
    /**
778
     * Apply the game created event
779
     */
780 48
    protected function applyHangmanGameStartedEvent()
781
    {
782 48
        $this->state = self::STATE_STARTED;
783 48
    }
784
785
    /**
786
     * Apply the player turn event
787
     *
788
     * @param HangmanPlayerTurnEvent $event
789
     */
790 48
    protected function applyHangmanPlayerTurnEvent(HangmanPlayerTurnEvent $event)
791
    {
792 48
        $this->currentPlayer = $this->getPlayer($event->getPlayerId());
793 48
    }
794
795
    /**
796
     * Apply the hangman player lost event
797
     *
798
     * @param HangmanPlayerLostEvent $event
799
     */
800 21
    protected function applyHangmanPlayerLostEvent(HangmanPlayerLostEvent $event)
801
    {
802 21
        $this->state = self::STATE_OVER;
803 21
        unset($this->gameOrder[array_search((string) $event->getPlayerId(), $this->gameOrder)]);
804 21
    }
805
806
    /**
807
     * Apply the hangman player win event
808
     *
809
     * @return void
810
     */
811 6
    protected function applyHangmanPlayerWinEvent()
812
    {
813 6
        $this->currentPlayer = null;
814 6
        $this->state = self::STATE_OVER;
815 6
    }
816
817
    /**
818
     * Apply the hangman lost by all event
819
     *
820
     * @return void
821
     */
822 3
    protected function applyHangmanGameLostEvent()
823
    {
824 3
        $this->currentPlayer = null;
825 3
        $this->state = self::STATE_OVER;
826 3
    }
827
828
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
829
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
830
    ////////////////////////////////////////////   EVENT SOURCED   /////////////////////////////////////////////////
831
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
832
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
833
834
    /**
835
     * @return HangmanPlayer[]
836
     */
837 75
    protected function getChildEntities()
838
    {
839 75
        return $this->getPlayers();
840
    }
841
842
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
843
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
844
    /////////////////////////////////////////   STATIC CONSTRUCTOR   ///////////////////////////////////////////////
845
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
846
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
847
848
    /**
849
     * Create a new instance
850
     *
851
     * @param  MiniGameId $id
852
     * @param  string     $word
853
     * @return Hangman
854
     */
855 75
    public static function createGame(MiniGameId $id, $word)
856
    {
857 75
        $hangman = new self();
858 75
        $hangman->initialize($id, $word);
859
860 75
        return $hangman;
861
    }
862
863
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
864
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
865
    ///////////////////////////////////////////   RECONSTITUTION   /////////////////////////////////////////////////
866
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
867
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
868
869
    /**
870
     * Static construction method for reconstitution
871
     *
872
     * @return Hangman
873
     */
874 3
    public static function instantiateForReconstitution()
875
    {
876 3
        return new self();
877
    }
878
}
879