0x88 engines

Discussion of chess software programming and technical issues.

Moderators: hgm, Rebel, chrisw

diep
Posts: 1822
Joined: Thu Mar 09, 2006 11:54 pm
Location: The Netherlands

Re: 0x88 engines

Post by diep »

Tord Romstad wrote:I don't feel that anyone is trying to pile on me, but I must admit that I am surprised my little remark caused so many replies. :)

Being a non-programmer, I am not sure how the terms "top-down" and "bottom-up" are generally understood in programming, but both of them make some sense when describing my approach: The program is designed from the top down, but if one wants to write and test the code piece by piece, it would probably be most practical to do this from the bottom up. I usually don't write and test code this way, though. More about this below.
bob wrote:I agree with how you think it ought to be developed, but your definition of "top down" is simply backward. In a classic top-down design, you write the main program. For every procedure you want to call, you write a dummy (aka a "stub") that does nothing. You then get the main program to function as intended. Then you take the layer of stubs right below the main program and you start to flesh those in. But whatever procedure you call you do not write, you just supply a stub. But now you are one layer deeper into the design and the code is getting more specific. You continue this until you reach what we would call the "tips" in a tree search. This is where the real work is done, and this is where it is necessary for all the basic data structures to be finalized.
I don't recall ever having written such stub functions, but the approach you describe resembles a technique I often use in Lisp (the language I use in my day job). Lisp allows me to compile and run code which calls undefined functions (the compiler will emit a warning, though). I often do this intentionally. When the undefined function gets called, the program enters a break loop where I can choose between several actions, including manually supplying a return value for the undefined function, selecting some other function to call instead, or defining the function before continuing.

When writing a chess engine in C, I do it differently: I write the entire program (in top-down style) on paper before I type a single line of code at the computer. I don't start typing the code before I'm 100% sure the program is correct (which, of course, it never quite is, even though I am 100% sure). When everything is ready, I need a day or two typing everything and fixing all the silly little errors that have crept in everywhere. I write everything at once, rather than one little piece at the time. This is boring work, but it doesn't take a lot of time, and at the end I have a complete, working, stable and clean-looking chess engine.

Previously, I used to work more like most other participants in this thread seems to do. I started writing a board representation, a move generator (without "advanced" stuff like castling or promotions at first), an SEE function, and so on, and tested each of them with a few ad-hoc, non-rigorous tests. As I proceeded to more and more high-level parts of the program, I invariably found that the low-level parts didn't fit together as well as I had hoped, and I had to throw in ugly little hacks everywhere to make things work as intended.

Moreover, there were always bugs. Segmentation faults, non-terminating loops, pieces which suddenly changed color for no good reason, search bugs, hash table bugs, mysterious non-reproducible losses on time with ponder on, and so on. I spent countless hours in the debugger, or inserting output commands everywhere in the code to find out why something didn't work as intended. I usually managed to fix the problems, but the process was unbearably painful, and the code looked more and more messy.

In the end, I decided that life is just too short to debug C/C++ code. The endless edit-compile-test-debug cycle is sheer torture. I only write code I know is correct, and the easiest achieve this is working top-down. It requires some mental discipline, but I end up with much cleaner code. Even more importantly, working with pencil and paper in a park or café is infinitely preferable to sitting in front of a computer and staring at a debugger. :)

Matt has a point, though: This style of working really only works when you already have a good understanding of the problem domain. If I were a beginner wanting to start chess programming, I would have started out with a more interactive programming language, and consider switching to C/C++ only when I had a satisfactory prototype.

Vincent also makes a good point: I am a mathematician, not a programmer, and this certainly has an impact on how I prefer to work.

Tord
Hi Tord,

Of course this is why mentionned you're a mathematician. With respect to Diep's parallellism, i also designed that of course in the mathematical manner. First write a model on paper that you can prove correct 100% that it never gets a deadlock nor race condition. That is how diep's parallellism has been designed. Otherwise you can't write a search where many processors simultaneously can split, fail high, all that without central locking.

This is a complete mathematical model of course.

First write it 100% on paper THEN prove it correct THEN implement it (after which it still takes 5 years to get it bugfree by the way).

With respect to top down design; the fundamental idea of top-down design is to have something that works and while it works you add slowly functionality.

In that sense it is crucial to have the datastructure to work as the first thing, because not a single other function can work bugfree otherwise.

Making moves and unmaking moves on a chessboard is the first function to get to work of course, as your entire program initially is a startposition with a makemove and unmakemove procedure.

At least, that's how Diep got started.

Then you can add other functions 1 by 1, like adding a function called search().

See it as space shuttle versus soyuz.

Soyuz has a great safety record transporting cosmonauts to and from ISS. They started with it long time ago, each time just 1 tiny thing gets modified. As a result it hardly ever explodes. So the odds a cosmonaut makes it alive to ISS and back with soyuz is 99.9%

Space shuttle on other hand they designed millions of components, put them together, and 40+ years later they're still busy debugging it. It still explodes regrettably, which has delayed the space program major league as space shuttle is the main vehicle to carry cargo.

Space shuttle is a classical NASA project, like so many, and a very typical example of a bottom-up project. Note ESA is nothing better there.

They will never improve there, what they achieved there half a century ago, since then they hardly progressed (other than for satellite technology).

Now of course sometimes the difficulty is that to get something to work first, you already need to do really a lot, but the idea of how to design hardware top-down they will never learn at government level.

It first has to follow 1 million a4 pages of paper demands i bet, BEFORE the simplest thing has been gotten to work :)
MattieShoes
Posts: 718
Joined: Fri Mar 20, 2009 8:59 pm

Re: 0x88 engines

Post by MattieShoes »

Well this wasn't the *first* engine I wrote really. The first thing I ever programmed in my life was a chess engine, but it was largely from reading TSCP and then writing it myself. I didn't *copy* a single line, and board rep was different, but just about every function in TSCP had an analog in mine. I got alpha-beta working but I didn't really understand how it works. At some point, I sat down with pencil and paper and made a little tree with scores and windows just to make it gel in my mind *why* it works. The guys who figured it out originally... Amazing! It never was totally stable, crashes every 10 or 20 games, etc. and I didn't have the knowledge needed to track down what was causing it.

It was actually a very useful exercise for me though. It was probably not the easiest way to learn about programming though -- I didn't even know basic syntax and I dove right into arrays, data structures, pointers, stacks, recursive functions, and the rest. Sort of a trial by fire!

I've programmed a lot since then, so recently when I came back to it, I wrote an engine in c# from scratch, then rewrote it in C++ after a couple weeks. So depending on how you count such things, this may be my third or fourth engine, eh? ;-) Now that I've had years of programming, I find it much more fun to play around with chess engine ideas since the programming side of things doesn't take up all the thinking time. :-)

I guess I write top-down but I don't start at the top. After picking board representation and hashing scheme, I wrote makemove and takeback with just stubs for the ancillary functions like incheck and filled them out afterwards. Then I wrote search and qsearch, added in the new stubs necessary, filled them in... then eval, and the stubs for that, and filled them in... :-)
bob
Posts: 20943
Joined: Mon Feb 27, 2006 7:30 pm
Location: Birmingham, AL

Re: 0x88 engines

Post by bob »

Dann Corbit wrote:
Uri Blass wrote:
Tord Romstad wrote:
bob wrote:The first step is to come up with a workable design that you are happy with. Which starts with board representation. Then a functional search and evaluation that plays chess.
I would recommend the opposite order: Write the search and evaluation function first, and do the board representation later. Starting with the board representation is a form of premature optimization: Before you have decided what sorts of questions you want to ask about the position in the search and evaluation, you can't know what board representation suits your needs.

Tord
If you write in abstract terms, you do not need any representation.

So (for instance) like this:

Code: Select all

Evaluation(ChessGame &game)
{
...
blockedPawnPenalty = game.CountOfBlockedPawns() * blockedPawnMultiplier;
}
As you can see, we do not need any specifics to code our evaluation function. It relies on the underlying methods to return the wanted values.



I do not see how do you write evaluation without some board representation.

You may suggest not to spend time on optimization of board representation but you need some board representation.

Uri
That doesn't work so well. You need to have an idea of the complexity of any task being done out at every leaf node, because the cost is multiplied by a huge number of calls. With a data structure in mind, you can visualize the cost before you actually write all that code, and decide on whether it is worth the effort or not... Additionally, as you are thinking about the data structures, and how they are to be used, you will discover various things that can be done more efficiently inside the search rather than at the tips, and vice-versa. If you postpone that until the end, you end up with a major rewrite.
Edsel Apostol
Posts: 803
Joined: Mon Jul 17, 2006 5:53 am
Full name: Edsel Apostol

Re: 0x88 engines

Post by Edsel Apostol »

MattieShoes wrote:Well this wasn't the *first* engine I wrote really. The first thing I ever programmed in my life was a chess engine, but it was largely from reading TSCP and then writing it myself. I didn't *copy* a single line, and board rep was different, but just about every function in TSCP had an analog in mine. I got alpha-beta working but I didn't really understand how it works. At some point, I sat down with pencil and paper and made a little tree with scores and windows just to make it gel in my mind *why* it works. The guys who figured it out originally... Amazing! It never was totally stable, crashes every 10 or 20 games, etc. and I didn't have the knowledge needed to track down what was causing it.

It was actually a very useful exercise for me though. It was probably not the easiest way to learn about programming though -- I didn't even know basic syntax and I dove right into arrays, data structures, pointers, stacks, recursive functions, and the rest. Sort of a trial by fire!

I've programmed a lot since then, so recently when I came back to it, I wrote an engine in c# from scratch, then rewrote it in C++ after a couple weeks. So depending on how you count such things, this may be my third or fourth engine, eh? ;-) Now that I've had years of programming, I find it much more fun to play around with chess engine ideas since the programming side of things doesn't take up all the thinking time. :-)

I guess I write top-down but I don't start at the top. After picking board representation and hashing scheme, I wrote makemove and takeback with just stubs for the ancillary functions like incheck and filled them out afterwards. Then I wrote search and qsearch, added in the new stubs necessary, filled them in... then eval, and the stubs for that, and filled them in... :-)
This was about the same way how I did start programming. My first program is a chess engine also while at the same time learning the language. Others may find my earliest source code in the chess engines yahoo group where I've uploaded it there around early 2005. It has 0x88 data structure and is not stable. I'm planning to revive that, fix the bugs and make it GPL to give beginners a good starting point for an engine.

By the way, I started the design of that engine on paper. I designed the data structure to be used and write down all the functions that will be needed. Then I started to fill the functions one by one from main to eval.

My previous engine, TL 0.xxx series and the current one TL yyyymmdd series was written through the same aproach.

So this is like a hybrid approach, designing the data structure bottom up, and the functions top-down.
User avatar
stegemma
Posts: 859
Joined: Mon Aug 10, 2009 10:05 pm
Location: Italy
Full name: Stefano Gemma

Re: 0x88 engines

Post by stegemma »

I think that defining data structures is the core of chess programming the same as defining good algorithms is. The beginners should start defining the way that they want to describe chessboard, pieces, moves, nodes and so on and just then pass to define algorithms, evaluation function and so on. What's important, for any beginner, is to write a playing program possibly from scratch. This could lead to many errors or bad structures or bad algorithms... but that's the better way to learn chess programming. When the first program has been finished, anybody can rewrite a new one, maybe experimenting new data structures or improving the ones used.

I've started with a 8x8 chessboard (i was working on Z80 and 6502 CPU!) and now i use a 16x16 chessboard, just because it's easiest to debug in assembly, on 32 bit platform.

So anyone should think about to change almost anything, in theyr first program... and do the major work in the second or third one.

Stefano Gemma
User avatar
Desperado
Posts: 879
Joined: Mon Dec 15, 2008 11:45 am

Re: 0x88 engines

Post by Desperado »

Hi,

just a simple question on the x88-mechanics.

Because i am writing my engine from scratch i am very interested
in the following.

It it necessary to define for example:

Code: Select all


	struct BOARD_T
		{
		 UI_08 brd[128]; //8x16 
	   //UI_08 brd[256]; //16x16
	   //...
		};
instead of

Code: Select all

	struct BOARD_T
		{
		 UI_08 brd[64];
		 //...
		};
The thought is, that x88 is based on checking the square index and
not the content of the board. I used once the 16x16 mechanics
with having small tables all having ID_64.

and if a check on the square index is necessary i just
looked up the following way.

Code: Select all


	const SQR_T xA1=0x44,xB1=0x45,xC1=0x46,xD1=0x47,xE1=0x48,xF1=0x49,xG1=0x4A,xH1=0x4B;
	const SQR_T xA2=0x54,xB2=0x55,xC2=0x56,xD2=0x57,xE2=0x58,xF2=0x59,xG2=0x5A,xH2=0x5B;
	const SQR_T xA3=0x64,xB3=0x65,xC3=0x66,xD3=0x67,xE3=0x68,xF3=0x69,xG3=0x6A,xH3=0x6B;
	const SQR_T xA4=0x74,xB4=0x75,xC4=0x76,xD4=0x77,xE4=0x78,xF4=0x79,xG4=0x7A,xH4=0x7B;
	const SQR_T xA5=0x84,xB5=0x85,xC5=0x86,xD5=0x87,xE5=0x88,xF5=0x89,xG5=0x8A,xH5=0x8B;
	const SQR_T xA6=0x94,xB6=0x95,xC6=0x96,xD6=0x97,xE6=0x98,xF6=0x99,xG6=0x9A,xH6=0x9B;
	const SQR_T xA7=0xA4,xB7=0xA5,xC7=0xA6,xD7=0xA7,xE7=0xA8,xF7=0xA9,xG7=0xAA,xH7=0xAB;
	const SQR_T xA8=0xB4,xB8=0xB5,xC8=0xB6,xD8=0xB7,xE8=0xB8,xF8=0xB9,xG8=0xBA,xH8=0xBB;

	const SQR_T toX88[ID_64] =
		{
		 xA1,xB1,xC1,xD1,xE1,xF1,xG1,xH1,
		 xA2,xB2,xC2,xD2,xE2,xF2,xG2,xH2,
		 xA3,xB3,xC3,xD3,xE3,xF3,xG3,xH3,
		 xA4,xB4,xC4,xD4,xE4,xF4,xG4,xH4,
		 xA5,xB5,xC5,xD5,xE5,xF5,xG5,xH5,
		 xA6,xB6,xC6,xD6,xE6,xF6,xG6,xH6,
		 xA7,xB7,xC7,xD7,xE7,xF7,xG7,xH7,
		 xA8,xB8,xC8,xD8,xE8,xF8,xG8,xH8
		};

	#define X88_IS_OK(SQ) (!(((SQ)-0x44)&0x88))

usage: if(X88_IS_OK(toX88[sq64])) //...as example

Most of the time such checks aren t necessary, and the tables keep
more compact, and i have full x88-mechanics support.
only operating with sq-indices (board contents doesnt matter)
(so i didnt see why using an _x88_ boardtype with [128] or [256] (same
for corresponding tables) index or any other greater than 64 is necessary ?!)

(or should this be called x88-mailbox approach ?)

pls correct me if i misunderstood sth. (it worked well and fast in practise).

Michael
User avatar
Desperado
Posts: 879
Joined: Mon Dec 15, 2008 11:45 am

Re: 0x88 engines

Post by Desperado »

Additionally to my last post i want to give a snapshot of
the code where i was using a hybrid-board:

Code: Select all

struct BOARD_T
	{
	 UI_08 sq64[64];
	 BTB    btb[13];
	 //...
	}
- x88-(mailbox)
- magic bitboads

Code: Select all

bool s_attack(BOARD_T *brd,SQUARE sq64,bool col)
	{
	 //LOCALS
	 //--------------------------------------

	 BTB occ;	//occupied squares
	 BTB att_s; //attacker squares
	 BTB att_p; //attacker pieces 

	 SQUARE  dst64;

	 //SETTINGS
	 //--------------------------------------

	 occ = brd->wpl | brd->bpl;

	 col==WHITE ? att_p = brd->wpl : att_p = brd->bpl;

	 //POTENTIAL ATTACKERS
	 //--------------------------------------

	 att_s = (Q_MAGIC(occ,sq64) | N_MAGIC(sq64)) & att_p;

 	 //TEST ATTACKERS(INCLUDING PAWNS)
	 //--------------------------------------

	 while(att_s)
		{
		 dst64 = bsf64(att_s);

		 if(attackdelta[X88_DELTA(toX88[sq64],toX88[dst64])] & brd->sq64[dst64])
				 return(true);

		 CLB64(att_s);
		}

	 return(false);
	}
which worked very fast.(combined magics and attackdelta(in x88-manner)).

only as example.

Micha
User avatar
Desperado
Posts: 879
Joined: Mon Dec 15, 2008 11:45 am

Re: 0x88 engines

Post by Desperado »

well,

i just want to rephrase my question.

Why do i need a physical _x88 board_, if all operations depend
on the square index, which is easy to emulate with toX88[sq64] ?

(and are used rarley in contrast with "normal" square operations,
where i dont need to "convert" the sq64)

i would be very happy, if someone can answer this question.


Have a nice day. :)
Aleks Peshkov
Posts: 892
Joined: Sun Nov 19, 2006 9:16 pm
Location: Russia

Re: 0x88 engines

Post by Aleks Peshkov »

Your toX88[] table is 64 byte long, so you get no win against a pure x88 engine at all. :)

The difference in speed is minimal of course, but it exists.
User avatar
stegemma
Posts: 859
Joined: Mon Aug 10, 2009 10:05 pm
Location: Italy
Full name: Stefano Gemma

Re: 0x88 engines

Post by stegemma »

I'm asking myself why do you need the toX88 array. if your board is arranged this way:

L=legal square
X=illegal square

LLLLLLLLXXXXXXXX
LLLLLLLLXXXXXXXX
...
LLLLLLLLXXXXXXXX
LLLLLLLLXXXXXXXX

then you have just to check index, without any translation. First square (a8) have index 0x00 while h8 have 0x07. The first illegal square have index 0x08. In fact, you just have to check the index in this way:

#define IS_NOT_LEGAL(index) ((index) & 0x88)

You can easly verify that you can move pieces all around the chessboard just adding a "delta" to theyr actual position.

But maybe i've missed something in your sample ;)