alex-patterson-webdev /
domino-game
| 1 | <?php |
||
| 2 | |||
| 3 | declare(strict_types=1); |
||
| 4 | |||
| 5 | namespace Arp\DominoGame\Value; |
||
| 6 | |||
| 7 | use Arp\DominoGame\Exception\InvalidArgumentException; |
||
| 8 | |||
| 9 | /** |
||
| 10 | * Value object that represents the placed dominoes of the game. Internally we manage a collection of dominoes that have |
||
| 11 | * been matched by the number of dots on the exposed tile. |
||
| 12 | * |
||
| 13 | * @author Alex Patterson <[email protected]> |
||
| 14 | * @package Arp\DominoGame\Value |
||
| 15 | */ |
||
| 16 | class Board |
||
| 17 | { |
||
| 18 | /** |
||
| 19 | * The 'start' of our stack is treated as the 'left' and the 'end' is treated as the right. |
||
| 20 | * |
||
| 21 | * @var DominoCollection |
||
| 22 | */ |
||
| 23 | private DominoCollection $placed; |
||
| 24 | |||
| 25 | /** |
||
| 26 | * In memory representation of the exposed domino tiles. |
||
| 27 | * |
||
| 28 | * @var Domino|null |
||
| 29 | */ |
||
| 30 | private ?Domino $virtualDomino; |
||
| 31 | |||
| 32 | /** |
||
| 33 | * Prepare the board dependencies. |
||
| 34 | */ |
||
| 35 | public function __construct() |
||
| 36 | { |
||
| 37 | $this->placed = new DominoCollection(); |
||
| 38 | $this->virtualDomino = null; |
||
| 39 | } |
||
| 40 | |||
| 41 | /** |
||
| 42 | * Check if the board is empty (zero placed pieces) |
||
| 43 | * |
||
| 44 | * @return bool |
||
| 45 | */ |
||
| 46 | public function isEmpty(): bool |
||
| 47 | { |
||
| 48 | return (0 === $this->placed->count()); |
||
| 49 | } |
||
| 50 | |||
| 51 | /** |
||
| 52 | * Return the placed dominoes collection. |
||
| 53 | * |
||
| 54 | * @return DominoCollection |
||
| 55 | */ |
||
| 56 | public function getPlaced(): DominoCollection |
||
| 57 | { |
||
| 58 | return $this->placed; |
||
| 59 | } |
||
| 60 | |||
| 61 | /** |
||
| 62 | * Place the provided domino on the board. If we have existing pieces on the board we generate a 'virtual' domino |
||
| 63 | * that represents both left and right tiles that can be matches against. |
||
| 64 | * |
||
| 65 | * If the provided domino matches |
||
| 66 | * |
||
| 67 | * @param Domino $domino |
||
| 68 | * |
||
| 69 | * @throws InvalidArgumentException If the provided domino is invalid |
||
| 70 | */ |
||
| 71 | public function place(Domino $domino): void |
||
| 72 | { |
||
| 73 | // If there is no virtual domino we can directly add to the board as it is our first piece. |
||
| 74 | if (0 === $this->placed->count()) { |
||
| 75 | if (! $domino->isDouble()) { |
||
| 76 | throw new InvalidArgumentException( |
||
| 77 | sprintf('The first domino place must be a double \'%s\' provided', $domino->getName()) |
||
| 78 | ); |
||
| 79 | } |
||
| 80 | $this->placed->addToStart($domino); |
||
| 81 | $this->virtualDomino = new Domino($domino->getTopTile(), $domino->getBottomTile()); |
||
| 82 | return; |
||
| 83 | } |
||
| 84 | |||
| 85 | $left = $this->virtualDomino->getTopTile(); |
||
|
0 ignored issues
–
show
|
|||
| 86 | if ($left === $domino->getTopTile() || $left === $domino->getBottomTile()) { |
||
| 87 | $this->placeLeft($domino); |
||
| 88 | return; |
||
| 89 | } |
||
| 90 | |||
| 91 | $right = $this->virtualDomino->getBottomTile(); |
||
| 92 | if ($right === $domino->getBottomTile() || $right === $domino->getTopTile()) { |
||
| 93 | $this->placeRight($domino); |
||
| 94 | return; |
||
| 95 | } |
||
| 96 | |||
| 97 | throw new InvalidArgumentException( |
||
| 98 | sprintf( |
||
| 99 | 'The domino \'%s\' cannot be placed on the board; tiles must match values \'%d\' or \'%d\'', |
||
| 100 | $domino->getName(), |
||
| 101 | $this->getLeftTile(), |
||
| 102 | $this->getRightTile() |
||
| 103 | ) |
||
| 104 | ); |
||
| 105 | } |
||
| 106 | |||
| 107 | /** |
||
| 108 | * Attempt to place the provided domino with the left side of the board's pieces. We can flip the domino |
||
| 109 | * both ways so we should check both ways before updating the board. |
||
| 110 | * |
||
| 111 | * @param Domino $domino The domino that is being placed. |
||
| 112 | */ |
||
| 113 | private function placeLeft(Domino $domino): void |
||
| 114 | { |
||
| 115 | $leftTitle = $this->virtualDomino->getTopTile(); // Represents left placement |
||
| 116 | $rightTile = $this->virtualDomino->getBottomTile(); // Represents right placement |
||
| 117 | |||
| 118 | // Does the top tile match the left side of the placed pieces? |
||
| 119 | if ($domino->getTopTile() === $leftTitle) { |
||
| 120 | $this->placed->addToStart($domino); |
||
| 121 | $this->virtualDomino = new Domino($domino->getBottomTile(), $rightTile); |
||
| 122 | return; |
||
| 123 | } |
||
| 124 | |||
| 125 | // Does the bottom tile match the left side of the placed pieces? |
||
| 126 | if ($domino->getBottomTile() === $leftTitle) { |
||
| 127 | $this->placed->addToStart($domino); |
||
| 128 | $this->virtualDomino = new Domino($domino->getTopTile(), $rightTile); |
||
| 129 | return; |
||
| 130 | } |
||
| 131 | } |
||
| 132 | |||
| 133 | /** |
||
| 134 | * Attempt to place the provided domino with the right side of the board's pieces. We can flip the domino |
||
| 135 | * both ways so we should check both ways before updating the board. |
||
| 136 | * |
||
| 137 | * @param Domino $domino The domino that is being placed. |
||
| 138 | */ |
||
| 139 | private function placeRight(Domino $domino): void |
||
| 140 | { |
||
| 141 | $rightTile = $this->virtualDomino->getBottomTile(); // Represents right placement |
||
| 142 | $leftTitle = $this->virtualDomino->getTopTile(); // Represents left placement |
||
| 143 | |||
| 144 | // Does the top tile match the right side of the placed pieces? |
||
| 145 | if ($domino->getTopTile() === $rightTile) { |
||
| 146 | $this->placed->addToEnd($domino); |
||
| 147 | $this->virtualDomino = new Domino($leftTitle, $domino->getBottomTile()); |
||
| 148 | return; |
||
| 149 | } |
||
| 150 | |||
| 151 | // Does the bottom tile match the right side of the placed pieces? |
||
| 152 | if ($domino->getBottomTile() === $rightTile) { |
||
| 153 | $this->placed->addToEnd($domino); |
||
| 154 | $this->virtualDomino = new Domino($leftTitle, $domino->getTopTile()); |
||
| 155 | return; |
||
| 156 | } |
||
| 157 | } |
||
| 158 | |||
| 159 | /** |
||
| 160 | * Remove all elements from the board and reset the virtual domino to null. |
||
| 161 | */ |
||
| 162 | public function clearBoard(): void |
||
| 163 | { |
||
| 164 | $this->placed->removeElements(null); |
||
| 165 | $this->virtualDomino = null; |
||
| 166 | } |
||
| 167 | |||
| 168 | /** |
||
| 169 | * Return the domino that is places on the left most position (first position in the collection). |
||
| 170 | * |
||
| 171 | * @return Domino|null |
||
| 172 | */ |
||
| 173 | public function getLeft(): ?Domino |
||
| 174 | { |
||
| 175 | /** @var Domino $domino */ |
||
| 176 | $domino = $this->placed->first(); |
||
| 177 | return $domino; |
||
| 178 | } |
||
| 179 | |||
| 180 | /** |
||
| 181 | * Return the value of the tile that is exposed in the left most position. This is one of the targets that players |
||
| 182 | * must match a double against and matches the value of the 'top' tile. |
||
| 183 | * |
||
| 184 | * @return int|null |
||
| 185 | */ |
||
| 186 | public function getLeftTile(): ?int |
||
| 187 | { |
||
| 188 | return isset($this->virtualDomino) ? $this->virtualDomino->getTopTile() : null; |
||
| 189 | } |
||
| 190 | |||
| 191 | /** |
||
| 192 | * Return the domino that is places on the right most position (last position in the collection). |
||
| 193 | * |
||
| 194 | * @return Domino|null |
||
| 195 | */ |
||
| 196 | public function getRight(): ?Domino |
||
| 197 | { |
||
| 198 | /** @var Domino $domino */ |
||
| 199 | $domino = $this->placed->last(); |
||
| 200 | |||
| 201 | return $domino; |
||
| 202 | } |
||
| 203 | |||
| 204 | /** |
||
| 205 | * Return the value of the tile that is exposed in the right most position. This is one of the targets that players |
||
| 206 | * must match a double against and matches the value of the 'bottom' tile. |
||
| 207 | * |
||
| 208 | * @return int|null |
||
| 209 | */ |
||
| 210 | public function getRightTile(): ?int |
||
| 211 | { |
||
| 212 | return isset($this->virtualDomino) ? $this->virtualDomino->getBottomTile() : null; |
||
| 213 | } |
||
| 214 | } |
||
| 215 |
This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.
This is most likely a typographical error or the method has been renamed.