Completed
Push — master ( 144ff2...6ebbcb )
by Jesse
02:12
created

Match::beginNextTurnFor()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 2
c 0
b 0
f 0
nc 1
nop 2
dl 0
loc 6
rs 10
1
<?php declare(strict_types=1);
2
3
namespace Stratadox\CardGame\Match;
4
5
use DateTimeInterface;
6
use Stratadox\CardGame\DomainEventRecorder;
7
use Stratadox\CardGame\DomainEventRecording;
8
use Stratadox\CardGame\Match\Event\MatchHasBegun;
9
use Stratadox\CardGame\Match\Event\NextTurnBegan;
10
use Stratadox\CardGame\Match\Event\StartedMatchForProposal;
11
use Stratadox\CardGame\Proposal\ProposalId;
12
13
final class Match implements DomainEventRecorder
14
{
15
    use DomainEventRecording;
16
17
    private $id;
18
    private $turn;
19
    private $players;
20
21
    private function __construct(
22
        MatchId $id,
23
        Turn $turn,
24
        Players $players,
25
        array $events
26
    ) {
27
        $this->id = $id;
28
        $this->turn = $turn;
29
        $this->players = $players;
30
        $this->happened(...$events);
31
    }
32
33
    public static function fromProposal(
34
        MatchId $id,
35
        ProposalId $proposal,
36
        Decks $decks,
37
        DateTimeInterface $startTime
38
    ): self {
39
        return Match::begin(
40
            $id,
41
            new StartedMatchForProposal($id, $proposal),
42
            new Players(
43
                Player::from(0, $decks[0]->cards()),
44
                Player::from(1, $decks[1]->cards())
45
            ),
46
            $startTime
47
        );
48
    }
49
50
    private static function begin(
51
        MatchId $id,
52
        MatchEvent $creationEvent,
53
        Players $players,
54
        DateTimeInterface $startTime
55
    ): Match {
56
        $whoBegins = $players->pickRandom();
57
        return new Match(
58
            $id,
59
            new Turn($whoBegins, $startTime),
60
            $players,
61
            [$creationEvent, new MatchHasBegun($id, $whoBegins)]
62
        );
63
    }
64
65
    public function id(): MatchId
66
    {
67
        return $this->id;
68
    }
69
70
    /**
71
     * @throws NotEnoughMana
72
     * @throws NotYourTurn
73
     */
74
    public function playTheCard(
75
        int $cardNumber,
76
        int $player,
77
        DateTimeInterface $when
78
    ): void {
79
        if ($this->turn->prohibitsPlaying($player, $when)) {
80
            throw NotYourTurn::cannotPlayCards();
81
        }
82
83
        $this->players[$player]->playTheCard($cardNumber, $this->id);
84
85
        $this->happened(...$this->players[$player]->domainEvents());
86
        $this->players[$player]->eraseEvents();
87
    }
88
89
    /**
90
     * @throws NoSuchCard
91
     * @throws NotYourTurn
92
     */
93
    public function attackWithCard(
94
        int $cardNumber,
95
        int $playerNumber,
96
        DateTimeInterface $when
97
    ): void {
98
        if ($this->turn->prohibitsAttacking($playerNumber, $when)) {
99
            throw NotYourTurn::cannotAttack();
100
        }
101
102
        $this->players[$playerNumber]->attackWith($cardNumber, $this->id);
103
104
        $this->happened(...$this->players[$playerNumber]->domainEvents());
105
        $this->players[$playerNumber]->eraseEvents();
106
    }
107
108
    /**
109
     * @throws NoSuchCard
110
     * @throws NotYourTurn
111
     */
112
    public function defendAgainst(
113
        int $attacker,
114
        int $defender,
115
        int $defendingPlayer,
116
        DateTimeInterface $when
117
    ): void {
118
        if ($this->turn->prohibitsDefending($defendingPlayer, $when)) {
119
            throw NotYourTurn::cannotDefend();
120
        }
121
122
        $this->players[$defendingPlayer]->defendAgainst($attacker, $defender, $this->id);
123
124
        $this->happened(...$this->players[$defendingPlayer]->domainEvents());
125
        $this->players[$defendingPlayer]->eraseEvents();
126
    }
127
128
    public function drawOpeningHands(): void
129
    {
130
        $this->players->drawOpeningHands($this->id);
131
132
        foreach ($this->players as $player) {
133
            $this->happened(...$player->domainEvents());
134
            $player->eraseEvents();
135
        }
136
    }
137
138
    /** @throws NotYourTurn */
139
    public function endCardPlayingPhaseFor(
140
        int $playerNumber,
141
        DateTimeInterface $when
142
    ): void {
143
        $this->turn = $this->turn->endCardPlayingPhaseFor($playerNumber, $when);
144
    }
145
146
    /** @throws NotYourTurn */
147
    public function endTurnOf(int $playerNumber, DateTimeInterface $when): void
148
    {
149
        $this->turn = $this->turn->beginTheTurnOf(
150
            $this->players->after($playerNumber),
151
            $when,
152
            $playerNumber
153
        );
154
        $this->happened(
155
            new NextTurnBegan($this->id, $this->players->after($playerNumber))
156
        );
157
    }
158
159
    /** @throws NotYourTurn */
160
    public function letTheCombatBegin(int $defender, DateTimeInterface $when): void
161
    {
162
        if ($this->turn->prohibitsStartingCombat($defender, $when)) {
163
            throw NotYourTurn::cannotStartCombat();
164
        }
165
166
        $this->players[$defender]->counterTheAttackersOf(
167
            $this->players->after($defender),
168
            $this->id,
169
            $this->players[$this->players->after($defender)]->attackers()
170
        );
171
        $this->turn = $this->turn->endCombatPhase();
172
173
        $this->happened(...$this->players[$defender]->domainEvents());
174
        $this->players[$defender]->eraseEvents();
175
    }
176
}
177