| 471 save_pgn(gamestate); |
471 save_pgn(gamestate); |
| 472 } else if (movestr[0] == 0) { |
472 } else if (movestr[0] == 0) { |
| 473 /* ignore empty move strings and ask again */ |
473 /* ignore empty move strings and ask again */ |
| 474 } else { |
474 } else { |
| 475 Move move; |
475 Move move; |
| 476 int result = eval_move_lazy(gamestate, |
476 int result = eval_move(gamestate, |
| 477 movestr, curcolor, &move); |
477 movestr, curcolor, &move); |
| 478 if (result == VALID_MOVE_SYNTAX) { |
478 if (result == VALID_MOVE_SYNTAX) { |
| 479 result = validate_move(gamestate, &move); |
479 result = validate_move(gamestate, &move); |
| 480 if (result == VALID_MOVE_SEMANTICS) { |
480 if (result == VALID_MOVE_SEMANTICS) { |
| 481 apply_move(gamestate, &move); |
481 apply_move(gamestate, &move); |
| 492 } |
492 } |
| 493 clrtoeol(); |
493 clrtoeol(); |
| 494 } |
494 } |
| 495 } |
495 } |
| 496 } |
496 } |
| |
497 } |
| |
498 |
| |
499 static NetMove hton_move(const Move *move) { |
| |
500 return (NetMove) { |
| |
501 .mtime_sec = htonl(move->movetime / 1000000ull), |
| |
502 .mtime_usec = htonl(move->movetime % 1000000ull), |
| |
503 .piece = move->piece, |
| |
504 .fromfile = move->fromfile, .fromrow = move->fromrow, |
| |
505 .tofile = move->tofile, .torow = move->torow, |
| |
506 .promotion = move->promotion |
| |
507 }; |
| |
508 } |
| |
509 |
| |
510 static Move ntoh_move(const NetMove *move) { |
| |
511 return (Move) { |
| |
512 .string = {0}, /* calculated before applying the move */ |
| |
513 .timestamp = {0}, /* planned to be removed */ |
| |
514 .movetime = (uint64_t)move->mtime_sec * 1000000ull + move->mtime_usec, |
| |
515 .piece = move->piece, |
| |
516 .fromfile = move->fromfile, .fromrow = move->fromrow, |
| |
517 .tofile = move->tofile, .torow = move->torow, |
| |
518 .promotion = move->promotion, |
| |
519 /* flags are also calculated before applying the move */ |
| |
520 0 |
| |
521 }; |
| 497 } |
522 } |
| 498 |
523 |
| 499 static int sendmove(GameState *gamestate, int opponent, uint8_t mycolor) { |
524 static int sendmove(GameState *gamestate, int opponent, uint8_t mycolor) { |
| 500 |
525 |
| 501 size_t bufpos = 0; |
526 size_t bufpos = 0; |
| 605 } |
630 } |
| 606 } else if (movestr[0] == 0) { |
631 } else if (movestr[0] == 0) { |
| 607 /* ignore empty move strings and ask again */ |
632 /* ignore empty move strings and ask again */ |
| 608 } else { |
633 } else { |
| 609 Move move; |
634 Move move; |
| 610 int eval_result = eval_move_lazy(gamestate, |
635 int eval_result = eval_move(gamestate, |
| 611 movestr, mycolor, &move); |
636 movestr, mycolor, &move); |
| 612 switch (eval_result) { |
637 switch (eval_result) { |
| 613 case VALID_MOVE_SYNTAX: |
638 case VALID_MOVE_SYNTAX: |
| 614 net_send_data(opponent, NETCODE_MOVE, &move, sizeof(Move)); |
639 NetMove nmove = hton_move(&move); |
| |
640 net_send_data(opponent, NETCODE_MOVE, &nmove, NETMOVE_LEN); |
| 615 code = net_recieve_code(opponent); |
641 code = net_recieve_code(opponent); |
| 616 /* we could validate the move's check/checkmate flag with |
642 /* we could validate the move's check/checkmate flag with |
| 617 * the network response code, but we choose not to do it */ |
643 * the network response code, but we choose not to do it */ |
| 618 gamestate->checkmate = code == NETCODE_CHECKMATE; |
644 gamestate->checkmate = code == NETCODE_CHECKMATE; |
| 619 gamestate->stalemate = code == NETCODE_STALEMATE; |
645 gamestate->stalemate = code == NETCODE_STALEMATE; |
| 758 /* silently decline, do not add message to UI */ |
784 /* silently decline, do not add message to UI */ |
| 759 net_send_code(opponent, NETCODE_DECLINE); |
785 net_send_code(opponent, NETCODE_DECLINE); |
| 760 } |
786 } |
| 761 break; |
787 break; |
| 762 case NETCODE_MOVE: { |
788 case NETCODE_MOVE: { |
| 763 Move move; |
789 NetMove nmove; |
| 764 net_recieve_data(opponent, &move, sizeof(Move)); |
790 net_recieve_data(opponent, &nmove, NETMOVE_LEN); |
| |
791 Move move = ntoh_move(&nmove); |
| |
792 format_move(gamestate, &move); |
| 765 code = validate_move(gamestate, &move); |
793 code = validate_move(gamestate, &move); |
| 766 if (code == VALID_MOVE_SEMANTICS) { |
794 if (code == VALID_MOVE_SEMANTICS) { |
| 767 apply_move(gamestate, &move); |
795 apply_move(gamestate, &move); |
| 768 if (gamestate->checkmate) { |
796 if (gamestate->checkmate) { |
| 769 net_send_code(opponent, NETCODE_CHECKMATE); |
797 net_send_code(opponent, NETCODE_CHECKMATE); |
| 1047 |
1075 |
| 1048 int fd = server.client->fd; |
1076 int fd = server.client->fd; |
| 1049 if (settings.continuepgn) { |
1077 if (settings.continuepgn) { |
| 1050 /* Continue game, send PGN data */ |
1078 /* Continue game, send PGN data */ |
| 1051 uint16_t mc = gamestate->movecount; |
1079 uint16_t mc = gamestate->movecount; |
| 1052 size_t pgndata_size = sizeof(GameInfo)+sizeof(mc)+mc*sizeof(Move); |
1080 size_t pgndata_size = sizeof(GameInfo) + 2 + mc * NETMOVE_LEN; |
| 1053 char *pgndata = malloc(pgndata_size); |
1081 char *pgndata = malloc(pgndata_size); |
| 1054 memcpy(pgndata, &(gamestate->info), sizeof(GameInfo)); |
1082 memcpy(pgndata, &(gamestate->info), sizeof(GameInfo)); |
| 1055 unsigned offset = sizeof(GameInfo); |
1083 unsigned offset = sizeof(GameInfo); |
| 1056 memcpy(pgndata+offset, &mc, sizeof(mc)); |
1084 uint16_t mcn = htons(mc); |
| 1057 offset += sizeof(mc); |
1085 memcpy(pgndata+offset, &mcn, 2); |
| 1058 memcpy(pgndata+offset, gamestate->moves, mc*sizeof(Move)); |
1086 offset += 2; |
| |
1087 for (unsigned i = 0 ; i < mc ; i++) { |
| |
1088 NetMove nmove = hton_move(gamestate->moves + i); |
| |
1089 memcpy(pgndata+offset, &nmove, NETMOVE_LEN); |
| |
1090 offset += NETMOVE_LEN; |
| |
1091 } |
| 1059 net_send_data(fd, NETCODE_PGNDATA, pgndata, pgndata_size); |
1092 net_send_data(fd, NETCODE_PGNDATA, pgndata, pgndata_size); |
| 1060 free(pgndata); |
1093 free(pgndata); |
| 1061 } else { |
1094 } else { |
| 1062 /* Start new game */ |
1095 /* Start new game */ |
| 1063 net_send_data(fd, NETCODE_GAMEINFO, |
1096 net_send_data(fd, NETCODE_GAMEINFO, |
| 1148 } |
1181 } |
| 1149 } else if (code == NETCODE_PGNDATA) { |
1182 } else if (code == NETCODE_PGNDATA) { |
| 1150 net_recieve_data(server.fd, &(gamestate->info), sizeof(GameInfo)); |
1183 net_recieve_data(server.fd, &(gamestate->info), sizeof(GameInfo)); |
| 1151 uint16_t mc; |
1184 uint16_t mc; |
| 1152 net_recieve_data(server.fd, &mc, sizeof(mc)); |
1185 net_recieve_data(server.fd, &mc, sizeof(mc)); |
| 1153 Move *moves = calloc(mc, sizeof(Move)); |
1186 mc = ntohs(mc); |
| 1154 net_recieve_data(server.fd, moves, mc*sizeof(Move)); |
1187 char *movedata = malloc(mc * NETMOVE_LEN); |
| |
1188 net_recieve_data(server.fd, movedata, mc*NETMOVE_LEN); |
| |
1189 unsigned offset = 0; |
| 1155 for (size_t i = 0 ; i < mc ; i++) { |
1190 for (size_t i = 0 ; i < mc ; i++) { |
| 1156 apply_move(gamestate, &(moves[i])); |
1191 NetMove nmove; |
| 1157 } |
1192 memcpy(&nmove, movedata+offset, NETMOVE_LEN); |
| 1158 free(moves); |
1193 offset += NETMOVE_LEN; |
| |
1194 Move move = ntoh_move(&nmove); |
| |
1195 format_move(gamestate, &move); |
| |
1196 apply_move(gamestate, &move); |
| |
1197 } |
| |
1198 free(movedata); |
| 1159 dump_gameinfo(gamestate); |
1199 dump_gameinfo(gamestate); |
| 1160 if (prompt_yesno( |
1200 if (prompt_yesno( |
| 1161 "\n\nServer wants to continue a game. Accept challenge")) { |
1201 "\n\nServer wants to continue a game. Accept challenge")) { |
| 1162 net_send_code(server.fd, NETCODE_ACCEPT); |
1202 net_send_code(server.fd, NETCODE_ACCEPT); |
| 1163 game_play(gamestate, server.fd, true); |
1203 game_play(gamestate, server.fd, true); |