Discussion of chess software programming and technical issues.
Moderator: Ras
Edsel Apostol
Posts: 803 Joined: Mon Jul 17, 2006 5:53 am
Full name: Edsel Apostol
Post
by Edsel Apostol » Wed Sep 14, 2022 10:05 pm
I have this monstrous code for checking if a hash move derived from the hash table is valid for a certain position. Is there a minimum rule to check for the validity of a move in a position? Here's the code in question:
Code: Select all
bool position_t::moveIsValid(move_t m, uint64_t pinned) {
const int from = m.from();
const int to = m.to();
const int pc = pieces[from];
const int cap = pieces[to];
const int absdiff = abs(from - to);
const int flag = m.flags();
const int prom = m.promoted();
if (pc == EMPTY) return false;
if (cap == KING) return false;
if (prom != EMPTY && (prom < KNIGHT || prom > QUEEN)) return false;
if (getSide(from) != side) return false;
if (cap != EMPTY && getSide(to) == side) return false;
if ((pinned & BitMask[from]) && (DirFromTo[from][kpos[side]] != DirFromTo[to][kpos[side]])) return false;
if (pc != PAWN && (pc != KING || absdiff != 2) && !(pieceAttacksFromBB(pc, from, occupiedBB) & BitMask[to])) return false;
if (pc == KING) {
if (BitMask[to] & kingMovesBB(kpos[side ^ 1])) return false;
if (absdiff == 2 && flag != MF_CASTLE) return false;
}
if (pc == PAWN) {
if (cap != EMPTY && !(pawnAttacksBB(from, side) & BitMask[to])) return false;
if (cap == EMPTY && to != stack.epsq && !((pawnMovesBB(from, side) | pawnMoves2BB(from, side)) & BitMask[to])) return false;
if (absdiff == 16 && flag != MF_PAWN2) return false;
if (to == stack.epsq && flag != MF_ENPASSANT) return false;
}
switch (flag) {
case MF_PAWN2: {
if (pc != PAWN) return false;
if (!(Rank2ByColorBB[side] & BitMask[from])) return false;
if (absdiff != 16) return false;
if (cap != EMPTY) return false;
if (pieces[(from + to) / 2] != EMPTY) return false;
} break;
case MF_ENPASSANT: {
if (pc != PAWN) return false;
if (cap != EMPTY) return false;
if (to != stack.epsq) return false;
if (pieces[(sqRank(from) << 3) + sqFile(to)] != PAWN) return false;
if (absdiff != 9 && absdiff != 7) return false;
} break;
case MF_CASTLE: {
if (pc != KING) return false;
if (absdiff != 2) return false;
if (from != E1 && from != E8) return false;
if (pieces[RookFrom[to / 56][(to % 8) > 5]] != ROOK) return false;
if (to > from) {
if (!canCastleKS(side)) return false;
if (occupiedBB & CastleMask1[side][0]) return false;
if (areaIsAttacked(side ^ 1, CastleMask2[side][0])) return false;
}
if (to < from) {
if (!canCastleQS(side)) return false;
if (occupiedBB & CastleMask1[side][1]) return false;
if (areaIsAttacked(side ^ 1, CastleMask2[side][1])) return false;
}
} break;
case MF_PROMN: case MF_PROMB: case MF_PROMR: case MF_PROMQ: {
if (pc != PAWN) return false;
if (prom == EMPTY) return false;
if (!(Rank7ByColorBB[side] & BitMask[from])) return false;
} break;
}
return true;
}
As you can see I'm a fan of doing terse code and this one is against my style. Any tips?
chrisw
Posts: 4624 Joined: Tue Apr 03, 2012 4:28 pm
Location: Midi-Pyrénées
Full name: Christopher Whittington
Post
by chrisw » Wed Sep 14, 2022 11:03 pm
Edsel Apostol wrote: ↑ Wed Sep 14, 2022 10:05 pm
I have this monstrous code for checking if a hash move derived from the hash table is valid for a certain position. Is there a minimum rule to check for the validity of a move in a position? Here's the code in question:
Code: Select all
bool position_t::moveIsValid(move_t m, uint64_t pinned) {
const int from = m.from();
const int to = m.to();
const int pc = pieces[from];
const int cap = pieces[to];
const int absdiff = abs(from - to);
const int flag = m.flags();
const int prom = m.promoted();
if (pc == EMPTY) return false;
if (cap == KING) return false;
if (prom != EMPTY && (prom < KNIGHT || prom > QUEEN)) return false;
if (getSide(from) != side) return false;
if (cap != EMPTY && getSide(to) == side) return false;
if ((pinned & BitMask[from]) && (DirFromTo[from][kpos[side]] != DirFromTo[to][kpos[side]])) return false;
if (pc != PAWN && (pc != KING || absdiff != 2) && !(pieceAttacksFromBB(pc, from, occupiedBB) & BitMask[to])) return false;
if (pc == KING) {
if (BitMask[to] & kingMovesBB(kpos[side ^ 1])) return false;
if (absdiff == 2 && flag != MF_CASTLE) return false;
}
if (pc == PAWN) {
if (cap != EMPTY && !(pawnAttacksBB(from, side) & BitMask[to])) return false;
if (cap == EMPTY && to != stack.epsq && !((pawnMovesBB(from, side) | pawnMoves2BB(from, side)) & BitMask[to])) return false;
if (absdiff == 16 && flag != MF_PAWN2) return false;
if (to == stack.epsq && flag != MF_ENPASSANT) return false;
}
switch (flag) {
case MF_PAWN2: {
if (pc != PAWN) return false;
if (!(Rank2ByColorBB[side] & BitMask[from])) return false;
if (absdiff != 16) return false;
if (cap != EMPTY) return false;
if (pieces[(from + to) / 2] != EMPTY) return false;
} break;
case MF_ENPASSANT: {
if (pc != PAWN) return false;
if (cap != EMPTY) return false;
if (to != stack.epsq) return false;
if (pieces[(sqRank(from) << 3) + sqFile(to)] != PAWN) return false;
if (absdiff != 9 && absdiff != 7) return false;
} break;
case MF_CASTLE: {
if (pc != KING) return false;
if (absdiff != 2) return false;
if (from != E1 && from != E8) return false;
if (pieces[RookFrom[to / 56][(to % 8) > 5]] != ROOK) return false;
if (to > from) {
if (!canCastleKS(side)) return false;
if (occupiedBB & CastleMask1[side][0]) return false;
if (areaIsAttacked(side ^ 1, CastleMask2[side][0])) return false;
}
if (to < from) {
if (!canCastleQS(side)) return false;
if (occupiedBB & CastleMask1[side][1]) return false;
if (areaIsAttacked(side ^ 1, CastleMask2[side][1])) return false;
}
} break;
case MF_PROMN: case MF_PROMB: case MF_PROMR: case MF_PROMQ: {
if (pc != PAWN) return false;
if (prom == EMPTY) return false;
if (!(Rank7ByColorBB[side] & BitMask[from])) return false;
} break;
}
return true;
}
As you can see I'm a fan of doing terse code and this one is against my style. Any tips?
Ah, well, that code is making assumptions right from the start. How do you know you even have a “move”?
If (from<0 || from>63) return false; // etc etc
Could be 0xffffffff or any kind of initialised data there,
and so on and so on ….