Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 67
0.00% covered (danger)
0.00%
0 / 8
CRAP
0.00% covered (danger)
0.00%
0 / 1
PgnGameParser
0.00% covered (danger)
0.00%
0 / 67
0.00% covered (danger)
0.00%
0 / 8
552
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getParsedData
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
2
 getMetadata
0.00% covered (danger)
0.00%
0 / 14
0.00% covered (danger)
0.00%
0 / 1
42
 getMetadataKeyAndValue
0.00% covered (danger)
0.00%
0 / 9
0.00% covered (danger)
0.00%
0 / 1
2
 getMoves
0.00% covered (danger)
0.00%
0 / 21
0.00% covered (danger)
0.00%
0 / 1
90
 getMovesAndComments
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
6
 getMovesAndVariationFromString
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
2
 getMoveString
0.00% covered (danger)
0.00%
0 / 7
0.00% covered (danger)
0.00%
0 / 1
6
1<?php
2/**
3 * This file is a part of ChessBrowser.
4 *
5 * ChessBrowser is free software: you can redistribute it and/or modify
6 *  it under the terms of the GNU General Public License as published by
7 *  the Free Software Foundation, either version 3 of the License, or
8 *  (at your option) any later version.
9 *
10 *  This program is distributed in the hope that it will be useful,
11 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 *  GNU General Public License for more details.
14 *
15 *  You should have received a copy of the GNU General Public License
16 *  along with this program.  If not, see <https://www.gnu.org/licenses/>.
17 *
18 * This file is a part of PgnParser
19 *
20 * PgnParser is free software: you can redistribute it and/or modify
21 *  it under the terms of the GNU Lesser General Public License as published by
22 *  the Free Software Foundation, either version 3 of the License, or
23 *  (at your option) any later version.
24 *
25 * This program is distributed in the hope that it will be useful,
26 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
27 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
28 *  GNU Lesser General Public License for more details.
29 *
30 *  You should have received a copy of the GNU Lesser General Public License
31 *  along with this program.  If not, see <https://www.gnu.org/licenses/>.
32 *
33 * @file PgnGameParser
34 * @ingroup ChessBrowser
35 * @author Alf Magne Kalleland
36 */
37
38namespace MediaWiki\Extension\ChessBrowser\PgnParser;
39
40class PgnGameParser {
41
42    private $pgnGame;
43
44    private $defaultFen = 'rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1';
45
46    private $specialMetadata = [
47        'event',
48        'site',
49        'white',
50        'black',
51        'result',
52        'plycount',
53        'eco',
54        'fen',
55        'timecontrol',
56        'round',
57        'date',
58        'annotator',
59        'termination'
60    ];
61
62    /**
63     * Set the parser's pgn
64     *
65     * @param string $pgnGame
66     */
67    public function __construct( $pgnGame ) {
68        $this->pgnGame = trim( $pgnGame );
69    }
70
71    /**
72     * Get the parsed data
73     *
74     * @return array
75     */
76    public function getParsedData() {
77        $gameData = $this->getMetadata();
78        $moveReferences = $this->getMoves();
79        $gameData[ChessJson::MOVE_MOVES] = $moveReferences[0];
80        $gameData[ChessJson::MOVE_COMMENT] = $moveReferences;
81        return $gameData;
82    }
83
84    /**
85     * Get the metadata
86     *
87     * @return array
88     */
89    private function getMetadata() {
90        $ret = [
91            ChessJson::GAME_METADATA => []
92        ];
93        // TODO set lastmoves property by reading last 3-4 moves in moves array
94        $lines = explode( "\n", $this->pgnGame );
95        foreach ( $lines as $line ) {
96            $line = trim( $line );
97            if ( substr( $line, 0, 1 ) === '[' && substr( $line, strlen( $line ) - 1, 1 ) === ']' ) {
98                $metadata = $this->getMetadataKeyAndValue( $line );
99                if ( in_array( $metadata['key'], $this->specialMetadata ) ) {
100                    $ret[$metadata['key']] = $metadata['value'];
101                } else {
102                    $ret[ChessJson::GAME_METADATA][$metadata['key']] = $metadata['value'];
103                }
104            }
105        }
106        if ( !isset( $ret[ChessJson::FEN] ) ) {
107            $ret[ChessJson::FEN] = $this->defaultFen;
108        }
109
110        return $ret;
111    }
112
113    /**
114     * Get the metadata key and value from a string
115     *
116     * @param string $metadataString
117     * @return array
118     */
119    private function getMetadataKeyAndValue( $metadataString ) {
120        $metadataString = preg_replace( "/[\[\]]/s", "", $metadataString );
121        $metadataString = str_replace( '"', '', $metadataString );
122        $tokens = explode( " ", $metadataString );
123
124        $key = $tokens[0];
125        $value = implode( " ", array_slice( $tokens, 1 ) );
126        return [
127            'key' => strtolower( $key ),
128            'value' => $value
129        ];
130    }
131
132    /**
133     * Get the moves
134     *
135     * @return array
136     */
137    private function getMoves() {
138        $moveBuilder = new MoveBuilder();
139
140        $parts = $this->getMovesAndComments();
141        for ( $i = 0, $count = count( $parts ); $i < $count; $i++ ) {
142            $move = trim( $parts[$i] );
143
144            switch ( $move ) {
145                case '{':
146                    if ( $i == 0 ) {
147                        $moveBuilder->addCommentBeforeFirstMove( $parts[$i + 1] );
148                    } else {
149                        $moveBuilder->addComment( $parts[$i + 1] );
150                    }
151                    $i += 2;
152                    break;
153                default:
154                    $moves = $this->getMovesAndVariationFromString( $move );
155                    foreach ( $moves as $move ) {
156                        switch ( $move ) {
157                            case '(':
158                                $moveBuilder->startVariation();
159                                break;
160                            case ')':
161                                $moveBuilder->endVariation();
162                                break;
163                            default:
164                                $moveBuilder->addMoves( $move );
165                        }
166                    }
167                    break;
168            }
169        }
170
171        return $moveBuilder->getMoves();
172    }
173
174    /**
175     * Get the moves and comments
176     *
177     * @return array
178     */
179    private function getMovesAndComments() {
180        $ret = preg_split( "/({|})/s", $this->getMoveString(), 0, PREG_SPLIT_DELIM_CAPTURE );
181        if ( !$ret[0] ) {
182            $ret = array_slice( $ret, 1 );
183        }
184        return $ret;
185    }
186
187    /**
188     * Get the moves and variations from a string
189     *
190     * TODO make static
191     *
192     * @param string $string
193     * @return array
194     */
195    private function getMovesAndVariationFromString( $string ) {
196        $string = " " . $string;
197
198        $string = preg_replace( "/\d+?\./s", "", $string );
199        $string = str_replace( " ..", "", $string );
200        $string = str_replace( "  ", " ", $string );
201        $string = trim( $string );
202
203        return preg_split( "/(\(|\))/s", $string, 0, PREG_SPLIT_DELIM_CAPTURE );
204    }
205
206    /**
207     * Get a move string
208     *
209     * @return string
210     */
211    private function getMoveString() {
212        $tokens = preg_split( "/\]\n\n/s", $this->pgnGame );
213        if ( !isset( $tokens[1] ) ) {
214            return "";
215        }
216        $gameData = $tokens[1];
217        $gameData = str_replace( "\n", " ", $gameData );
218        $gameData = preg_replace( "/(\s+)/", " ", $gameData );
219        return trim( $gameData );
220    }
221}