├── .gitignore ├── LICENSE ├── config.php.dist ├── problem-creator.php ├── README.md ├── functions ├── global.php ├── mateSequence.php └── captureAndPromotion.php └── resources └── example-problems.json /.gitignore: -------------------------------------------------------------------------------- 1 | resources/stockfish-dd-mac 2 | resources/stockfish-3-mac 3 | config.php 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT license 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is furnished 8 | to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /config.php.dist: -------------------------------------------------------------------------------- 1 | $game ) { 19 | 20 | if ( !isset( $game['game']['initialFen'] ) ) { 21 | 22 | $temp = createProblems( $game ); 23 | 24 | if ( !empty( $temp ) ) { 25 | 26 | foreach ( $temp as $problem ) { 27 | 28 | $problems[] = $problem; 29 | 30 | } 31 | } 32 | } 33 | } 34 | } 35 | 36 | if ( !empty( $problems ) ) { 37 | 38 | $json = json_encode( $problems ); 39 | 40 | $post = file_get_contents("http://en.lichess.org/api/puzzle?token=$LICHESS_API_TOKEN",null,stream_context_create(array( 41 | 'http' => array( 42 | 'protocol_version' => 1.1, 43 | 'user_agent' => 'PHPExample', 44 | 'method' => 'POST', 45 | 'header' => "Content-type: application/json\r\n". 46 | "Connection: close\r\n" . 47 | "Content-length: " . strlen($json) . "\r\n", 48 | 'content' => $json, 49 | ), 50 | ))); 51 | 52 | if ($post) { 53 | echo "$post\n"; 54 | } else { 55 | echo "POST failed\n"; 56 | } 57 | 58 | return $json; 59 | 60 | } 61 | } 62 | 63 | echo "+ = Check, T = Tension between lower and higher value piece, M = Mate threat, C = Next best move capture\n\n"; 64 | 65 | $nbBatches = isset($argv[1]) ? $argv[1] : 9999; 66 | 67 | for ( $x = 0; $x < intval($nbBatches); $x++ ) { 68 | printf( "Batch %10d of %10d\n", $x + 1, intval($nbBatches) ); 69 | echo problemGenerator( 1 )."\n"; 70 | } 71 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | problem-creator 2 | =============== 3 | 4 | create chess problems for lichess 5 | 6 | ### Installation 7 | 8 | Copy `config.php.dist` to `config.php`, then edit `config.php` to match your needs. 9 | 10 | The only settings you are required to change are `LICHESS_API_TOKEN` and `STOCKFISH_PATH`. 11 | 12 | ### problem-creator Command Line Interface: 13 | `user$ php problem-creator.php [number of attempts = 9999]` 14 | 15 | ### CLI Output: 16 | ``` 17 | Batch 1 of 10 18 | Parent -> Child | Mate In 19 | ========================== 20 | d3g6 -> a8a1 | +0 21 | d3g6 -> d4a1 | +0 22 | Array 23 | ( 24 | [tags] => Array 25 | ( 26 | [0] => forced mate 27 | ) 28 | 29 | [color] => black 30 | [position] => e2e4 c7c5 g1f3 e7e6 b1c3 b8c6 b2b3 f8e7 c1b2 e7f6 f1b5 g8e7 d1e2 a7a6 b5d3 e7g6 e1c1 d7d6 g2g3 e8g8 h2h4 c6b4 h4h5 g6e5 f3e5 f6e5 f2f4 e5c3 b2c3 b4a2 c1b2 a2c3 d2c3 b7b5 c3c4 c8b7 h5h6 g7g6 h1f1 d8a5 d1a1 a5b6 f4f5 b5b4 g3g4 a6a5 e4e5 a5a4 e5d6 b6d6 f5g6 d6d4 b2b1 h7g6 e2f2 a4b3 a1a8 b3c2 f2c2 f8a8 d3g6 31 | [solution] => Array 32 | ( 33 | [a8a1] => end 34 | [d4a1] => end 35 | ) 36 | 37 | [id] => f2fwl3en 38 | ) 39 | kthxbye 40 | [{"tags":["material advantage"],"color":"black","position":"e2e4 c7c5 g1f3 e7e6 b1c3 b8c6 b2b3 f8e7 c1b2 e7f6 f1b5 g8e7 d1e2 a7a6 b5d3 e7g6 e1c1 d7d6 g2g3 e8g8 h2h4 c6b4 h4h5 g6e5 f3e5 f6e5 f2f4 e5c3 b2c3 b4a2 c1b2 a2c3 d2c3 b7b5 c3c4 c8b7 h5h6 g7g6 h1f1 d8a5 d1a1 a5b6 f4f5 b5b4 g3g4 a6a5 e4e5 a5a4 e5d6 b6d6 f5g6 d6d4 b2b1 h7g6 e2f2 a4b3 a1a8 b3c2 f2c2 ","solution":{"f8a8":{"h6h7":"end"}},"id":"f2fwl3en"},{"tags":["forced mate"],"color":"black","position":"e2e4 c7c5 g1f3 e7e6 b1c3 b8c6 b2b3 f8e7 c1b2 e7f6 f1b5 g8e7 d1e2 a7a6 b5d3 e7g6 e1c1 d7d6 g2g3 e8g8 h2h4 c6b4 h4h5 g6e5 f3e5 f6e5 f2f4 e5c3 b2c3 b4a2 c1b2 a2c3 d2c3 b7b5 c3c4 c8b7 h5h6 g7g6 h1f1 d8a5 d1a1 a5b6 f4f5 b5b4 g3g4 a6a5 e4e5 a5a4 e5d6 b6d6 f5g6 d6d4 b2b1 h7g6 e2f2 a4b3 a1a8 b3c2 f2c2 f8a8 d3g6 ","solution":{"a8a1":"end","d4a1":"end"},"id":"f2fwl3en"}] 41 | ``` 42 | * `Batch 1 of 10` - Progress through batch set 43 | * `Parent -> Child` - The parent move that the current child node links to 44 | * `Mate In` or `Plies Left` - A countdown to when the line will complete or expire 45 | * Array representation of the problem 46 | * `kthnxbye` - The POST to the API was successful 47 | * JSON string of what was posted 48 | 49 | ### JSON Output: 50 | ```javascript 51 | [ 52 | { 53 | "tags":["material advantage"], // Tags related to the problem 54 | "color":"black", // Which side is solving the problem 55 | "position":"e2e4 c7c6 d2d4 d7d5 e4d5 c6d5 b1c3 g8f6 c1g5 c8g4 f2f3 g4f5 f1d3 f5d3 d1d3 e7e6 e1c1 b8c6 d1e1 f8e7 g5f6 e7f6 c3d5 ", // The starting position for the problem 56 | "solution":{ 57 | "d8d5":{ // The first move that the problem solver (player) has to play 58 | "c1b1":"end" // The computer response followed by either more moves or "end" indicating that the problem is complete 59 | } 60 | }, 61 | "id":"1ic77ndw" //The game ID that the problem came from 62 | }, 63 | { 64 | // ... More problems 65 | } 66 | ] 67 | ``` 68 | 69 | ### Final Notes 70 | 71 | * It is important to change the path to Stockfish to your own executable version. 72 | * Time settings can be adjusted as per the performance of your computer. Larger times means higher quality puzzles 73 | * Contact Thibault Duplessis if you wish to create puzzles for lichess. The key is necessary to successfully submit puzzles to lichess. 74 | 75 | The code is currently not compatible with Windows operating systems due to difficulty connecting to Stockfish. You can try to fix this in [functions/global.php](https://github.com/clarkerubber/problem-creator/blob/master/functions/global.php#L86-L119). 76 | -------------------------------------------------------------------------------- /functions/global.php: -------------------------------------------------------------------------------- 1 | $move ) { 12 | 13 | $SESSION_START = time(); 14 | 15 | unset( $prevMoveEval ); 16 | unset( $nextMoveEval ); 17 | unset( $nextMoveMate ); 18 | 19 | if ( isset( $game['analysis'][$moveKey + 1]['eval'] ) 20 | && isset( $game['analysis'][$moveKey - 1]['eval'] ) ) { 21 | 22 | $prevMoveEval = $game['analysis'][$moveKey - 1]['eval']; 23 | $nextMoveEval = $game['analysis'][$moveKey + 1]['eval']; 24 | 25 | } else if ( isset( $game['analysis'][$moveKey + 1]['mate'] ) ) { 26 | 27 | $nextMoveMate = $game['analysis'][$moveKey + 1]['mate']; 28 | 29 | } 30 | 31 | if ( isset( $move['eval'] ) 32 | && isset( $nextMoveEval ) 33 | && isset( $prevMoveEval ) ){ 34 | 35 | if ( ( ( $prevMoveEval <= $BALANCED && $move['eval'] <= $BALANCED && $nextMoveEval >= $UNBALANCED ) 36 | || ( $prevMoveEval >= -$BALANCED && $move['eval'] >= -$BALANCED && $nextMoveEval <= -$UNBALANCED ) ) 37 | && abs( $move['eval'] - $nextMoveEval ) >= $DIFFERENCE ) { 38 | 39 | //printf(" %5s -> %5s | Mate In %+6d \n", $lastMove, $move, -1 * $candidateMovesEval[$key] ); 40 | echo $move['eval']." - ".$nextMoveEval." = ".abs( $move['eval'] - $nextMoveEval )."\n"; 41 | echo " Parent -> Child | CP Adv | Plies | Adv | Var | + | T | M | C\n"; 42 | echo "==============================================================\n"; 43 | $temp = findCaptureLine( $game['uci'], $moveKey ); 44 | //$temp = FALSE; 45 | 46 | if ( $temp !== FALSE ) { 47 | 48 | $temp['id'] = $game['game']['id']; 49 | $lines[] = $temp; 50 | print_r($temp); 51 | 52 | } 53 | 54 | } 55 | 56 | } else if( isset( $move['eval'] ) && isset( $nextMoveMate ) ) { 57 | if ( ( $move['eval'] <= $MATE_EVAL_THRESHOLD && $nextMoveMate > 0 ) || 58 | ( $move['eval'] >= -$MATE_EVAL_THRESHOLD && $nextMoveMate < 0 ) ) { 59 | 60 | echo "Parent -> Child | Mate In \n"; 61 | echo "==========================\n"; 62 | $temp = findMateLine( $game['uci'], $moveKey, $nextMoveMate ); 63 | 64 | if ( $temp !== FALSE ) { 65 | 66 | $temp['id'] = $game['game']['id']; 67 | $lines[] = $temp; 68 | print_r($temp); 69 | 70 | } 71 | } 72 | 73 | 74 | 75 | } else if ( isset( $move['mate'] ) && isset( $nextMoveMate ) ) { 76 | 77 | if ( sign( $move['mate'] ) !== sign( $nextMoveMate ) ) { 78 | 79 | echo "Parent -> Child | Mate In \n"; 80 | echo "==========================\n"; 81 | $temp = findMateLine( $game['uci'], $moveKey, $nextMoveMate ); 82 | 83 | if ( $temp !== FALSE ) { 84 | 85 | $temp['id'] = $game['game']['id']; 86 | $lines[] = $temp; 87 | print_r($temp); 88 | 89 | } 90 | } 91 | } 92 | } 93 | 94 | return $lines; 95 | } 96 | 97 | function getUci ( $moveSequence, $moveTime, $multiPv = 1 ) { 98 | 99 | global $STOCKFISH_PATH, $STOCKFISH_THREADS; 100 | 101 | $descriptorspec = array( 102 | 0 => array( "pipe", "r" ), // stdin is a pipe that the child will read from 103 | 1 => array( "pipe", "w" ), // stdout is a pipe that the child will write to 104 | 2 => array( "file", "/tmp/error-output.txt", "a" ) // stderr is a file to write to 105 | ); 106 | 107 | $cwd = '/tmp'; 108 | $env = array( 'some_option' => 'aeiou' ); 109 | 110 | $process = proc_open( "$STOCKFISH_PATH", $descriptorspec, $pipes, $cwd, $env ); 111 | 112 | if (is_resource($process)) { 113 | 114 | fwrite( $pipes[0], "uci\n" ); 115 | fwrite( $pipes[0], "ucinewgame\n" ); 116 | fwrite( $pipes[0], "isready\n" ); 117 | fwrite( $pipes[0], "setoption name MultiPV value $multiPv\n" ); 118 | if ( is_int( $STOCKFISH_THREADS ) && isset( $STOCKFISH_THREADS ) ) { 119 | fwrite( $pipes[0], "setoption name Threads value $STOCKFISH_THREADS\n" ); 120 | } 121 | fwrite( $pipes[0], "position startpos moves $moveSequence\n" ); 122 | fwrite( $pipes[0], "go movetime $moveTime\n" ); 123 | usleep( 1000 * $moveTime + 100 ); 124 | fwrite( $pipes[0], "quit\n" ); 125 | fclose( $pipes[0] ); 126 | 127 | $output = stream_get_contents( $pipes[1] ); 128 | 129 | fclose( $pipes[1] ); 130 | } 131 | //print_r($output); 132 | return $output; 133 | } 134 | 135 | function sign ( $number ) { 136 | 137 | return ( $number > 0 ) ? 1 : ( ( $number < 0 ) ? -1 : 0 ); 138 | } 139 | 140 | function testParser ( $game ) { 141 | //Input: a game from the API 142 | //Output: the game played out. 143 | 144 | $captureArray = captureArray ( explode( ' ', $game['uci'] ), $game['analysis'] ); 145 | 146 | foreach ( $game['analysis'] as $key => $move ) { 147 | 148 | echo $move['move'].( ( $captureArray[$key] == 1 )? ' - CAPTURE' : '' )."\n"; 149 | 150 | } 151 | } -------------------------------------------------------------------------------- /functions/mateSequence.php: -------------------------------------------------------------------------------- 1 | array('forced mate'), 'color' => $color, 'position' => $startMoveString, 'solution' => $solutionMap ); 41 | 42 | } 43 | 44 | return $output; 45 | } 46 | 47 | function buildMateTree ( $moveString, $isMate ) { 48 | 49 | $movesList = getMateMovesFromPosition( $moveString, TRUE, $isMate ); 50 | $output = FALSE; 51 | 52 | $empty = TRUE; 53 | $abort = FALSE; 54 | 55 | if ( is_array( $movesList ) ) { 56 | foreach ( $movesList as $key => $value ) { 57 | 58 | if ( $value !== 'retry' ) { 59 | $empty = FALSE; 60 | } 61 | 62 | if ( $value === 'abort' ) { 63 | $abort = TRUE; 64 | } 65 | } 66 | } 67 | 68 | 69 | if ( $empty == FALSE && $abort == FALSE ) { 70 | 71 | $output = $movesList; 72 | 73 | } 74 | 75 | return $output; 76 | } 77 | 78 | function getMateMovesFromPosition ( $moveString, $player, $findMate ) { 79 | 80 | global $FIRST_PASS_TIME, $SECOND_PASS_TIME, $MAX_MATE_LINES, $SESSION_START, $SESSION_LENGTH; 81 | 82 | if ( time() - $SESSION_START >= $SESSION_LENGTH ) { 83 | echo "ABORT! TIME OUT!\n"; 84 | return 'abort'; 85 | } 86 | 87 | if ( $player == TRUE ) { 88 | $maxLines = $MAX_MATE_LINES; 89 | } else { 90 | $maxLines = 1; 91 | } 92 | 93 | $uciOutput = getUci( $moveString, $FIRST_PASS_TIME, $maxLines ); 94 | 95 | preg_match_all( "/info.*?mate (-?[0-9]+).*?([a-h][1-8][a-h][1-8][qrnb]?)/", $uciOutput, $matches ); 96 | 97 | $candidateMoves = array(); 98 | $candidateMovesEval = array(); 99 | 100 | $lastMove = explode( ' ', $moveString ); 101 | array_pop( $lastMove ); 102 | $lastMove = array_pop( $lastMove ); 103 | 104 | foreach ( $matches[2] as $key => $match ) { 105 | 106 | if ( $findMate == TRUE ) { 107 | 108 | if ( $matches[1][$key] == 1 && !in_array( $match, $candidateMoves ) ) { 109 | 110 | $candidateMoves[] = $match; 111 | 112 | } 113 | 114 | } else if ( !in_array( $match, $candidateMoves ) ) { 115 | 116 | if ( ( $player == TRUE && $matches[1][$key] > 0 ) || $player == FALSE ) { 117 | 118 | $candidateMoves[] = $match; 119 | 120 | } 121 | 122 | } 123 | 124 | } 125 | 126 | $checkmate = FALSE; 127 | 128 | if ( $findMate === TRUE ) { 129 | 130 | $checkmate = TRUE; 131 | 132 | foreach ( $candidateMoves as $key => $value ) { 133 | 134 | $candidateMovesEval[$key] = 0; 135 | 136 | } 137 | 138 | } else { 139 | 140 | foreach ( $candidateMoves as $key => $move ) { 141 | 142 | $candidateMovesEval[] = getPositionMate( "$moveString$move ", $SECOND_PASS_TIME ); 143 | 144 | } 145 | 146 | array_multisort( $candidateMovesEval, SORT_DESC, SORT_NUMERIC, $candidateMoves ); 147 | 148 | if ( !empty( $candidateMovesEval ) ) { 149 | 150 | while ( $candidateMovesEval[0] === FALSE ) { 151 | 152 | array_shift( $candidateMovesEval ); 153 | array_shift( $candidateMoves ); 154 | 155 | if ( empty( $candidateMovesEval ) ) { 156 | break; 157 | } 158 | } 159 | } 160 | } 161 | 162 | if ( isset( $candidateMovesEval[0] ) ) { 163 | 164 | $topEval = $candidateMovesEval[0]; 165 | 166 | } 167 | 168 | $moveArray = array(); 169 | 170 | foreach ( $candidateMoves as $key => $move ) { 171 | 172 | if ( $key < $maxLines && $candidateMovesEval[$key] == $topEval ) { 173 | 174 | printf(" %5s -> %5s | %+3d \n", $lastMove, $move, - $candidateMovesEval[$key] ); 175 | 176 | if ( $candidateMovesEval[$key] == 1 ) { 177 | 178 | $mateInOne = TRUE; 179 | 180 | } else { 181 | 182 | $mateInOne = FALSE; 183 | 184 | } 185 | 186 | if ( $player === TRUE && $checkmate === FALSE ) { 187 | 188 | $moveArray[$move] = getMateMovesFromPosition ( $moveString.$move.' ', FALSE, FALSE ); 189 | 190 | } else if ( $player === FALSE ) { 191 | 192 | $moveArray[$move] = getMateMovesFromPosition ( $moveString.$move.' ', TRUE, $mateInOne ); 193 | 194 | } else { 195 | 196 | $moveArray[$move] = 'win'; 197 | 198 | } 199 | 200 | if ( $moveArray[$move] === 'abort' ) { 201 | echo "$move -> ABORT! TIME OUT!\n"; 202 | return 'abort'; 203 | } 204 | 205 | } else if ( ( $candidateMovesEval[$key] = $topEval - 1 || $candidateMovesEval[$key] = $topEval - 2 ) && $player == TRUE ) { 206 | $moveArray[$move] = 'retry'; 207 | } 208 | 209 | } 210 | 211 | 212 | if ( !empty( $moveArray ) ) { 213 | 214 | $empty = TRUE; 215 | $abort = FALSE; 216 | 217 | foreach ( $moveArray as $key => $value ) { 218 | 219 | if ( $value !== 'retry' ) { 220 | 221 | $empty = FALSE; 222 | 223 | } 224 | 225 | if ( $value === 'abort' ) { 226 | $abort = TRUE; 227 | } 228 | 229 | } 230 | 231 | if ( $empty == TRUE || $abort == TRUE ) { 232 | $moveArray = 'abort'; 233 | echo "$lastMove -> ABORT!\n"; 234 | } 235 | 236 | } else { 237 | $moveArray = 'abort'; 238 | echo "$lastMove -> ABORT!\n\n"; 239 | } 240 | 241 | return $moveArray; 242 | } 243 | 244 | function getPositionMate ( $moveString, $moveTime ) { 245 | 246 | $uciOutput = getUci( $moveString, $moveTime ); 247 | $output = FALSE; 248 | 249 | preg_match_all( "/mate (-?[0-9]+) /", $uciOutput, $matches ); 250 | 251 | $end = end( $matches[1] ); 252 | 253 | if ( isset( $end ) ) { 254 | 255 | $output = $end; 256 | 257 | } 258 | 259 | return $output; 260 | } -------------------------------------------------------------------------------- /resources/example-problems.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "tags":["material advantage"], 4 | "color":"white", 5 | "position":"e2e4 e7e5 g1f3 b8c6 f1b5 a7a6 b5c6 d7c6 d2d4 e5d4 d1d4 c8e6 c1g5 f8e7 g5e7 g8e7 e1g1 e8g8 f1d1 b7b6 b1c3 c6c5 d4d3 e7c6 d1d2 c6b4 d3e2 d8g5 ", 6 | "solution":{ 7 | "f3g5":{ 8 | "a8e8":{ 9 | "g5e6":{ 10 | "e8e6":"end" 11 | } 12 | } 13 | } 14 | }, 15 | "id":"a1t3z4u5" 16 | }, 17 | { 18 | "tags":["material advantage"], 19 | "color":"black", 20 | "position":"e2e4 e7e5 g1f3 b8c6 f1b5 a7a6 b5c6 d7c6 d2d4 e5d4 d1d4 c8e6 c1g5 f8e7 g5e7 g8e7 e1g1 e8g8 f1d1 b7b6 b1c3 c6c5 d4d3 e7c6 d1d2 c6b4 d3e2 d8g5 a1d1 g5g6 a2a3 b4c6 d2d3 e6g4 e2d2 g4f3 d3f3 a8d8 d2e2 c6e5 f3g3 g6f6 d1d8 f8d8 c3d1 e5c4 b2b3 d8d2 e2e1 ", 21 | "solution":{ 22 | "f6a1":{ 23 | "g3d3":{ 24 | "d2d3":{ 25 | "c2d3":"end" 26 | } 27 | } 28 | } 29 | }, 30 | "id":"a1t3z4u5" 31 | }, 32 | { 33 | "tags":["forced mate"], 34 | "color":"black", 35 | "position":"e2e4 e7e5 g1f3 b8c6 f1b5 a7a6 b5c6 d7c6 d2d4 e5d4 d1d4 c8e6 c1g5 f8e7 g5e7 g8e7 e1g1 e8g8 f1d1 b7b6 b1c3 c6c5 d4d3 e7c6 d1d2 c6b4 d3e2 d8g5 a1d1 g5g6 a2a3 b4c6 d2d3 e6g4 e2d2 g4f3 d3f3 a8d8 d2e2 c6e5 f3g3 g6f6 d1d8 f8d8 c3d1 e5c4 b2b3 d8d2 e2e1 f6a1 b3c4 d2d1 g1f1 ", 36 | "solution":{ 37 | "d1e1":"end" 38 | }, 39 | "id":"a1t3z4u5" 40 | }, 41 | { 42 | "tags":["material advantage"], 43 | "color":"black", 44 | "position":"e2e4 e7e5 d2d4 e5d4 d1d4 b8c6 d4e3 g8f6 b1c3 f8b4 c1d2 e8g8 e1c1 f8e8 f1c4 d7d6 h2h3 c8e6 c4b5 a7a6 b5a4 b7b5 a4b3 c6e5 a2a3 b4c5 e3g3 e6b3 c2b3 b5b4 a3b4 c5b4 f2f4 e5g6 e4e5 d6e5 f4f5 g6f4 d2f4 e5f4 g3f4 b4d6 f4a4 d8e7 g1f3 e7e3 f3d2 d6g3 c1b1 e3d3 b1a2 d3f5 h1f1 f5g6 d2f3 f6e4 d1d4 ", 45 | "solution":{ 46 | "e4c3":{ 47 | "b2c3":"end" 48 | } 49 | }, 50 | "id":"dvz729iw" 51 | }, 52 | { 53 | "tags":["forced mate"], 54 | "color":"black", 55 | "position":"e2e4 e7e5 d2d4 e5d4 d1d4 b8c6 d4e3 g8f6 b1c3 f8b4 c1d2 e8g8 e1c1 f8e8 f1c4 d7d6 h2h3 c8e6 c4b5 a7a6 b5a4 b7b5 a4b3 c6e5 a2a3 b4c5 e3g3 e6b3 c2b3 b5b4 a3b4 c5b4 f2f4 e5g6 e4e5 d6e5 f4f5 g6f4 d2f4 e5f4 g3f4 b4d6 f4a4 d8e7 g1f3 e7e3 f3d2 d6g3 c1b1 e3d3 b1a2 d3f5 h1f1 f5g6 d2f3 f6e4 d1d4 e4c3 b2c3 g6c2 a2a3 e8e2 a4c4 ", 56 | "solution":{ 57 | "c2a2":{ 58 | "a3b4":{ 59 | "a8b8":{ 60 | "b4c5":{ 61 | "a2a5":{ 62 | "c5c6":{ 63 | "b8b6":{ 64 | "c6d7":{ 65 | "a5f5":{ 66 | "c4e6":{ 67 | "f5e6":{ 68 | "d7d8":{ 69 | "b6b8":"end" 70 | } 71 | } 72 | } 73 | } 74 | } 75 | } 76 | } 77 | } 78 | } 79 | } 80 | } 81 | } 82 | }, 83 | "id":"dvz729iw" 84 | }, 85 | { 86 | "tags":["material advantage"], 87 | "color":"white", 88 | "position":"e2e4 e7e5 d2d4 e5d4 d1d4 b8c6 d4e3 g8f6 b1c3 f8b4 c1d2 e8g8 e1c1 f8e8 f1c4 d7d6 h2h3 c8e6 c4b5 a7a6 b5a4 b7b5 a4b3 c6e5 a2a3 b4c5 e3g3 e6b3 c2b3 b5b4 a3b4 c5b4 f2f4 e5g6 e4e5 d6e5 f4f5 g6f4 d2f4 e5f4 g3f4 b4d6 f4a4 d8e7 g1f3 e7e3 f3d2 d6g3 c1b1 e3d3 b1a2 d3f5 h1f1 f5g6 d2f3 f6e4 d1d4 e4c3 b2c3 g6c2 a2a3 e8e2 a4c4 g3d6 d4d6 c7d6 f3d2 c2a2 ", 89 | "solution":{ 90 | "a3a2":{ 91 | "e2d2":"end" 92 | } 93 | }, 94 | "id":"dvz729iw" 95 | }, 96 | { 97 | "tags":["material advantage"], 98 | "color":"black", 99 | "position":"g1f3 b7b6 e2e4 c8b7 b1c3 e7e6 d2d4 d7d5 e4e5 c7c5 b2b3 b8c6 c1b2 c5d4 f3d4 f8b4 f1b5 g8e7 d1d3 a7a6 b5c6 e7c6 d4c6 b7c6 e1c1 e8g8 f2f4 a6a5 h2h4 b4c3 d3c3 a8c8 c3d4 d8c7 h1g1 c6b5 c2c3 b5e2 d1d2 e2h5 a2a4 h5g6 g2g4 h7h6 h4h5 g6h7 d2f2 c7c5 d4c5 b6c5 f4f5 c5c4 b3b4 a5b4 c3b4 c4c3 b2a3 e6f5 g4f5 f8e8 b4b5 e8e5 b5b6 c8b8 a4a5 d5d4 a3c5 ", 100 | "solution":{ 101 | "e5c5":{ 102 | "c1c2":"end" 103 | } 104 | }, 105 | "id":"onico0b8" 106 | }, 107 | { 108 | "tags":["material advantage"], 109 | "color":"white", 110 | "position":"e2e4 c7c5 c2c4 b8c6 g1f3 e7e5 b1c3 d7d6 h2h3 c6d4 f1e2 g8f6 d2d3 g7g6 c1g5 f8g7 c3d5 d8a5 f3d2 c8d7 ", 111 | "solution":{ 112 | "g5f6":{ 113 | "g7f6":{ 114 | "d5f6":{ 115 | "e8e7":"end" 116 | } 117 | } 118 | }, 119 | "d5f6":{ 120 | "g7f6":{ 121 | "g5f6":{ 122 | "e8g8":"end" 123 | } 124 | } 125 | } 126 | }, 127 | "id":"qs516xa9" 128 | }, 129 | { 130 | "tags":["material advantage"], 131 | "color":"black", 132 | "position":"d2d4 d7d5 c2c4 e7e6 b1c3 f8b4 e2e3 g8f6 g1f3 c7c5 c1d2 b4c3 d2c3 c5d4 f3d4 b8c6 a1c1 e8g8 f1e2 f8e8 e1g1 f6e4 e2d3 e4c3 c1c3 c6d4 e3d4 d8b6 f1e1 c8d7 b2b3 b6a5 d1c1 a5a2 d3b1 a2a5 c3h3 h7h6 e1d1 e6e5 h3g3 g8f8 c4d5 e5d4 h2h3 a7a6 d5d6 ", 133 | "solution":{ 134 | "a8c8":{ 135 | "c1f4":{ 136 | "e8e1":{ 137 | "d1e1":{ 138 | "a5e1":{ 139 | "g1h2":"end" 140 | } 141 | } 142 | } 143 | } 144 | } 145 | }, 146 | "id":"5m2gsfzp" 147 | }, 148 | { 149 | "tags":["material advantage"], 150 | "color":"white", 151 | "position":"d2d4 d7d5 c2c4 e7e6 b1c3 f8b4 e2e3 g8f6 g1f3 c7c5 c1d2 b4c3 d2c3 c5d4 f3d4 b8c6 a1c1 e8g8 f1e2 f8e8 e1g1 f6e4 e2d3 e4c3 c1c3 c6d4 e3d4 d8b6 f1e1 c8d7 b2b3 b6a5 d1c1 a5a2 d3b1 a2a5 c3h3 h7h6 e1d1 e6e5 h3g3 g8f8 c4d5 e5d4 h2h3 a7a6 d5d6 d7c6 b1h7 a8d8 c1h6 e8e1 d1e1 a5e1 g1h2 e1e5 h6h4 e5d6 h7d3 c6b5 h4h8 f8e7 h8h4 e7f8 h4h8 f8e7 h8h4 f7f6 h4e4 d6e6 e4b7 d8d7 b7f3 e6b3 ", 152 | "solution":{ 153 | "g3g7":{ 154 | "e7f8":{ 155 | "g7d7":{ 156 | "b5d7":"end" 157 | } 158 | } 159 | } 160 | }, 161 | "id":"5m2gsfzp" 162 | }, 163 | { 164 | "tags":["forced mate"], 165 | "color":"white", 166 | "position":"d2d4 d7d5 c2c4 e7e6 b1c3 f8b4 e2e3 g8f6 g1f3 c7c5 c1d2 b4c3 d2c3 c5d4 f3d4 b8c6 a1c1 e8g8 f1e2 f8e8 e1g1 f6e4 e2d3 e4c3 c1c3 c6d4 e3d4 d8b6 f1e1 c8d7 b2b3 b6a5 d1c1 a5a2 d3b1 a2a5 c3h3 h7h6 e1d1 e6e5 h3g3 g8f8 c4d5 e5d4 h2h3 a7a6 d5d6 d7c6 b1h7 a8d8 c1h6 e8e1 d1e1 a5e1 g1h2 e1e5 h6h4 e5d6 h7d3 c6b5 h4h8 f8e7 h8h4 e7f8 h4h8 f8e7 h8h4 f7f6 h4e4 d6e6 e4b7 d8d7 b7f3 e6b3 g3g7 e7f8 f3f6 f8e8 ", 167 | "solution":{ 168 | "d3g6":{ 169 | "d7f7":{ 170 | "f6d6":{ 171 | "b3h3":{ 172 | "g2h3":{ 173 | "d4d3":{ 174 | "g6f7":"end" 175 | } 176 | } 177 | } 178 | }, 179 | "g6f7":{ 180 | "e8d7":{ 181 | "f7b3":{ 182 | "d7c8":{ 183 | "f6f8":{ 184 | "b5e8":{ 185 | "f8e8":"end" 186 | } 187 | } 188 | } 189 | } 190 | } 191 | } 192 | } 193 | } 194 | }, 195 | "id":"5m2gsfzp" 196 | }, 197 | { 198 | "tags":["material advantage"], 199 | "color":"black", 200 | "position":"e2e4 g7g6 d2d4 f8g7 g1f3 e7e6 f1b5 c7c6 b5a4 g8e7 e1g1 e8g8 c1g5 h7h6 g5f4 g8h7 c2c3 d7d6 b1d2 f7f5 e4f5 e6f5 d2c4 b7b5 c4d6 b5a4 d1a4 e7d5 d6c8 ", 201 | "solution":{"d5f4":{"c8a7":"end"}}, 202 | "id":"815xhg2w" 203 | }, 204 | { 205 | "tags":["forced mate"], 206 | "color":"black", 207 | "position":"e2e4 g7g6 d2d4 f8g7 g1f3 e7e6 f1b5 c7c6 b5a4 g8e7 e1g1 e8g8 c1g5 h7h6 g5f4 g8h7 c2c3 d7d6 b1d2 f7f5 e4f5 e6f5 d2c4 b7b5 c4d6 b5a4 d1a4 e7d5 d6c8 d5f4 c8b6 d8b6 d4d5 f4e2 g1h1 c6d5 a1e1 b6b2 a4h4 e2c3 e1e7 c3e4 e7c7 b8a6 c7d7 a8c8 h4e7 a6c5 d7a7 e4f2 h1g1 c5e4 h2h3 f8g8 f3e5 ", 208 | "solution":{"c8c1":{"e7d6":{"c1f1":{"g1f1":{"b2a1":{"f1e2":{"a1d1":{"e2e3":{"d1e1":{"e3f3":{"e4g5":{"f3f4":{"f2h3":{"g2h3":{"g5h3":{"f4f3":{"e1f2":"end"}}}}}}}}}}}},"e4g3":{"f1g1":{"b2a1":{"g1h2":{"a1h1":{"h2g3":{"f2e4":{"g3f4":{"h1f1":{"e5f3":{"f1c1":{"f3d2":{"c1d2":{"f4f3":{"d2f2":"end"}}}}}}}}}}}}}}}}}}}, 209 | "id":"815xhg2w" 210 | }, 211 | { 212 | "tags":["forced mate"], 213 | "color":"black", 214 | "position":"e2e4 g7g6 d2d4 f8g7 g1f3 e7e6 f1b5 c7c6 b5a4 g8e7 e1g1 e8g8 c1g5 h7h6 g5f4 g8h7 c2c3 d7d6 b1d2 f7f5 e4f5 e6f5 d2c4 b7b5 c4d6 b5a4 d1a4 e7d5 d6c8 d5f4 c8b6 d8b6 d4d5 f4e2 g1h1 c6d5 a1e1 b6b2 a4h4 e2c3 e1e7 c3e4 e7c7 b8a6 c7d7 a8c8 h4e7 a6c5 d7a7 e4f2 h1g1 c5e4 h2h3 f8g8 f3e5 b2b6 g1h2 h7h8 e7f7 ", 215 | "solution":{"g7e5":{"g2g3":{"f2g4":{"h2h1":{"e4g3":{"h1g2":{"c8c2":{"f1f2":{"b6f2":"end"}}}}}}}}}, 216 | "id":"815xhg2w" 217 | }, 218 | { 219 | "tags":["forced mate"], 220 | "color":"black", 221 | "position":"e2e4 g7g6 d2d4 f8g7 g1f3 e7e6 f1b5 c7c6 b5a4 g8e7 e1g1 e8g8 c1g5 h7h6 g5f4 g8h7 c2c3 d7d6 b1d2 f7f5 e4f5 e6f5 d2c4 b7b5 c4d6 b5a4 d1a4 e7d5 d6c8 d5f4 c8b6 d8b6 d4d5 f4e2 g1h1 c6d5 a1e1 b6b2 a4h4 e2c3 e1e7 c3e4 e7c7 b8a6 c7d7 a8c8 h4e7 a6c5 d7a7 e4f2 h1g1 c5e4 h2h3 f8g8 f3e5 b2b6 g1h2 h7h8 e7f7 b6d6 g2g3 ", 222 | "solution":{"d6e5":{"f7g6":{"c8c2":{"g6g7":{"g8g7":{"a7a8":{"h8h7":{"a8h8":{"h7h8":{"f1g1":{"f2g4":{"h2h1":{"c2h2":"end"}}}}}}}}}}}}}, 223 | "id":"815xhg2w" 224 | }, 225 | { 226 | "tags":["forced mate"], 227 | "color":"black", 228 | "position":"e2e4 g7g6 d2d4 f8g7 g1f3 e7e6 f1b5 c7c6 b5a4 g8e7 e1g1 e8g8 c1g5 h7h6 g5f4 g8h7 c2c3 d7d6 b1d2 f7f5 e4f5 e6f5 d2c4 b7b5 c4d6 b5a4 d1a4 e7d5 d6c8 d5f4 c8b6 d8b6 d4d5 f4e2 g1h1 c6d5 a1e1 b6b2 a4h4 e2c3 e1e7 c3e4 e7c7 b8a6 c7d7 a8c8 h4e7 a6c5 d7a7 e4f2 h1g1 c5e4 h2h3 f8g8 f3e5 b2b6 g1h2 h7h8 e7f7 b6d6 g2g3 c8c2 e5g6 ", 229 | "solution":{"d6g6":{"f7g6":{"f2g4":{"h2g1":{"g7d4":{"f1f2":{"d4f2":{"g1h1":{"f2a7":{"g6g8":{"h8g8":{"a2a3":{"e4g3":"end"}}}}}}}}}}}}}, 230 | "id":"815xhg2w" 231 | }, 232 | { "tags":["material advantage"], 233 | "color":"black","position":"e2e4 e7e5 f2f4 e5f4 g1f3 f8e7 f1c4 e7h4 e1f1 d7d6 d2d3 c8g4 c1f4 g4f3 d1f3 d8f6 b1c3 g8e7 e4e5 d6e5 a1e1 ", 234 | "solution":{"f6f4":{"f3f4":{"e5f4":{"g2g3":"end"}}}}, 235 | "id":"im1wvs00" 236 | }, 237 | { 238 | "tags":["forced mate"], 239 | "color":"white", 240 | "position":"e2e4 d7d5 d2d3 d5e4 d3e4 d8d1 e1d1 c8e6 f1d3 b8c6 g1f3 g8f6 d1e2 e6d7 c1e3 e7e6 b1c3 f8b4 h1d1 e8g8 a2a3 b4c3 b2c3 a7a6 c3c4 c6a7 c2c3 d7c6 d3c2 c6e4 c2e4 f6e4 d1d3 f8d8 a1d1 d8d3 d1d3 h7h6 e3a7 a8a7 e2e3 e4f6 d3d8 g8h7 f3e5 b7b5 e5f7 b5c4 d8h8 h7g6 f7e5 g6f5 f2f4 f6d5 e3f3 d5c3 ", 241 | "solution":{"h8f8":"end"}, 242 | "id":"yxtn7ejj" 243 | }, 244 | { 245 | "tags":["material advantage"], 246 | "color":"black", 247 | "position":"e2e4 d7d5 d2d3 d5e4 d3e4 d8d1 e1d1 c8e6 f1d3 b8c6 g1f3 g8f6 d1e2 e6d7 c1e3 e7e6 b1c3 f8b4 h1d1 e8g8 a2a3 b4c3 b2c3 a7a6 c3c4 c6a7 c2c3 d7c6 d3c2 c6e4 c2e4 f6e4 d1d3 f8d8 a1d1 d8d3 d1d3 h7h6 e3a7 a8a7 e2e3 e4f6 d3d8 g8h7 f3e5 b7b5 e5f7 b5c4 d8h8 h7g6 f7e5 g6f5 f2f4 f6d5 e3f3 d5c3 g2g4 f5f6 h8f8 f6e7 f8f7 e7d6 f7g7 a7b7 e5c4 d6d5 c4e3 d5d6 f4f5 e6f5 g4f5 b7b3 g7g6 d6e5 g6e6 e5d4 e3c2 d4d5 c2b4 d5c5 e6e5 c5d4 e5e4 ", 248 | "solution":{"c3e4":{"f3f4":"end"}}, 249 | "id":"yxtn7ejj" 250 | }, 251 | { 252 | "tags":["forced mate"], 253 | "color":"black", 254 | "position":"d2d4 e7e6 e2e3 g8f6 c2c4 d7d5 g1f3 c7c5 b2b3 c5d4 f3d4 b8c6 c1b2 f8e7 f1e2 e8g8 e1g1 c8d7 b1c3 d7e8 e2d3 a8c8 e3e4 d5e4 d4c6 e8c6 d3c2 d8d1 f1d1 e7c5 c3e2 f6g4 b2d4 c5d4 e2d4 g4f6 d4c6 c8c6 d1e1 f8d8 c2e4 f6e4 e1e4 d8d2 g2g3 h7h6 g1g2 f7f6 g2f3 g8f7 f3e3 d2c2 e4d4 f7e7 a2a3 c2c3 d4d3 c3d3 e3d3 c6b6 b3b4 b6d6 d3e3 e6e5 c4c5 d6d5 a1a2 e7d7 f2f4 e5f4 e3f4 d7c6 f4e4 d5h5 h2h4 h5e5 e4f4 c6b5 g3g4 a7a5 h4h5 a5b4 a3a4 b5c5 a4a5 b4b3 a2b2 c5b4 a5a6 b7a6 g4g5 h6g5 f4g4 a6a5 b2c2 ", 255 | "solution":{"b3c2":{"h5h6":{"g7g6":{"g4h3":{"c2c1q":{"h3g2":{"e5e2":{"g2g3":{"c1g1":{"g3h3":{"e2h2":"end"}}}}}}}}}}}, 256 | "id":"s65y6xvx" 257 | }, 258 | { 259 | "tags":["forced mate"], 260 | "color":"black", 261 | "position":"e2e3 g7g6 b2b3 f8g7 b1c3 c7c5 c1b2 d7d5 a1b1 b8c6 g1e2 g8f6 g2g3 d5d4 e3d4 c5d4 c3a4 d8d5 h1g1 e7e5 b2a1 e8g8 f1g2 d5d6 d2d3 f6d5 e1d2 g7h6 f2f4 e5f4 g3f4 d5f4 d2e1 f8e8 g2f3 e8e3 f3c6 b7c6 a1d4 e3e2 d1e2 f4e2 e1e2 d6d4 c2c3 ", 262 | "solution":{"d4e3":{"e2f1":{"c8h3":{"g1g2":{"e3f3":{"f1e1":{"a8e8":{"g2e2":{"f3e2":"end"}}}}}}}}}, 263 | "id":"p94sh8fg" 264 | }, 265 | { 266 | "tags":["forced mate"], 267 | "color":"white", 268 | "position":"d2d4 e7e5 d4e5 d7d6 e2e4 b8c6 f1b5 c8d7 g1f3 c6e5 f3e5 d7b5 e5f7 d8e7 f7h8 e7e4 c1e3 e8c8 b1c3 e4g2 d1d5 g2d5 c3d5 b5c6 e1c1 g8f6 c2c4 b7b5 b2b3 b5c4 b3c4 c6a4 d1d2 f6e4 d2b2 c7c5 h8f7 d8d7 f7g5 e4g5 e3g5 h7h6 g5f4 g7g5 f4g3 f8g7 b2d2 a4c6 h1e1 a7a5 d5b6 c8d8 b6d7 d8d7 d2d6 d7c7 d6g6 c7b6 ", 269 | "solution":{"e1e6":{"a5a4":{"e6c6":{"b6a5":{"a2a3":{"g7b2":{"c1b2":{"g5g4":{"c6c5":"end"}}}}}}}}}, 270 | "id":"hmsr9x2x" 271 | }, 272 | { 273 | "tags":["forced mate"], 274 | "color":"white", 275 | "position":"d2d4 e7e5 d4e5 d7d6 e2e4 b8c6 f1b5 c8d7 g1f3 c6e5 f3e5 d7b5 e5f7 d8e7 f7h8 e7e4 c1e3 e8c8 b1c3 e4g2 d1d5 g2d5 c3d5 b5c6 e1c1 g8f6 c2c4 b7b5 b2b3 b5c4 b3c4 c6a4 d1d2 f6e4 d2b2 c7c5 h8f7 d8d7 f7g5 e4g5 e3g5 h7h6 g5f4 g7g5 f4g3 f8g7 b2d2 a4c6 h1e1 a7a5 d5b6 c8d8 b6d7 d8d7 d2d6 d7c7 d6g6 c7b6 g6g7 a5a4 ", 276 | "solution":{"g3c7":{"b6b7":{"e1e6":{"g5g4":{"c7a5":{"b7a8":{"e6c6":{"a8b8":{"c6h6":{"a4a3":{"h6h8":"end"}}}}}}}},"e1e7":{"h6h5":{"c7a5":{"c6d7":{"e7d7":{"b7c6":{"d7d1":{"a4a3":{"g7c7":"end"}}}}}}}}}}}, 277 | "id":"hmsr9x2x" 278 | }, 279 | { 280 | "tags":["material advantage"], 281 | "color":"white", 282 | "position":"d2d4 d7d5 c2c4 e7e6 e2e3 b8c6 g1f3 g8f6 b1c3 f8b4 c1d2 a7a6 a2a3 b4c3 d2c3 d5c4 f1c4 b7b5 c4a2 e8g8 e1g1 c6e7 c3b4 f8e8 f3e5 c8b7 a1c1 e7d5 b4c5 f6d7 d1f3 f7f6 e5d7 d8d7 f1d1 b7c6 ", 283 | "solution":{"e3e4":{"a6a5":{"e4d5":{"c6d5":{"a2d5":{"e6d5":"end"}}}}}},"id":"l9xwq2d7" 284 | }, 285 | { 286 | "tags":["forced mate"], 287 | "color":"white", 288 | "position":"d2d4 d7d5 c2c4 e7e6 e2e3 b8c6 g1f3 g8f6 b1c3 f8b4 c1d2 a7a6 a2a3 b4c3 d2c3 d5c4 f1c4 b7b5 c4a2 e8g8 e1g1 c6e7 c3b4 f8e8 f3e5 c8b7 a1c1 e7d5 b4c5 f6d7 d1f3 f7f6 e5d7 d8d7 f1d1 b7c6 e3e4 d5e7 d4d5 e6d5 c5e7 g8h8 e7b4 d5d4 a2d5 c6d5 e4d5 a6a5 b4c5 b5b4 c5d4 a8b8 d4c5 e8e5 d5d6 b8c8 d6c7 d7c7 c5e3 c7b8 e3f4 c8c1 d1c1 b4a3 f4e5 f6e5 f3a3 h7h6 g2g3 b8b5 ", 289 | "solution":{"a3f8":{"h8h7":{"f8f5":{"g7g6":{"f5f7":{"h7h8":{"c1c8":{"b5e8":{"c8e8":"end"}}}}}}}}}, 290 | "id":"l9xwq2d7" 291 | }, 292 | { 293 | "tags":["forced mate"], 294 | "color":"white", 295 | "position":"d2d4 d7d5 c2c4 e7e6 e2e3 b8c6 g1f3 g8f6 b1c3 f8b4 c1d2 a7a6 a2a3 b4c3 d2c3 d5c4 f1c4 b7b5 c4a2 e8g8 e1g1 c6e7 c3b4 f8e8 f3e5 c8b7 a1c1 e7d5 b4c5 f6d7 d1f3 f7f6 e5d7 d8d7 f1d1 b7c6 e3e4 d5e7 d4d5 e6d5 c5e7 g8h8 e7b4 d5d4 a2d5 c6d5 e4d5 a6a5 b4c5 b5b4 c5d4 a8b8 d4c5 e8e5 d5d6 b8c8 d6c7 d7c7 c5e3 c7b8 e3f4 c8c1 d1c1 b4a3 f4e5 f6e5 f3a3 h7h6 g2g3 b8b5 c1c5 b5e2 g1g2 e2e4 a3f3 e4b1 c5e5 b1g6 f3f8 h8h7 f8f5 a5a4 f5g6 h7g6 e5a5 a4a3 a5a3 g6f7 b2b4 f7e7 a3d3 g7g5 ", 296 | "solution":{"b4b5":{"h6h5":{"b5b6":{"h5h4":{"b6b7":{"e7f6":{"b7b8q":{"h4h3":{"g2f3":{"g5g4":{"f3g4":{"f6e6":{"b8f8":{"e6e5":{"f8f5":"end"}}}}}},"g2h3":{"f6f7":{"f2f4":{"g5f4":{"d3d6":{"f4g3":{"b8c7":{"f7g8":{"d6d8":"end"}}}}}}}}}}}}}}}}}, 297 | "id":"l9xwq2d7" 298 | }, 299 | { 300 | "tags":["material advantage"], 301 | "color":"white", 302 | "position":"e2e4 g8f6 b1c3 e7e5 g1f3 b8c6 f1c4 f8b4 f3g5 h7h5 ", 303 | "solution":{"g5f7":{"d8e7":{"f7h8":{"b4c3":{"d2c3":{"e7f8":"end"},"b2c3":{"e7f8":"end"}}}}}}, 304 | "id":"ecqekppl" 305 | }, 306 | { 307 | "tags":["forced mate"], 308 | "color":"black", 309 | "position":"e2e4 g8f6 b1c3 e7e5 g1f3 b8c6 f1c4 f8b4 f3g5 h7h5 g5f7 d8e7 f7h8 e7c5 d2d3 c6d4 a2a3 a7a5 a3b4 c5b6 a1a4 d4c6 c1g5 f6g4 c3d5 ", 310 | "solution":{"b6f2":"end"}, 311 | "id":"ecqekppl" 312 | }, 313 | { 314 | "tags":["material advantage"], 315 | "color":"white","position":"e2e4 c7c6 g1e2 d7d5 e2g3 d5e4 g3e4 b8d7 f1e2 g8f6 e4g3 g7g6 e1g1 f8g7 d2d3 h7h5 f1e1 h5h4 g3f1 d7b6 c1f4 f6d5 f4c1 h4h3 g2g3 d5f6 a2a4 a7a5 c2c4 d8d4 d1b3 b6d7 c1e3 d7c5 ", 316 | "solution":{"b3a3":{"d4e5":{"e3c5":{"f6d7":"end"},"f2f4":{"e5c7":{"e3c5":{"b7b6":"end"}}},"d3d4":{"e5f5":{"d4c5":{"f6g4":{"e2g4":{"f5g4":"end"}}}}},"a3c5":{"e5b2":"end"}}}}, 317 | "id":"w734wejq" 318 | }, 319 | { 320 | "tags":["material advantage"], 321 | "color":"white", 322 | "position":"e2e4 e7e5 g1f3 g8f6 f3e5 f8d6 e5f3 f6e4 d1e2 d8e7 d2d3 e4f6 b1c3 e8g8 c1g5 d6b4 e1c1 e7e2 c3e2 f6d5 g2g3 d7d6 f1g2 c7c6 g5d2 c8g4 h1e1 b4c5 d3d4 c5b6 c2c3 f8e8 h2h3 g4h5 ", 323 | "solution":{"e2f4":{"b8d7":{"f4h5":{"d5f6":{"e1e8":{"a8e8":{"h5f6":{"d7f6":{"d1e1":{"e8e1":{"f3e1":{"d6d5":"end"},"d2e1":{"g8f8":"end"}}}}}}},"h5f6":{"d7f6":{"e1e8":{"a8e8":{"d1e1":{"e8e1":{"f3e1":{"d6d5":"end"},"d2e1":{"g8f8":"end"}}}}}}}}}, 324 | "e1e8":{"a8e8":{"f4h5":{"g7g6":"end"}}}}}}, 325 | "id":"19a80p13" 326 | }, 327 | { 328 | "tags":["material advantage"], 329 | "color":"white", 330 | "position":"e2e4 e7e5 g1f3 g8f6 f3e5 f8d6 e5f3 f6e4 d1e2 d8e7 d2d3 e4f6 b1c3 e8g8 c1g5 d6b4 e1c1 e7e2 c3e2 f6d5 g2g3 d7d6 f1g2 c7c6 g5d2 c8g4 h1e1 b4c5 d3d4 c5b6 c2c3 f8e8 h2h3 g4h5 g3g4 h5g6 f3h4 g6d3 ", 331 | "solution":{"e2f4":{"b8d7":{"f4d3":{"d5e7":"end"},"e1e8":{"a8e8":{"f4d3":{"g7g6":{"g2d5":{"c6d5":"end"}}}}}}}}, 332 | "id":"19a80p13" 333 | }, 334 | { 335 | "tags":["forced mate"], 336 | "color":"white", 337 | "position":"e2e4 e7e5 d1h5 b8c6 f1c4 g7g6 h5f3 g8f6 c2c3 f8g7 c4e2 d7d6 h2h3 e8g8 d2d3 d6d5 g2g4 d5e4 d3e4 b7b6 g4g5 f6h5 f3g2 h5f4 c1f4 e5f4 g2f3 d8d6 b1a3 c6e5 f3g2 e5d3 e2d3 d6d3 a1d1 d3a6 g1e2 c8b7 e2f4 f8e8 f2f3 g7c3 b2c3 a6a3 e1g1 a3c3 d1c1 c3d4 g1h1 c7c5 c1d1 d4e3 g2g4 a8d8 d1d8 e8d8 f4g2 e3e2 g4f4 e2f1 h1h2 d8c8 f4d6 f1e2 d6d7 e2a6 g2f4 a6a2 h2g3 a2a6 e4e5 c5c4 e5e6 c4c3 ", 338 | "solution":{"e6f7":{"g8g7":{"f4e6":{"g7h8":{"d7d4":"end"}}}}}, 339 | "id":"5xenjam7" 340 | }, 341 | { 342 | "tags":["forced mate"], 343 | "color":"white","position":"e2e4 e7e5 d1h5 b8c6 f1c4 g7g6 h5f3 g8f6 c2c3 f8g7 c4e2 d7d6 h2h3 e8g8 d2d3 d6d5 g2g4 d5e4 d3e4 b7b6 g4g5 f6h5 f3g2 h5f4 c1f4 e5f4 g2f3 d8d6 b1a3 c6e5 f3g2 e5d3 e2d3 d6d3 a1d1 d3a6 g1e2 c8b7 e2f4 f8e8 f2f3 g7c3 b2c3 a6a3 e1g1 a3c3 d1c1 c3d4 g1h1 c7c5 c1d1 d4e3 g2g4 a8d8 d1d8 e8d8 f4g2 e3e2 g4f4 e2f1 h1h2 d8c8 f4d6 f1e2 d6d7 e2a6 g2f4 a6a2 h2g3 a2a6 e4e5 c5c4 e5e6 c4c3 d7f7 g8h8 e6e7 b7c6 ", 344 | "solution":{"f7f8":{"c8f8":{"e7f8q":"end"}}}, 345 | "id":"5xenjam7" 346 | }, 347 | { 348 | "tags":["material advantage"], 349 | "color":"white", 350 | "position":"e2e4 e7e5 g1f3 d8h4 ", 351 | "solution":{"f3h4":{"g8f6":"end"}}, 352 | "id":"b9m1v9h5" 353 | }, 354 | { 355 | "tags":["material advantage"], 356 | "color":"black","position":"e2e4 e7e5 g1f3 d8h4 g2g3 h4f6 b1c3 g8h6 f1c4 f8c5 c3b5 b8a6 d2d3 h6g4 c1g5 f6g6 f3h4 ", 357 | "solution":{"c5f2":{"e1f1":{"g6g5":{"h4f5":"end"}}}}, 358 | "id":"b9m1v9h5" 359 | }, 360 | { 361 | "tags":["material advantage"], 362 | "color":"white", 363 | "position":"e2e4 e7e5 g1f3 d8h4 g2g3 h4f6 b1c3 g8h6 f1c4 f8c5 c3b5 b8a6 d2d3 h6g4 c1g5 f6g6 f3h4 g6h5 f2f4 g4f2 ", 364 | "solution":{"d1h5":{"d7d5":"end"},"b5d6":{"c7d6":{"d1h5":{"d6d5":"end"}}},"b5c7":{"a6c7":{"d1h5":{"d7d5":"end"}}}}, 365 | "id":"b9m1v9h5" 366 | }, 367 | { 368 | "tags":["forced mate"], 369 | "color":"white", 370 | "position":"e2e4 e7e5 g1f3 d8h4 g2g3 h4f6 b1c3 g8h6 f1c4 f8c5 c3b5 b8a6 d2d3 h6g4 c1g5 f6g6 f3h4 g6h5 f2f4 g4f2 d1h5 f2h1 ", 371 | "solution":{"h5f7":"end"}, 372 | "id":"b9m1v9h5" 373 | }, 374 | { 375 | "tags":["material advantage"], 376 | "color":"black", 377 | "position":"d2d4 c7c6 c2c4 e7e6 g1f3 d7d5 c1f4 h7h6 e2e3 f8d6 f4d6 d8d6 c4c5 d6e7 b1c3 a7a6 f1d3 g8f6 h2h3 b8d7 b2b4 e6e5 d4e5 d7e5 d3e2 e5f3 e2f3 e8g8 d1d3 c8d7 e1g1 f6h7 f1e1 f7f5 f3h5 e7g5 d3e2 h7f6 h5f3 f6e4 c3e4 d5e4 f3h5 d7e6 g2g3 a8d8 h3h4 g5f6 e2c2 f6e5 a1c1 ", 378 | "solution":{"f5f4":{"e3f4":{"e5h5":{"c2e4":"end"}}}}, 379 | "id":"smvnd9d8" 380 | }, 381 | { 382 | "tags":["material advantage"], 383 | "color":"black", 384 | "position":"d2d4 c7c6 c2c4 e7e6 g1f3 d7d5 c1f4 h7h6 e2e3 f8d6 f4d6 d8d6 c4c5 d6e7 b1c3 a7a6 f1d3 g8f6 h2h3 b8d7 b2b4 e6e5 d4e5 d7e5 d3e2 e5f3 e2f3 e8g8 d1d3 c8d7 e1g1 f6h7 f1e1 f7f5 f3h5 e7g5 d3e2 h7f6 h5f3 f6e4 c3e4 d5e4 f3h5 d7e6 g2g3 a8d8 h3h4 g5f6 e2c2 f6e5 a1c1 d8d7 c2c3 e5c3 c1c3 e6a2 g1g2 a2e6 h5e2 f8d8 f2f3 e4f3 g2f3 d7d2 e3e4 e6f7 e4f5 f7h5 f3e3 ", 385 | "solution":{"d2e2":{"e1e2":"end"}}, 386 | "id":"smvnd9d8" 387 | }, 388 | { 389 | "tags":["material advantage"], 390 | "color":"white", 391 | "position":"d2d4 c7c6 c2c4 e7e6 g1f3 d7d5 c1f4 h7h6 e2e3 f8d6 f4d6 d8d6 c4c5 d6e7 b1c3 a7a6 f1d3 g8f6 h2h3 b8d7 b2b4 e6e5 d4e5 d7e5 d3e2 e5f3 e2f3 e8g8 d1d3 c8d7 e1g1 f6h7 f1e1 f7f5 f3h5 e7g5 d3e2 h7f6 h5f3 f6e4 c3e4 d5e4 f3h5 d7e6 g2g3 a8d8 h3h4 g5f6 e2c2 f6e5 a1c1 d8d7 c2c3 e5c3 c1c3 e6a2 g1g2 a2e6 h5e2 f8d8 f2f3 e4f3 g2f3 d7d2 e3e4 e6f7 e4f5 f7h5 f3e3 d2e2 e1e2 h5e2 e3e2 d8d5 c3f3 g8f7 e2e3 f7f6 g3g4 d5e5 e3d4 e5d5 d4e4 d5e5 e4d4 e5d5 d4e4 g7g6 ", 392 | "solution":{"f5g6":{"f6g6":{"f3d3":{"a6a5":{"d3d5":{"c6d5":"end"}}}}}}, 393 | "id":"smvnd9d8" 394 | }, 395 | { 396 | "tags":["forced mate"], 397 | "color":"black", 398 | "position":"e2e4 d7d6 d2d4 e7e5 d4d5 f7f5 b1c3 f8e7 g1f3 f5e4 c3e4 b8d7 h2h3 g8f6 f1d3 f6e4 d3e4 d7f6 d1d3 f6e4 d3e4 e8g8 e1g1 g7g6 c1h6 f8e8 c2c4 c8f5 e4e3 e5e4 f3d4 e7f6 d4f5 g6f5 e3g3 g8h8 a1b1 d8d7 g3f4 f6e5 f4g5 e8g8 g5e3 g8g6 h6f4 a8g8 f4e5 d6e5 g2g3 f5f4 e3e4 f4g3 f2g3 g6g3 g1f2 d7h3 e4e5 g3g7 f1h1 g8f8 f2e2 h3g2 e2d3 ", 399 | "solution":{"f8f3":{"e5e3":{"f3e3":{"d3d4":{"g2d2":{"d4c5":{"e3e6":{"h1h7":{"g7h7":{"b2b4":{"a7a6":{"a2a3":{"b7b6":"end","d2f2":"end","d2e3":"end"}},"c7c6":{"a2a3":{"b7b6":"end","d2f2":"end","d2e3":"end"}}}}}}}}}}}}}, 400 | "id":"969s46wj" 401 | }, 402 | { 403 | "tags":["material advantage"], 404 | "color":"black", 405 | "position":"e2e4 c7c5 c2c3 b8c6 d2d4 c5d4 c3d4 g7g6 d4d5 c6e5 d1d4 f8g7 c1h6 ", 406 | "solution":{"e5f3":{"g1f3":{"g7d4":{"h6c1":"end"}}}}, 407 | "id":"2u1nd0uq" 408 | }, 409 | { 410 | "tags":["material advantage"], 411 | "color":"white", 412 | "position":"e2e4 c7c5 c2c3 b8c6 d2d4 c5d4 c3d4 g7g6 d4d5 c6e5 d1d4 f8g7 c1h6 e5f3 g1f3 g7d4 f3d4 e7e5 h6g7 e5d4 g7h8 f7f6 e4e5 d8e7 f2f4 g6g5 g2g3 d7d6 e5e6 c8e6 d5e6 e7e6 f1e2 d4d3 e1g1 d3e2 f1e1 e6e3 g1g2 e3e4 g2f2 e4d4 f2e2 d4e4 e2f1 e4e1 f1e1 e8e7 ", 413 | "solution":{"f4g5":{"f6g5":{"h8g7":{"g8f6":{"g7f6":{"e7f6":"end"}}}}}}, 414 | "id":"2u1nd0uq" 415 | }, 416 | { 417 | "tags":["forced mate"], 418 | "color":"white", 419 | "position":"e2e4 c7c5 c2c3 b8c6 d2d4 c5d4 c3d4 g7g6 d4d5 c6e5 d1d4 f8g7 c1h6 e5f3 g1f3 g7d4 f3d4 e7e5 h6g7 e5d4 g7h8 f7f6 e4e5 d8e7 f2f4 g6g5 g2g3 d7d6 e5e6 c8e6 d5e6 e7e6 f1e2 d4d3 e1g1 d3e2 f1e1 e6e3 g1g2 e3e4 g2f2 e4d4 f2e2 d4e4 e2f1 e4e1 f1e1 e8e7 b1c3 e7f7 f4g5 a8e8 e1f2 g8e7 h8f6 e7g6 a1e1 e8e1 f2e1 f7e6 c3b5 a7a6 b5c7 e6f5 h2h4 f5g4 e1f2 g4f5 c7d5 g6e5 d5e7 f5e6 f6e5 e6e5 g3g4 d6d5 h4h5 d5d4 g5g6 d4d3 g6h7 e5e4 h7h8q d3d2 f2e2 e4f4 ", 420 | "solution":{"h8d4":{"f4g3":{"e7f5":{"g3h3":{"d4g1":{"d2d1b":{"e2d1":{"a6a5":{"g1g3":"end"}},"e2d2":{"a6a5":{"g1g3":"end"}},"e2e1":{"a6a5":{"g1g3":"end"}},"e2e3":{"a6a5":{"g1g3":"end"}},"e2f2":{"a6a5":{"g1g2":"end","g1g3":"end"}}}}}}}}}, 421 | "id":"2u1nd0uq" 422 | }, 423 | { 424 | "tags":["forced mate"], 425 | "color":"white", 426 | "position":"e2e4 c7c5 c2c3 b8c6 d2d4 c5d4 c3d4 g7g6 d4d5 c6e5 d1d4 f8g7 c1h6 e5f3 g1f3 g7d4 f3d4 e7e5 h6g7 e5d4 g7h8 f7f6 e4e5 d8e7 f2f4 g6g5 g2g3 d7d6 e5e6 c8e6 d5e6 e7e6 f1e2 d4d3 e1g1 d3e2 f1e1 e6e3 g1g2 e3e4 g2f2 e4d4 f2e2 d4e4 e2f1 e4e1 f1e1 e8e7 b1c3 e7f7 f4g5 a8e8 e1f2 g8e7 h8f6 e7g6 a1e1 e8e1 f2e1 f7e6 c3b5 a7a6 b5c7 e6f5 h2h4 f5g4 e1f2 g4f5 c7d5 g6e5 d5e7 f5e6 f6e5 e6e5 g3g4 d6d5 h4h5 d5d4 g5g6 d4d3 g6h7 e5e4 h7h8q d3d2 f2e2 e4f4 h8d8 f4g4 ", 427 | "solution":{"d8d2":{"a6a5":{"d2d5":{"a5a4":{"e2f2":{"g4h4":{"d5f5":{"a4a3":{"e7g6":"end"}}}}}},"e2f2":{"g4h5":{"d2c2":{"h5h4":{"c2f5":{"a5a4":{"e7g6":"end"}}}},"d2d3":{"h5h4":{"d3f5":{"a5a4":{"e7g6":"end"}}}},"d2f4":{"b7b6":{"f2g3":{"a5a4":{"f4h4":"end"}},"f4f5":{"h5h6":{"f5g6":"end"}}}},"f2g3":{"b7b6":{"d2c2":{"a5a4":{"c2g6":"end"}},"d2d3":{"a5a4":{"d3g6":"end"}},"d2d6":{"a5a4":{"d6g6":"end"}},"d2f4":{"a5a4":{"f4h4":"end"}},"d2h2":{"h5g5":{"h2h4":"end"}}}}}}}}}, 428 | "id":"2u1nd0uq" 429 | } 430 | ] -------------------------------------------------------------------------------- /functions/captureAndPromotion.php: -------------------------------------------------------------------------------- 1 | array('material advantage'), 'color' => $color, 'position' => $startMoveString, 'solution' => $solutionMap ); 37 | 38 | } 39 | 40 | return $output; 41 | } 42 | 43 | function buildCaptureTree ( $moveString ) { 44 | //Input: List of moves in UCI format 45 | //Output: Map of the correct tactical line 46 | 47 | global $MAX_CAPTURE_LINES, $MAJOR_MOVE_THRESHOLD; 48 | 49 | //function getMovesListFromPosition ( $moveString, $player, $tally, $pliesLeft ) { 50 | $movesList = getMovesListFromPosition( $moveString, TRUE, 0, $MAJOR_MOVE_THRESHOLD ); 51 | $output = FALSE; 52 | 53 | if ( !empty( $movesList ) && $movesList !== 'retry' && $movesList !== 'abort' ) { 54 | 55 | $output = $movesList; 56 | 57 | } 58 | 59 | return $output; 60 | } 61 | 62 | 63 | function getMovesListFromPosition ( $moveString, $player, $tally, $pliesLeft ) { 64 | 65 | global $FIRST_PASS_TIME, $SECOND_PASS_TIME, $ALT_THRESHOLD, $RETRY_THRESHOLD, $MAJOR_MOVE_THRESHOLD; 66 | global $MAX_CAPTURE_LINES, $SESSION_START, $SESSION_LENGTH; 67 | 68 | if ( time() - $SESSION_START >= $SESSION_LENGTH ) { 69 | echo "ABORT! TIME OUT!\n"; 70 | return 'abort'; 71 | } 72 | 73 | if ( $player == TRUE ) { 74 | $maxLines = $MAX_CAPTURE_LINES; 75 | } else { 76 | $maxLines = 1; 77 | } 78 | 79 | $uciOutput = getUci( $moveString, $FIRST_PASS_TIME, $maxLines ); 80 | 81 | preg_match_all( "/info.*?cp (-?[0-9]+).*?([a-h][1-8][a-h][1-8][qrnb]?)/", $uciOutput, $matches ); 82 | 83 | //Abort puzzles that go from material advantage to mate in N 84 | if ( $player === TRUE ) { 85 | preg_match_all( "/info.*?mate ([0-9]+).*?([a-h][1-8][a-h][1-8][qrnb]?)/", $uciOutput, $mate_matches ); 86 | 87 | if ( !empty( $mate_matches[0] ) ) { 88 | echo "POSITION CHANGED TO MATE!\n"; 89 | return 'abort'; 90 | } 91 | } else { 92 | preg_match_all( "/info.*?mate (-[0-9]+).*?([a-h][1-8][a-h][1-8][qrnb]?)/", $uciOutput, $mate_matches ); 93 | 94 | if ( !empty( $mate_matches[0] ) ) { 95 | echo "POSITION CHANGED TO MATE!\n"; 96 | return 'abort'; 97 | } 98 | } 99 | 100 | $candidateMoves = array(); 101 | $candidateMovesEval = array(); 102 | 103 | $lastMove = explode( ' ', $moveString ); 104 | array_pop( $lastMove ); 105 | $lastMove = array_pop( $lastMove ); 106 | 107 | foreach ( $matches[2] as $key => $match ) { 108 | 109 | if ( !in_array( $match , $candidateMoves) ) { 110 | 111 | $candidateMoves[] = $match; 112 | 113 | } 114 | 115 | } 116 | 117 | foreach ( $candidateMoves as $key => $move ) { 118 | 119 | $candidateMovesEval[] = getPositionEval( "$moveString$move ", $SECOND_PASS_TIME ); 120 | 121 | } 122 | 123 | array_multisort( $candidateMovesEval, SORT_ASC, SORT_NUMERIC, $candidateMoves ); 124 | 125 | if ( !empty( $candidateMovesEval ) ) { 126 | 127 | while ( $candidateMovesEval[0] === FALSE ) { 128 | 129 | array_shift( $candidateMovesEval ); 130 | array_shift( $candidateMoves ); 131 | 132 | if ( empty( $candidateMovesEval ) ) { 133 | break; 134 | } 135 | 136 | } 137 | 138 | } 139 | 140 | 141 | if ( isset( $candidateMovesEval[0] ) ) { 142 | $topEval = $candidateMovesEval[0]; 143 | } 144 | 145 | $moveArray = array(); 146 | 147 | foreach ( $candidateMoves as $key => $move ) { 148 | 149 | if ( abs( $candidateMovesEval[$key] - $topEval ) <= abs( $topEval * $ALT_THRESHOLD ) 150 | && $key < $maxLines ) { 151 | 152 | $parsedTally = $tally; 153 | 154 | $changeThisTurn = abs( materialChange( $moveString.$move ) ); 155 | $isCheck = isCheck( $moveString.$move ); 156 | $isTension = isTension( $moveString.$move ); 157 | $nextMoveCapture = nextMoveCapture( $moveString.$move ); 158 | 159 | $confirmTension = FALSE; 160 | 161 | if ( $player === FALSE ) { 162 | $isMateThreat = isMateThreat( $moveString.$move ); 163 | $nextMoveCapture = nextMoveCapture( $moveString.$move ); 164 | if ( $isTension === TRUE ) { 165 | $confirmTension = confirmTension( $moveString.$move ); 166 | } 167 | } else { 168 | $isMateThreat = FALSE; 169 | $nextMoveCapture = FALSE; 170 | } 171 | 172 | if ( $player == TRUE ) { 173 | if ( $changeThisTurn > 1 ) { 174 | $parsedTally += $changeThisTurn; 175 | } 176 | } else { 177 | $changeThisTurn = - $changeThisTurn; 178 | if ( $changeThisTurn < -1 ) { 179 | $parsedTally += $changeThisTurn; 180 | } 181 | } 182 | //echo " Parent -> Child | CP Adv | Plies | Adv | Var | + | T\n"; 183 | printf("%1s: %5s -> %5s | %+6d | %5d | %+3d | %+3d | %1s | %1s | %1s | %1s\n", 184 | $player? 'P' : 'C', 185 | $lastMove, 186 | $move, 187 | -1 * $candidateMovesEval[$key], 188 | $pliesLeft, 189 | $parsedTally, 190 | $changeThisTurn, 191 | $isCheck? '+' : '-', 192 | $isTension? ( $confirmTension? '#' : '+' ) : '-', 193 | $isMateThreat? '+' : '-', 194 | $nextMoveCapture? '+' : '-' ); 195 | 196 | if ( $player == TRUE ) { 197 | 198 | if ( $parsedTally > 0 && $pliesLeft == 1 ) { 199 | $moveArray[$move] = 'win'; 200 | echo "$move -> WIN\n"; 201 | } else { 202 | if ( $changeThisTurn > 1 ) { 203 | //Something happened 204 | $moveArray[$move] = getMovesListFromPosition ( $moveString.$move.' ', FALSE, $parsedTally, $MAJOR_MOVE_THRESHOLD ); 205 | } else if ( $pliesLeft - 1 > 0 ) { 206 | //Nothing happened 207 | $moveArray[$move] = getMovesListFromPosition ( $moveString.$move.' ', FALSE, $parsedTally, $pliesLeft - 1 ); 208 | } else { 209 | $moveArray[$move] = 'retry'; 210 | echo "$move -> RETRY\n"; 211 | } 212 | } 213 | 214 | } else { 215 | if ( $parsedTally > 0 && $isCheck === FALSE && $isTension === FALSE ) { 216 | $moveArray[$move] = 'win'; 217 | echo "$move -> WIN\n"; 218 | } else if ( $parsedTally <= 0 219 | && $changeThisTurn === 0 220 | && $isCheck === FALSE 221 | && $isTension === FALSE 222 | && $isMateThreat === FALSE 223 | && $pliesLeft - 1 > 0 ) { 224 | //Nothing has happened and we aren't complete 225 | $moveArray[$move] = getMovesListFromPosition ( $moveString.$move.' ', TRUE, $parsedTally, $pliesLeft - 1 ); 226 | } else if ( abs( $changeThisTurn ) > 1 227 | || $isCheck === TRUE 228 | || $confirmTension === TRUE 229 | || $nextMoveCapture === TRUE ) { 230 | //Somthing noteworthy has happened 231 | $moveArray[$move] = getMovesListFromPosition ( $moveString.$move.' ', TRUE, $parsedTally, $MAJOR_MOVE_THRESHOLD ); 232 | } else if ( ( $isTension === TRUE 233 | || $isMateThreat === TRUE ) 234 | && $pliesLeft - 1 > 0 ) { 235 | //Something UNnoteworthy happened 236 | $moveArray[$move] = getMovesListFromPosition ( $moveString.$move.' ', TRUE, $parsedTally, $pliesLeft - 1 ); 237 | } else { 238 | $moveArray[$move] = 'retry'; 239 | echo "$move -> RETRY\n"; 240 | } 241 | } 242 | 243 | if ( $moveArray[$move] === 'abort' ) { 244 | echo "$move -> ABORT! TIME OUT!\n"; 245 | return 'abort'; 246 | } 247 | } else if ( abs( $candidateMovesEval[$key] - $topEval ) <= abs( $topEval * $RETRY_THRESHOLD ) && 248 | abs( $candidateMovesEval[$key] - $topEval ) > abs( $topEval * $ALT_THRESHOLD ) && $player === TRUE ) { 249 | $moveArray[$move] = 'retry'; 250 | echo "$move -> RETRY\n"; 251 | } 252 | } 253 | 254 | $empty = TRUE; 255 | 256 | foreach ( $moveArray as $key => $value ) { 257 | 258 | if ( $value !== 'retry' ) { 259 | 260 | $empty = FALSE; 261 | 262 | } 263 | 264 | } 265 | 266 | if ( $empty == TRUE ) { 267 | $moveArray = 'retry'; 268 | echo "$lastMove -> NO WIN\n"; 269 | } 270 | 271 | 272 | return $moveArray; 273 | } 274 | 275 | function confirmTension ( $moveString ) { 276 | // If the next player move is bad (i.e. passing/null) will they lose material? 277 | global $FIND_BAD_MOVE_TIME, $TENSION_THREAT_WIDTH; 278 | $uciOutput = getUci( $moveString, $FIND_BAD_MOVE_TIME, $TENSION_THREAT_WIDTH ); 279 | 280 | preg_match_all( "/info.*?cp (-?[0-9]+).*?([a-h][1-8][a-h][1-8][qrnb]?)/", $uciOutput, $matches ); 281 | 282 | $candidateMoves = array(); 283 | $candidateMovesEval = array(); 284 | 285 | foreach ( $matches[2] as $key => $match ) { 286 | 287 | if ( !in_array( $match , $candidateMoves) ) { 288 | 289 | $candidateMoves[] = $match; 290 | 291 | } 292 | 293 | } 294 | 295 | foreach ( $candidateMoves as $key => $move ) { 296 | 297 | $candidateMovesEval[] = getPositionEval( "$moveString$move ", $FIND_BAD_MOVE_TIME ); 298 | 299 | } 300 | 301 | array_multisort( $candidateMovesEval, SORT_DESC, SORT_NUMERIC, $candidateMoves ); 302 | 303 | if ( !empty( $candidateMovesEval ) ) { 304 | 305 | while ( $candidateMovesEval[0] === FALSE ) { 306 | 307 | array_shift( $candidateMovesEval ); 308 | array_shift( $candidateMoves ); 309 | 310 | if ( empty( $candidateMovesEval ) ) { 311 | break; 312 | } 313 | 314 | } 315 | 316 | } 317 | 318 | $output = FALSE; 319 | 320 | if ( !empty( $candidateMoves ) ) { 321 | $worstMove = array_shift( $candidateMoves ); 322 | if ( nextMoveCapture( $moveString.' '.$worstMove ) === TRUE ) { 323 | $output = TRUE; 324 | } 325 | } 326 | 327 | return $output; 328 | } 329 | 330 | function nextMoveCapture ( $moveString ) { 331 | global $SECOND_PASS_TIME; 332 | $uciOutput = getUci( $moveString, $SECOND_PASS_TIME ); 333 | 334 | preg_match_all( "/bestmove ([a-h][1-8][a-h][1-8][rbnq]?)/", $uciOutput, $matches ); 335 | 336 | $output = FALSE; 337 | 338 | if ( isset( $matches[1][0] ) ) { 339 | if ( abs( materialChange( $moveString.' '.$matches[1][0] ) ) > 1 ) { 340 | $output = TRUE; 341 | } 342 | } 343 | 344 | return $output; 345 | } 346 | 347 | function isMateThreat ( $moveString ) { 348 | // Given a position, if the next move is a passing move, is there a mate threat? 349 | global $MATE_THREAT_WIDTH, $SECOND_PASS_TIME; 350 | $uciOutput = getUci( $moveString, $SECOND_PASS_TIME, $MATE_THREAT_WIDTH ); 351 | 352 | preg_match_all( "/info.*?mate (-[0-9]+).*?([a-h][1-8][a-h][1-8][qrnb]?)/", $uciOutput, $matches ); 353 | 354 | $output = FALSE; 355 | 356 | if ( !empty( $matches[0] ) ) { 357 | $output = TRUE; 358 | } 359 | 360 | return $output; 361 | } 362 | 363 | function getPositionEval ( $moveString, $moveTime ) { 364 | 365 | $uciOutput = getUci( $moveString, $moveTime ); 366 | $output = FALSE; 367 | 368 | preg_match_all( "/cp (-?[0-9]+) /", $uciOutput, $matches ); 369 | 370 | $end = end( $matches[1] ); 371 | 372 | if ( isset( $end ) ) { 373 | 374 | $output = $end; 375 | 376 | } 377 | 378 | return $output; 379 | } 380 | 381 | function materialChange ( $moveString ) { 382 | //Input: A string of moves in coordinate notation (e2e4) 383 | // And if to limit results to major cpatures (i.e. not pawn captures) 384 | //Output: If the last move is a capture 385 | 386 | $moves = explode( ' ', $moveString ); 387 | 388 | $position = 389 | array( 390 | // a, b, c, d, e, f, g, h 391 | array('r','n','b','q','k','b','n','r'), // 8 392 | array('p','p','p','p','p','p','p','p'), // 7 393 | array(0,0,0,0,0,0,0,0), // 6 394 | array(0,0,0,0,0,0,0,0), // 5 395 | array(0,0,0,0,0,0,0,0), // 4 396 | array(0,0,0,0,0,0,0,0), // 3 397 | array('P','P','P','P','P','P','P','P'), // 2 398 | array('R','N','B','Q','K','B','N','R'), // 1 399 | ); // indexed [number][letter] 400 | 401 | $oldPieceCount = 48; 402 | 403 | foreach ( $moves as $key => $move ) { 404 | 405 | $position = updatePosition( $position, $move ); 406 | 407 | $pieceCount = 0; 408 | 409 | foreach ( $position as $rowKey => $row ) { 410 | 411 | foreach ( $row as $squareKey => $square ) { 412 | 413 | if ( $square === 'p' || $square === 'P' ) { 414 | 415 | $pieceCount += 1; 416 | 417 | } else if ( $square === 'q' || $square === 'Q' ) { 418 | 419 | $pieceCount += 9; 420 | 421 | } else if ( $square === 'r' || $square === 'R' ) { 422 | 423 | $pieceCount += 5; 424 | 425 | } else if ( $square === 'b' || $square === 'B' || $square === 'n' || $square === 'N' ) { 426 | 427 | $pieceCount += 3; 428 | 429 | } 430 | 431 | } 432 | 433 | } 434 | 435 | if ( $oldPieceCount - $pieceCount !== 0 ) { 436 | 437 | $output = abs ( $pieceCount - $oldPieceCount ); 438 | 439 | } else { 440 | 441 | $output = 0; 442 | 443 | } 444 | 445 | $oldPieceCount = $pieceCount; 446 | 447 | } 448 | 449 | if ( $output == 8 ) { 450 | $output = 9; 451 | } else if ( $output == 4 ) { 452 | $output = 5; 453 | } else if ( $output == 2 ) { 454 | $output = 3; 455 | } 456 | 457 | return $output; 458 | } 459 | 460 | function isCheck ( $moveString ) { 461 | //Input: A string of moves in coordinate notation (e2e4) 462 | // And if to limit results to major cpatures (i.e. not pawn captures) 463 | //Output: If the last move is a capture 464 | //echo "help! I'm stuck!\n"; 465 | $moves = explode( ' ', $moveString ); 466 | 467 | $position = 468 | array( 469 | // a, b, c, d, e, f, g, h 470 | array('r','n','b','q','k','b','n','r'), // 8 471 | array('p','p','p','p','p','p','p','p'), // 7 472 | array(0,0,0,0,0,0,0,0), // 6 473 | array(0,0,0,0,0,0,0,0), // 5 474 | array(0,0,0,0,0,0,0,0), // 4 475 | array(0,0,0,0,0,0,0,0), // 3 476 | array('P','P','P','P','P','P','P','P'), // 2 477 | array('R','N','B','Q','K','B','N','R'), // 1 478 | ); // indexed [number][letter] 479 | 480 | foreach ( $moves as $key => $move ) { 481 | 482 | $position = updatePosition ( $position, $move ); 483 | 484 | $isCheck = FALSE; 485 | 486 | foreach ( $position as $number => $column ) { 487 | //echo "1\n"; 488 | foreach ( $column as $letter => $square ) { 489 | //echo "2\n"; 490 | if ( $square !== 0 ) { 491 | // Now to work out if the locus of each piece hits an opposite side king 492 | if ( $square === 'q' ) { 493 | 494 | $collided = array( '+x' => FALSE, '+y' => FALSE, '-x' => FALSE, '-y' => FALSE, 495 | '+x+y' => FALSE, '+x-y' => FALSE, '-x+y' => FALSE, '-x-y' => FALSE ); 496 | 497 | // straights 498 | 499 | // +x 500 | for ( $x = $number + 1; $x < 8; $x++ ) { 501 | //echo "$x 3\n"; 502 | if ( $collided['+x'] === FALSE && $position[$x][$letter] === 'K' ) { 503 | $isCheck = TRUE; 504 | } else if ( $collided['+x'] === FALSE && $position[$x][$letter] !== 0 ) { 505 | $collided['+x'] = TRUE; 506 | } 507 | } 508 | 509 | // -x 510 | for ( $x = $number - 1; $x >= 0; $x-- ) { 511 | //echo "4\n"; 512 | if ( $collided['-x'] === FALSE && $position[$x][$letter] === 'K' ) { 513 | $isCheck = TRUE; 514 | } else if ( $collided['-x'] === FALSE && $position[$x][$letter] !== 0 ) { 515 | $collided['-x'] = TRUE; 516 | } 517 | } 518 | 519 | // +y 520 | for ( $x = $letter + 1; $x < 8; $x++ ) { 521 | //echo "5\n"; 522 | if ( $collided['+y'] === FALSE && $position[$number][$x] === 'K' ) { 523 | $isCheck = TRUE; 524 | } else if ( $collided['+y'] === FALSE && $position[$number][$x] !== 0 ) { 525 | $collided['+y'] = TRUE; 526 | } 527 | } 528 | 529 | // -y 530 | for ( $x = $letter - 1; $x >= 0; $x-- ) { 531 | //echo "6\n"; 532 | if ( $collided['-y'] === FALSE && $position[$number][$x] === 'K' ) { 533 | $isCheck = TRUE; 534 | } else if ( $collided['-y'] === FALSE && $position[$number][$x] !== 0 ) { 535 | $collided['-y'] = TRUE; 536 | } 537 | } 538 | 539 | // diagonals 540 | 541 | // +x +y 542 | $x = $letter + 1; 543 | $y = $number + 1; 544 | while ( $x < 8 && $y < 8 && $x >= 0 && $y >= 0 ) { 545 | //echo "7\n"; 546 | if ( $collided['+x+y'] == FALSE && $position[$y][$x] === 'K' ) { 547 | $isCheck = TRUE; 548 | } else if ( $collided['+x+y'] == FALSE && $position[$y][$x] !== 0 ) { 549 | $collided['+x+y'] = TRUE; 550 | } 551 | $x++; 552 | $y++; 553 | } 554 | 555 | // +x -y 556 | $x = $letter + 1; 557 | $y = $number - 1; 558 | while ( $x < 8 && $y < 8 && $x >= 0 && $y >= 0 ) { 559 | //echo "8\n"; 560 | if ( $collided['+x-y'] == FALSE && $position[$y][$x] === 'K' ) { 561 | $isCheck = TRUE; 562 | } else if ( $collided['+x-y'] == FALSE && $position[$y][$x] !== 0 ) { 563 | $collided['+x-y'] = TRUE; 564 | } 565 | $x++; 566 | $y--; 567 | } 568 | 569 | // -x +y 570 | $x = $letter - 1; 571 | $y = $number + 1; 572 | while ( $x < 8 && $y < 8 && $x >= 0 && $y >= 0 ) { 573 | //echo "9\n"; 574 | if ( $collided['-x+y'] == FALSE && $position[$y][$x] === 'K' ) { 575 | $isCheck = TRUE; 576 | } else if ( $collided['-x+y'] == FALSE && $position[$y][$x] !== 0 ) { 577 | $collided['-x+y'] = TRUE; 578 | } 579 | $x--; 580 | $y++; 581 | } 582 | 583 | // -x -y 584 | $x = $letter - 1; 585 | $y = $number - 1; 586 | while ( $x < 8 && $y < 8 && $x >= 0 && $y >= 0 ) { 587 | //echo "10\n"; 588 | if ( $collided['-x-y'] == FALSE && $position[$y][$x] === 'K' ) { 589 | $isCheck = TRUE; 590 | } else if ( $collided['-x-y'] == FALSE && $position[$y][$x] !== 0 ) { 591 | $collided['-x-y'] = TRUE; 592 | } 593 | $x--; 594 | $y--; 595 | } 596 | 597 | 598 | } else if ( $square === 'r' ) { 599 | 600 | $collided = array( '+x' => FALSE, '+y' => FALSE, '-x' => FALSE, '-y' => FALSE ); 601 | 602 | 603 | // straights 604 | 605 | // +x 606 | for ( $x = $number + 1; $x < 8; $x++ ) { 607 | //echo "11\n"; 608 | if ( $collided['+x'] === FALSE && $position[$x][$letter] === 'K' ) { 609 | $isCheck = TRUE; 610 | } else if ( $collided['+x'] === FALSE && $position[$x][$letter] !== 0 ) { 611 | $collided['+x'] = TRUE; 612 | } 613 | } 614 | 615 | // -x 616 | for ( $x = $number - 1; $x >= 0; $x-- ) { 617 | //echo "12\n"; 618 | if ( $collided['-x'] === FALSE && $position[$x][$letter] === 'K' ) { 619 | $isCheck = TRUE; 620 | } else if ( $collided['-x'] === FALSE && $position[$x][$letter] !== 0 ) { 621 | $collided['-x'] = TRUE; 622 | } 623 | } 624 | 625 | // +y 626 | for ( $x = $letter + 1; $x < 8; $x++ ) { 627 | //echo "13\n"; 628 | if ( $collided['+y'] === FALSE && $position[$number][$x] === 'K' ) { 629 | $isCheck = TRUE; 630 | } else if ( $collided['+y'] === FALSE && $position[$number][$x] !== 0 ) { 631 | $collided['+y'] = TRUE; 632 | } 633 | } 634 | 635 | // -y 636 | for ( $x = $letter - 1; $x >= 0; $x-- ) { 637 | //echo "14\n"; 638 | if ( $collided['-y'] === FALSE && $position[$number][$x] === 'K' ) { 639 | $isCheck = TRUE; 640 | } else if ( $collided['-y'] === FALSE && $position[$number][$x] !== 0 ) { 641 | $collided['-y'] = TRUE; 642 | } 643 | } 644 | 645 | 646 | } else if ( $square === 'b' ) { 647 | 648 | $collided = array( '+x+y' => FALSE, '+x-y' => FALSE, '-x+y' => FALSE, '-x-y' => FALSE ); 649 | 650 | // diagonals 651 | 652 | // +x +y 653 | $x = $letter + 1; 654 | $y = $number + 1; 655 | while ( $x < 8 && $y < 8 && $x >= 0 && $y >= 0 ) { 656 | //echo "15\n"; 657 | if ( $collided['+x+y'] == FALSE && $position[$y][$x] === 'K' ) { 658 | $isCheck = TRUE; 659 | } else if ( $collided['+x+y'] == FALSE && $position[$y][$x] !== 0 ) { 660 | $collided['+x+y'] = TRUE; 661 | } 662 | $x++; 663 | $y++; 664 | } 665 | 666 | // +x -y 667 | $x = $letter + 1; 668 | $y = $number - 1; 669 | while ( $x < 8 && $y < 8 && $x >= 0 && $y >= 0 ) { 670 | //echo "16\n"; 671 | if ( $collided['+x-y'] == FALSE && $position[$y][$x] === 'K' ) { 672 | $isCheck = TRUE; 673 | } else if ( $collided['+x-y'] == FALSE && $position[$y][$x] !== 0 ) { 674 | $collided['+x-y'] = TRUE; 675 | } 676 | $x++; 677 | $y--; 678 | } 679 | 680 | // -x +y 681 | $x = $letter - 1; 682 | $y = $number + 1; 683 | while ( $x < 8 && $y < 8 && $x >= 0 && $y >= 0 ) { 684 | //echo "17\n"; 685 | if ( $collided['-x+y'] == FALSE && $position[$y][$x] === 'K' ) { 686 | $isCheck = TRUE; 687 | } else if ( $collided['-x+y'] == FALSE && $position[$y][$x] !== 0 ) { 688 | $collided['-x+y'] = TRUE; 689 | } 690 | $x--; 691 | $y++; 692 | } 693 | 694 | // -x -y 695 | $x = $letter - 1; 696 | $y = $number - 1; 697 | while ( $x < 8 && $y < 8 && $x >= 0 && $y >= 0 ) { 698 | //echo "18\n"; 699 | if ( $collided['-x-y'] == FALSE && $position[$y][$x] === 'K' ) { 700 | $isCheck = TRUE; 701 | } else if ( $collided['-x-y'] == FALSE && $position[$y][$x] !== 0 ) { 702 | $collided['-x-y'] = TRUE; 703 | } 704 | $x--; 705 | $y--; 706 | } 707 | 708 | } else if ( $square === 'n' ) { 709 | //L shapes 710 | 711 | // ++x +y 712 | if ( $letter + 2 < 8 && $number + 1 < 8 ) { 713 | if ( $position[$number + 1][$letter + 2] === 'K' ) { 714 | $isCheck = TRUE; 715 | } 716 | } 717 | 718 | // ++x -y 719 | if ( $letter + 2 < 8 && $number - 1 >= 0 ) { 720 | if ( $position[$number - 1][$letter + 2] === 'K' ) { 721 | $isCheck = TRUE; 722 | } 723 | } 724 | 725 | // --x +y 726 | if ( $letter - 2 >= 0 && $number + 1 < 8 ) { 727 | if ( $position[$number + 1][$letter - 2] === 'K' ) { 728 | $isCheck = TRUE; 729 | } 730 | } 731 | 732 | // --x -y 733 | if ( $letter - 2 >= 0 && $number - 1 >= 0 ) { 734 | if ( $position[$number - 1][$letter - 2] === 'K' ) { 735 | $isCheck = TRUE; 736 | } 737 | } 738 | 739 | // ++y +x 740 | if ( $letter + 1 < 8 && $number + 2 < 8 ) { 741 | if ( $position[$number + 2][$letter + 1] === 'K' ) { 742 | $isCheck = TRUE; 743 | } 744 | } 745 | 746 | // ++y -x 747 | if ( $letter - 1 >= 0 && $number + 2 < 8 ) { 748 | if ( $position[$number + 2][$letter - 1] === 'K' ) { 749 | $isCheck = TRUE; 750 | } 751 | } 752 | 753 | // --y +x 754 | if ( $letter + 1 < 8 && $number - 2 >= 0 ) { 755 | if ( $position[$number - 2][$letter + 1] === 'K' ) { 756 | $isCheck = TRUE; 757 | } 758 | } 759 | 760 | // --y -x 761 | if ( $letter - 1 >= 0 && $number - 2 >= 0 ) { 762 | if ( $position[$number - 2][$letter - 1] === 'K' ) { 763 | $isCheck = TRUE; 764 | } 765 | } 766 | 767 | } else if ( $square === 'p' ) { 768 | // +y -x 769 | if ( $letter - 1 >= 0 && $number + 1 < 8 ) { 770 | if ( $position[$number + 1][$letter - 1] === 'K' ) { 771 | $isCheck = TRUE; 772 | } 773 | } 774 | 775 | // +y +x 776 | if ( $letter + 1 < 8 && $number + 1 < 8 ) { 777 | if ( $position[$number + 1][$letter + 1] === 'K' ) { 778 | $isCheck = TRUE; 779 | } 780 | } 781 | 782 | } else if ( $square === 'Q' ) { 783 | 784 | $collided = array( '+x' => FALSE, '+y' => FALSE, '-x' => FALSE, '-y' => FALSE, 785 | '+x+y' => FALSE, '+x-y' => FALSE, '-x+y' => FALSE, '-x-y' => FALSE ); 786 | 787 | // straights 788 | 789 | // +x 790 | for ( $x = $number + 1; $x < 8; $x++ ) { 791 | //echo "19\n"; 792 | if ( $collided['+x'] === FALSE && $position[$x][$letter] === 'k' ) { 793 | $isCheck = TRUE; 794 | } else if ( $collided['+x'] === FALSE && $position[$x][$letter] !== 0 ) { 795 | $collided['+x'] = TRUE; 796 | } 797 | } 798 | 799 | // -x 800 | for ( $x = $number - 1; $x >= 0; $x-- ) { 801 | //echo "20\n"; 802 | if ( $collided['-x'] === FALSE && $position[$x][$letter] === 'k' ) { 803 | $isCheck = TRUE; 804 | } else if ( $collided['-x'] === FALSE && $position[$x][$letter] !== 0 ) { 805 | $collided['-x'] = TRUE; 806 | } 807 | } 808 | 809 | // +y 810 | for ( $x = $letter + 1; $x < 8; $x++ ) { 811 | //echo "21\n"; 812 | if ( $collided['+y'] === FALSE && $position[$number][$x] === 'k' ) { 813 | $isCheck = TRUE; 814 | } else if ( $collided['+y'] === FALSE && $position[$number][$x] !== 0 ) { 815 | $collided['+y'] = TRUE; 816 | } 817 | } 818 | 819 | // -y 820 | for ( $x = $letter - 1; $x >= 0 ;$x-- ) { 821 | //echo "22\n"; 822 | if ( $collided['-y'] === FALSE && $position[$number][$x] === 'k' ) { 823 | $isCheck = TRUE; 824 | } else if ( $collided['-y'] === FALSE && $position[$number][$x] !== 0 ) { 825 | $collided['-y'] = TRUE; 826 | } 827 | } 828 | 829 | // diagonals 830 | 831 | // +x +y 832 | $x = $letter + 1; 833 | $y = $number + 1; 834 | while ( $x < 8 && $y < 8 && $x >= 0 && $y >= 0 ) { 835 | //echo "23\n"; 836 | if ( $collided['+x+y'] == FALSE && $position[$y][$x] === 'k' ) { 837 | $isCheck = TRUE; 838 | } else if ( $collided['+x+y'] == FALSE && $position[$y][$x] !== 0 ) { 839 | $collided['+x+y'] = TRUE; 840 | } 841 | $x++; 842 | $y++; 843 | } 844 | 845 | // +x -y 846 | $x = $letter + 1; 847 | $y = $number - 1; 848 | while ( $x < 8 && $y < 8 && $x >= 0 && $y >= 0 ) { 849 | //echo "24\n"; 850 | if ( $collided['+x-y'] == FALSE && $position[$y][$x] === 'k' ) { 851 | $isCheck = TRUE; 852 | } else if ( $collided['+x-y'] == FALSE && $position[$y][$x] !== 0 ) { 853 | $collided['+x-y'] = TRUE; 854 | } 855 | $x++; 856 | $y--; 857 | } 858 | 859 | // -x +y 860 | $x = $letter - 1; 861 | $y = $number + 1; 862 | while ( $x < 8 && $y < 8 && $x >= 0 && $y >= 0 ) { 863 | //echo "25\n"; 864 | if ( $collided['-x+y'] == FALSE && $position[$y][$x] === 'k' ) { 865 | $isCheck = TRUE; 866 | } else if ( $collided['-x+y'] == FALSE && $position[$y][$x] !== 0 ) { 867 | $collided['-x+y'] = TRUE; 868 | } 869 | $x--; 870 | $y++; 871 | } 872 | 873 | // -x -y 874 | $x = $letter - 1; 875 | $y = $number - 1; 876 | while ( $x < 8 && $y < 8 && $x >= 0 && $y >= 0 ) { 877 | //echo "26\n"; 878 | if ( $collided['-x-y'] == FALSE && $position[$y][$x] === 'k' ) { 879 | $isCheck = TRUE; 880 | } else if ( $collided['-x-y'] == FALSE && $position[$y][$x] !== 0 ) { 881 | $collided['-x-y'] = TRUE; 882 | } 883 | $x--; 884 | $y--; 885 | } 886 | 887 | } else if ( $square === 'R' ) { 888 | 889 | $collided = array( '+x' => FALSE, '+y' => FALSE, '-x' => FALSE, '-y' => FALSE ); 890 | 891 | // straights 892 | 893 | // +x 894 | for ( $x = $number + 1; $x < 8; $x++ ) { 895 | //echo "27\n"; 896 | if ( $collided['+x'] === FALSE && $position[$x][$letter] === 'k' ) { 897 | $isCheck = TRUE; 898 | } else if ( $collided['+x'] === FALSE && $position[$x][$letter] !== 0 ) { 899 | $collided['+x'] = TRUE; 900 | } 901 | } 902 | 903 | // -x 904 | for ( $x = $number - 1; $x >= 0; $x-- ) { 905 | //echo "28\n"; 906 | if ( $collided['-x'] === FALSE && $position[$x][$letter] === 'k' ) { 907 | $isCheck = TRUE; 908 | } else if ( $collided['-x'] === FALSE && $position[$x][$letter] !== 0 ) { 909 | $collided['-x'] = TRUE; 910 | } 911 | } 912 | 913 | // +y 914 | for ( $x = $letter + 1; $x < 8; $x++ ) { 915 | //echo "29\n"; 916 | if ( $collided['+y'] === FALSE && $position[$number][$x] === 'k' ) { 917 | $isCheck = TRUE; 918 | } else if ( $collided['+y'] === FALSE && $position[$number][$x] !== 0 ) { 919 | $collided['+y'] = TRUE; 920 | } 921 | } 922 | 923 | // -y 924 | for ( $x = $letter - 1; $x >= 0; $x-- ) { 925 | //echo "30\n"; 926 | if ( $collided['-y'] === FALSE && $position[$number][$x] === 'k' ) { 927 | $isCheck = TRUE; 928 | } else if ( $collided['-y'] === FALSE && $position[$number][$x] !== 0 ) { 929 | $collided['-y'] = TRUE; 930 | } 931 | } 932 | 933 | } else if ( $square === 'B' ) { 934 | $collided = array( '+x+y' => FALSE, '+x-y' => FALSE, '-x+y' => FALSE, '-x-y' => FALSE ); 935 | 936 | // diagonals 937 | 938 | // +x +y 939 | $x = $letter + 1; 940 | $y = $number + 1; 941 | while ( $x < 8 && $y < 8 && $x >= 0 && $y >= 0 ) { 942 | //echo "31\n"; 943 | if ( $collided['+x+y'] == FALSE && $position[$y][$x] === 'k' ) { 944 | $isCheck = TRUE; 945 | } else if ( $collided['+x+y'] == FALSE && $position[$y][$x] !== 0 ) { 946 | $collided['+x+y'] = TRUE; 947 | } 948 | $x++; 949 | $y++; 950 | } 951 | 952 | // +x -y 953 | $x = $letter + 1; 954 | $y = $number - 1; 955 | while ( $x < 8 && $y < 8 && $x >= 0 && $y >= 0 ) { 956 | //echo "32\n"; 957 | if ( $collided['+x-y'] == FALSE && $position[$y][$x] === 'k' ) { 958 | $isCheck = TRUE; 959 | } else if ( $collided['+x-y'] == FALSE && $position[$y][$x] !== 0 ) { 960 | $collided['+x-y'] = TRUE; 961 | } 962 | $x++; 963 | $y--; 964 | } 965 | 966 | // -x +y 967 | $x = $letter - 1; 968 | $y = $number + 1; 969 | while ( $x < 8 && $y < 8 && $x >= 0 && $y >= 0 ) { 970 | //echo "33\n"; 971 | if ( $collided['-x+y'] == FALSE && $position[$y][$x] === 'k' ) { 972 | $isCheck = TRUE; 973 | } else if ( $collided['-x+y'] == FALSE && $position[$y][$x] !== 0 ) { 974 | $collided['-x+y'] = TRUE; 975 | } 976 | $x--; 977 | $y++; 978 | } 979 | 980 | // -x -y 981 | $x = $letter - 1; 982 | $y = $number - 1; 983 | while ( $x < 8 && $y < 8 && $x >= 0 && $y >= 0 ) { 984 | //echo "34\n"; 985 | if ( $collided['-x-y'] == FALSE && $position[$y][$x] === 'k' ) { 986 | $isCheck = TRUE; 987 | } else if ( $collided['-x-y'] == FALSE && $position[$y][$x] !== 0 ) { 988 | $collided['-x-y'] = TRUE; 989 | } 990 | $x--; 991 | $y--; 992 | } 993 | 994 | } else if ( $square === 'N' ) { 995 | //L shapes 996 | 997 | // ++x +y 998 | if ( $letter + 2 < 8 && $number + 1 < 8 ) { 999 | if ( $position[$number + 1][$letter + 2] === 'k' ) { 1000 | $isCheck = TRUE; 1001 | } 1002 | } 1003 | 1004 | // ++x -y 1005 | if ( $letter + 2 < 8 && $number - 1 >= 0 ) { 1006 | if ( $position[$number - 1][$letter + 2] === 'k' ) { 1007 | $isCheck = TRUE; 1008 | } 1009 | } 1010 | 1011 | // --x +y 1012 | if ( $letter - 2 >= 0 && $number + 1 < 8 ) { 1013 | if ( $position[$number + 1][$letter - 2] === 'k' ) { 1014 | $isCheck = TRUE; 1015 | } 1016 | } 1017 | 1018 | // --x -y 1019 | if ( $letter - 2 >= 0 && $number - 1 >= 0 ) { 1020 | if ( $position[$number - 1][$letter - 2] === 'k' ) { 1021 | $isCheck = TRUE; 1022 | } 1023 | } 1024 | 1025 | // ++y +x 1026 | if ( $letter + 1 < 8 && $number + 2 < 8 ) { 1027 | if ( $position[$number + 2][$letter + 1] === 'k' ) { 1028 | $isCheck = TRUE; 1029 | } 1030 | } 1031 | 1032 | // ++y -x 1033 | if ( $letter - 1 >= 0 && $number + 2 < 8 ) { 1034 | if ( $position[$number + 2][$letter - 1] === 'k' ) { 1035 | $isCheck = TRUE; 1036 | } 1037 | } 1038 | 1039 | // --y +x 1040 | if ( $letter + 1 < 8 && $number - 2 >= 0 ) { 1041 | if ( $position[$number - 2][$letter + 1] === 'k' ) { 1042 | $isCheck = TRUE; 1043 | } 1044 | } 1045 | 1046 | // --y -x 1047 | if ( $letter - 1 >= 0 && $number - 2 >= 0 ) { 1048 | if ( $position[$number - 2][$letter - 1] === 'k' ) { 1049 | $isCheck = TRUE; 1050 | } 1051 | } 1052 | 1053 | } else if ( $square === 'P' ) { 1054 | 1055 | // -y -x 1056 | if ( $letter - 1 >= 0 && $number - 1 >= 0 ) { 1057 | if ( $position[$number - 1][$letter - 1] === 'k' ) { 1058 | $isCheck = TRUE; 1059 | } 1060 | } 1061 | 1062 | // -y +x 1063 | if ( $letter + 1 < 8 && $number - 1 >= 0 ) { 1064 | if ( $position[$number - 1][$letter + 1] === 'k' ) { 1065 | $isCheck = TRUE; 1066 | } 1067 | } 1068 | } 1069 | } 1070 | } 1071 | } 1072 | } 1073 | //echo "Just kidding!\n"; 1074 | return $isCheck; 1075 | } 1076 | 1077 | function isTension ( $moveString ) { 1078 | //detect is a major piece is under attack 1079 | //Input: A string of moves in coordinate notation (e2e4) 1080 | // And if to limit results to major cpatures (i.e. not pawn captures) 1081 | 1082 | $moves = explode( ' ', $moveString ); 1083 | 1084 | $position = 1085 | array( 1086 | // a, b, c, d, e, f, g, h 1087 | array('r','n','b','q','k','b','n','r'), // 8 1088 | array('p','p','p','p','p','p','p','p'), // 7 1089 | array(0,0,0,0,0,0,0,0), // 6 1090 | array(0,0,0,0,0,0,0,0), // 5 1091 | array(0,0,0,0,0,0,0,0), // 4 1092 | array(0,0,0,0,0,0,0,0), // 3 1093 | array('P','P','P','P','P','P','P','P'), // 2 1094 | array('R','N','B','Q','K','B','N','R'), // 1 1095 | ); // indexed [number][letter] 1096 | 1097 | foreach ( $moves as $key => $move ) { 1098 | 1099 | $position = updatePosition ( $position, $move ); 1100 | 1101 | $isCheck = FALSE; 1102 | 1103 | foreach ( $position as $number => $column ) { 1104 | //echo "1\n"; 1105 | foreach ( $column as $letter => $square ) { 1106 | //echo "2\n"; 1107 | if ( $square !== 0 ) { 1108 | // Now to work out if the locus of each piece hits an opposite side king 1109 | if ( $square === 'q' ) { 1110 | 1111 | $collided = array( '+x' => FALSE, '+y' => FALSE, '-x' => FALSE, '-y' => FALSE, 1112 | '+x+y' => FALSE, '+x-y' => FALSE, '-x+y' => FALSE, '-x-y' => FALSE ); 1113 | 1114 | // straights 1115 | 1116 | // +x 1117 | for ( $x = $number + 1; $x < 8; $x++ ) { 1118 | //echo "$x 3\n"; 1119 | if ( $collided['+x'] === FALSE && $position[$x][$letter] === 'Q' ) { 1120 | $isCheck = TRUE; 1121 | $collided['+x'] = TRUE; 1122 | } else if ( $collided['+x'] === FALSE && $position[$x][$letter] !== 0 ) { 1123 | $collided['+x'] = TRUE; 1124 | } 1125 | } 1126 | 1127 | // -x 1128 | for ( $x = $number - 1; $x >= 0; $x-- ) { 1129 | //echo "4\n"; 1130 | if ( $collided['-x'] === FALSE && $position[$x][$letter] === 'Q' ) { 1131 | $isCheck = TRUE; 1132 | $collided['-x'] = TRUE; 1133 | } else if ( $collided['-x'] === FALSE && $position[$x][$letter] !== 0 ) { 1134 | $collided['-x'] = TRUE; 1135 | } 1136 | } 1137 | 1138 | // +y 1139 | for ( $x = $letter + 1; $x < 8; $x++ ) { 1140 | //echo "5\n"; 1141 | if ( $collided['+y'] === FALSE && $position[$number][$x] === 'Q' ) { 1142 | $isCheck = TRUE; 1143 | $collided['+y'] = TRUE; 1144 | } else if ( $collided['+y'] === FALSE && $position[$number][$x] !== 0 ) { 1145 | $collided['+y'] = TRUE; 1146 | } 1147 | } 1148 | 1149 | // -y 1150 | for ( $x = $letter - 1; $x >= 0; $x-- ) { 1151 | //echo "6\n"; 1152 | if ( $collided['-y'] === FALSE && $position[$number][$x] === 'Q' ) { 1153 | $isCheck = TRUE; 1154 | $collided['-y'] = TRUE; 1155 | } else if ( $collided['-y'] === FALSE && $position[$number][$x] !== 0 ) { 1156 | $collided['-y'] = TRUE; 1157 | } 1158 | } 1159 | 1160 | // diagonals 1161 | 1162 | // +x +y 1163 | $x = $letter + 1; 1164 | $y = $number + 1; 1165 | while ( $x < 8 && $y < 8 && $x >= 0 && $y >= 0 ) { 1166 | //echo "7\n"; 1167 | if ( $collided['+x+y'] == FALSE && $position[$y][$x] === 'Q' ) { 1168 | $isCheck = TRUE; 1169 | $collided['+x+y'] = TRUE; 1170 | } else if ( $collided['+x+y'] == FALSE && $position[$y][$x] !== 0 ) { 1171 | $collided['+x+y'] = TRUE; 1172 | } 1173 | $x++; 1174 | $y++; 1175 | } 1176 | 1177 | // +x -y 1178 | $x = $letter + 1; 1179 | $y = $number - 1; 1180 | while ( $x < 8 && $y < 8 && $x >= 0 && $y >= 0 ) { 1181 | //echo "8\n"; 1182 | if ( $collided['+x-y'] == FALSE && $position[$y][$x] === 'Q' ) { 1183 | $isCheck = TRUE; 1184 | $collided['+x-y'] = TRUE; 1185 | } else if ( $collided['+x-y'] == FALSE && $position[$y][$x] !== 0 ) { 1186 | $collided['+x-y'] = TRUE; 1187 | } 1188 | $x++; 1189 | $y--; 1190 | } 1191 | 1192 | // -x +y 1193 | $x = $letter - 1; 1194 | $y = $number + 1; 1195 | while ( $x < 8 && $y < 8 && $x >= 0 && $y >= 0 ) { 1196 | //echo "9\n"; 1197 | if ( $collided['-x+y'] == FALSE && $position[$y][$x] === 'Q' ) { 1198 | $isCheck = TRUE; 1199 | $collided['-x+y'] = TRUE; 1200 | } else if ( $collided['-x+y'] == FALSE && $position[$y][$x] !== 0 ) { 1201 | $collided['-x+y'] = TRUE; 1202 | } 1203 | $x--; 1204 | $y++; 1205 | } 1206 | 1207 | // -x -y 1208 | $x = $letter - 1; 1209 | $y = $number - 1; 1210 | while ( $x < 8 && $y < 8 && $x >= 0 && $y >= 0 ) { 1211 | //echo "10\n"; 1212 | if ( $collided['-x-y'] == FALSE && $position[$y][$x] === 'Q' ) { 1213 | $isCheck = TRUE; 1214 | $collided['-x-y'] = TRUE; 1215 | } else if ( $collided['-x-y'] == FALSE && $position[$y][$x] !== 0 ) { 1216 | $collided['-x-y'] = TRUE; 1217 | } 1218 | $x--; 1219 | $y--; 1220 | } 1221 | 1222 | 1223 | } else if ( $square === 'r' ) { 1224 | 1225 | $collided = array( '+x' => FALSE, '+y' => FALSE, '-x' => FALSE, '-y' => FALSE ); 1226 | 1227 | // straights 1228 | 1229 | // +x 1230 | for ( $x = $number + 1; $x < 8; $x++ ) { 1231 | //echo "11\n"; 1232 | if ( $collided['+x'] === FALSE && $position[$x][$letter] === 'Q' ) { 1233 | $isCheck = TRUE; 1234 | $collided['+x'] = TRUE; 1235 | } else if ( $collided['+x'] === FALSE && $position[$x][$letter] !== 0 ) { 1236 | $collided['+x'] = TRUE; 1237 | } 1238 | } 1239 | 1240 | // -x 1241 | for ( $x = $number - 1; $x >= 0; $x-- ) { 1242 | //echo "12\n"; 1243 | if ( $collided['-x'] === FALSE && $position[$x][$letter] === 'Q' ) { 1244 | $isCheck = TRUE; 1245 | $collided['-x'] = TRUE; 1246 | } else if ( $collided['-x'] === FALSE && $position[$x][$letter] !== 0 ) { 1247 | $collided['-x'] = TRUE; 1248 | } 1249 | } 1250 | 1251 | // +y 1252 | for ( $x = $letter + 1; $x < 8; $x++ ) { 1253 | //echo "13\n"; 1254 | if ( $collided['+y'] === FALSE && $position[$number][$x] === 'Q' ) { 1255 | $isCheck = TRUE; 1256 | $collided['+y'] = TRUE; 1257 | } else if ( $collided['+y'] === FALSE && $position[$number][$x] !== 0 ) { 1258 | $collided['+y'] = TRUE; 1259 | } 1260 | } 1261 | 1262 | // -y 1263 | for ( $x = $letter - 1; $x >= 0; $x-- ) { 1264 | //echo "14\n"; 1265 | if ( $collided['-y'] === FALSE && $position[$number][$x] === 'Q' ) { 1266 | $isCheck = TRUE; 1267 | $collided['-y'] = TRUE; 1268 | } else if ( $collided['-y'] === FALSE && $position[$number][$x] !== 0 ) { 1269 | $collided['-y'] = TRUE; 1270 | } 1271 | } 1272 | 1273 | } else if ( $square === 'b' ) { 1274 | 1275 | $collided = array( '+x+y' => FALSE, '+x-y' => FALSE, '-x+y' => FALSE, '-x-y' => FALSE ); 1276 | 1277 | // diagonals 1278 | 1279 | // +x +y 1280 | $x = $letter + 1; 1281 | $y = $number + 1; 1282 | while ( $x < 8 && $y < 8 && $x >= 0 && $y >= 0 ) { 1283 | //echo "15\n"; 1284 | if ( $collided['+x+y'] == FALSE && ( $position[$y][$x] === 'Q' || $position[$y][$x] === 'R' ) ) { 1285 | $isCheck = TRUE; 1286 | $collided['+x+y'] = TRUE; 1287 | } else if ( $collided['+x+y'] == FALSE && $position[$y][$x] !== 0 ) { 1288 | $collided['+x+y'] = TRUE; 1289 | } 1290 | $x++; 1291 | $y++; 1292 | } 1293 | 1294 | // +x -y 1295 | $x = $letter + 1; 1296 | $y = $number - 1; 1297 | while ( $x < 8 && $y < 8 && $x >= 0 && $y >= 0 ) { 1298 | //echo "16\n"; 1299 | if ( $collided['+x-y'] == FALSE && ( $position[$y][$x] === 'Q' || $position[$y][$x] === 'R' ) ) { 1300 | $isCheck = TRUE; 1301 | $collided['+x-y'] = TRUE; 1302 | } else if ( $collided['+x-y'] == FALSE && $position[$y][$x] !== 0 ) { 1303 | $collided['+x-y'] = TRUE; 1304 | } 1305 | $x++; 1306 | $y--; 1307 | } 1308 | 1309 | // -x +y 1310 | $x = $letter - 1; 1311 | $y = $number + 1; 1312 | while ( $x < 8 && $y < 8 && $x >= 0 && $y >= 0 ) { 1313 | //echo "17\n"; 1314 | if ( $collided['-x+y'] == FALSE && ( $position[$y][$x] === 'Q' || $position[$y][$x] === 'R' ) ) { 1315 | $isCheck = TRUE; 1316 | $collided['-x+y'] = TRUE; 1317 | } else if ( $collided['-x+y'] == FALSE && $position[$y][$x] !== 0 ) { 1318 | $collided['-x+y'] = TRUE; 1319 | } 1320 | $x--; 1321 | $y++; 1322 | } 1323 | 1324 | // -x -y 1325 | $x = $letter - 1; 1326 | $y = $number - 1; 1327 | while ( $x < 8 && $y < 8 && $x >= 0 && $y >= 0 ) { 1328 | //echo "18\n"; 1329 | if ( $collided['-x-y'] == FALSE && ( $position[$y][$x] === 'Q' || $position[$y][$x] === 'R' ) ) { 1330 | $isCheck = TRUE; 1331 | $collided['-x-y'] = TRUE; 1332 | } else if ( $collided['-x-y'] == FALSE && $position[$y][$x] !== 0 ) { 1333 | $collided['-x-y'] = TRUE; 1334 | } 1335 | $x--; 1336 | $y--; 1337 | } 1338 | 1339 | } else if ( $square === 'n' ) { 1340 | //L shapes 1341 | 1342 | // ++x +y 1343 | if ( $letter + 2 < 8 && $number + 1 < 8 ) { 1344 | if ( $position[$number + 1][$letter + 2] === 'Q' || $position[$number + 1][$letter + 2] === 'R' ) { 1345 | $isCheck = TRUE; 1346 | } 1347 | } 1348 | 1349 | // ++x -y 1350 | if ( $letter + 2 < 8 && $number - 1 >= 0 ) { 1351 | if ( $position[$number - 1][$letter + 2] === 'Q' || $position[$number - 1][$letter + 2] === 'R' ) { 1352 | $isCheck = TRUE; 1353 | } 1354 | } 1355 | 1356 | // --x +y 1357 | if ( $letter - 2 >= 0 && $number + 1 < 8 ) { 1358 | if ( $position[$number + 1][$letter - 2] === 'Q' || $position[$number + 1][$letter - 2] === 'R' ) { 1359 | $isCheck = TRUE; 1360 | } 1361 | } 1362 | 1363 | // --x -y 1364 | if ( $letter - 2 >= 0 && $number - 1 >= 0 ) { 1365 | if ( $position[$number - 1][$letter - 2] === 'Q' || $position[$number - 1][$letter - 2] === 'R' ) { 1366 | $isCheck = TRUE; 1367 | } 1368 | } 1369 | 1370 | // ++y +x 1371 | if ( $letter + 1 < 8 && $number + 2 < 8 ) { 1372 | if ( $position[$number + 2][$letter + 1] === 'Q' || $position[$number + 2][$letter + 1] === 'R' ) { 1373 | $isCheck = TRUE; 1374 | } 1375 | } 1376 | 1377 | // ++y -x 1378 | if ( $letter - 1 >= 0 && $number + 2 < 8 ) { 1379 | if ( $position[$number + 2][$letter - 1] === 'Q' || $position[$number + 2][$letter - 1] === 'R' ) { 1380 | $isCheck = TRUE; 1381 | } 1382 | } 1383 | 1384 | // --y +x 1385 | if ( $letter + 1 < 8 && $number - 2 >= 0 ) { 1386 | if ( $position[$number - 2][$letter + 1] === 'Q' || $position[$number - 2][$letter + 1] === 'R' ) { 1387 | $isCheck = TRUE; 1388 | } 1389 | } 1390 | 1391 | // --y -x 1392 | if ( $letter - 1 >= 0 && $number - 2 >= 0 ) { 1393 | if ( $position[$number - 2][$letter - 1] === 'Q' || $position[$number - 2][$letter - 1] === 'R' ) { 1394 | $isCheck = TRUE; 1395 | } 1396 | } 1397 | 1398 | } else if ( $square === 'p' ) { 1399 | // +y -x 1400 | if ( $letter - 1 >= 0 && $number + 1 < 8 ) { 1401 | if ( $position[$number + 1][$letter - 1] === 'Q' 1402 | || $position[$number + 1][$letter - 1] === 'R' 1403 | || $position[$number + 1][$letter - 1] === 'N' 1404 | || $position[$number + 1][$letter - 1] === 'B' ) { 1405 | $isCheck = TRUE; 1406 | } 1407 | } 1408 | 1409 | // +y +x 1410 | if ( $letter + 1 < 8 && $number + 1 < 8 ) { 1411 | if ( $position[$number + 1][$letter + 1] === 'Q' 1412 | || $position[$number + 1][$letter + 1] === 'R' 1413 | || $position[$number + 1][$letter + 1] === 'N' 1414 | || $position[$number + 1][$letter + 1] === 'B' ) { 1415 | $isCheck = TRUE; 1416 | } 1417 | } 1418 | 1419 | } else if ( $square === 'Q' ) { 1420 | 1421 | $collided = array( '+x' => FALSE, '+y' => FALSE, '-x' => FALSE, '-y' => FALSE, 1422 | '+x+y' => FALSE, '+x-y' => FALSE, '-x+y' => FALSE, '-x-y' => FALSE ); 1423 | 1424 | // straights 1425 | 1426 | // +x 1427 | for ( $x = $number + 1; $x < 8; $x++ ) { 1428 | //echo "19\n"; 1429 | if ( $collided['+x'] === FALSE && $position[$x][$letter] === 'q' ) { 1430 | $isCheck = TRUE; 1431 | $collided['+x'] = TRUE; 1432 | } else if ( $collided['+x'] === FALSE && $position[$x][$letter] !== 0 ) { 1433 | $collided['+x'] = TRUE; 1434 | } 1435 | } 1436 | 1437 | // -x 1438 | for ( $x = $number - 1; $x >= 0; $x-- ) { 1439 | //echo "20\n"; 1440 | if ( $collided['-x'] === FALSE && $position[$x][$letter] === 'q' ) { 1441 | $isCheck = TRUE; 1442 | $collided['-x'] = TRUE; 1443 | } else if ( $collided['-x'] === FALSE && $position[$x][$letter] !== 0 ) { 1444 | $collided['-x'] = TRUE; 1445 | } 1446 | } 1447 | 1448 | // +y 1449 | for ( $x = $letter + 1; $x < 8; $x++ ) { 1450 | //echo "21\n"; 1451 | if ( $collided['+y'] === FALSE && $position[$number][$x] === 'q' ) { 1452 | $isCheck = TRUE; 1453 | $collided['+y'] = TRUE; 1454 | } else if ( $collided['+y'] === FALSE && $position[$number][$x] !== 0 ) { 1455 | $collided['+y'] = TRUE; 1456 | } 1457 | } 1458 | 1459 | // -y 1460 | for ( $x = $letter - 1; $x >= 0 ;$x-- ) { 1461 | //echo "22\n"; 1462 | if ( $collided['-y'] === FALSE && $position[$number][$x] === 'q' ) { 1463 | $isCheck = TRUE; 1464 | $collided['-y'] = TRUE; 1465 | } else if ( $collided['-y'] === FALSE && $position[$number][$x] !== 0 ) { 1466 | $collided['-y'] = TRUE; 1467 | } 1468 | } 1469 | 1470 | // diagonals 1471 | 1472 | // +x +y 1473 | $x = $letter + 1; 1474 | $y = $number + 1; 1475 | while ( $x < 8 && $y < 8 && $x >= 0 && $y >= 0 ) { 1476 | //echo "23\n"; 1477 | if ( $collided['+x+y'] == FALSE && $position[$y][$x] === 'q' ) { 1478 | $isCheck = TRUE; 1479 | $collided['+x+y'] = TRUE; 1480 | } else if ( $collided['+x+y'] == FALSE && $position[$y][$x] !== 0 ) { 1481 | $collided['+x+y'] = TRUE; 1482 | } 1483 | $x++; 1484 | $y++; 1485 | } 1486 | 1487 | // +x -y 1488 | $x = $letter + 1; 1489 | $y = $number - 1; 1490 | while ( $x < 8 && $y < 8 && $x >= 0 && $y >= 0 ) { 1491 | //echo "24\n"; 1492 | if ( $collided['+x-y'] == FALSE && $position[$y][$x] === 'q' ) { 1493 | $isCheck = TRUE; 1494 | $collided['+x-y'] = TRUE; 1495 | } else if ( $collided['+x-y'] == FALSE && $position[$y][$x] !== 0 ) { 1496 | $collided['+x-y'] = TRUE; 1497 | } 1498 | $x++; 1499 | $y--; 1500 | } 1501 | 1502 | // -x +y 1503 | $x = $letter - 1; 1504 | $y = $number + 1; 1505 | while ( $x < 8 && $y < 8 && $x >= 0 && $y >= 0 ) { 1506 | //echo "25\n"; 1507 | if ( $collided['-x+y'] == FALSE && $position[$y][$x] === 'q' ) { 1508 | $isCheck = TRUE; 1509 | $collided['-x+y'] = TRUE; 1510 | } else if ( $collided['-x+y'] == FALSE && $position[$y][$x] !== 0 ) { 1511 | $collided['-x+y'] = TRUE; 1512 | } 1513 | $x--; 1514 | $y++; 1515 | } 1516 | 1517 | // -x -y 1518 | $x = $letter - 1; 1519 | $y = $number - 1; 1520 | while ( $x < 8 && $y < 8 && $x >= 0 && $y >= 0 ) { 1521 | //echo "26\n"; 1522 | if ( $collided['-x-y'] == FALSE && $position[$y][$x] === 'q' ) { 1523 | $isCheck = TRUE; 1524 | $collided['-x-y'] = TRUE; 1525 | } else if ( $collided['-x-y'] == FALSE && $position[$y][$x] !== 0 ) { 1526 | $collided['-x-y'] = TRUE; 1527 | } 1528 | $x--; 1529 | $y--; 1530 | } 1531 | 1532 | } else if ( $square === 'R' ) { 1533 | 1534 | $collided = array( '+x' => FALSE, '+y' => FALSE, '-x' => FALSE, '-y' => FALSE ); 1535 | 1536 | // straights 1537 | 1538 | // +x 1539 | for ( $x = $number + 1; $x < 8; $x++ ) { 1540 | //echo "27\n"; 1541 | if ( $collided['+x'] === FALSE && $position[$x][$letter] === 'q' ) { 1542 | $isCheck = TRUE; 1543 | $collided['+x'] = TRUE; 1544 | } else if ( $collided['+x'] === FALSE && $position[$x][$letter] !== 0 ) { 1545 | $collided['+x'] = TRUE; 1546 | } 1547 | } 1548 | 1549 | // -x 1550 | for ( $x = $number - 1; $x >= 0; $x-- ) { 1551 | //echo "28\n"; 1552 | if ( $collided['-x'] === FALSE && $position[$x][$letter] === 'q' ) { 1553 | $isCheck = TRUE; 1554 | $collided['-x'] = TRUE; 1555 | } else if ( $collided['-x'] === FALSE && $position[$x][$letter] !== 0 ) { 1556 | $collided['-x'] = TRUE; 1557 | } 1558 | } 1559 | 1560 | // +y 1561 | for ( $x = $letter + 1; $x < 8; $x++ ) { 1562 | //echo "29\n"; 1563 | if ( $collided['+y'] === FALSE && $position[$number][$x] === 'q' ) { 1564 | $isCheck = TRUE; 1565 | $collided['+y'] = TRUE; 1566 | } else if ( $collided['+y'] === FALSE && $position[$number][$x] !== 0 ) { 1567 | $collided['+y'] = TRUE; 1568 | } 1569 | } 1570 | 1571 | // -y 1572 | for ( $x = $letter - 1; $x >= 0; $x-- ) { 1573 | //echo "30\n"; 1574 | if ( $collided['-y'] === FALSE && $position[$number][$x] === 'q' ) { 1575 | $isCheck = TRUE; 1576 | $collided['-y'] = TRUE; 1577 | } else if ( $collided['-y'] === FALSE && $position[$number][$x] !== 0 ) { 1578 | $collided['-y'] = TRUE; 1579 | } 1580 | } 1581 | 1582 | } else if ( $square === 'B' ) { 1583 | $collided = array( '+x+y' => FALSE, '+x-y' => FALSE, '-x+y' => FALSE, '-x-y' => FALSE ); 1584 | 1585 | // diagonals 1586 | 1587 | // +x +y 1588 | $x = $letter + 1; 1589 | $y = $number + 1; 1590 | while ( $x < 8 && $y < 8 && $x >= 0 && $y >= 0 ) { 1591 | //echo "31\n"; 1592 | if ( $collided['+x+y'] == FALSE && ( $position[$y][$x] === 'q' || $position[$y][$x] === 'r' ) ) { 1593 | $isCheck = TRUE; 1594 | $collided['+x+y'] = TRUE; 1595 | } else if ( $collided['+x+y'] == FALSE && $position[$y][$x] !== 0 ) { 1596 | $collided['+x+y'] = TRUE; 1597 | } 1598 | $x++; 1599 | $y++; 1600 | } 1601 | 1602 | // +x -y 1603 | $x = $letter + 1; 1604 | $y = $number - 1; 1605 | while ( $x < 8 && $y < 8 && $x >= 0 && $y >= 0 ) { 1606 | //echo "32\n"; 1607 | if ( $collided['+x-y'] == FALSE && ( $position[$y][$x] === 'q' || $position[$y][$x] === 'r' ) ) { 1608 | $isCheck = TRUE; 1609 | $collided['+x-y'] = TRUE; 1610 | } else if ( $collided['+x-y'] == FALSE && $position[$y][$x] !== 0 ) { 1611 | $collided['+x-y'] = TRUE; 1612 | } 1613 | $x++; 1614 | $y--; 1615 | } 1616 | 1617 | // -x +y 1618 | $x = $letter - 1; 1619 | $y = $number + 1; 1620 | while ( $x < 8 && $y < 8 && $x >= 0 && $y >= 0 ) { 1621 | //echo "33\n"; 1622 | if ( $collided['-x+y'] == FALSE && ( $position[$y][$x] === 'q' || $position[$y][$x] === 'r' ) ) { 1623 | $isCheck = TRUE; 1624 | $collided['-x+y'] = TRUE; 1625 | } else if ( $collided['-x+y'] == FALSE && $position[$y][$x] !== 0 ) { 1626 | $collided['-x+y'] = TRUE; 1627 | } 1628 | $x--; 1629 | $y++; 1630 | } 1631 | 1632 | // -x -y 1633 | $x = $letter - 1; 1634 | $y = $number - 1; 1635 | while ( $x < 8 && $y < 8 && $x >= 0 && $y >= 0 ) { 1636 | //echo "34\n"; 1637 | if ( $collided['-x-y'] == FALSE && ( $position[$y][$x] === 'q' || $position[$y][$x] === 'r' ) ) { 1638 | $isCheck = TRUE; 1639 | $collided['-x-y'] = TRUE; 1640 | } else if ( $collided['-x-y'] == FALSE && $position[$y][$x] !== 0 ) { 1641 | $collided['-x-y'] = TRUE; 1642 | } 1643 | $x--; 1644 | $y--; 1645 | } 1646 | 1647 | } else if ( $square === 'N' ) { 1648 | //L shapes 1649 | 1650 | // ++x +y 1651 | if ( $letter + 2 < 8 && $number + 1 < 8 ) { 1652 | if ( $position[$number + 1][$letter + 2] === 'q' || $position[$number + 1][$letter + 2] === 'r' ) { 1653 | $isCheck = TRUE; 1654 | } 1655 | } 1656 | 1657 | // ++x -y 1658 | if ( $letter + 2 < 8 && $number - 1 >= 0 ) { 1659 | if ( $position[$number - 1][$letter + 2] === 'q' || $position[$number - 1][$letter + 2] === 'r' ) { 1660 | $isCheck = TRUE; 1661 | } 1662 | } 1663 | 1664 | // --x +y 1665 | if ( $letter - 2 >= 0 && $number + 1 < 8 ) { 1666 | if ( $position[$number + 1][$letter - 2] === 'q' || $position[$number + 1][$letter - 2] === 'r' ) { 1667 | $isCheck = TRUE; 1668 | } 1669 | } 1670 | 1671 | // --x -y 1672 | if ( $letter - 2 >= 0 && $number - 1 >= 0 ) { 1673 | if ( $position[$number - 1][$letter - 2] === 'q' || $position[$number - 1][$letter - 2] === 'r' ) { 1674 | $isCheck = TRUE; 1675 | } 1676 | } 1677 | 1678 | // ++y +x 1679 | if ( $letter + 1 < 8 && $number + 2 < 8 ) { 1680 | if ( $position[$number + 2][$letter + 1] === 'q' || $position[$number + 2][$letter + 1] === 'r' ) { 1681 | $isCheck = TRUE; 1682 | } 1683 | } 1684 | 1685 | // ++y -x 1686 | if ( $letter - 1 >= 0 && $number + 2 < 8 ) { 1687 | if ( $position[$number + 2][$letter - 1] === 'q' || $position[$number + 2][$letter - 1] === 'r' ) { 1688 | $isCheck = TRUE; 1689 | } 1690 | } 1691 | 1692 | // --y +x 1693 | if ( $letter + 1 < 8 && $number - 2 >= 0 ) { 1694 | if ( $position[$number - 2][$letter + 1] === 'q' || $position[$number - 2][$letter + 1] === 'r' ) { 1695 | $isCheck = TRUE; 1696 | } 1697 | } 1698 | 1699 | // --y -x 1700 | if ( $letter - 1 >= 0 && $number - 2 >= 0 ) { 1701 | if ( $position[$number - 2][$letter - 1] === 'q' || $position[$number - 2][$letter - 1] === 'r' ) { 1702 | $isCheck = TRUE; 1703 | } 1704 | } 1705 | 1706 | } else if ( $square === 'P' ) { 1707 | 1708 | // -y -x 1709 | if ( $letter - 1 >= 0 && $number - 1 >= 0 ) { 1710 | if ( $position[$number - 1][$letter - 1] === 'q' 1711 | || $position[$number - 1][$letter - 1] === 'r' 1712 | || $position[$number - 1][$letter - 1] === 'n' 1713 | || $position[$number - 1][$letter - 1] === 'b' ) { 1714 | $isCheck = TRUE; 1715 | } 1716 | } 1717 | 1718 | // -y +x 1719 | if ( $letter + 1 < 8 && $number - 1 >= 0 ) { 1720 | if ( $position[$number - 1][$letter + 1] === 'q' 1721 | || $position[$number - 1][$letter + 1] === 'r' 1722 | || $position[$number - 1][$letter + 1] === 'n' 1723 | || $position[$number - 1][$letter + 1] === 'b' ) { 1724 | $isCheck = TRUE; 1725 | } 1726 | } 1727 | } 1728 | } 1729 | } 1730 | } 1731 | } 1732 | 1733 | return $isCheck; 1734 | } 1735 | 1736 | function updatePosition ( $position, $move ) { 1737 | //Take a position and a move and return the new board position 1738 | 1739 | $reference = array( 1740 | 'a' => 0, 1741 | 'b' => 1, 1742 | 'c' => 2, 1743 | 'd' => 3, 1744 | 'e' => 4, 1745 | 'f' => 5, 1746 | 'g' => 6, 1747 | 'h' => 7, 1748 | '1' => 7, 1749 | '2' => 6, 1750 | '3' => 5, 1751 | '4' => 4, 1752 | '5' => 3, 1753 | '6' => 2, 1754 | '7' => 1, 1755 | '8' => 0 1756 | ); 1757 | 1758 | $moveSplit = str_split( $move ); 1759 | 1760 | if ( $move == 'e8c8' && $position[$reference['8']][$reference['e']] === 'k' ) { 1761 | //black long castle 1762 | 1763 | $position[$reference['8']][$reference['c']] = 'k'; 1764 | $position[$reference['8']][$reference['d']] = 'r'; 1765 | $position[$reference['8']][$reference['e']] = 0; 1766 | $position[$reference['8']][$reference['a']] = 0; 1767 | 1768 | } else if ( $move == 'e8g8' && $position[$reference['8']][$reference['e']] === 'k' ) { 1769 | //black short castle 1770 | 1771 | $position[$reference['8']][$reference['g']] = 'k'; 1772 | $position[$reference['8']][$reference['f']] = 'r'; 1773 | $position[$reference['8']][$reference['e']] = 0; 1774 | $position[$reference['8']][$reference['h']] = 0; 1775 | 1776 | } else if ( $move == 'e1c1' && $position[$reference['1']][$reference['e']] === 'K' ) { 1777 | //white long castle 1778 | 1779 | $position[$reference['1']][$reference['c']] = 'K'; 1780 | $position[$reference['1']][$reference['d']] = 'R'; 1781 | $position[$reference['1']][$reference['e']] = 0; 1782 | $position[$reference['1']][$reference['a']] = 0; 1783 | 1784 | } else if ( $move == 'e1g1' && $position[$reference['1']][$reference['e']] === 'K' ) { 1785 | //white short castle 1786 | 1787 | $position[$reference['1']][$reference['g']] = 'K'; 1788 | $position[$reference['1']][$reference['f']] = 'R'; 1789 | $position[$reference['1']][$reference['e']] = 0; 1790 | $position[$reference['1']][$reference['h']] = 0; 1791 | 1792 | } else if ( $position[$reference[$moveSplit[1]]][$reference[$moveSplit[0]]] === 'P' 1793 | && $moveSplit[0] !== $moveSplit[2] 1794 | && $position[$reference[$moveSplit[3]]][$reference[$moveSplit[2]]] === 0 ) { 1795 | //White en passant 1796 | 1797 | $position[$reference[$moveSplit[3]]][$reference[$moveSplit[2]]] = 'P'; 1798 | $position[$reference[$moveSplit[3]]+1][$reference[$moveSplit[2]]] = 0; 1799 | $position[$reference[$moveSplit[1]]][$reference[$moveSplit[0]]] = 0; 1800 | 1801 | } else if ( $position[$reference[$moveSplit[1]]][$reference[$moveSplit[0]]] == 'p' 1802 | && $moveSplit[0] !== $moveSplit[2] 1803 | && $position[$reference[$moveSplit[3]]][$reference[$moveSplit[2]]] === 0 ) { 1804 | //Black en passant 1805 | 1806 | $position[$reference[$moveSplit[3]]][$reference[$moveSplit[2]]] = 'p'; 1807 | $position[$reference[$moveSplit[3]]-1][$reference[$moveSplit[2]]] = 0; 1808 | $position[$reference[$moveSplit[1]]][$reference[$moveSplit[0]]] = 0; 1809 | 1810 | } else if ( count( $moveSplit ) == 5 ) { 1811 | //promotion 1812 | if ( $position[$reference[$moveSplit[1]]][$reference[$moveSplit[0]]] === 'P' ) { 1813 | 1814 | $position[$reference[$moveSplit[3]]][$reference[$moveSplit[2]]] = strtoupper( $moveSplit[4] ); 1815 | 1816 | } else { 1817 | 1818 | $position[$reference[$moveSplit[3]]][$reference[$moveSplit[2]]] = strtolower( $moveSplit[4] ); 1819 | 1820 | } 1821 | 1822 | $position[$reference[$moveSplit[1]]][$reference[$moveSplit[0]]] = 0; 1823 | 1824 | } else if ( count( $moveSplit ) == 4 ) { 1825 | //Normal move 1826 | $position[$reference[$moveSplit[3]]][$reference[$moveSplit[2]]] = $position[$reference[$moveSplit[1]]][$reference[$moveSplit[0]]]; 1827 | $position[$reference[$moveSplit[1]]][$reference[$moveSplit[0]]] = 0; 1828 | } 1829 | 1830 | return $position; 1831 | } --------------------------------------------------------------------------------