DominoCollection::has()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 1
c 1
b 0
f 0
dl 0
loc 3
rs 10
cc 1
nc 1
nop 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Arp\DominoGame\Value;
6
7
use Arp\DominoGame\Exception\DominoGameException;
8
9
/**
10
 * @author  Alex Patterson <[email protected]>
11
 * @package Arp\DominoGame\Value
12
 */
13
class DominoCollection extends AbstractCollection
14
{
15
    /**
16
     * @param Domino $domino
17
     *
18
     * @return bool
19
     */
20
    public function has(Domino $domino): bool
21
    {
22
        return in_array($domino, $this->elements, true);
23
    }
24
25
    /**
26
     * Add a new domino to the collection.
27
     *
28
     * @param Domino $domino
29
     */
30
    public function add(Domino $domino): void
31
    {
32
        if (!$this->has($domino)) {
33
            $this->elements[] = $domino;
34
        }
35
    }
36
37
    /**
38
     * Randomly shuffle the collection elements
39
     *
40
     * @return bool
41
     */
42
    public function shuffle(): bool
43
    {
44
        return shuffle($this->elements);
45
    }
46
47
    /**
48
     * Add a domino to the start of the collection.
49
     *
50
     * @param Domino $domino
51
     */
52
    public function addToStart(Domino $domino): void
53
    {
54
        array_unshift($this->elements, $domino);
55
    }
56
57
    /**
58
     * Add a domino to the end of the collection.
59
     *
60
     * @param Domino $domino
61
     */
62
    public function addToEnd(Domino $domino): void
63
    {
64
        $this->elements[] = $domino;
65
    }
66
67
    /**
68
     * Return the summed value of all the tiles in the player's hand
69
     *
70
     * @return int
71
     */
72
    public function getValue(): int
73
    {
74
        $value = 0;
75
76
        /** @var Domino $domino */
77
        foreach ($this->elements as $domino) {
78
            $value += $domino->getValue();
79
        }
80
81
        return $value;
82
    }
83
84
    /**
85
     * Return a single domino with the highest value (if there are matching values the order is undefined)
86
     *
87
     * @return Domino|null
88
     */
89
    public function getDominoWithHighestValue(): ?Domino
90
    {
91
        $sortedCollection = $this->createCollectionSortedByHighestTileValue();
92
93
        if ($sortedCollection->isEmpty()) {
94
            return null;
95
        }
96
97
        /** @var Domino|null $domino */
98
        $domino = $sortedCollection->first();
99
        return $domino;
100
    }
101
102
    /**
103
     * Create a new DominoCollection instance with the $elements sorted by the highest tile (sum) values.
104
     *
105
     * @return DominoCollection
106
     */
107
    public function createCollectionSortedByHighestTileValue(): DominoCollection
108
    {
109
        $elements = $this->elements;
110
111
        uasort(
112
            $elements,
113
            static function (Domino $dominoA, Domino $dominoB) {
114
                return $dominoA->getValue() <=> $dominoB->getValue();
115
            }
116
        );
117
118
        return new static($elements);
119
    }
120
121
    /**
122
     * Create a new collection containing any dominoes that have tile values matching the provided $value.
123
     *
124
     * @param int $value The value that should be matched.
125
     *
126
     * @return DominoCollection
127
     */
128
    public function createCollectionWithMatchingTiles(int $value): DominoCollection
129
    {
130
        $matches = [];
131
132
        /** @var Domino $domino */
133
        foreach ($this->elements as $domino) {
134
            if ($value === $domino->getTopTile() || $value === $domino->getBottomTile()) {
135
                $matches[] = $domino;
136
            }
137
        }
138
139
        return new static($matches);
140
    }
141
142
    /**
143
     * Pick a random domino from the collection.
144
     *
145
     * @return Domino
146
     *
147
     * @throws DominoGameException If the random pick is impossible or removal from the collection fails
148
     */
149
    public function pickRandom(): Domino
150
    {
151
        if ($this->isEmpty()) {
152
            throw new DominoGameException('Unable to pick a domino from an empty collection');
153
        }
154
155
        try {
156
            $values = array_values($this->elements);
157
            $domino = $values[random_int(0, count($values) - 1)];
158
        } catch (\Throwable $e) {
159
            throw new DominoGameException(
160
                sprintf('Failed to pick a random domino from the collection: %s', $e->getMessage()),
161
                $e->getCode(),
162
                $e
163
            );
164
        }
165
166
        if (!$this->removeElement($domino)) {
167
            throw new DominoGameException('Failed to remove the picked domino from the collection');
168
        }
169
170
        return $domino;
171
    }
172
173
    /**
174
     * Return the collection represented as a string.
175
     *
176
     * @return string
177
     */
178
    public function __toString()
179
    {
180
        $string = '';
181
182
        foreach ($this->elements as $element) {
183
            $string .= $element . ' ';
184
        }
185
186
        return trim($string);
187
    }
188
}
189