1 #include "chess.h"
2 #include "data.h"
3 /* last modified 05/16/14 */
4 /*
5 *******************************************************************************
6 * *
7 * SEE() is used to analyze capture moves to see whether or not they appear *
8 * to be profitable. The basic algorithm is extremely fast since it uses *
9 * the bitmaps to determine which squares are attacking the [target] square. *
10 * *
11 * The algorithm is quite simple. Using the attack bitmaps, we enumerate *
12 * all the pieces that are attacking [target] for either side. Then we *
13 * simply use the lowest piece (value) for the correct side to capture on *
14 * [target]. we continually "flip" sides taking the lowest piece each time. *
15 * *
16 * As a piece is used, if it is a sliding piece (pawn, bishop, rook or *
17 * queen) we remove the piece, then generate moves of bishop/queen or *
18 * rook/queen and then add those in to the attackers, removing any attacks *
19 * that have already been used. *
20 * *
21 *******************************************************************************
22 */
SEE(TREE * RESTRICT tree,int wtm,int move)23 int SEE(TREE * RESTRICT tree, int wtm, int move) {
24 uint64_t attacks, temp = 0, toccupied = OccupiedSquares;
25 uint64_t bsliders =
26 Bishops(white) | Bishops(black) | Queens(white) | Queens(black);
27 uint64_t rsliders =
28 Rooks(white) | Rooks(black) | Queens(white) | Queens(black);
29 int attacked_piece, piece, nc = 1, see_list[32];
30 int source = From(move), target = To(move);
31
32 /*
33 ************************************************************
34 * *
35 * Determine which squares attack <target> for each side. *
36 * initialize by placing the piece on <target> first in *
37 * the list as it is being captured to start things off. *
38 * *
39 ************************************************************
40 */
41 attacks = AttacksTo(tree, target);
42 attacked_piece = pcval[Captured(move)];
43 /*
44 ************************************************************
45 * *
46 * The first piece to capture on <target> is the piece *
47 * standing on <source>. *
48 * *
49 ************************************************************
50 */
51 wtm = Flip(wtm);
52 see_list[0] = attacked_piece;
53 piece = Piece(move);
54 attacked_piece = pcval[piece];
55 Clear(source, toccupied);
56 if (piece & 1)
57 attacks |= BishopAttacks(target, toccupied) & bsliders;
58 if (piece != king && (piece == pawn || piece & 4))
59 attacks |= RookAttacks(target, toccupied) & rsliders;
60 /*
61 ************************************************************
62 * *
63 * Now pick out the least valuable piece for the correct *
64 * side that is bearing on <target>. As we find one, we *
65 * update the attacks (if this is a sliding piece) to get *
66 * the attacks for any sliding piece that is lined up *
67 * behind the attacker we are removing. *
68 * *
69 * Once we know there is a piece attacking the last *
70 * capturing piece, add it to the see list and repeat *
71 * until one side has no more captures. *
72 * *
73 ************************************************************
74 */
75 for (attacks &= toccupied; attacks; attacks &= toccupied) {
76 for (piece = pawn; piece <= king; piece++)
77 if ((temp = Pieces(wtm, piece) & attacks))
78 break;
79 if (piece > king)
80 break;
81 toccupied ^= (temp & -temp);
82 if (piece & 1)
83 attacks |= BishopAttacks(target, toccupied) & bsliders;
84 if (piece != king && piece & 4)
85 attacks |= RookAttacks(target, toccupied) & rsliders;
86 see_list[nc] = -see_list[nc - 1] + attacked_piece;
87 attacked_piece = pcval[piece];
88 if (see_list[nc++] - attacked_piece > 0)
89 break;
90 wtm = Flip(wtm);
91 }
92 /*
93 ************************************************************
94 * *
95 * Starting at the end of the sequence of values, use a *
96 * "minimax" like procedure to decide where the captures *
97 * will stop. *
98 * *
99 ************************************************************
100 */
101 while (--nc)
102 see_list[nc - 1] = -Max(-see_list[nc - 1], see_list[nc]);
103 return see_list[0];
104 }
105
106 /* last modified 05/16/14 */
107 /*
108 *******************************************************************************
109 * *
110 * SEEO() is used to analyze a move already made to see if it appears to be *
111 * safe. It is similar to SEE() except that the move has already been made *
112 * and we are checking to see whether the opponent can gain material by *
113 * capturing the piece just moved. *
114 * *
115 *******************************************************************************
116 */
SEEO(TREE * RESTRICT tree,int wtm,int move)117 int SEEO(TREE * RESTRICT tree, int wtm, int move) {
118 uint64_t attacks, temp = 0, toccupied = OccupiedSquares;
119 uint64_t bsliders =
120 Bishops(white) | Bishops(black) | Queens(white) | Queens(black);
121 uint64_t rsliders =
122 Rooks(white) | Rooks(black) | Queens(white) | Queens(black);
123 int attacked_piece, piece, nc = 1, see_list[32], target = To(move);
124
125 /*
126 ************************************************************
127 * *
128 * Determine which squares attack <target> for each side. *
129 * initialize by placing the piece on <target> first in *
130 * the list as it is being captured to start things off. *
131 * *
132 ************************************************************
133 */
134 attacks = AttacksTo(tree, target);
135 attacked_piece = pcval[Piece(move)];
136 /*
137 ************************************************************
138 * *
139 * The first piece to capture on <target> is the piece *
140 * standing on that square. We have to find out the least *
141 * valuable attacker for that square first. *
142 * *
143 ************************************************************
144 */
145 wtm = Flip(wtm);
146 see_list[0] = attacked_piece;
147 for (piece = pawn; piece <= king; piece++)
148 if ((temp = Pieces(wtm, piece) & attacks))
149 break;
150 if (piece > king)
151 return 0;
152 toccupied ^= (temp & -temp);
153 if (piece & 1)
154 attacks |= BishopAttacks(target, toccupied) & bsliders;
155 if (piece != king && piece & 4)
156 attacks |= RookAttacks(target, toccupied) & rsliders;
157 attacked_piece = pcval[piece];
158 wtm = Flip(wtm);
159 /*
160 ************************************************************
161 * *
162 * Now pick out the least valuable piece for the correct *
163 * side that is bearing on <target>. As we find one, we *
164 * update the attacks (if this is a sliding piece) to get *
165 * the attacks for any sliding piece that is lined up *
166 * behind the attacker we are removing. *
167 * *
168 * Once we know there is a piece attacking the last *
169 * capturing piece, add it to the see list and repeat *
170 * until one side has no more captures. *
171 * *
172 ************************************************************
173 */
174 for (attacks &= toccupied; attacks; attacks &= toccupied) {
175 for (piece = pawn; piece <= king; piece++)
176 if ((temp = Pieces(wtm, piece) & attacks))
177 break;
178 if (piece > king)
179 break;
180 toccupied ^= (temp & -temp);
181 if (piece & 1)
182 attacks |= BishopAttacks(target, toccupied) & bsliders;
183 if (piece != king && piece & 4)
184 attacks |= RookAttacks(target, toccupied) & rsliders;
185 see_list[nc] = -see_list[nc - 1] + attacked_piece;
186 attacked_piece = pcval[piece];
187 if (see_list[nc++] - attacked_piece > 0)
188 break;
189 wtm = Flip(wtm);
190 }
191 /*
192 ************************************************************
193 * *
194 * Starting at the end of the sequence of values, use a *
195 * "minimax" like procedure to decide where the captures *
196 * will stop. *
197 * *
198 ************************************************************
199 */
200 while (--nc)
201 see_list[nc - 1] = -Max(-see_list[nc - 1], see_list[nc]);
202 return see_list[0];
203 }
204