Test Setup Failed
Push — master ( 647a95...23a558 )
by Jesse
02:13
created

Player::from()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
cc 1
eloc 1
c 1
b 0
f 1
nc 1
nop 2
dl 0
loc 3
rs 10
1
<?php declare(strict_types=1);
2
3
namespace Stratadox\CardGame\Match;
4
5
use function count;
6
use Stratadox\CardGame\DomainEventRecorder;
7
use Stratadox\CardGame\DomainEventRecording;
8
use Throwable;
9
10
final class Player implements DomainEventRecorder
11
{
12
    use DomainEventRecording;
13
14
    private $playerNumber;
15
    private $cards;
16
    private $maxHandSize;
17
    private $mana;
18
19
    public function __construct(
20
        int $id,
21
        Cards $cards,
22
        int $maxHandSize,
23
        Mana $mana
24
    ) {
25
        $this->playerNumber = $id;
26
        $this->cards = $cards;
27
        $this->maxHandSize = $maxHandSize;
28
        $this->mana = $mana;
29
    }
30
31
    public static function from(int $playerId, Cards $cards): self
32
    {
33
        return new self($playerId, $cards, 7, new Mana(4));
34
    }
35
36
    /** @throws NotEnoughMana */
37
    public function playTheCard(int $cardNumber, MatchId $match): void
38
    {
39
        $card = $this->cards->inHand()[$cardNumber];
40
41
        if ($this->mana->isLessThan($card->cost())) {
42
            throw NotEnoughMana::toPlayThatCard();
43
        }
44
45
        $this->mana = $this->mana->minus($card->cost());
46
        $card->play($match, count($this->cards->inPlay()), $this->playerNumber);
47
48
        $this->happened(...$card->domainEvents());
49
        $card->eraseEvents();
50
    }
51
52
    /** @throws NoSuchCard */
53
    public function attackWith(int $cardNumber, MatchId $match): void
54
    {
55
        $card = $this->cardInPlay($cardNumber);
56
        $card->sendToAttack($match, count($this->attackers()), $this->playerNumber);
57
58
        $this->happened(...$card->domainEvents());
59
        $card->eraseEvents();
60
    }
61
62
    /** @throws NoSuchCard */
63
    public function defendAgainst(
64
        int $attacker,
65
        int $defender,
66
        MatchId $match
67
    ): void {
68
        $card = $this->cardInPlay($defender);
69
        $card->sendToDefendAgainst($match, $attacker, $this->playerNumber);
70
71
        $this->happened(...$card->domainEvents());
72
        $card->eraseEvents();
73
    }
74
75
    public function attackers(): Cards
76
    {
77
        return $this->cards->thatAttack();
78
    }
79
80
    public function hasAttackingUnits(): bool
81
    {
82
        return count($this->attackers()) > 0;
83
    }
84
85
    public function drawOpeningHand(MatchId $match): void
86
    {
87
        for ($i = 0; $i < $this->maxHandSize; $i++) {
88
            $this->cards->drawFromTopOfDeck($match, $this->playerNumber);
89
        }
90
        foreach ($this->cards->inHand() as $card) {
91
            $this->happened(...$card->domainEvents());
92
            $card->eraseEvents();
93
        }
94
    }
95
96
    public function counterTheAttackersOf(
97
        int $attackingPlayer,
98
        MatchId $match,
99
        Cards $attackers
100
    ): void {
101
        foreach ($this->cards->thatDefend() as $defender) {
102
            $defender->counterAttack(
103
                $match,
104
                $attackers->theOneThatAttacksTheAmbushOf($defender),
105
                $this->playerNumber,
106
                $attackingPlayer
107
            );
108
            $this->happened(...$defender->domainEvents());
109
            $defender->eraseEvents();
110
        }
111
    }
112
113
    public function endCombatPhase(MatchId $match): void
114
    {
115
        $cards = $this->cards->inPlay();
116
        foreach ($cards as $position => $card) {
117
            $card->regroup($match, $position, $this->playerNumber);
118
            $this->happened(...$card->domainEvents());
119
            $card->eraseEvents();
120
        }
121
    }
122
123
    /** @throws NoSuchCard */
124
    private function cardInPlay(int $number): Card
125
    {
126
        try {
127
            return $this->cards->inPlay()[$number];
128
        } catch (Throwable $notFound) {
129
            throw NoSuchCard::atPosition($number, $notFound);
130
        }
131
    }
132
}
133