51 case 'K': return KING; |
75 case 'K': return KING; |
52 default: return 0; |
76 default: return 0; |
53 } |
77 } |
54 } |
78 } |
55 |
79 |
56 /** |
80 static int getlocation(GameState *gamestate, Move *move) { |
57 * Guesses the location of a piece for short algebraic notation. |
|
58 * |
|
59 * @param board the current state of the board |
|
60 * @param move the move date to operate on |
|
61 * @return status code (see rules/rules.h for the codes) |
|
62 */ |
|
63 static int getlocation(Board board, Move *move) { |
|
64 uint8_t piece = move->piece & PIECE_MASK; |
81 uint8_t piece = move->piece & PIECE_MASK; |
65 switch (piece) { |
82 switch (piece) { |
66 case PAWN: return pawn_getlocation(board, move); |
83 case PAWN: return pawn_getlocation(gamestate, move); |
67 case ROOK: return rook_getlocation(board, move); |
84 case ROOK: return rook_getlocation(gamestate, move); |
68 case KNIGHT: return knight_getlocation(board, move); |
85 case KNIGHT: return knight_getlocation(gamestate, move); |
69 case BISHOP: return bishop_getlocation(board, move); |
86 case BISHOP: return bishop_getlocation(gamestate, move); |
70 case QUEEN: return queen_getlocation(board, move); |
87 case QUEEN: return queen_getlocation(gamestate, move); |
71 case KING: return king_getlocation(board, move); |
88 case KING: return king_getlocation(gamestate, move); |
72 default: return INVALID_MOVE_SYNTAX; |
89 default: return INVALID_MOVE_SYNTAX; |
73 } |
90 } |
74 } |
91 } |
75 |
92 |
76 |
93 |
77 void apply_move(Board board, Move *move) { |
94 void apply_move(GameState *gamestate, Move *move) { |
78 uint8_t piece = move->piece & PIECE_MASK; |
95 uint8_t piece = move->piece & PIECE_MASK; |
79 uint8_t color = move->piece & COLOR_MASK; |
96 uint8_t color = move->piece & COLOR_MASK; |
80 |
97 |
81 /* en passant capture */ |
98 /* en passant capture */ |
82 if (move->capture && piece == PAWN && |
99 if (move->capture && piece == PAWN && |
83 mdst(board, move) == 0) { |
100 mdst(gamestate->board, move) == 0) { |
84 board[move->fromrow][move->tofile] = 0; |
101 gamestate->board[move->fromrow][move->tofile] = 0; |
85 } |
102 } |
86 |
103 |
87 /* remove old en passant threats */ |
104 /* remove old en passant threats */ |
88 for (uint8_t file = 0 ; file < 8 ; file++) { |
105 for (uint8_t file = 0 ; file < 8 ; file++) { |
89 board[3][file] &= ~ENPASSANT_THREAT; |
106 gamestate->board[3][file] &= ~ENPASSANT_THREAT; |
90 board[4][file] &= ~ENPASSANT_THREAT; |
107 gamestate->board[4][file] &= ~ENPASSANT_THREAT; |
91 } |
108 } |
92 |
109 |
93 /* add new en passant threat */ |
110 /* add new en passant threat */ |
94 if (piece == PAWN && ( |
111 if (piece == PAWN && ( |
95 (move->fromrow == 1 && move->torow == 3) || |
112 (move->fromrow == 1 && move->torow == 3) || |
96 (move->fromrow == 6 && move->torow == 4))) { |
113 (move->fromrow == 6 && move->torow == 4))) { |
97 move->piece |= ENPASSANT_THREAT; |
114 move->piece |= ENPASSANT_THREAT; |
98 } |
115 } |
99 |
116 |
100 /* move (and maybe capture or promote) */ |
117 /* move (and maybe capture or promote) */ |
101 msrc(board, move) = 0; |
118 msrc(gamestate->board, move) = 0; |
102 if (move->promotion) { |
119 if (move->promotion) { |
103 mdst(board, move) = move->promotion; |
120 mdst(gamestate->board, move) = move->promotion; |
104 } else { |
121 } else { |
105 mdst(board, move) = move->piece; |
122 mdst(gamestate->board, move) = move->piece; |
106 } |
123 } |
107 |
124 |
108 /* castling */ |
125 /* castling */ |
109 if (piece == KING && |
126 if (piece == KING && |
110 move->fromfile == fileidx('e')) { |
127 move->fromfile == fileidx('e')) { |
111 |
128 |
112 if (move->tofile == fileidx('g')) { |
129 if (move->tofile == fileidx('g')) { |
113 board[move->torow][fileidx('h')] = 0; |
130 gamestate->board[move->torow][fileidx('h')] = 0; |
114 board[move->torow][fileidx('f')] = color|ROOK; |
131 gamestate->board[move->torow][fileidx('f')] = color|ROOK; |
115 } else if (move->tofile == fileidx('c')) { |
132 } else if (move->tofile == fileidx('c')) { |
116 board[move->torow][fileidx('a')] = 0; |
133 gamestate->board[move->torow][fileidx('a')] = 0; |
117 board[move->torow][fileidx('d')] = color|ROOK; |
134 gamestate->board[move->torow][fileidx('d')] = color|ROOK; |
118 } |
135 } |
119 } |
136 } |
120 } |
137 |
121 |
138 addmove(gamestate, move); |
122 _Bool validate_move(Board board, Move *move) { |
139 } |
|
140 |
|
141 _Bool validate_move(GameState *gamestate, Move *move) { |
123 _Bool result; |
142 _Bool result; |
124 |
143 |
125 /* validate indices (don't trust opponent) */ |
144 /* validate indices (don't trust opponent) */ |
126 if (!chkidx(move)) { |
145 if (!chkidx(move)) { |
127 return 0; |
146 return 0; |
131 if (move->fromfile == move->tofile && move->fromrow == move->torow) { |
150 if (move->fromfile == move->tofile && move->fromrow == move->torow) { |
132 return 0; |
151 return 0; |
133 } |
152 } |
134 |
153 |
135 /* does piece exist */ |
154 /* does piece exist */ |
136 result = msrc(board, move) == move->piece; |
155 result = msrc(gamestate->board, move) == move->piece; |
137 |
156 |
138 /* can't capture own pieces */ |
157 /* can't capture own pieces */ |
139 if ((mdst(board, move) & COLOR_MASK) == (move->piece & COLOR_MASK)) { |
158 if ((mdst(gamestate->board, move) & COLOR_MASK) |
|
159 == (move->piece & COLOR_MASK)) { |
140 return 0; |
160 return 0; |
141 } |
161 } |
142 |
162 |
143 /* validate individual rules */ |
163 /* validate individual rules */ |
144 switch (move->piece & PIECE_MASK) { |
164 switch (move->piece & PIECE_MASK) { |
145 case PAWN: |
165 case PAWN: |
146 result = result && pawn_chkrules(board, move); |
166 result = result && pawn_chkrules(gamestate, move); |
147 result = result && !pawn_isblocked(board, move); |
167 result = result && !pawn_isblocked(gamestate, move); |
148 break; |
168 break; |
149 case ROOK: |
169 case ROOK: |
150 result = result && rook_chkrules(move); |
170 result = result && rook_chkrules(move); |
151 result = result && !rook_isblocked(board, move); |
171 result = result && !rook_isblocked(gamestate, move); |
152 break; |
172 break; |
153 case KNIGHT: |
173 case KNIGHT: |
154 result = result && knight_chkrules(move); |
174 result = result && knight_chkrules(move); |
155 result = result && !knight_isblocked(board, move); |
175 result = result && !knight_isblocked(gamestate, move); |
156 break; |
176 break; |
157 case BISHOP: |
177 case BISHOP: |
158 result = result && bishop_chkrules(move); |
178 result = result && bishop_chkrules(move); |
159 result = result && !bishop_isblocked(board, move); |
179 result = result && !bishop_isblocked(gamestate, move); |
160 break; |
180 break; |
161 case QUEEN: |
181 case QUEEN: |
162 result = result && queen_chkrules(move); |
182 result = result && queen_chkrules(move); |
163 result = result && !queen_isblocked(board, move); |
183 result = result && !queen_isblocked(gamestate, move); |
164 break; |
184 break; |
165 case KING: |
185 case KING: |
166 result = result && king_chkrules(board, move); |
186 result = result && king_chkrules(gamestate, move); |
167 result = result && !king_isblocked(board, move); |
187 result = result && !king_isblocked(gamestate, move); |
168 break; |
188 break; |
169 default: |
189 default: |
170 result = 0; |
190 result = 0; |
171 } |
191 } |
172 |
192 |