Implement undo command
[bonanza.git] / valid.c
1 #include <assert.h>
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include "shogi.h"
5
6
7 int
8 is_move_valid( tree_t * restrict __ptree__, unsigned int move, int turn )
9 {
10   tree_t * restrict ptree = __ptree__;
11   int from = (int)I2From(move);
12   int to   = (int)I2To(move);
13   int piece_move;
14   unsigned int u;
15   bitboard_t bb;
16
17   if ( from < nsquare )
18     {
19       piece_move = (int)I2PieceMove(move);
20       if ( turn )
21         {
22           if ( BOARD[from] != -piece_move )       { return 0; }
23           if ( BOARD[to]   != (int)UToCap(move) ) { return 0; }
24         }
25       else {
26         if ( BOARD[from] !=  piece_move )        { return 0; }
27         if ( BOARD[to]   != -(int)UToCap(move) ) { return 0; }
28       }
29       
30       switch ( piece_move )
31         {
32         case 0:  return 0;
33
34         case lance:  case bishop:  case horse:  case rook:  case dragon:
35           BBOr( bb, BB_BOCCUPY, BB_WOCCUPY );
36           BBAnd( bb, bb, abb_obstacle[from][to] );
37           if ( BBToU( bb ) ) { return 0; }
38           break;
39         }
40
41       return 1;
42     }
43
44   if ( BOARD[to] ) { return 0; }
45   else {
46     u = turn ? HAND_W : HAND_B;
47     switch ( From2Drop(from) )
48       {
49       case pawn:
50         if ( ! IsHandPawn(u) ) { return 0; }
51         {
52           if ( turn )
53             {
54               u = BBToU( BB_WPAWN_ATK );
55               if ( ( mask_file1 >> aifile[to] ) & u ) { return 0; }
56               if ( IsMateWPawnDrop(__ptree__, to) )   { return 0; }
57             }
58           else {
59             u = BBToU( BB_BPAWN_ATK );
60             if ( ( mask_file1 >> aifile[to] ) & u ) { return 0; }
61             if ( IsMateBPawnDrop(__ptree__, to) )   { return 0; }
62           }
63           return 1;
64         }
65       case lance:   if ( IsHandLance(u) )  { return 1; }  break;
66       case knight:  if ( IsHandKnight(u) ) { return 1; }  break;
67       case silver:  if ( IsHandSilver(u) ) { return 1; }  break;
68       case gold:    if ( IsHandGold(u) )   { return 1; }  break;
69       case bishop:  if ( IsHandBishop(u) ) { return 1; }  break;
70       default:      assert( From2Drop(from) == rook );
71                     if ( IsHandRook(u) )   { return 1; }  break;
72       }
73   }
74   return 0;
75 }
76
77
78 #define NpchkReturn(piece) if ( (n ## piece) > (n ## piece ## _max) ) {  \
79                              str_error = "too many " # piece "s";        \
80                              return -2; }
81
82 int
83 exam_tree( const tree_t * restrict ptree )
84 {
85   int npawn, nlance, nknight, nsilver, ngold, nbishop, nrook;
86   int nwking, nbking, isquare, ifile, irank, wcounter, bcounter;
87
88   /* total number of each piece */
89   npawn   = (int)(I2HandPawn( HAND_B )   + I2HandPawn( HAND_W ));
90   nlance  = (int)(I2HandLance( HAND_B )  + I2HandLance( HAND_W ));
91   nknight = (int)(I2HandKnight( HAND_B ) + I2HandKnight( HAND_W ));
92   nsilver = (int)(I2HandSilver( HAND_B ) + I2HandSilver( HAND_W ));
93   ngold   = (int)(I2HandGold( HAND_B )   + I2HandGold( HAND_W ));
94   nbishop = (int)(I2HandBishop( HAND_B ) + I2HandBishop( HAND_W ));
95   nrook   = (int)(I2HandRook( HAND_B )   + I2HandRook( HAND_W ));
96   nwking = nbking = 0;
97
98   for ( isquare = 0; isquare < nsquare; isquare++ )
99     switch ( abs( BOARD[isquare] ) )
100       {
101       case empty:                                 break;
102       case pawn:    case pro_pawn:    npawn++;    break;
103       case lance:   case pro_lance:   nlance++;   break;
104       case knight:  case pro_knight:  nknight++;  break;
105       case silver:  case pro_silver:  nsilver++;  break;
106       case gold:                      ngold++;    break;
107       case bishop:  case horse:       nbishop++;  break;
108       case rook:    case dragon:      nrook++;    break;
109       case king:
110         if ( BOARD[isquare] == king ) { nbking++; }
111         else                            { nwking++; }
112         break;
113       }
114   NpchkReturn( pawn );    NpchkReturn( lance );
115   NpchkReturn( knight );  NpchkReturn( silver );
116   NpchkReturn( gold );    NpchkReturn( bishop );
117   NpchkReturn( rook );
118   if ( nbking != 1 || nwking != 1 )
119     {
120       str_error = "invalid number of kings";
121       return -2;
122     }
123
124   /* double pawns */
125   for ( ifile = 0; ifile < 9; ifile++ )
126     {
127       bcounter = wcounter = 0;
128       for ( irank = 0; irank < 9; irank++ )
129         {
130           if ( BOARD[ irank*nfile+ifile ] ==  pawn ) { bcounter++; }
131           if ( BOARD[ irank*nfile+ifile ] == -pawn ) { wcounter++; }
132         }
133       if ( bcounter > 1 )
134         {
135           str_error = "two black pawns at a file";
136           return -2;
137         }
138       if ( wcounter > 1 )
139         {
140           str_error="two white pawns at a file";
141           return -2;
142         }
143     }
144
145   /* pieces can not move */
146   for ( isquare = 0; isquare < 9; isquare++ )
147     {
148       if ( BOARD[ isquare ] == pawn )
149         {
150           str_error = "black pawns in rank 1";
151           return -2;
152         }
153       if ( BOARD[ isquare ] == lance )
154         {
155           str_error = "black lances in rank 1";
156           return -2;
157         }
158     }
159   for ( isquare = 0; isquare < 18; isquare++ )
160     if ( BOARD[ isquare ] == knight )
161       {
162         str_error = "black knights in rank 1-2";
163         return -2;
164       }
165
166   for ( isquare = 72; isquare < 81; isquare++ )
167     {
168       if ( BOARD[ isquare ] == -pawn )
169         {
170           str_error = "white pawns in rank 9";
171           return -2;
172         }
173       if ( BOARD[ isquare ] == -lance )
174         {
175           str_error = "white lances in rank 9";
176           return -2;
177         }
178     }
179   for ( isquare = 63; isquare < 81; isquare++ )
180     if ( BOARD[ isquare ] == -knight )
181       {
182         str_error = "white knights in rank 8-9";
183         return -2;
184       }
185
186   if ( InCheck( Flip(root_turn) ) )
187     {
188       str_error = str_king_hang;
189       return -2;
190     }
191
192   assert( exam_bb( ptree ) );
193
194   return 1;
195 }
196
197 #undef NpchkReturn