World Chess Move Generation Speed Competition 2015

Discussion of chess software programming and technical issues.

Moderator: Ras

Henk
Posts: 7251
Joined: Mon May 27, 2013 10:31 am

Re: World Chess Move Generation Speed Competition 2015

Post by Henk »

hgm wrote:Well, qperft does not do fully legal move generation. It doesn't generate illegal moves with pinned pieces (which saves it some time), so the only moves that would have to be tested to see if it puts itself in check are King moves and e.p. capture. So it makes those at the 1-ply level. And it then tests for check using the 0x88 attack test for all non-Pawns in the piece list, and testing the two board squares from which it could be checked by a Pawn.
If the side to move is not in check then the only pieces that can capture it's king are the pieces located on the squares of the x-ray queen moves of the square that is not longer occupied by the move of the side to move if that move is not a king move or an en passant move

Am I right ? Unfortunately that does not work in Skipper. But I don't know why.
User avatar
stegemma
Posts: 859
Joined: Mon Aug 10, 2009 10:05 pm
Location: Italy
Full name: Stefano Gemma

Re: World Chess Move Generation Speed Competition 2015

Post by stegemma »

Satana on Pentium i7 4970k, single core used, no hash for perft, all legal moves:

Code: Select all

Nodes: 4085603, Time: 102 ms, Nodes/s: 39666048
My perft code:

Code: Select all

uint64_t clsEngineSimple5::PerftLoop(int iDepth)
{
  pNode->boCastlings = board.boCastlings;
  uint64_t nMoves = 0;
  uint64_t mkMoves = MakeAllMoves();
  FOR_MOVES // for (pNode->pMove = pNode->pFirstMove; pNode->pMove<(pNode + 1)->pFirstMove; pNode->pMove++)
  {
    if ((pLoopMove->boFlags & flg_isTakenKing)!=flg_empty)
    {
      return -1;
    }
    ExecuteMove(pLoopMove);
    {
      if (!IsInCheck(board.boKings & board.boFriends))
      {
        if (iDepth == 0)
        {
          ++nMoves;
        }	else
        {
          pNode->pMove = pLoopMove;
          SwapColor();
            ++pNode;
              uint64_t kMoves = PerftLoop(iDepth - 1);
              if (kMoves>0) nMoves += kMoves;
          --pNode;
          SwapColor();
          if (pNode == pFirstNode && bDivideMode)
          {
            sfout.Push(GetUserMove(pLoopMove, true) + " " + clsString(kMoves));
          }
        }
      }
      else
      {
        pLoopMove->boFlags |= flg_illegal;
      }
      UndoMove(pLoopMove);
    }
  }
  return nMoves;
}
Author of Drago, Raffaela, Freccia, Satana, Sabrina.
http://www.linformatica.com
User avatar
hgm
Posts: 28461
Joined: Fri Mar 10, 2006 10:06 am
Location: Amsterdam
Full name: H G Muller

Re: World Chess Move Generation Speed Competition 2015

Post by hgm »

Qperft approaches it from the piece list. It just runs through all sliders to test if they are aligned with the King. When they are, it has to scan the ray from King to slider to see if there is a single blocker. If there is a single blocker, that blocker is pinned. It then generates the moves of that blocker along the pin line (if any), and marks the piece in the piece list as absent for the normal part of the move generation.
Henk
Posts: 7251
Joined: Mon May 27, 2013 10:31 am

Re: World Chess Move Generation Speed Competition 2015

Post by Henk »

Skipper does not use legal move generation when it plays chess. So no doubt that it is far from optimal.

But a very fast KingInCheck test method is still necessary for normal chess.
Joost Buijs
Posts: 1671
Joined: Thu Jul 16, 2009 10:47 am
Location: Almere, The Netherlands

Re: World Chess Move Generation Speed Competition 2015

Post by Joost Buijs »

Nightmare takes 26 msec. on 1 core of a 5960X at 3.6 GHz.
No hashing, no bulk counting, just the plain movegen and domove I use for the engine.
Robert Pope
Posts: 570
Joined: Sat Mar 25, 2006 8:27 pm
Location: USA
Full name: Robert Pope

Re: World Chess Move Generation Speed Competition 2015

Post by Robert Pope »

Abbess gets perft 4 in 0.4 seconds. Full pseudo-legal movegen, with check detection after MakeMove.
Sven
Posts: 4052
Joined: Thu May 15, 2008 9:57 pm
Location: Berlin, Germany
Full name: Sven Schüle

Re: World Chess Move Generation Speed Competition 2015

Post by Sven »

Henk wrote:
hgm wrote:Well, qperft does not do fully legal move generation. It doesn't generate illegal moves with pinned pieces (which saves it some time), so the only moves that would have to be tested to see if it puts itself in check are King moves and e.p. capture. So it makes those at the 1-ply level. And it then tests for check using the 0x88 attack test for all non-Pawns in the piece list, and testing the two board squares from which it could be checked by a Pawn.
If the side to move is not in check then the only pieces that can capture it's king are the pieces located on the squares of the x-ray queen moves of the square that is not longer occupied by the move of the side to move if that move is not a king move or an en passant move

Am I right ? Unfortunately that does not work in Skipper. But I don't know why.
A possible reason is that your description above is hard to understand. Rewrite the phrase in way that can easily be transformed into a simple algorithm. Also it seems your definition does not deal with a king being attacked by a knight. The most simple way to detect whether a king has been left in check (i.e., is attacked by an enemy piece) is to test for attacks in all possible directions starting at the king square:
- is it attacked by a pawn,
- by a knight,
- by a king,
- by a rook or queen on a horizonal/vertical ray, or
- by a bishop or queen on a diagonal ray?
You can try to be more clever by using information about the last move, as you mentioned, but you do not get this for free. If you do so, and it does not work, then watch out for the bug, or go the simple way first and postpone the clever way.

A pseudo-legal move can be illegal in one of these four cases:
- it is a check evasion,
- it is a king move,
- it is an ep capture, or
- it is a move of a pinned piece.
All other pseudo-legal moves are legal and do not require a make-unmake for legality testing.
The set of moves given above can even be reduced a bit in some cases but doing so usually does not give you another drastical improvement.

Code: Select all

bool MoveIsLegal(Move move)
{
    bool legal = true; // most pseudo-legal moves are legal
    Color self = sideToMove;
    if (inCheckFlag || IsKingMove(move) || IsEpMove(move) || IsPinned(move.from)) // move could be illegal
    {
        do(move);
        legal = !IsAttackedBy(KingSquare(self), Opponent(self));
        undo(move);
    }
    return legal;
}

MoveList LegalMoves()
{
    MoveList pMoves = PseudoLegalMoves();
    MoveList moves;
    inCheckFlag = IsInCheck();
    DetectPins();
    foreach (move in pMoves)
    {
        if (MoveIsLegal(move))
        {
            moves.add(move);
        }
    }
    return moves;
}
Regarding IsPinned(), even if Skipper is not a bitboard engine you can still use a bitboard for that purpose. DetectPins() finds all pieces pinned to the king of the moving side and stores their locations in a 64-bit number. IsPinned() maps the given square to a bit position and does a simple AND.
Henk
Posts: 7251
Joined: Mon May 27, 2013 10:31 am

Re: World Chess Move Generation Speed Competition 2015

Post by Henk »

Sven Schüle wrote:
Henk wrote:
hgm wrote:Well, qperft does not do fully legal move generation. It doesn't generate illegal moves with pinned pieces (which saves it some time), so the only moves that would have to be tested to see if it puts itself in check are King moves and e.p. capture. So it makes those at the 1-ply level. And it then tests for check using the 0x88 attack test for all non-Pawns in the piece list, and testing the two board squares from which it could be checked by a Pawn.
If the side to move is not in check then the only pieces that can capture it's king are the pieces located on the squares of the x-ray queen moves of the square that is not longer occupied by the move of the side to move if that move is not a king move or an en passant move

Am I right ? Unfortunately that does not work in Skipper. But I don't know why.
A possible reason is that your description above is hard to understand. Rewrite the phrase in way that can easily be transformed into a simple algorithm. Also it seems your definition does not deal with a king being attacked by a knight. The most simple way to detect whether a king has been left in check (i.e., is attacked by an enemy piece) is to test for attacks in all possible directions starting at the king square:
- is it attacked by a pawn,
- by a knight,
- by a king,
- by a rook or queen on a horizonal/vertical ray, or
- by a bishop or queen on a diagonal ray?
You can try to be more clever by using information about the last move, as you mentioned, but you do not get this for free. If you do so, and it does not work, then watch out for the bug, or go the simple way first and postpone the clever way.

A pseudo-legal move can be illegal in one of these four cases:
- it is a check evasion,
- it is a king move,
- it is an ep capture, or
- it is a move of a pinned piece.
All other pseudo-legal moves are legal and do not require a make-unmake for legality testing.
The set of moves given above can even be reduced a bit in some cases but doing so usually does not give you another drastical improvement.

Code: Select all

bool MoveIsLegal(Move move)
{
    bool legal = true; // most pseudo-legal moves are legal
    Color self = sideToMove;
    if (inCheckFlag || IsKingMove(move) || IsEpMove(move) || IsPinned(move.from)) // move could be illegal
    {
        do(move);
        legal = !IsAttackedBy(KingSquare(self), Opponent(self));
        undo(move);
    }
    return legal;
}

MoveList LegalMoves()
{
    MoveList pMoves = PseudoLegalMoves();
    MoveList moves;
    inCheckFlag = IsInCheck();
    DetectPins();
    foreach (move in pMoves)
    {
        if (MoveIsLegal(move))
        {
            moves.add(move);
        }
    }
    return moves;
}
Regarding IsPinned(), even if Skipper is not a bitboard engine you can still use a bitboard for that purpose. DetectPins() finds all pieces pinned to the king of the moving side and stores their locations in a 64-bit number. IsPinned() maps the given square to a bit position and does a simple AND.
If side to move:
- is not in check (before it makes a move)
- does not do a king move
then knight attacks of opponent cause no illegal moves.
Same holds for pawn attacks. Only sliding pieces (might) count if they are one the line between move.Start square and king.Location square.
Henk
Posts: 7251
Joined: Mon May 27, 2013 10:31 am

Re: World Chess Move Generation Speed Competition 2015

Post by Henk »

If Skipper only counts material it's speed is about 2 million nodes per second when playing normal chess.
AlvaroBegue
Posts: 932
Joined: Tue Mar 09, 2010 3:46 pm
Location: New York
Full name: Álvaro Begué (RuyDos)

Re: World Chess Move Generation Speed Competition 2015

Post by AlvaroBegue »

Henk wrote:If Skipper only counts material it's speed is about 2 million nodes per second when playing normal chess.
I see. But when you just count the nodes it only does 1 million nodes per second. That makes sense...