Skip to content

Instantly share code, notes, and snippets.

@Ravenslofty
Created June 21, 2017 18:14
Show Gist options
  • Select an option

  • Save Ravenslofty/1133d0867f795d7dec77433d042b954a to your computer and use it in GitHub Desktop.

Select an option

Save Ravenslofty/1133d0867f795d7dec77433d042b954a to your computer and use it in GitHub Desktop.
/*
* attacks.c - attack table update code.
*
* Copyright (C) 2016 Dan Ravensloft <[email protected]>
*
* This file is part of Dorpsgek.
*
* Dorpsgek is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Dorpsgek is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Dorpsgek. If not, see <http://www.gnu.org/licenses/>.
*/
#include <functional>
#include <assert.h>
#include <stdbool.h>
#include <string.h>
#include "definitions.h"
#include "functions.h"
auto AddBits = [](unsigned int bitlist, unsigned int bit) { return bitlist | bit; };
auto RemoveBits = [](unsigned int bitlist, unsigned int bit) { return bitlist & ~bit; };
void AddBitlist(struct Board * b, unsigned int bit, int piece, int from)
{
if (piece == PAWN) {
int col = COL(from);
if (bit & b->sidemask[WHITE]) {
if (col) {
b->bitlist[from + 7] |= bit;
}
if (col < 7) {
b->bitlist[from + 9] |= bit;
}
}
if (bit & b->sidemask[BLACK]) {
if (col) {
b->bitlist[from - 9] |= bit;
}
if (col < 7) {
b->bitlist[from - 7] |= bit;
}
}
} else {
int delta;
int from16x12 = TO16x12(from);
for (int dir = 0; dir < 8; dir++) {
delta = rays[piece][dir];
if (!delta) {
break;
}
int to = from16x12 + delta;
while (board16x12[to] != INVALID) {
b->bitlist[board16x12[to]] |= bit;
assert(ray_vector[VECTOR(from16x12, to)] == delta);
if (!slide[piece] || b->index[board16x12[to]] != INVALID) {
break;
}
to += delta;
}
}
}
}
void RemoveBitlist(struct Board * b, unsigned int bit, int piece, int from)
{
if (piece == PAWN) {
int col = COL(from);
if (bit & b->sidemask[WHITE]) {
if (col) {
b->bitlist[from + 7] &= ~bit;
}
if (col < 7) {
b->bitlist[from + 9] &= ~bit;
}
}
if (bit & b->sidemask[BLACK]) {
if (col) {
b->bitlist[from - 9] &= ~bit;
}
if (col < 7) {
b->bitlist[from - 7] &= ~bit;
}
}
} else {
int dir, delta;
int from16x12 = TO16x12(from);
for (dir = 0; dir < 8; dir++) {
delta = rays[piece][dir];
if (!delta) {
break;
}
int to = from16x12 + delta;
while (board16x12[to] != INVALID) {
b->bitlist[board16x12[to]] &= ~bit;
assert(ray_vector[VECTOR(from16x12, to)] == delta);
if (!slide[piece] || b->index[board16x12[to]] != INVALID) {
break;
}
to += delta;
}
}
}
}
void ExtendSliders(struct Board * b, int sq)
{
uint32_t bits = b->bitlist[sq] & (b->piecemask[BISHOP] | b->piecemask[ROOK] | b->piecemask[QUEEN]);
int sq16x12 = TO16x12(sq);
while (bits) {
int bit = CountTrailingZeroes(bits);
int from = b->piecelist[bit];
int from16x12 = TO16x12(from);
bits &= bits - 1;
int vec = VECTOR(from16x12, sq16x12);
int dir = ray_vector[vec];
int to = sq16x12 + dir;
while (board16x12[to] != INVALID) {
b->bitlist[board16x12[to]] |= 1u << bit;
if (b->index[board16x12[to]] != INVALID) {
break;
}
to += dir;
}
}
}
void BlockSliders(struct Board * b, int sq)
{
uint32_t bits = b->bitlist[sq] & (b->piecemask[BISHOP] | b->piecemask[ROOK] | b->piecemask[QUEEN]);
int sq16x12 = TO16x12(sq);
while (bits) {
int bit = CountTrailingZeroes(bits);
int from = b->piecelist[bit];
int from16x12 = TO16x12(from);
bits &= bits - 1;
int vec = VECTOR(from16x12, sq16x12);
int dir = ray_vector[vec];
int to = sq16x12 + dir;
while (board16x12[to] != INVALID) {
b->bitlist[board16x12[to]] &= ~(1u << bit);
if (b->index[board16x12[to]] != INVALID) {
break;
}
to += dir;
}
}
}
template<typename Func>
void UpdateSliders(struct Board * b, int sq, Func update_func)
{
uint32_t bits = b->bitlist[sq] & (b->piecemask[BISHOP] | b->piecemask[ROOK] | b->piecemask[QUEEN]);
int sq16x12 = TO16x12(sq);
while (bits) {
int bit = CountTrailingZeroes(bits);
int from = b->piecelist[bit];
int from16x12 = TO16x12(from);
bits &= bits - 1;
int vec = VECTOR(from16x12, sq16x12);
int dir = ray_vector[vec];
int to = sq16x12 + dir;
while (board16x12[to] != INVALID) {
b->bitlist[board16x12[to]] = update_func(b->bitlist[board16x12[to]], 1u << bit);
if (b->index[board16x12[to]] != INVALID) {
break;
}
to += dir;
}
}
}
void RecalculateAttacksFromScratch(struct Board * b)
{
int idx, sq;
unsigned int i;
memset(b->bitlist, 0, sizeof(b->bitlist));
for (idx = 0; idx < 32; idx++) {
sq = b->piecelist[idx];
if (sq == INVALID) {
continue;
}
i = 1u << idx;
AddBitlist(b, i, GetPieceByBit(b, i), sq);
}
}
void RecalculateAttacksForQuiets(struct Board * c, struct Move m)
{
int from = m.from;
int dest = m.dest;
unsigned int bit = 1u << c->index[dest];
int piece = GetPieceByBit(c, bit);
RemoveBitlist(c, bit, piece, from);
AddBitlist(c, bit, piece, dest);
UpdateSliders(c, from, AddBits);
UpdateSliders(c, from, RemoveBits);
}
void RecalculateAttacksForCaptures(struct Board * c, struct Move m)
{
int from = m.from;
int dest = m.dest;
unsigned int bit = 1u << c->index[dest];
int att = GetPieceByBit(c, bit);
RemoveBitlist(c, bit, att, from);
AddBitlist(c, bit, att, dest);
// It turns out that because we remove the captured piece bit in the masks,
// we can actually ignore resetting the captured piece bits without affecting
// correctness.
//RemoveBitlist(c, def_bit, def, dest);
ExtendSliders(c, from);
}
void RecalculateAttacksForPromotions(struct Board * c, struct Move m)
{
int from = m.from;
int dest = m.dest;
int bit = 1 << c->index[dest];
RemoveBitlist(c, bit, PAWN, from);
switch (m.type) {
case MoveTypePromotionKnight:
AddBitlist(c, bit, KNIGHT, dest);
break;
case MoveTypePromotionBishop:
AddBitlist(c, bit, BISHOP, dest);
break;
case MoveTypePromotionRook:
AddBitlist(c, bit, ROOK, dest);
break;
case MoveTypePromotionQueen:
AddBitlist(c, bit, QUEEN, dest);
break;
}
ExtendSliders(c, from);
BlockSliders(c, dest);
}
void RecalculateAttacksForCapturePromotions(struct Board * c, struct Move m)
{
int from = m.from;
int dest = m.dest;
int att_bit = 1 << c->index[dest];
int att = GetPieceByBit(c, att_bit);
RemoveBitlist(c, att_bit, PAWN, from);
switch (m.type) {
case MoveTypeCapturePromotionKnight:
AddBitlist(c, att_bit, KNIGHT, dest);
break;
case MoveTypeCapturePromotionBishop:
AddBitlist(c, att_bit, BISHOP, dest);
break;
case MoveTypeCapturePromotionRook:
AddBitlist(c, att_bit, ROOK, dest);
break;
case MoveTypeCapturePromotionQueen:
AddBitlist(c, att_bit, QUEEN, dest);
break;
}
// It turns out that because we remove the captured piece bit in the masks,
// we can actually ignore resetting the captured piece bits without affecting
// correctness.
//RemoveBitlist(c, def_bit, def, dest);
ExtendSliders(c, from);
}
void RecalculateAttacks(struct Board * c, struct Move move)
{
if (move.type == MoveTypeNormal || move.type == MoveTypeDoublePush) {
RecalculateAttacksForQuiets(c, move);
} else if (move.type == MoveTypeCapture) {
RecalculateAttacksForCaptures(c, move);
} else if (move.type >= MoveTypePromotionQueen && move.type <= MoveTypePromotionKnight) {
RecalculateAttacksForPromotions(c, move);
} else if (move.type >= MoveTypeCapturePromotionQueen && move.type <= MoveTypeCapturePromotionKnight) {
RecalculateAttacksForCapturePromotions(c, move);
} else {
RecalculateAttacksFromScratch(c);
}
//RecalculateAttacksFromScratch_Bad(c);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment