Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
98.04% covered (success)
98.04%
50 / 51
80.00% covered (warning)
80.00%
4 / 5
CRAP
0.00% covered (danger)
0.00%
0 / 1
SgfParser
97.92% covered (success)
97.92%
47 / 48
80.00% covered (warning)
80.00%
4 / 5
18
0.00% covered (danger)
0.00%
0 / 1
 process
100.00% covered (success)
100.00%
15 / 15
100.00% covered (success)
100.00%
1 / 1
4
 detectBoardSize
87.50% covered (warning)
87.50%
7 / 8
0.00% covered (danger)
0.00%
0 / 1
3.02
 normalizeOrientation
100.00% covered (success)
100.00%
8 / 8
100.00% covered (success)
100.00%
1 / 1
3
 getInitialPosition
100.00% covered (success)
100.00%
9 / 9
100.00% covered (success)
100.00%
1 / 1
4
 getInitialPositionEnd
100.00% covered (success)
100.00%
8 / 8
100.00% covered (success)
100.00%
1 / 1
4
1<?php
2
3declare(strict_types=1);
4
5require_once(__DIR__ . "/BoardBounds.php");
6require_once(__DIR__ . "/BoardPosition.php");
7require_once(__DIR__ . "/SgfBoard.php");
8
9class SgfParser
10{
11    /**
12     * Parse SGF and return board, stones and info array.
13     *
14     * @param string $sgf
15     * @return SgfBoard
16     */
17    public static function process(string $sgf, $correctMoves = []): SgfBoard
18    {
19        $boardSize = self::detectBoardSize($sgf);
20        $sgfArr = str_split($sgf);
21
22        $blackStones = self::getInitialPosition(strpos($sgf, 'AB'), $sgfArr);
23        $whiteStones = self::getInitialPosition(strpos($sgf, 'AW'), $sgfArr);
24
25        $stones = [];
26        foreach ($blackStones as $blackStone)
27            $stones[$blackStone] = SgfBoard::BLACK;
28        foreach ($whiteStones as $whiteStone)
29            $stones[$whiteStone] = SgfBoard::WHITE;
30
31        $boardBounds = new BoardBounds();
32        foreach ($stones as $position => $color)
33            $boardBounds->add($position);
34
35        self::normalizeOrientation($stones, $correctMoves, $boardBounds, $boardSize);
36        $tInfo = [$boardBounds->x->max, $boardBounds->y->max];
37        return new SgfBoard($stones, $tInfo, $boardSize, $correctMoves);
38    }
39
40    private static function detectBoardSize(string $sgf): int
41    {
42        $boardSizePos = strpos($sgf, 'SZ');
43        if ($boardSizePos === false)
44            return 19;
45
46        $sgfArr = str_split($sgf);
47        $size = $sgfArr[$boardSizePos + 3] . $sgfArr[$boardSizePos + 4];
48        if (substr($size, 1) == ']')
49            $size = substr($size, 0, 1);
50
51        return (int) $size;
52    }
53
54    private static function normalizeOrientation(array &$stones, array&$correctMoves, BoardBounds $boardBounds, int $boardSize): void
55    {
56        if ($boardBounds->x->isCloserToEnd($boardSize))
57        {
58            $stones = SgfBoard::getStonesFlipedX($stones, $boardSize);
59            $correctMoves = SgfBoard::getStonesFlipedX($correctMoves, $boardSize);
60            $boardBounds->x->flip($boardSize);
61        }
62        if ($boardBounds->y->isCloserToEnd($boardSize))
63        {
64            $stones = SgfBoard::getStonesFlipedY($stones, $boardSize);
65            $correctMoves = SgfBoard::getStonesFlipedY($correctMoves, $boardSize);
66            $boardBounds->y->flip($boardSize);
67        }
68    }
69
70    private static function getInitialPosition(int|bool $pos, array $sgfArr): array
71    {
72        if ($pos === false)
73            return [];
74
75        $coords = [];
76        $end = self::getInitialPositionEnd($pos, $sgfArr);
77        for ($i = $pos + 2; $i < $end; $i++)
78            if ($sgfArr[$i] == '[')
79            {
80                $coords[] = BoardPosition::fromLetters($sgfArr[$i + 1], $sgfArr[$i + 2]);
81                $i += 3;
82            }
83        return $coords;
84    }
85
86    private static function getInitialPositionEnd(int $pos, array $sgfArr): int
87    {
88        $endCondition = $pos;
89        $currentPos1 = $pos + 2;
90        $currentPos2 = $pos + 5;
91        while (isset($sgfArr[$currentPos1], $sgfArr[$currentPos2]) && $sgfArr[$currentPos1] == '[' && $sgfArr[$currentPos2] == ']')
92        {
93            $endCondition = $currentPos2;
94            $currentPos1 += 4;
95            $currentPos2 += 4;
96        }
97
98        return $endCondition;
99    }
100}