Position flipping

Discussion of chess software programming and technical issues.

Moderators: hgm, Rebel, chrisw

User avatar
sje
Posts: 4675
Joined: Mon Mar 13, 2006 7:43 pm

Re: Position flipping

Post by sje »

mcostalba wrote:
sje wrote:
mcostalba wrote:Anyhow it is easier to flip with string manipulation (at least in C++) starting from the FEN representation of a position:
That code doesn't flip any position history. Move retraction will not work, and neither will repetition detection.
This was your previous (few hours ago) definition of flip:

Code: Select all

A position flip is the action by which a position is replaced with a copy of itself modified such that each man is replaced with the corresponding man of the opposite color and then moved to the opposite side (front/back) of the board (file is same, but rank is flipped).

Other items must also be flipped: these include the color on the move, the castling status, and the en passant target square. 
And this is also the definition most engines follow (if this makes any sense for you).

What I have written flips according to this definition.
Note that "other items include" part. "Include" means "necessary" but not always "sufficient".
User avatar
sje
Posts: 4675
Joined: Mon Mar 13, 2006 7:43 pm

Re: Position flipping

Post by sje »

Code: Select all

void Position::Flip(void)
{
  Position position(GetIfen()); // Initial FEN
  
  Board tmpboard = position.RefBoard();
  Color tmpgood  = position.GetGood();
  Cabs  tmpcabs  = position.GetCabs();
  Sq    tmpepsq  = position.GetEpSq();
  ui    tmphmvc  = position.GetHmvc();
  ui    tmpfmvn  = position.GetFmvn();
  
  tmpboard.Flip();
  FlipColor(tmpgood);
  FlipCabs(tmpcabs);
  FlipMetaSq(tmpepsq);
  
  MoveNodePtr mnptr = RefHistory().GetHead();
  
  position.Load(tmpboard, tmpgood, tmpcabs, tmpepsq, tmphmvc, tmpfmvn);
  while (mnptr)
  {
    position.PlayMove(mnptr->Other());
    mnptr = mnptr->GetNext();
  };
  *this = position;
}
User avatar
Don
Posts: 5106
Joined: Tue Apr 29, 2008 4:27 pm

Re: Position flipping

Post by Don »

mcostalba wrote:
sje wrote:A position flip
This is another thing I am about to drop from Stockfish. The only reason while is still there is because it is from original Tord's code....but I found no use for it even once in the last years...
This is a good debugging feature.
Capital punishment would be more effective as a preventive measure if it were administered prior to the crime.
mvk
Posts: 589
Joined: Tue Jun 04, 2013 10:15 pm

Re: Position flipping

Post by mvk »

I use this:

Code: Select all

#!/usr/bin/python
#
#  Small program that flips a board position (exchanges White and Black)
#

import sys
import string

if len(sys.argv) != 2:
        print >> sys.stderr, "%s: arguments" % sys.argv[0]
        exit(10)

fen = sys.argv[1].split()
if len(fen) != 4:
        print >> sys.stderr, "%s: not a FEN string (%s)" %\
                (sys.argv[0], repr(sys.argv[1]))
        exit(10)


fen[0] = fen[0].translate(string.maketrans("kqrbnpKQRBNP", "KQRBNPkqrbnp"))
fen[1] = fen[1].translate(string.maketrans("wb", "bw"))
fen[2] = fen[2].translate(string.maketrans("kqKQ", "KQkq"))
fen[3] = fen[3].translate(string.maketrans("36", "63"))

rows = fen[0].split("/")
if len(rows) != 8:
        print >> sys.stderr, "%s: not a FEN string (%s)" %\
                (sys.argv[0], repr(sys.argv[1]))
        exit(10)

rows.reverse()
fen[0] = "/".join(rows)

print " ".join(fen)
It doesn't re-normalise the castling field, but my program eats the output anyway.
mcostalba
Posts: 2684
Joined: Sat Jun 14, 2008 9:17 pm

Re: Position flipping

Post by mcostalba »

sje wrote:

Code: Select all

void Position::Flip(void)
This is just a skeleton used as a dispatcher, the actual code is missing:

Code: Select all

  
  tmpboard.Flip();
  FlipColor(tmpgood);
  FlipCabs(tmpcabs);
  FlipMetaSq(tmpepsq);
mcostalba
Posts: 2684
Joined: Sat Jun 14, 2008 9:17 pm

Re: Position flipping

Post by mcostalba »

mvk wrote:

Code: Select all

fen[2] = fen[2].translate(string.maketrans("kqKQ", "KQkq"))
This does not work for Chess960
mvk
Posts: 589
Joined: Tue Jun 04, 2013 10:15 pm

Re: Position flipping

Post by mvk »

It also does not work for checkers and pac man.
User avatar
sje
Posts: 4675
Joined: Mon Mar 13, 2006 7:43 pm

Re: Position flipping

Post by sje »

mcostalba wrote:
sje wrote:

Code: Select all

void Position::Flip(void)
This is just a skeleton used as a dispatcher, the actual code is missing:

Code: Select all

  
  tmpboard.Flip();
  FlipColor(tmpgood);
  FlipCabs(tmpcabs);
  FlipMetaSq(tmpepsq);
Board::Flip() is a two line loop over the squares which calls OtherMan() and OtherSq(). FlipCabs() is a two line loop over the castling availability bits which calls FlipCastling(). The other two (and several other scalar flippers) are all one liners.

A little more work is done by Move::Other(). It has six statements, each flipping or copying a move component.
bob
Posts: 20943
Joined: Mon Feb 27, 2006 7:30 pm
Location: Birmingham, AL

Re: Position flipping

Post by bob »

sje wrote:A position flip is the action by which a position is replaced with a copy of itself modified such that each man is replaced with the corresponding man of the opposite color and then moved to the opposite side (front/back) of the board (file is same, but rank is flipped).

Other items must also be flipped: these include the color on the move, the castling status, and the en passant target square.

I notice that in Crafty, which has a flip command, there doesn't seem to be a flip of the en passant target. Am I missing something here?

Symbolic goes a bit further with its position flip. Not only are the board and the FEN scalars flipped, but also the entire move history and the saved state history. This means that it's possible to retract played moves in the flipped position all the way back to its flipped start. Also: flip(flip(P)) ≡ P

A position flip is a handy user command. It can also be used during opening book generation when (position, move) pair data are all stored using a White-to-move convention; this allows retrieval of "reversed" opening data.
An oversight. I have a procedure "tested" that uses a flip and flop command (flop mirrors left to right at the d/e file point, flip mirrors using the 4/5 rank point. tested computes the static eval, then flips and computes, then flops and computes, then flips again to give the 4th option and computes again. All 4 scores must match. This detects the occasional black/white asymmetry, or the left/right asymmetry. I don't use them to search positions at all, so I never added the ep target.
User avatar
sje
Posts: 4675
Joined: Mon Mar 13, 2006 7:43 pm

Re: Position flipping

Post by sje »

bob wrote:I have a procedure "tested" that uses a flip and flop command (flop mirrors left to right at the d/e file point, flip mirrors using the 4/5 rank point. tested computes the static eval, then flips and computes, then flops and computes, then flips again to give the 4th option and computes again. All 4 scores must match. This detects the occasional black/white asymmetry, or the left/right asymmetry.
Interesting. I had never thought of a flop() like Crafty's, but I can see where it would be useful. Alas, a flop() must destroy castling availability data, so it has no inverse.

Symbolic does have ReflectX0(), ReflectY0(), and ReflectXY(). But they are used only for tablebase index generation and are not user commands.

A Position class instance in Symbolic contains a Board class instance as a member To flip the board, the following is used:

Code: Select all

void Board::Flip(void)
{
  Board otherboard;

  for &#40;Sq sq = &#40;Sq&#41; 0; sq < SqLen; IncrSq&#40;sq&#41;)
    otherboard.PutMan&#40;sq, OtherMan&#40;GetMan&#40;OtherSq&#40;sq&#41;)));
  *this = otherboard;
&#125;