Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
0.00% |
0 / 67 |
|
0.00% |
0 / 8 |
CRAP | |
0.00% |
0 / 1 |
PgnGameParser | |
0.00% |
0 / 67 |
|
0.00% |
0 / 8 |
552 | |
0.00% |
0 / 1 |
__construct | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
getParsedData | |
0.00% |
0 / 5 |
|
0.00% |
0 / 1 |
2 | |||
getMetadata | |
0.00% |
0 / 14 |
|
0.00% |
0 / 1 |
42 | |||
getMetadataKeyAndValue | |
0.00% |
0 / 9 |
|
0.00% |
0 / 1 |
2 | |||
getMoves | |
0.00% |
0 / 21 |
|
0.00% |
0 / 1 |
90 | |||
getMovesAndComments | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
6 | |||
getMovesAndVariationFromString | |
0.00% |
0 / 6 |
|
0.00% |
0 / 1 |
2 | |||
getMoveString | |
0.00% |
0 / 7 |
|
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 | |
38 | namespace MediaWiki\Extension\ChessBrowser\PgnParser; |
39 | |
40 | class 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 | } |