| 665 switch (eval_result) { |
665 switch (eval_result) { |
| 666 case VALID_MOVE_SYNTAX: |
666 case VALID_MOVE_SYNTAX: |
| 667 NetMove nmove = hton_move(move); |
667 NetMove nmove = hton_move(move); |
| 668 net_send_data(opponent, NETCODE_MOVE, &nmove, NETMOVE_LEN); |
668 net_send_data(opponent, NETCODE_MOVE, &nmove, NETMOVE_LEN); |
| 669 code = net_recieve_code(opponent); |
669 code = net_recieve_code(opponent); |
| 670 /* we could validate the move's check/checkmate flag with |
|
| 671 * the network response code, but we choose not to do it */ |
|
| 672 gamestate->checkmate = code == NETCODE_CHECKMATE; |
|
| 673 gamestate->stalemate = code == NETCODE_STALEMATE; |
|
| 674 if (code == NETCODE_DECLINE_MOVE) { |
670 if (code == NETCODE_DECLINE_MOVE) { |
| 675 uint8_t reason; |
671 uint8_t reason; |
| 676 net_recieve_data(opponent, &reason, 1); |
672 net_recieve_data(opponent, &reason, 1); |
| 677 eval_move_failed_msg(reason); |
673 eval_move_failed_msg(reason); |
| 678 } else if (code == NETCODE_ACCEPT |
674 } else if (code == NETCODE_ACCEPT) { |
| 679 || code == NETCODE_CHECK |
|
| 680 || code == NETCODE_CHECKMATE |
|
| 681 || code == NETCODE_STALEMATE |
|
| 682 || code == NETCODE_NOMATERIAL) { |
|
| 683 format_move(gamestate, &move); |
675 format_move(gamestate, &move); |
| 684 apply_move(gamestate, &move); |
676 apply_move(gamestate, &move); |
| 685 if (is_game_running(gamestate)) { |
677 /* switch to waiting, even when the game ended. |
| 686 return 0; |
678 * we want to receive the "game end" code from the |
| 687 } else { |
679 * other party. |
| 688 return 1; |
680 */ |
| 689 } |
681 return 0; |
| 690 } else if (code == NETCODE_CONNLOST) { |
682 } else if (code == NETCODE_CONNLOST) { |
| 691 printw("Your opponent left the game."); |
683 printw("Your opponent left the game."); |
| 692 return 1; |
684 return 1; |
| 693 } else { |
685 } else { |
| 694 printw("Invalid network response."); |
686 printw("Invalid network response."); |
| 799 } else { |
791 } else { |
| 800 net_send_code(opponent, NETCODE_DECLINE); |
792 net_send_code(opponent, NETCODE_DECLINE); |
| 801 } |
793 } |
| 802 } |
794 } |
| 803 break; |
795 break; |
| |
796 /* validate "the game has ended" claims */ |
| 804 case NETCODE_THREEFOLD: |
797 case NETCODE_THREEFOLD: |
| 805 /* validate the claim */ |
798 case NETCODE_NOMATERIAL: |
| 806 if (check_threefold_repetition(gamestate)) { |
799 case NETCODE_STALEMATE: |
| |
800 case NETCODE_CHECKMATE: |
| |
801 if ((code == NETCODE_THREEFOLD && gamestate->threefold) || |
| |
802 (code == NETCODE_NOMATERIAL && gamestate->nomaterial) || |
| |
803 (code == NETCODE_STALEMATE && gamestate->stalemate) || |
| |
804 (code == NETCODE_CHECKMATE && gamestate->checkmate)) { |
| 807 /* auto-accept the claim */ |
805 /* auto-accept the claim */ |
| 808 gamestate->threefold = true; |
|
| 809 net_send_code(opponent, NETCODE_ACCEPT); |
806 net_send_code(opponent, NETCODE_ACCEPT); |
| 810 return 1; |
807 return 1; |
| 811 } else { |
808 } else { |
| 812 /* silently decline, do not add message to UI */ |
809 /* silently decline, do not add message to UI */ |
| 813 net_send_code(opponent, NETCODE_DECLINE); |
810 net_send_code(opponent, NETCODE_DECLINE); |
| 819 Move move = ntoh_move(nmove); |
816 Move move = ntoh_move(nmove); |
| 820 code = validate_move(gamestate, &move); |
817 code = validate_move(gamestate, &move); |
| 821 if (code == VALID_MOVE_SEMANTICS) { |
818 if (code == VALID_MOVE_SEMANTICS) { |
| 822 format_move(gamestate, &move); |
819 format_move(gamestate, &move); |
| 823 apply_move(gamestate, &move); |
820 apply_move(gamestate, &move); |
| |
821 net_send_code(opponent, NETCODE_ACCEPT); |
| |
822 |
| |
823 /* send a code for ending the game, if required */ |
| |
824 bool endgame = true; |
| 824 if (gamestate->checkmate) { |
825 if (gamestate->checkmate) { |
| 825 net_send_code(opponent, NETCODE_CHECKMATE); |
826 net_send_code(opponent, NETCODE_CHECKMATE); |
| 826 return 1; |
|
| 827 } else if (gamestate->stalemate) { |
827 } else if (gamestate->stalemate) { |
| 828 net_send_code(opponent, NETCODE_STALEMATE); |
828 net_send_code(opponent, NETCODE_STALEMATE); |
| 829 return 1; |
|
| 830 } else if (gamestate->nomaterial) { |
829 } else if (gamestate->nomaterial) { |
| 831 net_send_code(opponent, NETCODE_NOMATERIAL); |
830 net_send_code(opponent, NETCODE_NOMATERIAL); |
| 832 return 1; |
831 } else if (gamestate->threefold) { |
| 833 } else if (move.check) { |
832 /* Note: in our implementation it is an auto-draw claimed |
| 834 net_send_code(opponent, NETCODE_CHECK); |
833 * by the player confronted with the position. By standard |
| |
834 * chess rules, also the player who creates the position may |
| |
835 * claim the draw. But since we do it automatically, it |
| |
836 * makes no practical difference. |
| |
837 */ |
| |
838 net_send_code(opponent, NETCODE_THREEFOLD); |
| 835 } else { |
839 } else { |
| 836 net_send_code(opponent, NETCODE_ACCEPT); |
840 endgame = false; |
| 837 } |
841 } |
| 838 /* check for threefold repetition */ |
842 /* await a response to the "end game" code */ |
| 839 /* Note: in our implementation it is an auto-draw claimed |
843 if (endgame) { |
| 840 * by the player confronted with the position. By standard |
|
| 841 * chess rules, also the player who creates the position may |
|
| 842 * claim the draw. But since we do it automatically, it makes |
|
| 843 * no practical difference. |
|
| 844 */ |
|
| 845 if (gamestate->threefold) { |
|
| 846 /* send this as a new package (basically as next move) */ |
|
| 847 net_send_code(opponent, NETCODE_THREEFOLD); |
|
| 848 /* the protocol supports declining the claim */ |
|
| 849 uint8_t resp = net_recieve_code(opponent); |
844 uint8_t resp = net_recieve_code(opponent); |
| 850 if (resp == NETCODE_ACCEPT) { |
845 if (resp == NETCODE_ACCEPT) { |
| 851 return 1; |
846 return 1; |
| 852 } else { |
847 } else { |
| 853 /* does not happen in our implementation */ |
848 /* does not happen in our implementation */ |
| 854 // TODO: but what do we do if some other client declines? simply rage quit? |
849 // TODO: but what do we do if some other client declines? |
| 855 // should we instead rework the protocol that it's not possible to decline? |
850 // currently, we simply continue playing, |
| |
851 // but that does not make any sense |
| 856 return 0; |
852 return 0; |
| 857 } |
853 } |
| 858 } else { |
|
| 859 return 0; |
|
| 860 } |
854 } |
| |
855 /* now it's our turn */ |
| |
856 return 0; |
| 861 } else { |
857 } else { |
| 862 net_send_data(opponent, NETCODE_DECLINE_MOVE, &code, 1); |
858 net_send_data(opponent, NETCODE_DECLINE_MOVE, &code, 1); |
| 863 } |
859 } |
| 864 break; |
860 break; |
| 865 } |
861 } |