Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
85.99% covered (warning)
85.99%
135 / 157
40.00% covered (danger)
40.00%
2 / 5
CRAP
0.00% covered (danger)
0.00%
0 / 1
BoardComparator
85.90% covered (warning)
85.90%
134 / 156
40.00% covered (danger)
40.00%
2 / 5
59.58
0.00% covered (danger)
0.00%
0 / 1
 compare
83.33% covered (warning)
83.33%
65 / 78
0.00% covered (danger)
0.00%
0 / 1
18.34
 processDiffResult
82.22% covered (warning)
82.22%
37 / 45
0.00% covered (danger)
0.00%
0 / 1
28.51
 compareWithoutCorrectMoves
100.00% covered (success)
100.00%
21 / 21
100.00% covered (success)
100.00%
1 / 1
1
 compareSingle
100.00% covered (success)
100.00%
8 / 8
100.00% covered (success)
100.00%
1 / 1
6
 positionArraysMatch
75.00% covered (warning)
75.00%
3 / 4
0.00% covered (danger)
0.00%
0 / 1
3.14
1<?php
2
3require_once __DIR__ . '/BoardComparisonResult.php';
4
5class BoardComparator
6{
7    public static function compare(
8        array $aStones,
9        string $aFirstMoveColor,
10        array $aCorrectMoves,
11        array $bStones,
12        string $bFirstMoveColor,
13        array $bCorrectMoves): ?BoardComparisonResult
14    {
15        if (empty($aStones) || empty($bStones))
16            return null;
17
18        if (($aFirstMoveColor == 'N') != ($bFirstMoveColor == 'N'))
19            return null;
20
21        // correct moves length was supposed to be checked long before this step as optimisation
22        if (empty($aCorrectMoves))
23            return self::compareWithoutCorrectMoves($aStones, $bStones);
24
25        $aCorrectLowest = SgfBoard::getLowestPosition($aCorrectMoves);
26        $bCorrectLowest = SgfBoard::getLowestPosition($bCorrectMoves);
27        $shift = BoardPosition::diff($aCorrectLowest, $bCorrectLowest);
28        // we always shift A to b, so we can later show diff positions relative to original B
29        $aCorrectMovesShifted = SgfBoard::getShiftedPositions($aCorrectMoves, $shift);
30
31        $aShifted = SgfBoard::getShiftedPositions($aStones, $shift);
32        $diff = null;
33        $diffColorSwitched = null;
34
35        $diffHorizontallyMirrored = null;
36        $diffHorizontallyMirroredColorSwitched = null;
37
38        $diffVerticallyMirrored = null;
39        $diffVerticallyMirroredColorSwitched = null;
40
41        $diffMirrored = null;
42        $diffMirroredColorSwitched = null;
43
44        $aShiftedColorSwitched = null;
45
46        $aShiftedHorizontallyMirrored = null;
47        $aShiftedHorizontallyMirroredColorSwitched = null;
48
49        $aShiftedVerticallyMirrored = null;
50        $aShiftedVerticallyMirroredColorSwitched = null;
51
52        $aShiftedMirrored = null;
53        $aShiftedMirroredColorSwitched = null;
54
55        if (BoardComparator::positionArraysMatch($aCorrectMovesShifted, $bCorrectMoves))
56        {
57            if ($aFirstMoveColor == 'N')
58            {
59                $diff = BoardComparator::compareSingle($aShifted, $bStones);
60                $aShiftedColorSwitched = SgfBoard::getColorSwitchedStones($aShifted);
61                $diffColorSwitched = BoardComparator::compareSingle($aShiftedColorSwitched, $bStones);
62            }
63            elseif ($aFirstMoveColor == $bFirstMoveColor)
64                $diff = BoardComparator::compareSingle($aShifted, $bStones);
65            else
66            {
67                $aShiftedColorSwitched = SgfBoard::getColorSwitchedStones($aShifted);
68                $diffColorSwitched = BoardComparator::compareSingle($aShiftedColorSwitched, $bStones);
69            }
70        }
71
72        $aCorrectMovesShiftedHorizontallyMirrored = SgfBoard::getPositionsHorizontallyMirroredAround($aCorrectMovesShifted, $bCorrectLowest);
73
74        if (BoardComparator::positionArraysMatch($aCorrectMovesShiftedHorizontallyMirrored, $bCorrectMoves))
75        {
76            $aShiftedHorizontallyMirrored = SgfBoard::getPositionsHorizontallyMirroredAround($aShifted, $bCorrectLowest);
77            if ($aFirstMoveColor == 'N')
78            {
79                $diffHorizontallyMirrored = BoardComparator::compareSingle($aShiftedHorizontallyMirrored, $bStones);
80                $aShiftedHorizontallyMirroredColorSwitched = SgfBoard::getColorSwitchedStones($aShiftedHorizontallyMirrored);
81                $diffHorizontallyMirroredColorSwitched = BoardComparator::compareSingle($aShiftedHorizontallyMirroredColorSwitched, $bStones);
82            }
83            elseif ($aFirstMoveColor == $bFirstMoveColor)
84                $diffHorizontallyMirrored = BoardComparator::compareSingle($aShiftedHorizontallyMirrored, $bStones);
85            else
86            {
87                $aShiftedHorizontallyMirroredColorSwitched = SgfBoard::getColorSwitchedStones($aShiftedHorizontallyMirrored);
88                $diffHorizontallyMirroredColorSwitched = BoardComparator::compareSingle($aShiftedHorizontallyMirroredColorSwitched, $bStones);
89            }
90        }
91
92        $aCorrectMovesShiftedVerticallyMirrored = SgfBoard::getPositionsVerticallyMirroredAround($aCorrectMovesShifted, $bCorrectLowest);
93
94        if (BoardComparator::positionArraysMatch($aCorrectMovesShiftedVerticallyMirrored, $bCorrectMoves))
95        {
96            $aShiftedVerticallyMirrored = SgfBoard::getPositionsVerticallyMirroredAround($aShifted, $bCorrectLowest);
97            if ($aFirstMoveColor == 'N')
98            {
99                $diffVerticallyMirrored = BoardComparator::compareSingle($aShiftedVerticallyMirrored, $bStones);
100                $aShiftedVerticallyMirroredColorSwitched = SgfBoard::getColorSwitchedStones($aShiftedVerticallyMirrored);
101                $diffVerticallyMirroredColorSwitched = BoardComparator::compareSingle($aShiftedVerticallyMirroredColorSwitched, $bStones);
102            }
103            elseif ($aFirstMoveColor == $bFirstMoveColor)
104                $diffVerticallyMirrored = BoardComparator::compareSingle($aShiftedVerticallyMirrored, $bStones);
105            else
106            {
107                $aShiftedVerticallyMirroredColorSwitched = SgfBoard::getColorSwitchedStones($aShiftedVerticallyMirrored);
108                $diffVerticallyMirroredColorSwitched = BoardComparator::compareSingle($aShiftedVerticallyMirroredColorSwitched, $bStones);
109            }
110        }
111
112        $aCorrectMovesShiftedMirrored = SgfBoard::getPositionsMirroredAround($aCorrectMovesShifted, $bCorrectLowest);
113
114        if (BoardComparator::positionArraysMatch($aCorrectMovesShiftedMirrored, $bCorrectMoves))
115        {
116            $aShiftedMirrored = SgfBoard::getPositionsMirroredAround($aShifted, $bCorrectLowest);
117            if ($aFirstMoveColor == 'N')
118            {
119                $diffMirrored = BoardComparator::compareSingle($aShiftedMirrored, $bStones);
120                $aShiftedMirroredColorSwitched = SgfBoard::getColorSwitchedStones($aShiftedMirrored);
121                $diffMirroredColorSwitched = BoardComparator::compareSingle($aShiftedMirroredColorSwitched, $bStones);
122            }
123            elseif ($aFirstMoveColor == $bFirstMoveColor)
124                $diffMirrored = BoardComparator::compareSingle($aShiftedMirrored, $bStones);
125            else
126            {
127                $aShiftedMirroredColorSwitched = SgfBoard::getColorSwitchedStones($aShiftedMirrored);
128                $diffMirroredColorSwitched = BoardComparator::compareSingle($aShiftedMirroredColorSwitched, $bStones);
129            }
130        }
131
132        return self::processDiffResult(
133            $bStones,
134            $diff, $aShifted,
135            $diffColorSwitched, $aShiftedColorSwitched,
136            $diffHorizontallyMirrored, $aShiftedHorizontallyMirrored,
137            $diffHorizontallyMirroredColorSwitched, $aShiftedHorizontallyMirroredColorSwitched,
138            $diffVerticallyMirrored, $aShiftedVerticallyMirrored,
139            $diffVerticallyMirroredColorSwitched, $aShiftedVerticallyMirroredColorSwitched,
140            $diffMirrored, $aShiftedMirrored,
141            $diffMirroredColorSwitched, $aShiftedMirroredColorSwitched);
142    }
143
144    public static function processDiffResult(
145        array $bStones,
146        ?int $diff, ?array $aShifted,
147        ?int $diffColorSwitch, ?array $aShiftedColorSwitched,
148        ?int $diffHorizontallyMirrored, ?array $aShiftedHorizontallyMirrored,
149        ?int $diffHorizontallyMirroredColorSwitched, ?array $aShiftedHorizontallyMirroredColorSwitched,
150        ?int $diffVerticallyMirrored, ?array $aShiftedVerticallyMirrored,
151        ?int $diffVerticallyMirroredColorSwitched, ?array $aShiftedVerticallyMirroredColorSwitched,
152        ?int $diffMirrored, ?array $aShiftedMirrored,
153        ?int $diffMirroredColorSwitch, ?array $aShiftedMirroredColorSwitched): ?BoardComparisonResult
154    {
155        $indexOfSmallestDiff = -1;
156        $smallestDiff = 1000;
157        if (!is_null($diff))
158        {
159            $smallestDiff = $diff;
160            $indexOfSmallestDiff = 0;
161        }
162        if (!is_null($diffColorSwitch) && $diffColorSwitch < $smallestDiff)
163        {
164            $indexOfSmallestDiff = 1;
165            $smallestDiff = $diffColorSwitch;
166        }
167
168        if (!is_null($diffHorizontallyMirrored) && $diffHorizontallyMirrored < $smallestDiff)
169        {
170            $indexOfSmallestDiff = 2;
171            $smallestDiff = $diffHorizontallyMirrored;
172        }
173
174        if (!is_null($diffHorizontallyMirroredColorSwitched) && $diffHorizontallyMirroredColorSwitched < $smallestDiff)
175        {
176            $indexOfSmallestDiff = 3;
177            $smallestDiff = $diffHorizontallyMirroredColorSwitched;
178        }
179
180        if (!is_null($diffVerticallyMirrored) && $diffVerticallyMirrored < $smallestDiff)
181        {
182            $indexOfSmallestDiff = 4;
183            $smallestDiff = $diffVerticallyMirrored;
184        }
185
186        if (!is_null($diffVerticallyMirroredColorSwitched) && $diffVerticallyMirroredColorSwitched < $smallestDiff)
187        {
188            $indexOfSmallestDiff = 5;
189            $smallestDiff = $diffVerticallyMirroredColorSwitched;
190        }
191
192        if (!is_null($diffMirrored) && $diffMirrored < $smallestDiff)
193        {
194            $indexOfSmallestDiff = 6;
195            $smallestDiff = $diffMirrored;
196        }
197
198        if (!is_null($diffMirroredColorSwitch) && $diffMirroredColorSwitch < $smallestDiff)
199        {
200            $indexOfSmallestDiff = 7;
201            $smallestDiff = $diffMirroredColorSwitch;
202        }
203
204        if ($indexOfSmallestDiff == -1)
205            return null;
206
207        if ($smallestDiff > 5)
208            return null;
209
210        if ($indexOfSmallestDiff == 0)
211            return new BoardComparisonResult($smallestDiff, SgfBoard::getDifferentStones($aShifted, $bStones));
212        if ($indexOfSmallestDiff == 1)
213            return new BoardComparisonResult($smallestDiff, SgfBoard::getDifferentStones($aShiftedColorSwitched, $bStones));
214        if ($indexOfSmallestDiff == 2)
215            return new BoardComparisonResult($smallestDiff, SgfBoard::getDifferentStones($aShiftedHorizontallyMirrored, $bStones));
216        if ($indexOfSmallestDiff == 3)
217            return new BoardComparisonResult($smallestDiff, SgfBoard::getDifferentStones($aShiftedHorizontallyMirroredColorSwitched, $bStones));
218        if ($indexOfSmallestDiff == 4)
219            return new BoardComparisonResult($smallestDiff, SgfBoard::getDifferentStones($aShiftedVerticallyMirrored, $bStones));
220        if ($indexOfSmallestDiff == 5)
221            return new BoardComparisonResult($smallestDiff, SgfBoard::getDifferentStones($aShiftedVerticallyMirroredColorSwitched, $bStones));
222        if ($indexOfSmallestDiff == 6)
223            return new BoardComparisonResult($smallestDiff, SgfBoard::getDifferentStones($aShiftedMirrored, $bStones));
224        //if ($indexOfSmallestDiff == 7)
225        return new BoardComparisonResult($smallestDiff, SgfBoard::getDifferentStones($aShiftedMirroredColorSwitched, $bStones));
226    }
227
228    public static function compareWithoutCorrectMoves($aStones, $bStones): ?BoardComparisonResult
229    {
230        $aLowest = SgfBoard::getLowestPosition($aStones);
231        $bLowest = SgfBoard::getLowestPosition($bStones);
232        $shift = BoardPosition::diff($aLowest, $bLowest);
233
234        $aShifted = SgfBoard::getShiftedPositions($aStones, $shift);
235
236        $diff = BoardComparator::compareSingle($aShifted, $bStones);
237        $aShiftedColorSwitched = SgfBoard::getColorSwitchedStones($aShifted);
238        $diffColorSwitched = BoardComparator::compareSingle($aShiftedColorSwitched, $bStones);
239
240        $aShiftedMirrored = SgfBoard::getPositionsMirroredAround($aShifted, $bLowest);
241        $diffMirrored = BoardComparator::compareSingle($aShiftedMirrored, $bStones);
242        $aShiftedMirroredColorSwitched = SgfBoard::getColorSwitchedStones($aShiftedMirrored);
243        $diffMirroredColorSwitched = BoardComparator::compareSingle($aShiftedMirroredColorSwitched, $bStones);
244        return self::processDiffResult(
245            $bStones,
246            $diff, $aShifted,
247            $diffColorSwitched, $aShiftedColorSwitched,
248            null, null,
249            null, null,
250            null, null,
251            null, null,
252            $diffMirrored, $aShiftedMirrored,
253            $diffMirroredColorSwitched, $aShiftedMirroredColorSwitched);
254    }
255
256    public static function compareSingle(array $stonesA, array $stonesB): int
257    {
258        $diff = 0;
259        foreach ($stonesA as $position => $color)
260            if (!isset($stonesB[$position]) || $stonesB[$position] != $color)
261                $diff++;
262        foreach ($stonesB as $position => $color)
263            if (!isset($stonesA[$position]))
264                $diff++;
265        return $diff;
266    }
267
268    // I'm assuming $a and $b are arrays of packed positions, and they have
269    // already been checked to have the same size and are unique
270    private static function positionArraysMatch(array $a, array $b): bool
271    {
272        foreach ($a as $position => $x)
273            if (!isset($b[$position]))
274                return false;
275        return true;
276    }
277}