Completed
Push — master ( 3a9d45...3a1491 )
by Rémi
02:34
created

Hangman::currentPlayerGoodProposition()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 14
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 2

Importance

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