bpaul-chess

UCI chess engine to replace Omelette Chess Engine
Log | Files | Refs | README | LICENSE

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 }