| 39 #include <stdlib.h> |
39 #include <stdlib.h> |
| 40 #include <sys/time.h> |
40 #include <sys/time.h> |
| 41 |
41 |
| 42 static GameState gamestate_copy_sim(GameState *gamestate) { |
42 static GameState gamestate_copy_sim(GameState *gamestate) { |
| 43 GameState simulation = *gamestate; |
43 GameState simulation = *gamestate; |
| 44 simulation.movecount = 0; /* simulations do not count moves */ |
44 |
| 45 if (simulation.lastmove) { |
45 // create a new move list for the simulation |
| 46 MoveList *lastmovecopy = malloc(sizeof(MoveList)); |
46 simulation.movecapacity = 4; |
| 47 *lastmovecopy = *(simulation.lastmove); |
47 simulation.movecount = 0; |
| 48 simulation.movelist = simulation.lastmove = lastmovecopy; |
48 simulation.moves = malloc(4 * sizeof(Move)); |
| |
49 |
| |
50 // copy the most recent move if a move was played |
| |
51 if (gamestate->movecount > 0) { |
| |
52 simulation.moves[0] = last_move(gamestate); |
| |
53 simulation.movecount++; |
| 49 } |
54 } |
| 50 |
55 |
| 51 return simulation; |
56 return simulation; |
| 52 } |
57 } |
| 53 |
58 |
| 136 if (move->check) { |
141 if (move->check) { |
| 137 string[idx++] = gamestate->checkmate?'#':'+'; |
142 string[idx++] = gamestate->checkmate?'#':'+'; |
| 138 } |
143 } |
| 139 } |
144 } |
| 140 |
145 |
| 141 static void addmove(GameState* gamestate, Move *move) { |
146 static void addmove(GameState* gamestate, Move *data) { |
| 142 MoveList *elem = malloc(sizeof(MoveList)); |
147 if (gamestate->movecount == gamestate->movecapacity) { |
| 143 elem->next = NULL; |
148 gamestate->movecapacity += 64; /* 32 more full moves */ |
| 144 elem->move = *move; |
149 gamestate->moves = realloc(gamestate->moves, |
| 145 |
150 gamestate->movecapacity * sizeof(Move)); |
| |
151 } |
| |
152 |
| |
153 Move *move = &gamestate->moves[gamestate->movecount]; |
| |
154 *move = *data; |
| |
155 |
| 146 struct timeval curtimestamp; |
156 struct timeval curtimestamp; |
| 147 gettimeofday(&curtimestamp, NULL); |
157 gettimeofday(&curtimestamp, NULL); |
| 148 elem->move.timestamp.tv_sec = curtimestamp.tv_sec; |
158 move->timestamp.tv_sec = curtimestamp.tv_sec; |
| 149 elem->move.timestamp.tv_usec = curtimestamp.tv_usec; |
159 move->timestamp.tv_usec = (int32_t) curtimestamp.tv_usec; |
| 150 |
160 |
| 151 if (gamestate->lastmove) { |
161 if (gamestate->movecount > 0) { |
| 152 struct movetimeval *lasttstamp = &(gamestate->lastmove->move.timestamp); |
162 struct movetimeval lasttstamp = last_move(gamestate).timestamp; |
| 153 uint64_t sec = curtimestamp.tv_sec - lasttstamp->tv_sec; |
163 uint64_t sec = curtimestamp.tv_sec - lasttstamp.tv_sec; |
| 154 suseconds_t micros; |
164 suseconds_t micros; |
| 155 if (curtimestamp.tv_usec < lasttstamp->tv_usec) { |
165 if (curtimestamp.tv_usec < lasttstamp.tv_usec) { |
| 156 micros = 1e6L-(lasttstamp->tv_usec - curtimestamp.tv_usec); |
166 micros = 1000000-(lasttstamp.tv_usec - curtimestamp.tv_usec); |
| 157 sec--; |
167 sec--; |
| 158 } else { |
168 } else { |
| 159 micros = curtimestamp.tv_usec - lasttstamp->tv_usec; |
169 micros = curtimestamp.tv_usec - lasttstamp.tv_usec; |
| 160 } |
170 } |
| 161 |
171 |
| 162 elem->move.movetime.tv_sec = sec; |
172 move->movetime.tv_sec = sec; |
| 163 elem->move.movetime.tv_usec = micros; |
173 move->movetime.tv_usec = (int32_t) micros; |
| 164 |
|
| 165 gamestate->lastmove->next = elem; |
|
| 166 gamestate->lastmove = elem; |
|
| 167 gamestate->movecount++; |
|
| 168 } else { |
174 } else { |
| 169 elem->move.movetime.tv_usec = 0; |
175 move->movetime.tv_usec = 0; |
| 170 elem->move.movetime.tv_sec = 0; |
176 move->movetime.tv_sec = 0; |
| 171 gamestate->movelist = gamestate->lastmove = elem; |
177 } |
| 172 gamestate->movecount = 1; |
178 gamestate->movecount++; |
| 173 } |
|
| 174 } |
179 } |
| 175 |
180 |
| 176 char getpiecechr(uint8_t piece) { |
181 char getpiecechr(uint8_t piece) { |
| 177 switch (piece & PIECE_MASK) { |
182 switch (piece & PIECE_MASK) { |
| 178 case ROOK: return 'R'; |
183 case ROOK: return 'R'; |
| 365 gamestate_cleanup(&simulation); |
370 gamestate_cleanup(&simulation); |
| 366 if ((move->piece & PIECE_MASK) == KING) { |
371 if ((move->piece & PIECE_MASK) == KING) { |
| 367 return KING_MOVES_INTO_CHECK; |
372 return KING_MOVES_INTO_CHECK; |
| 368 } else { |
373 } else { |
| 369 /* last move is always not null in this case */ |
374 /* last move is always not null in this case */ |
| 370 return gamestate->lastmove->move.check ? |
375 return last_move(gamestate).check ? |
| 371 KING_IN_CHECK : PIECE_PINNED; |
376 KING_IN_CHECK : PIECE_PINNED; |
| 372 } |
377 } |
| 373 } |
378 } |
| 374 |
379 |
| 375 /* correct check and checkmate flags (move is still valid) */ |
380 /* correct check and checkmate flags (move is still valid) */ |
| 567 |
572 |
| 568 static int getlocation(GameState *gamestate, Move *move) { |
573 static int getlocation(GameState *gamestate, Move *move) { |
| 569 |
574 |
| 570 uint8_t color = move->piece & COLOR_MASK; |
575 uint8_t color = move->piece & COLOR_MASK; |
| 571 uint8_t piece = move->piece & PIECE_MASK; |
576 uint8_t piece = move->piece & PIECE_MASK; |
| 572 bool incheck = gamestate->lastmove?gamestate->lastmove->move.check:false; |
577 bool incheck = gamestate->movecount > 0 ? last_move(gamestate).check:false; |
| 573 |
578 |
| 574 Move threats[16], *threat = NULL; |
579 Move threats[16], *threat = NULL; |
| 575 uint8_t threatcount; |
580 uint8_t threatcount; |
| 576 |
581 |
| 577 if (get_threats(gamestate, move->torow, move->tofile, color, |
582 if (get_threats(gamestate, move->torow, move->tofile, color, |
| 766 uint8_t color) { |
771 uint8_t color) { |
| 767 if (!gameinfo->timecontrol) { |
772 if (!gameinfo->timecontrol) { |
| 768 return 0; |
773 return 0; |
| 769 } |
774 } |
| 770 |
775 |
| 771 if (gamestate->movelist) { |
776 if (gamestate->movecount > 0) { |
| 772 uint16_t time = gameinfo->time; |
777 uint16_t time = gameinfo->time; |
| 773 suseconds_t micros = 0; |
778 suseconds_t micros = 0; |
| 774 |
779 |
| 775 MoveList *movelist = color == WHITE ? |
780 for (unsigned i = color == WHITE ? 0 : 1 |
| 776 gamestate->movelist : gamestate->movelist->next; |
781 ; i < gamestate->movecount ; i += 2) { |
| 777 |
|
| 778 while (movelist) { |
|
| 779 time += gameinfo->addtime; |
782 time += gameinfo->addtime; |
| 780 |
783 |
| 781 struct movetimeval *movetime = &(movelist->move.movetime); |
784 if (gamestate->moves[i].movetime.tv_sec >= time) { |
| 782 if (movetime->tv_sec >= time) { |
|
| 783 return 0; |
785 return 0; |
| 784 } |
786 } |
| 785 |
787 |
| 786 time -= movetime->tv_sec; |
788 time -= gamestate->moves[i].movetime.tv_sec; |
| 787 micros += movetime->tv_usec; |
789 micros += gamestate->moves[i].movetime.tv_usec; |
| 788 |
|
| 789 movelist = movelist->next ? movelist->next->next : NULL; |
|
| 790 } |
790 } |
| 791 |
791 |
| 792 time_t sec; |
792 time_t sec; |
| 793 movelist = gamestate->lastmove; |
793 Move *lastmove = &last_move(gamestate); |
| 794 if ((movelist->move.piece & COLOR_MASK) != color) { |
794 if ((lastmove->piece & COLOR_MASK) != color) { |
| 795 struct movetimeval *lastmovetstamp = &(movelist->move.timestamp); |
795 struct movetimeval lastmovetstamp = lastmove->timestamp; |
| 796 struct timeval currenttstamp; |
796 struct timeval currenttstamp; |
| 797 gettimeofday(¤ttstamp, NULL); |
797 gettimeofday(¤ttstamp, NULL); |
| 798 micros += currenttstamp.tv_usec - lastmovetstamp->tv_usec; |
798 micros += currenttstamp.tv_usec - lastmovetstamp.tv_usec; |
| 799 sec = currenttstamp.tv_sec - lastmovetstamp->tv_sec; |
799 sec = currenttstamp.tv_sec - lastmovetstamp.tv_sec; |
| 800 if (sec >= time) { |
800 if (sec >= time) { |
| 801 return 0; |
801 return 0; |
| 802 } |
802 } |
| 803 |
803 |
| 804 time -= sec; |
804 time -= sec; |
| 805 } |
805 } |
| 806 |
806 |
| 807 sec = micros / 1e6L; |
807 sec = micros / 1000000; |
| 808 |
808 |
| 809 if (sec >= time) { |
809 if (sec >= time) { |
| 810 return 0; |
810 return 0; |
| 811 } |
811 } |
| 812 |
812 |