per test
[rattatechess.git] / attack.cpp
blob17760a68845aeb08039310f6d4cdc4b704a5bdfd
1 /***************************************************************************
2 attack.cpp - Implmentation of attacking-related functions
3 -------------------
4 begin : Dom Oct 30 2005
5 copyright : (C) 2005 by Maurizio Monge
6 email : monge@linuz.sns.it
7 ***************************************************************************/
9 /***************************************************************************
10 * *
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the GNU General Public License as published by *
13 * the Free Software Foundation; either version 2 of the License, or *
14 * (at your option) any later version. *
15 * *
16 ***************************************************************************/
18 #include "board.h"
21 bool
22 Board::under_attack(uint8_t pos,uint8_t attacker)
24 A88 d = data;
25 uint8_t check;
26 uint8_t killer;
28 #if TRACK_ATTACKS
29 #ifdef DEBUG
30 check_attacks();
31 #endif
33 /* check bishop or rook attacks */
34 A88 attacks = IS_WHITE(attacker) ? w_attacks : b_attacks;
35 if(attacks[pos])
36 return true;
37 #endif //TRACK_ATTACKS
39 /* check if attacked by a knight */
40 killer = KNIGHT|attacker;
42 KnightMove* hm= &knightmoves[pos];
43 for(int i=hm->numm;i>=0;i--)
45 register uint8_t tmp = hm->jump[i];
46 if(d[tmp] == killer)
47 return true;
51 #if !TRACK_ATTACKS
52 uint8_t inc;
54 /* check bishop (or queen) attacks */
55 killer = BISHOP|attacker;
57 for(int i=3;i>=0;i--)
59 inc = bishmoves[i];
60 check = pos;
63 check += inc;
64 if(OUT_OF_BOARD(check))
65 break;
66 if((d[check] & ((uint8_t)~ROOK)) == killer)
67 return true;
69 while(IS_VOID(d[check]));
72 /* check rook (or queen) attacks */
73 killer = ROOK|attacker;
75 for(int i=3;i>=0;i--)
77 inc = rookmoves[i];
78 check = pos;
81 check += inc;
82 if(OUT_OF_BOARD(check))
83 break;
84 if((d[check] & ((uint8_t)~BISHOP)) == killer)
85 return true;
87 while(IS_VOID(d[check]));
89 #endif // !TRACK_ATTACKS
91 /* check if attacked by a pawn */
93 killer = PAWN|attacker;
94 check = pos - up_dir[IS_WHITE(attacker)] + RIGHT;
95 if(!OUT_OF_BOARD(check) && (d[check] == killer))
96 return true;
98 check += 2*LEFT;
99 if(!OUT_OF_BOARD(check) && (d[check] == killer))
100 return true;
103 /* check if attacked by the other king */
105 killer = KING|attacker;
106 for(int i=7;i>=0;i--)
108 check = pos + kingmoves[i];
109 if(OUT_OF_BOARD(check))
110 continue;
111 if(d[check] == killer)
112 return true;
115 return false;
118 /* count attackes (end possibly defenders) of a piece/square.
119 an array is passed to give info about pinned attacker pieces */
121 Board::list_attackers(uint8_t pos, uint8_t attacker, A88 pins, AttackList* a)
123 A88 d = data;
124 uint8_t killer;
125 int num_atck = 0;
127 a[num_atck].curr = a[num_atck].count = 0;
129 /* check if attacked by a knight */
130 killer = KNIGHT|attacker;
132 KnightMove* hm= &knightmoves[pos];
133 for(int i=hm->numm;i>=0;i--)
135 register uint8_t tmp = hm->jump[i];
136 if(d[tmp] == killer && !pins[tmp])
137 a[num_atck].piece[a[num_atck].count++] = KNIGHT;
141 /* check if attacked by the king.
142 the king cannot be pinned, at least :) */
144 int deltax = X(king_pos[IS_WHITE(attacker)])-X(pos);
145 int deltay = Y(king_pos[IS_WHITE(attacker)])-Y(pos);
146 if(ABS(deltax)<=1 && ABS(deltay)<=1)
147 a[num_atck].piece[a[num_atck].count++] = KING;
150 if(a[num_atck].count)
151 num_atck++;
153 #if TRACK_ATTACKS
154 A88 attacks = IS_WHITE(attacker) ? w_attacks : b_attacks;
155 uint8_t up1 = up_dir[1-IS_WHITE(attacker)] + LEFT;
156 uint8_t up2 = up_dir[1-IS_WHITE(attacker)] + RIGHT;
158 for(int r=0;r<8;r++)
160 uint8_t m = 1<<r;
162 if(!(attacks[pos] & m))
163 continue;
165 uint8_t inc = -attack_dirs[r];
166 uint8_t currpos = pos+inc;
167 a[num_atck].curr = a[num_atck].count = 0;
169 if( (inc == up1 || inc == up2)
170 && !OUT_OF_BOARD(currpos)
171 && d[currpos]==(PAWN|attacker) )
173 /* we found a pawn, enlist it and skip */
174 a[num_atck].piece[a[num_atck].count++] = PAWN;
175 currpos += inc;
178 while(!OUT_OF_BOARD(currpos))
180 if(d[currpos])
182 a[num_atck].piece[a[num_atck].count++] = PIECE_OF(d[currpos]);
183 if(!(attacks[currpos] & m))
184 break;
187 currpos += inc;
190 if(a[num_atck].count)
191 num_atck++;
193 #else //TRACK_ATTACKS
194 /* check bishop (or queen) attacks */
195 killer = BISHOP|attacker;
197 for(int i=3;i>=0;i--)
199 uint8_t inc = bishmoves[i];
200 uint8_t currpos = pos+inc;
201 a[num_atck].curr = a[num_atck].count = 0;
203 if(OUT_OF_BOARD(currpos))
204 continue;
205 if( ( (0xf0&(inc+1)) == up_dir[1-IS_WHITE(attacker)])
206 && d[currpos]==(PAWN|attacker)
207 && (!pins[currpos] || ((pins[currpos]&DIAG) &&
208 (bishmoves[pins[currpos]&0x0f]==inc ||
209 bishmoves[pins[currpos]&0x0f]==(uint8_t)-inc))))
211 /* we found a pawn, enlist it and skip */
212 a[num_atck].piece[a[num_atck].count++] = PAWN;
213 currpos += inc;
216 while(1)
218 if(OUT_OF_BOARD(currpos))
219 break;
220 if( ((d[currpos] & ((uint8_t)~ROOK))==killer)
221 && (!pins[currpos] || ((pins[currpos]&DIAG) &&
222 (bishmoves[pins[currpos]&0x0f]==inc ||
223 bishmoves[pins[currpos]&0x0f]==(uint8_t)-inc))))
224 a[num_atck].piece[a[num_atck].count++] = PIECE_OF(d[currpos]);
225 else if(d[currpos])
226 break;
227 currpos += inc;
229 if(a[num_atck].count)
230 num_atck++;
233 /* check rook (or queen) attacks */
234 killer = ROOK|attacker;
236 for(int i=3;i>=0;i--)
238 uint8_t inc = rookmoves[i];
239 uint8_t currpos = pos+inc;
240 a[num_atck].curr = a[num_atck].count = 0;
242 while(1)
244 if(OUT_OF_BOARD(currpos))
245 break;
246 if( ((d[currpos] & ((uint8_t)~BISHOP)) == killer)
247 && (!pins[currpos] || ((pins[currpos]&COLM) &&
248 (rookmoves[pins[currpos]&0x0f]==inc ||
249 rookmoves[pins[currpos]&0x0f]==(uint8_t)-inc))))
250 a[num_atck].piece[a[num_atck].count++] = PIECE_OF(d[currpos]);
251 else if(d[currpos])
252 break;
253 currpos += inc;
255 if(a[num_atck].count)
256 num_atck++;
258 #endif //TRACK_ATTACKS
260 return num_atck;
264 Board::propagate_see(uint8_t victim, int numa, AttackList* a, int numd, AttackList* d)
266 uint8_t newvict = KING;
267 int idxnewvict = -1;
269 for(int i=0;i<numa;i++)
270 if(a[i].curr < a[i].count)
272 if(idxnewvict==-1 || simple_values[a[i].piece[a[i].curr]] < simple_values[newvict])
274 idxnewvict = i;
275 newvict = a[i].piece[a[i].curr];
279 if(idxnewvict == -1)
280 return 0;
282 a[idxnewvict].curr++;
283 return MAX(0, simple_values[victim] - propagate_see(newvict, numd, d, numa, a) );
286 /* calculate how much is winning the exchange sequence stating with Move */
288 Board::move_see_val(const Move& m)
290 AttackList atck[12];
291 AttackList def[12];
292 int atck_num;
293 int def_num;
295 uint8_t piece = data[m.from];
296 int bof = simple_values[PIECE_OF(data[m.to])] - simple_values[PIECE_OF(piece)];
297 if(bof>0)
298 return bof;
300 data[m.from] = 0;
301 #if TRACK_ATTACKS
302 del_attacks(piece, m.from);
303 #endif //TRACK_ATTACKS
304 atck_num = list_attackers(m.to, color_to_move, pins, atck);
305 def_num = list_attackers(m.to, other_color, oth_pins, def);
306 data[m.from] = piece;
307 #if TRACK_ATTACKS
308 add_attacks(piece, m.from);
309 #endif //TRACK_ATTACKS
311 return simple_values[PIECE_OF(m.capture)] -
312 propagate_see( PIECE_OF(data[m.from]), def_num, def, atck_num, atck);