[futurebasic] Re: [FB] re: greetings & pChess 0.7.7

Message: < previous - next > : Reply : Subscribe : Cleanse
Home   : October 2009 : Group Archive : Group : All Groups

From: Robert Purves <listrp@...>
Date: Sat, 31 Oct 2009 20:50:00 +1300
John Penner wrote:

> i've got a question for the chess listers out there -- because i try  
> to put everything
> possible into local for passing between FN's -- i thought of storing  
> the entire game state
> in some sort of STRUCT or RECORD -- but passing records seemed  
> complicated
> to me, and i wanted to keep it simple -- so i stored the game state
> in a bunch of global variables:

A well chosen record definition is better than a bunch of global  
variables and arrays. A record, being a single object, is easy to copy  
and pass as a parameter to a function. The board representation is  
going to be copied millions of times during a search, so it should  
contain only what's needed to generate moves and evaluate a position;  
it shouldn't contain the complete game history.

Below is a minimal definition. Some fields that your program will need  
(for fully correct play), or may want (e.g. to avoid slow searching,  
or slow recomputation of material balance) are commented out. If you  
uncomment them, those fields immediately become available to every  
function that takes a Board parameter. That extensibility is a big  
advantage of a record over multiple globals; it allows a program to  
grow simply, from small beginnings.

'---------
begin record Board
dim as byte     squareContent[63]
dim as byte     sideToPlay // 1 white; -1 black
//dim as Boolean  whiteCanCastleKSide, whiteCanCastleQSide
//dim as Boolean  blackCanCastleKSide, blackCanCastleQSide
//dim as byte     enPassantSquare
//dim as byte     whiteKingSquare, blackKingSquare
//dim as short    whiteRawMaterialScore, blackRawMaterialScore
end record


// feeble demo of Board variables
dim as Board  currentBoard, copyBoard
dim as long   k

copyBoard = currentBoard
for k = 0 to 63 // how to scan the entire board
long if ( copyBoard.squareContent[k] == 0 )
// the square is empty
xelse
//...do something
end if
next
'---------


Then, with another record definition to represent a move, we start to  
see what real chess code with these records might look like. To me it  
looks compact, comprehensible and fast.

'---------
begin record MoveRec
dim as byte  fromSquare, toSquare
end record

local fn MakeMove( theBoard as ^Board, theMove as ^MoveRec )
'~'1
dim as byte  movingPiece

theBoard.sideToPlay = -theBoard.sideToPlay
movingPiece = theBoard.squareContent[theMove.fromSquare]
// special handling for K R and P omitted
theBoard.squareContent[theMove.toSquare] = movingPiece
theBoard.squareContent[theMove.fromSquare] = 0
end fn
'---------


> a  function called mTree() which provides to the eval function a  
> list of every possible move the current colour can make -- since i  
> dont think i can pass that whole list of possible moves as a single  
> variable (i.e. END FN = x%) -- i thot i was forced to return the  
> results of the mTree FN through yet another global variable

An array parameter would allow the entire move list to be returned  
without recourse to a global.

> so -- my problem is -- if i nest the eval() FN recursively, just how  
> will it deal with the states of these global variables??

It won't and can't. You will have pass the relevant state (i.e the  
current board) as a parameter to the recursive call. Your Evaluate  
function would keep its list of generated moves in a local array, and  
make each move on a copy of the board that was passed to it.

...
dim as Board    tempBoard
dim as long     nMoves, j
dim as MoveRec  moves(200)
nMoves = fn GenerateAllMoves( theBoard, moves(0) )
for j = 0 to nMoves - 1
   tempBoard = theBoard // copy
   fn MakeMove( tempBoard, moves(j) )
  // Evaluate recursively...
next
...

You have made great progress in writing a (nearly) fully functional  
chess program with little reference to existing art. This may be a  
good time to consider Fred Brooks' famous advice on big software  
projects: "...plan to throw one away; you will, anyhow."

I also recommend a switch to FB5, especially if you decide to rewrite  
your program. FB4 is obsolete. One of FB5's advantages is not being  
confused by non-breaking spaces in the code snippets above. FB5 does,  
however, enforce the discipline of declaring all local variables.

Robert P.