[GoWiki] Generate diagram from SGF
10) { $movecnt = 10; } if ($startmove < 1) { $startmove = 1; } if ($startmove > 400) { $startmove = 400; } $nextstart = $startmove ? $startmove + $movecnt : 1; $nextcount = $movecnt ?: 10; ?>

Start move: · Number of moves (0-10): · generate($startmove, $movecnt); ?>


Notes: Questions, feedback? -> GenerateDiagramFromSGF sgf = $sgf; } function generate($startmove, $movecnt) { if (empty($this->sgf)) { return; } // init board $this->board = []; for ($y = 0; $y < 19; $y++) { $this->board[$y] = array_fill(0, 19, 0); } if ($movecnt > 0) { $movecnt--; $showposition = false; } else { $showposition = true; } $moves = preg_split('/;\s*/', $this->sgf); $movenum = 0; $title = ''; for ($mnum = 0; $mnum < count($moves); $mnum++) { // AB, AW, AE if (preg_match_all('/[^A-Z]?A(dd)?([BWE])(lack|hite|mpty)?((\[[a-s][a-s]\])+)/', $moves[$mnum], $matches)) { $this->add_stones($matches[2], $matches[4]); } // B, W if (!preg_match('/(^|[^A-Z])([BW])(lack|hite)?\[(([a-t])([a-t]))?\]/', $moves[$mnum], $matches)) { continue; } $movenum++; if ($movenum - $startmove < 9) { $mvchar = chr(ord('1') + $movenum - $startmove); } else { $mvchar = '0'; } $mvnum = ($mvchar == '0') ? '10' : $mvchar; if ($matches[5] != 't' && $matches[6] != 't' && $matches[4] != '') { // !(pass move) $x = ord($matches[5]) - ord('a'); $y = ord($matches[6]) - ord('a'); $col = ($matches[2] == 'W') ? -1 : 1; if ($movenum < $startmove || $showposition) { $this->play_move($x, $y, $col); } else { if ($movenum == $startmove) { $startColor = $matches[2]; } if (!is_int($this->board[$y][$x])) { // there is already a move at that position $title .= " ($mvnum at " . $this->board[$y][$x] . ')'; } else { $this->board[$y][$x] = $mvchar; } } } elseif ($movenum >= $startmove && !$showposition) { $title .= " ($mvnum: pass)"; } if ($movenum >= $startmove + $movecnt) { break; } } if ($movenum < $startmove) { echo "
Sorry. Your starting move number is beyond the end of the game.
This game has only $movenum moves. The end position looks like this: 
"; $this->print('', 'End position'); } else { if ($showposition) { $title = "Position at move $startmove"; } else { $title = "Moves $startmove to $movenum$title"; } $this->print($startColor, $title); } } function add_stones($property, $propvalues): void { for ($i = 0; $i < count($property); $i++) { $color = match ($property[$i]) { 'B' => 1, 'W' => -1, default => 0, }; $values = preg_split('/\[/', $propvalues[$i]); for ($j = 0; $j < count($values); $j++) { $x = ord($values[$j][0]) - ord('a'); $y = ord($values[$j][1]) - ord('a'); $this->board[$y][$x] = $color; } } } function play_move($x, $y, $col): void { $this->board[$y][$x] = $col; $this->do_capture($x - 1, $y, $col); $this->do_capture($x + 1, $y, $col); $this->do_capture($x, $y - 1, $col); $this->do_capture($x, $y + 1, $col); // suicide? $this->do_capture($x, $y, -$col); } function do_capture($x, $y, $col): void { if ($x < 0 || $y < 0 || $x >= 19 || $y >= 19) { return; } if ($this->board[$y][$x] != -$col) { return; } $captures = []; if (!$this->capture($x, $y, $col, $captures)) { return; } foreach($captures as [$y, $x]) { $this->board[$y][$x] = 0; // remove stone } } // recursive function to mark group (searches for liberties) // returns false if a liberty was found, true otherwise function capture($x, $y, $col, &$captures): bool { if (isset($captures["$y:$x"])) { // already visited? return true; } if ($x < 0 || $y < 0 || $x >= 19 || $y >= 19) { // out of bounds? return true; } if ($this->board[$y][$x] == $col) { // found opposite color return true; } if ($this->board[$y][$x] == 0) { // found a liberty return false; } $captures["$y:$x"] = [$y, $x]; return $this->capture($x - 1, $y, $col, $captures) && $this->capture($x + 1, $y, $col, $captures) && $this->capture($x, $y - 1, $col, $captures) && $this->capture($x, $y + 1, $col, $captures); } function print($startColor, $title): void { echo "
\$\$$startColor $title\n";
        echo "\$\$  ---------------------------------------\n";

        for ($y = 0; $y < 19; $y++) {
            echo '$$ | ';
            for ($x = 0; $x < 19; $x++) {
                if ($this->board[$y][$x] === 1) {
                    echo 'X ';
                } elseif ($this->board[$y][$x] === -1) {
                    echo 'O ';
                } elseif ($this->board[$y][$x] === 0) {
                    if (($x == 3 || $x == 9 || $x == 15) && ($y == 3 || $y == 9 || $y == 15)) {
                        echo ', ';
                    } else {
                        echo '. ';
                    }
                } else {
                    echo $this->board[$y][$x] . ' ';
                }
            }
            echo "|\n";
        }
        echo "\$\$  ---------------------------------------\n";
        echo "
\n\n"; } }