| 142 if (move->check) { |
142 if (move->check) { |
| 143 string[idx++] = gamestate->checkmate?'#':'+'; |
143 string[idx++] = gamestate->checkmate?'#':'+'; |
| 144 } |
144 } |
| 145 } |
145 } |
| 146 |
146 |
| 147 static void addmove(GameState* gamestate, Move *data) { |
147 static void calc_movetime(GameState *gamestate, Move *move) { |
| 148 if (gamestate->movecount == gamestate->movecapacity) { |
|
| 149 gamestate->movecapacity += 64; /* 32 more full moves */ |
|
| 150 gamestate->moves = realloc(gamestate->moves, |
|
| 151 gamestate->movecapacity * sizeof(Move)); |
|
| 152 } |
|
| 153 |
|
| 154 Move *move = &gamestate->moves[gamestate->movecount]; |
|
| 155 *move = *data; |
|
| 156 |
|
| 157 struct timeval curtimestamp; |
148 struct timeval curtimestamp; |
| 158 gettimeofday(&curtimestamp, NULL); |
149 gettimeofday(&curtimestamp, NULL); |
| 159 move->timestamp.tv_sec = curtimestamp.tv_sec; |
150 move->timestamp.tv_sec = curtimestamp.tv_sec; |
| 160 move->timestamp.tv_usec = (int32_t) curtimestamp.tv_usec; |
151 move->timestamp.tv_usec = (int32_t) curtimestamp.tv_usec; |
| 161 |
152 |
| 162 if (gamestate->movecount > 1) { |
153 if (gamestate->movecount > 1) { |
| 163 struct movetimeval lasttstamp = last_move(gamestate).timestamp; |
154 struct movetimeval lasttstamp = last_move(gamestate).timestamp; |
| 164 uint64_t sec = curtimestamp.tv_sec - lasttstamp.tv_sec; |
155 uint64_t sec = curtimestamp.tv_sec - lasttstamp.tv_sec; |
| 165 suseconds_t micros; |
156 suseconds_t micros; |
| 166 if (curtimestamp.tv_usec < lasttstamp.tv_usec) { |
157 if (curtimestamp.tv_usec < lasttstamp.tv_usec) { |
| 167 micros = 1000000-(lasttstamp.tv_usec - curtimestamp.tv_usec); |
158 micros = 1000000-(lasttstamp.tv_usec - curtimestamp.tv_usec); |
| 168 sec--; |
159 sec--; |
| 169 } else { |
160 } else { |
| 170 micros = curtimestamp.tv_usec - lasttstamp.tv_usec; |
161 micros = curtimestamp.tv_usec - lasttstamp.tv_usec; |
| 171 } |
162 } |
| 172 |
163 |
| 173 move->movetime.tv_sec = sec; |
164 move->movetime.tv_sec = sec; |
| 174 move->movetime.tv_usec = (int32_t) micros; |
165 move->movetime.tv_usec = (int32_t) micros; |
| 175 } else { |
166 } else { |
| 176 /* no move time for the first move of both white and black */ |
167 /* no move time for the first move of both white and black */ |
| 177 move->movetime.tv_usec = 0; |
168 move->movetime.tv_usec = 0; |
| 178 move->movetime.tv_sec = 0; |
169 move->movetime.tv_sec = 0; |
| 179 } |
170 } |
| |
171 } |
| |
172 |
| |
173 static void addmove(GameState* gamestate, Move *data) { |
| |
174 if (gamestate->movecount == gamestate->movecapacity) { |
| |
175 gamestate->movecapacity += 64; /* 32 more full moves */ |
| |
176 gamestate->moves = realloc(gamestate->moves, |
| |
177 gamestate->movecapacity * sizeof(Move)); |
| |
178 } |
| |
179 |
| |
180 Move *move = &gamestate->moves[gamestate->movecount]; |
| |
181 *move = *data; |
| |
182 |
| |
183 /* only if move has no time info, compute it */ |
| |
184 if (move->movetime.tv_sec == 0 && move->movetime.tv_usec == 0) { |
| |
185 calc_movetime(gamestate, move); |
| |
186 } |
| |
187 |
| |
188 /* important: only "add" the move after calculating the time! */ |
| 180 gamestate->movecount++; |
189 gamestate->movecount++; |
| 181 } |
190 } |
| 182 |
191 |
| 183 char getpiecechr(uint8_t piece) { |
192 char getpiecechr(uint8_t piece) { |
| 184 switch (piece & PIECE_MASK) { |
193 switch (piece & PIECE_MASK) { |
| 278 /* add move, even in simulation (checkmate test needs it) */ |
287 /* add move, even in simulation (checkmate test needs it) */ |
| 279 addmove(gamestate, move); |
288 addmove(gamestate, move); |
| 280 } |
289 } |
| 281 |
290 |
| 282 void apply_move(GameState *gamestate, Move *move) { |
291 void apply_move(GameState *gamestate, Move *move) { |
| 283 apply_move_impl(gamestate, move, 0); |
292 apply_move_impl(gamestate, move, false); |
| |
293 } |
| |
294 |
| |
295 void gamestate_at_move(GameState *gamestate, |
| |
296 unsigned move_number, GameState *replay) { |
| |
297 gamestate_init(replay); |
| |
298 replay->review = true; |
| |
299 if (move_number > gamestate->movecount) { |
| |
300 move_number = gamestate->movecount; |
| |
301 } |
| |
302 for (unsigned i = 0 ; i < move_number ; i++) { |
| |
303 apply_move_impl(replay, &(gamestate->moves[i]), true); |
| |
304 } |
| 284 } |
305 } |
| 285 |
306 |
| 286 static int validate_move_rules(GameState *gamestate, Move *move) { |
307 static int validate_move_rules(GameState *gamestate, Move *move) { |
| 287 /* validate indices (don't trust opponent) */ |
308 /* validate indices (don't trust opponent) */ |
| 288 if (!chkidx(move)) { |
309 if (!chkidx(move)) { |
| 355 } |
376 } |
| 356 |
377 |
| 357 /* simulate move for check validation */ |
378 /* simulate move for check validation */ |
| 358 GameState simulation = gamestate_copy_sim(gamestate); |
379 GameState simulation = gamestate_copy_sim(gamestate); |
| 359 Move simmove = *move; |
380 Move simmove = *move; |
| 360 apply_move_impl(&simulation, &simmove, 1); |
381 apply_move_impl(&simulation, &simmove, true); |
| 361 |
382 |
| 362 /* find kings for check validation */ |
383 /* find kings for check validation */ |
| 363 uint8_t piececolor = (move->piece & COLOR_MASK); |
384 uint8_t piececolor = (move->piece & COLOR_MASK); |
| 364 |
385 |
| 365 uint8_t mykingfile = 0, mykingrow = 0, opkingfile = 0, opkingrow = 0; |
386 uint8_t mykingfile = 0, mykingrow = 0, opkingfile = 0, opkingrow = 0; |