Fix force mode after setboard
[bonanza.git] / swap.c
1 #include <stdlib.h>
2 #include <limits.h>
3 #include <assert.h>
4 #include "shogi.h"
5
6 int CONV
7 swap( const tree_t * restrict ptree, unsigned int move, int root_alpha,
8       int root_beta, int turn )
9 {
10   bitboard_t bb, bb_temp, bb_attack;
11   int attacked_piece, from, to, nc;
12   int piece_cap, piece, value, xvalue, alpha, beta, is_promo;
13
14   from = (int)I2From( move );
15   to   = (int)I2To( move );
16
17   if ( from >= nsquare )
18     {
19       value          = 0;
20       piece          = From2Drop( from );
21       attacked_piece = p_value_ex[15+piece];
22     }
23   else {
24     piece     = (int)I2PieceMove( move );
25     piece_cap = (int)UToCap( move );
26     is_promo  = (int)I2IsPromote( move );
27     
28     value          = p_value_ex[15+piece_cap];
29     attacked_piece = p_value_ex[15+piece];
30     if ( is_promo )
31       {
32         value          += p_value_pm[7+piece];
33         attacked_piece += p_value_pm[7+piece];
34       }
35     xvalue = value - attacked_piece - MT_PRO_PAWN;
36     if ( xvalue >= root_beta ) { return xvalue; }
37   }
38
39   bb_attack = attacks_to_piece( ptree, to );
40   alpha     = INT_MIN;
41   beta      = value;
42   for ( nc = 1;; nc++ )
43     {
44       /* remove an attacker, and add a hidden piece to bb_attack */
45       if ( from < nsquare )
46         {
47           Xor( from, bb_attack );
48           switch ( adirec[to][from] )
49             {
50             case direc_rank:
51               bb = AttackRank( from );
52               if ( from > to ) { BBAnd( bb, bb, abb_plus_rays[from] ); }
53               else             { BBAnd( bb, bb, abb_minus_rays[from] ); }
54               BBOr( bb_temp, BB_B_RD, BB_W_RD );
55               BBAndOr( bb_attack, bb, bb_temp );
56               break;
57
58             case direc_file:
59               bb = AttackFile( from );
60               BBOr( bb_temp, BB_B_RD, BB_W_RD );
61               if ( from > to )
62                 {
63                   BBOr( bb_temp, bb_temp, BB_BLANCE );
64                   BBAnd( bb, bb, abb_plus_rays[from] );
65                 }
66               else {
67                 BBOr( bb_temp, bb_temp, BB_WLANCE );
68                 BBAnd( bb, bb, abb_minus_rays[from] );
69               }
70               BBAnd( bb, bb, bb_temp );
71               BBOr( bb_attack, bb_attack, bb );
72               break;
73               
74             case direc_diag1:
75               bb = AttackDiag1( from );
76               if ( from > to ) { BBAnd( bb, bb, abb_plus_rays[from] ); }
77               else             { BBAnd( bb, bb, abb_minus_rays[from] ); }
78               BBOr( bb_temp, BB_B_BH, BB_W_BH );
79               BBAnd( bb, bb, bb_temp );
80               BBOr( bb_attack, bb_attack, bb );
81               break;
82               
83             case direc_diag2:
84               bb = AttackDiag2( from );
85               if ( from > to ) { BBAnd( bb, bb, abb_plus_rays[from] ); }
86               else               { BBAnd( bb, bb, abb_minus_rays[from] ); }
87               BBOr( bb_temp, BB_B_BH, BB_W_BH );
88               BBAnd( bb, bb, bb_temp );
89               BBOr( bb_attack, bb_attack, bb );
90               break;
91               
92             }
93         }
94
95       /* find the cheapest piece attacks the target */
96       if ( turn ) {
97
98         if ( ! BBContract( bb_attack, BB_BOCCUPY ) ) { break; }
99         value = attacked_piece - value;
100
101         if( BBContract( bb_attack, BB_BPAWN ) )
102           {
103             from           = to+nfile;
104             attacked_piece = MT_CAP_PAWN;
105             if ( to < 27 )
106               {
107                 value          += MT_PRO_PAWN;
108                 attacked_piece += MT_PRO_PAWN;
109               }
110             goto ab_cut;
111           }
112         BBAnd( bb, BB_BLANCE, bb_attack );
113         if( BBTest( bb ) )
114           {
115             from           = FirstOne( bb );
116             attacked_piece = MT_CAP_LANCE;
117             if ( to < 27 )
118               {
119                 value          += MT_PRO_LANCE;
120                 attacked_piece += MT_PRO_LANCE;
121               }
122             goto ab_cut;
123           }
124         BBAnd( bb, BB_BKNIGHT, bb_attack );
125         if( BBTest( bb ) )
126           {
127             from           = FirstOne( bb );
128             attacked_piece = MT_CAP_KNIGHT;
129             if ( to < 27 )
130               {
131                 value          += MT_PRO_KNIGHT;
132                 attacked_piece += MT_PRO_KNIGHT;
133               }
134             goto ab_cut;
135           }
136         BBAnd( bb, BB_BPRO_PAWN, bb_attack );
137         if( BBTest( bb ) )
138           {
139             from           = FirstOne( bb );
140             attacked_piece = MT_CAP_PRO_PAWN;
141             goto ab_cut;
142           }
143         BBAnd( bb, BB_BPRO_LANCE, bb_attack );
144         if( BBTest( bb ) )
145           {
146             from           = FirstOne( bb );
147             attacked_piece = MT_CAP_PRO_LANCE;
148             goto ab_cut;
149           }
150         BBAnd( bb, BB_BPRO_KNIGHT, bb_attack );
151         if( BBTest( bb ) )
152           {
153             from           = FirstOne( bb );
154             attacked_piece = MT_CAP_PRO_KNIGHT;
155             goto ab_cut;
156           }
157         BBAnd( bb, BB_BSILVER, bb_attack );
158         if( BBTest( bb ) )
159           {
160             from           = FirstOne( bb );
161             attacked_piece = MT_CAP_SILVER;
162             if ( from < 27 || to < 27 )
163               {
164                 value          += MT_PRO_SILVER;
165                 attacked_piece += MT_PRO_SILVER;
166               }
167             goto ab_cut;
168           }
169         BBAnd( bb, BB_BPRO_SILVER, bb_attack );
170         if( BBTest( bb ) )
171           {
172             from           = FirstOne( bb );
173             attacked_piece = MT_CAP_PRO_SILVER;
174             goto ab_cut;
175           }
176         BBAnd( bb, BB_BGOLD, bb_attack );
177         if( BBTest( bb ) )
178           {
179             from           = FirstOne( bb );
180             attacked_piece = MT_CAP_GOLD;
181             goto ab_cut;
182           }
183         BBAnd( bb, BB_BBISHOP, bb_attack );
184         if( BBTest( bb ) )
185           {
186             from          = FirstOne( bb );
187             attacked_piece = MT_CAP_BISHOP;
188             if ( from < 27 || to < 27 )
189               {
190                 value          += MT_PRO_BISHOP;
191                 attacked_piece += MT_PRO_BISHOP;
192               }
193             goto ab_cut;
194           }
195         BBAnd( bb, BB_BHORSE, bb_attack );
196         if( BBTest( bb ) )
197           {
198             from           = FirstOne( bb );
199             attacked_piece = MT_CAP_HORSE;
200             goto ab_cut;
201           }
202         BBAnd( bb, BB_BROOK, bb_attack );
203         if( BBTest( bb ) )
204           {
205             from           = FirstOne( bb );
206             attacked_piece = MT_CAP_ROOK;
207             if ( from < 27 || to < 27 )
208               {
209                 value          += MT_PRO_ROOK;
210                 attacked_piece += MT_PRO_ROOK;
211               }
212             goto ab_cut;
213           }
214         BBAnd( bb, BB_BDRAGON, bb_attack );
215         if( BBTest( bb ) )
216           {
217             from           = FirstOne( bb );
218             attacked_piece = MT_CAP_DRAGON;
219             goto ab_cut;
220           }
221         
222         assert( BBContract( bb_attack, BB_BKING ) );
223         
224         from           = SQ_BKING;
225         attacked_piece = MT_CAP_KING;
226         
227       } else {
228         
229         if ( ! BBContract( bb_attack, BB_WOCCUPY ) ) { break; }
230         
231         value = attacked_piece - value;
232
233         if( BBContract( bb_attack, BB_WPAWN ) )
234           {
235             from           = to-nfile;
236             attacked_piece = MT_CAP_PAWN;
237             if ( to > 53 )
238               {
239                 value          += MT_PRO_PAWN;
240                 attacked_piece += MT_PRO_PAWN;
241               }
242             goto ab_cut;
243           }
244         BBAnd( bb, BB_WLANCE, bb_attack );
245         if( BBTest( bb ) )
246           {
247             from           = FirstOne( bb );
248             attacked_piece = MT_CAP_LANCE;
249             if ( to > 53 )
250               {
251                 value          += MT_PRO_LANCE;
252                 attacked_piece += MT_PRO_LANCE;
253               }
254             goto ab_cut;
255           }
256         BBAnd( bb, BB_WKNIGHT, bb_attack );
257         if( BBTest( bb ) )
258           {
259             from           = FirstOne( bb );
260             attacked_piece = MT_CAP_KNIGHT;
261             if ( to > 53 )
262               {
263                 value          += MT_PRO_KNIGHT;
264                 attacked_piece += MT_PRO_KNIGHT;
265               }
266             goto ab_cut;
267           }
268         BBAnd( bb, BB_WPRO_PAWN, bb_attack );
269         if( BBTest( bb ) )
270           {
271             from           = FirstOne( bb );
272             attacked_piece = MT_CAP_PRO_PAWN;
273             goto ab_cut;
274           }
275         BBAnd( bb, BB_WPRO_LANCE, bb_attack );
276         if( BBTest( bb ) )
277           {
278             from           = FirstOne( bb );
279             attacked_piece = MT_CAP_PRO_LANCE;
280             goto ab_cut;
281           }
282         BBAnd( bb, BB_WPRO_KNIGHT, bb_attack );
283         if( BBTest( bb ) )
284           {
285             from           = FirstOne( bb );
286             attacked_piece = MT_CAP_PRO_KNIGHT;
287             goto ab_cut;
288           }
289         BBAnd( bb, BB_WSILVER, bb_attack );
290         if( BBTest( bb ) )
291           {
292             from          = FirstOne( bb );
293             attacked_piece = MT_CAP_SILVER;
294             if ( from > 53 || to > 53 )
295               {
296                 value          += MT_PRO_SILVER;
297                 attacked_piece += MT_PRO_SILVER;
298               }
299             goto ab_cut;
300           }
301         BBAnd( bb, BB_WPRO_SILVER, bb_attack );
302         if( BBTest( bb ) )
303           {
304             from           = FirstOne( bb );
305             attacked_piece = MT_CAP_PRO_SILVER;
306             goto ab_cut;
307           }
308         BBAnd( bb, BB_WGOLD, bb_attack );
309         if( BBTest( bb ) )
310           {
311             from           = FirstOne( bb );
312             attacked_piece = MT_CAP_GOLD;
313             goto ab_cut;
314           }
315         BBAnd( bb, BB_WBISHOP, bb_attack );
316         if( BBTest( bb ) )
317           {
318             from           = FirstOne( bb );
319             attacked_piece = MT_CAP_BISHOP;
320             if ( from > 53 || to > 53 )
321               {
322                 value          += MT_PRO_BISHOP;
323                 attacked_piece += MT_PRO_BISHOP;
324               }
325             goto ab_cut;
326           }
327         BBAnd( bb, BB_WHORSE, bb_attack );
328         if( BBTest( bb ) )
329           {
330             from           = FirstOne( bb );
331             attacked_piece = MT_CAP_HORSE;
332             goto ab_cut;
333           }
334         BBAnd( bb, BB_WROOK, bb_attack );
335         if( BBTest( bb ) )
336           {
337             from           = FirstOne( bb );
338             attacked_piece = MT_CAP_ROOK;
339             if ( from > 53 || to > 53 )
340               {
341                 value          += MT_PRO_ROOK;
342                 attacked_piece += MT_PRO_ROOK;
343               }
344             goto ab_cut;
345           }
346         BBAnd( bb, BB_WDRAGON, bb_attack );
347         if( BBTest( bb ) )
348           {
349             from           = FirstOne( bb );
350             attacked_piece = MT_CAP_DRAGON;
351             goto ab_cut;
352           }
353         
354         assert( BBContract( bb_attack, BB_WKING ) );
355         from           = SQ_WKING;
356         attacked_piece = MT_CAP_KING;
357       }
358
359     ab_cut:
360       turn = Flip( turn );
361       if ( nc & 1 )
362         {
363           if ( -value > alpha )
364             {
365               if ( -value >= beta )      { return beta; }
366               if ( -value >= root_beta ) { return -value; }
367               alpha = -value;
368             }
369           else {
370             xvalue = attacked_piece + MT_PRO_PAWN - value;
371             if ( xvalue <= alpha )      { return alpha; }
372             if ( xvalue <= root_alpha ) { return xvalue; }
373           }
374         }
375       else {
376         if ( value < beta )
377           {
378             if ( value <= alpha )      { return alpha; }
379             if ( value <= root_alpha ) { return value; }
380             beta = value;
381           }
382         else {
383           xvalue = value - attacked_piece - MT_PRO_PAWN;
384           if ( xvalue >= beta )      { return beta; }
385           if ( xvalue >= root_beta ) { return xvalue; }
386         }
387       }
388     }
389   
390   if ( nc & 1 ) { return beta; }
391   else          { return alpha; }
392 }