pos.c (6742B)
1 #include <assert.h> 2 #include <immintrin.h> 3 #include <stdbool.h> 4 #include <stdio.h> 5 #include <stdlib.h> 6 7 #include "bb.h" 8 #include "pos.h" 9 10 unsigned char 11 side(unsigned char p) { 12 return p >> 3; 13 } 14 15 unsigned char 16 piece(unsigned char p) { 17 return p & 7; 18 } 19 20 unsigned char 21 rank(unsigned char sq) { 22 return sq >> 3; 23 } 24 25 unsigned char 26 file(unsigned char sq) { 27 return sq & 7; 28 } 29 30 unsigned char 31 square(unsigned char r, unsigned char f) { 32 return r*8 + f; 33 } 34 35 void 36 setpiece(pos *p, unsigned char pc, unsigned char sq) { 37 setbit(&p->sides[side(pc)], sq); 38 setbit(&p->pieces[piece(pc)], sq); 39 p->mailbox[sq] = pc; 40 } 41 42 void 43 reset_board(pos *p) { 44 int i; 45 for (i = 0; i < 2; i++) p->sides[i] = 0; 46 for (i = 0; i < 6; i++) p->pieces[i] = 0; 47 for (i = 0; i < 64; i++) p->mailbox[i] = nP; 48 p->castle = 0; 49 p->enpas = NO_SQ; 50 p->fifty = 0; 51 p->game_length = 0; 52 p->turn = WHITE; 53 } 54 55 void 56 parse_fen(pos *p, char *fen) { 57 reset_board(p); 58 59 char phase, sq; 60 61 phase = 0; 62 sq = 56; 63 64 while (*fen) { 65 /* Piece placement */ 66 if (phase == 0) { 67 switch (*fen) { 68 /* Place a piece on the current square */ 69 case 'P': setpiece(p, wP, sq); sq++; break; 70 case 'N': setpiece(p, wN, sq); sq++; break; 71 case 'B': setpiece(p, wB, sq); sq++; break; 72 case 'R': setpiece(p, wR, sq); sq++; break; 73 case 'Q': setpiece(p, wQ, sq); sq++; break; 74 case 'K': setpiece(p, wK, sq); sq++; break; 75 case 'p': setpiece(p, bP, sq); sq++; break; 76 case 'n': setpiece(p, bN, sq); sq++; break; 77 case 'b': setpiece(p, bB, sq); sq++; break; 78 case 'r': setpiece(p, bR, sq); sq++; break; 79 case 'q': setpiece(p, bQ, sq); sq++; break; 80 case 'k': setpiece(p, bK, sq); sq++; break; 81 82 /* Move over to the rightby the number specified */ 83 case '1': 84 case '2': 85 case '3': 86 case '4': 87 case '5': 88 case '6': 89 case '7': 90 case '8': 91 /* In case you were unaware, subtracting '0' from an ascii 92 * character which is a number gives the integer value of 93 * the number. For example, '8' - '0' = 8. */ 94 sq += *fen - '0'; 95 break; 96 97 case '/': 98 /* This should only occur after we have moved past the last 99 * column in the current row. We will be placed in the 100 * first column of the row above the current one, but we 101 * would want to be in the row below us, so we get shifted 102 * by 2 rows downwards. */ 103 assert(sq % 8 == 0); 104 sq -= 16; 105 break; 106 107 case ' ': 108 phase = 1; 109 fen++; 110 break; 111 112 default: 113 /* There was an error in the fen */ 114 printf("Fen error, character %c, sq %d", *fen, sq); 115 } 116 } 117 118 /* Turn */ 119 if (phase == 1) { 120 fen++; 121 if (*fen == 'w') { 122 p->turn = WHITE; 123 } else { 124 p->turn = BLACK; 125 } 126 phase++; 127 fen += 2; 128 } 129 130 /* Castling rights */ 131 if (phase == 2 && *fen != ' ') { 132 switch (*fen) { 133 /* The castling rights value is a bitset, i.e. each of the 134 * first four bits represent a different castling right. */ 135 case 'K': p->castle |= 8; break; 136 case 'Q': p->castle |= 4; break; 137 case 'k': p->castle |= 2; break; 138 case 'q': p->castle |= 1; break; 139 140 /* If it is not one of these characters there is 141 * something wrong with the fen */ 142 default: printf("Fen error"); 143 } 144 } else if (phase == 2) phase++; 145 146 /* En passant */ 147 if (phase == 3) { 148 fen++; 149 /* Extract the column and row */ 150 char c = *fen - 'a'; 151 fen++; 152 char r = *fen - '1'; 153 /* Calculate the square based on the column and row */ 154 p->enpas = square(r, c); 155 fen+=2; 156 } 157 158 /* I cant be bothered to do the rest right now */ 159 160 161 162 /* Fifty-move rule */ 163 164 /* Turn count */ 165 166 fen++; 167 } 168 } 169 170 #ifndef NDEBUG 171 void 172 print_board(pos *p) { 173 int r,c; 174 for (r = 7; r >= 0; r--) { 175 for (c = 0; c <= 7; c++) { 176 /* This is a funky string index lookup thing where the piece at the 177 * current square is the index in the string */ 178 putchar("pnbrqk PNBRQK."[p->mailbox[square(r,c)]]); 179 } 180 puts(""); 181 } 182 } 183 #endif 184 185 /* Piece attack bitboards */ 186 187 int 188 slider_idx(char sq, bb occ, magic magic) { 189 return _pext_u64(occ, magic.mask); 190 } 191 192 193 bb knight_attacks[64]; 194 bb king_attacks[64]; 195 magic bishop_magics[64]; 196 magic rook_magics[64]; 197 198 bb 199 knight_att(char sq) { 200 return knight_attacks[sq]; 201 } 202 203 bb 204 king_att(char sq) { 205 return king_attacks[sq]; 206 } 207 208 bb 209 bishop_att(char sq, bb occ) { 210 return bishop_magics[sq].attacks[slider_idx(sq, occ, bishop_magics[sq])]; 211 } 212 213 bb 214 rook_att(char sq, bb occ) { 215 return rook_magics[sq].attacks[slider_idx(sq, occ, rook_magics[sq])]; 216 } 217 218 bb 219 queen_att(char sq, bb occ) { 220 return bishop_att(sq, occ) | rook_att(sq, occ); 221 } 222 223 void 224 gen_knight_attacks(void) { 225 char sq; 226 for (sq = 0; sq < 64; sq++) { 227 knight_attacks[sq] = (1ULL << sq >> 17) & 0xFEFEFEFEFEFEFEFE; 228 knight_attacks[sq] |= (1ULL << sq >> 15) & 0x7F7F7F7F7F7F7F7F; 229 knight_attacks[sq] |= (1ULL << sq >> 9) & 0xFCFCFCFCFCFCFCFC; 230 knight_attacks[sq] |= (1ULL << sq >> 7) & 0x3F3F3F3F3F3F3F3F; 231 knight_attacks[sq] |= (1ULL << sq << 7) & 0xFCFCFCFCFCFCFCFC; 232 knight_attacks[sq] |= (1ULL << sq << 9) & 0x3F3F3F3F3F3F3F3F; 233 knight_attacks[sq] |= (1ULL << sq << 15) & 0xFEFEFEFEFEFEFEFE; 234 knight_attacks[sq] |= (1ULL << sq << 17) & 0x7F7F7F7F7F7F7F7F; 235 } 236 } 237 238 void 239 gen_king_attacks(void) { 240 char sq; 241 for (sq = 0; sq < 64; sq++) { 242 king_attacks[sq] = (1ULL << sq >> 9) & 0xFEFEFEFEFEFEFEFE; 243 king_attacks[sq] |= (1ULL << sq >> 8); 244 king_attacks[sq] |= (1ULL << sq >> 7) & 0x7F7F7F7F7F7F7F7F; 245 king_attacks[sq] |= (1ULL << sq >> 1) & 0xFEFEFEFEFEFEFEFE; 246 king_attacks[sq] |= (1ULL << sq << 1) & 0x7F7F7F7F7F7F7F7F; 247 king_attacks[sq] |= (1ULL << sq << 7) & 0xFEFEFEFEFEFEFEFE; 248 king_attacks[sq] |= (1ULL << sq << 8); 249 king_attacks[sq] |= (1ULL << sq << 9) & 0x7F7F7F7F7F7F7F7F; 250 } 251 } 252 253 /* Sliding attacks are weird */ 254 255 bb 256 get_slider_attack(char sq, bb occ, char dirs[4]) { 257 char dir; 258 bb s, att; 259 for (dir = 0; dir < 4; dir++) { 260 s = 1ULL << sq; 261 while ((s = shift(s, dirs[dir]))) { 262 att |= s; 263 s &= ~occ; 264 } 265 } 266 return att; 267 } 268 269 void 270 gen_magic(char sq, magic magics[64], char dirs[4]) { 271 bb occ, edges; 272 273 edges = 0xFF000000000000FF & ~(0xFF << 8*rank(sq)); 274 edges |= 0x8181818181818181 & ~(0x0101010101010101 << file(sq)); 275 276 occ = magics[sq].mask = get_slider_attack(sq, 0, dirs) & ~edges; 277 278 magics[sq].attacks = malloc((1 << popcnt(occ)) * sizeof(bb)); 279 /* Magic bit hacking to loop over all relevant occupancies */ 280 do { 281 magics[sq].attacks[slider_idx(sq, occ, magics[sq])] = 282 get_slider_attack(sq, occ, dirs); 283 } while ((occ = (occ - 1) & magics[sq].mask)); 284 } 285 286 void 287 init_sliders(void) { 288 char sq, bishop_dirs[4] = {9,7,-7,-9}, rook_dirs[4] = {8,1,-1,-8}; 289 for (sq = 0; sq < 64; sq++) { 290 gen_magic(sq, bishop_magics, bishop_dirs); 291 gen_magic(sq, rook_magics, rook_dirs); 292 } 293 } 294 295 void 296 init_attacks(void) { 297 gen_knight_attacks(); 298 gen_king_attacks(); 299 }