Issues (977)

src/Game/PokerSquareGame.php (1 issue)

Severity
1
<?php
2
3
namespace App\Game;
4
5
use App\Card\Card;
6
use App\Card\DeckOfCards;
7
8
/**
9
 * Klassen representerar spelet Poker Square.
10
 *
11
 * Spelet går ut på att placera ut kort i en 5x5-rutnätslayout,
12
 * och poäng ges baserat på pokerhänder som bildas i varje rad och kolumn.
13
 *
14
 * Kort dras från en kortlek och placeras på specifika positioner i rutnätet.
15
 * Klassen hanterar kortdragning, placering, beräkning av poäng och
16
 * förslag på nästa bästa drag.
17
 */
18
class PokerSquareGame
19
{
20
    /**
21
     * Rutnätet som lagrar placerade kort, indexerat som "rad-kolumn" (t.ex. "0-0").
22
     *
23
     * @var array<string, Card|null>
24
     */
25
    private array $grid = [];
26
27
    /**
28
     * Kortleken som används i spelet.
29
     */
30
    private DeckOfCards $deck;
31
32
    /**
33
     * Det aktuella kortet som ska placeras.
34
     */
35
    private ?Card $currentCard = null;
36
37
    /**
38
     * Initierar ett nytt spel med en ny kortlek och drar första kortet.
39
     */
40 8
    public function __construct()
41
    {
42 8
        $this->deck = new DeckOfCards(true);
43 8
        $this->deck->shuffle();
44 8
        $this->drawNextCard();
45
    }
46
47
    /**
48
     * Hämtar den aktuella spelrutnätsmatrisen med placerade kort.
49
     *
50
     * @return array<string, Card|null> Rutnätet med kortpositioner
51
     */
52 3
    public function getGrid(): array
53
    {
54 3
        return $this->grid;
55
    }
56
57
    /**
58
     * Hämtar det aktuella kortet som ska placeras.
59
     *
60
     * @return Card|null Det aktuella kortet, eller null om inga kort finns kvar
61
     */
62 3
    public function getCurrentCard(): ?Card
63
    {
64 3
        return $this->currentCard;
65
    }
66
67
    /**
68
     * Placerar det aktuella kortet på angiven position i rutnätet.
69
     * Ignorerar om kortet redan är placerat eller om positionen är upptagen.
70
     *
71
     * @param string $position Position i formatet "rad-kolumn", t.ex. "2-3"
72
     */
73 6
    public function placeCard(string $position): void
74
    {
75 6
        if (!$this->currentCard || isset($this->grid[$position])) {
76 1
            return;
77
        }
78
79 6
        $this->grid[$position] = $this->currentCard;
80 6
        $this->drawNextCard();
81
    }
82
83
    /**
84
     * Drar nästa kort från kortleken och uppdaterar det aktuella kortet.
85
     */
86 8
    public function drawNextCard(): void
87
    {
88 8
        $drawn = $this->deck->draw(1);
89 8
        $this->currentCard = $drawn[0] ?? null;
90
    }
91
92
    /**
93
     * Kontrollerar om spelet är slut (rutnätet är fullt eller inga kort kvar).
94
     *
95
     * @return bool True om spelet är slut, annars false
96
     */
97 4
    public function isGameOver(): bool
98
    {
99 4
        return count($this->grid) >= 25 || null === $this->currentCard;
100
    }
101
102
    /**
103
     * Beräknar poängen för varje rad och kolumn i rutnätet.
104
     * Använder interna regler för poängberäkning av pokerhänder.
105
     *
106
     * @return array<string, array<int, int>> Associativ array med 'rows' och 'cols' poäng
107
     */
108 2
    public function getGridScores(): array
109
    {
110 2
        $scores = [
111 2
            'rows' => [],
112 2
            'cols' => [],
113 2
        ];
114
115 2
        for ($i = 0; $i < 5; ++$i) {
116 2
            $row = [];
117 2
            $col = [];
118
119 2
            for ($j = 0; $j < 5; ++$j) {
120 2
                $rowKey = $i.'-'.$j;
121 2
                $colKey = $j.'-'.$i;
122
123 2
                $row[] = $this->grid[$rowKey] ?? null;
124 2
                $col[] = $this->grid[$colKey] ?? null;
125
            }
126
127 2
            $scores['rows'][$i] = $this->calculateHandScore($row);
128 2
            $scores['cols'][$i] = $this->calculateHandScore($col);
129
        }
130
131 2
        return $scores;
132
    }
133
134
    /**
135
     * Beräknar poängen för en given hand med 5 kort.
136
     * Returnerar 0 om handen är ofullständig.
137
     * OBS: För tillfället returnerar metoden ett slumpmässigt värde.
138
     *
139
     * @param array<int, Card|null> $hand En rad eller kolumn med 5 kort
140
     *
141
     * @return int Poängen för handen
142
     */
143 3
    private function calculateHandScore(array $hand): int
144
    {
145 3
        if (in_array(null, $hand, true)) {
146 3
            return 0;
147
        }
148
149
        // TODO: Implementera riktig pokerhand-utvärdering istället för slumpmässigt värde
150 2
        return random_int(1, 10);
151
    }
152
153
    /**
154
     * Beräknar den totala poängen för hela rutnätet (rader + kolumner).
155
     *
156
     * @return int Total poäng
157
     */
158 1
    public function getTotalScore(): int
159
    {
160 1
        $scores = $this->getGridScores();
161
162 1
        return array_sum($scores['rows']) + array_sum($scores['cols']);
0 ignored issues
show
Bug Best Practice introduced by
The expression return array_sum($scores...ay_sum($scores['cols']) returns the type double which is incompatible with the type-hinted return integer.
Loading history...
163
    }
164
165
    /**
166
     * Föreslår den bästa positionen för att placera det aktuella kortet
167
     * baserat på en simulering som maximerar poängen.
168
     *
169
     * @return string|null Position som "rad-kolumn" eller null om inget drag möjligt
170
     */
171 1
    public function getSuggestedMove(): ?string
172
    {
173 1
        if (!$this->currentCard || $this->isGameOver()) {
174
            return null;
175
        }
176
177 1
        $bestScore = -1;
178 1
        $bestPos = null;
179
180 1
        for ($row = 0; $row < 5; ++$row) {
181 1
            for ($col = 0; $col < 5; ++$col) {
182 1
                $pos = "$row-$col";
183 1
                if (isset($this->grid[$pos])) {
184
                    continue;
185
                }
186
187 1
                $tempGrid = $this->grid;
188 1
                $tempGrid[$pos] = $this->currentCard;
189
190 1
                $score = $this->simulateScore($tempGrid);
191
192 1
                if ($score > $bestScore) {
193 1
                    $bestScore = $score;
194 1
                    $bestPos = $pos;
195
                }
196
            }
197
        }
198
199 1
        return $bestPos;
200
    }
201
202
    /**
203
     * Simulerar poängen för ett givet rutnät.
204
     * Används internt för att hitta bästa drag.
205
     *
206
     * @param array<string, Card|null> $grid Rutnät med kort
207
     *
208
     * @return int Simulerad total poäng
209
     */
210 1
    private function simulateScore(array $grid): int
211
    {
212 1
        $score = 0;
213
214 1
        for ($i = 0; $i < 5; ++$i) {
215 1
            $row = [];
216 1
            $col = [];
217
218 1
            for ($j = 0; $j < 5; ++$j) {
219 1
                $row[] = $grid["$i-$j"] ?? null;
220 1
                $col[] = $grid["$j-$i"] ?? null;
221
            }
222
223 1
            $score += $this->calculateHandScore($row);
224 1
            $score += $this->calculateHandScore($col);
225
        }
226
227 1
        return $score;
228
    }
229
}
230