MadChess 2.0 Development

Discussion of chess software programming and technical issues.

Moderators: hgm, Rebel, chrisw

User avatar
stegemma
Posts: 859
Joined: Mon Aug 10, 2009 10:05 pm
Location: Italy
Full name: Stefano Gemma

Re: MadChess 2.0 Development

Post by stegemma »

I like the console output of your program, it is very clean. Reading your site, i've seen that you switched from classes to native dta structure. I've verified that this is not an optimization (for my engine) because there are no overhead at assembly level. Even some kind of indirection is not bad thing. I don't know C# but i hope that you avoid managed allocation and use pre-allocated structures/classes only.

My Satana engine is about as your program, from an ELO point of view but i use a different approach to move generation.
User avatar
emadsen
Posts: 434
Joined: Thu Apr 26, 2012 1:51 am
Location: Oak Park, IL, USA
Full name: Erik Madsen

Re: MadChess 2.0 Development

Post by emadsen »

I like the console output of your program, it is very clean.
Thanks. I intend to embed a lot of Debug.Asserts in my code, and add a lot of test commands to ensure everything is working as expected.
I don't know C# but i hope that you avoid managed allocation and use pre-allocated structures/classes only.
Madchess 1.x did allocate and garbage collect objects during search. I wrote it in the spirit of a business application, with object oriented constructs and little concern for memory management.
My Satana engine is about as your program, from an ELO point of view but i use a different approach to move generation.
I'll download your engine and check it out.
My C# chess engine: https://www.madchess.net
User avatar
lucasart
Posts: 3232
Joined: Mon May 31, 2010 1:29 pm
Full name: lucasart

Re: MadChess 2.0 Development

Post by lucasart »

I dont think performance hit has anything to do with OOP. The same C code can be written with classes in C++ with no performance penalty (except a few edge cases), and vice versa. I dont see any reason why it would be differnt in C#.

The slowness is inherent to managed languages that are not compiled into machine code, and repy on garbage collectror. The performance cost of C# can be reduced to a factor 2 compared to C++, as shown by portfish, but at the cost of a lot of work and not doing things the C# way but the C way (preallocated arrays or manually allocated and deallocated etc.)

However the religious belief that every piece of code should belong to an object (whatever that means), which is typical of Java programmers, leads to bad design decision, which may result inmessy, unmaintainable, and slow code.

Sometimes OOP is nice and natural. Sometimes not. Bjarn Stroustrup keeps repeating in his talk that he's fed up of people trying to fit class hierarchies where they dont belong (eg. Java programmers who use classes instead of namespaces).

For example:
- it makes sense to make the board a class. It can have several instances (it has to for SMP). It can be constructed from a fen, or another board. It may have to allocate some memory, depending on how you manage the game stack, that should be freed in the destructor.
- It makes no sense at all to define a piece or a square as a class. This inevitably leads to complicated and inefficient code. This is where the OOP brainwashed people go wrong.
Theory and practice sometimes clash. And when that happens, theory loses. Every single time.
User avatar
stegemma
Posts: 859
Joined: Mon Aug 10, 2009 10:05 pm
Location: Italy
Full name: Stefano Gemma

Re: MadChess 2.0 Development

Post by stegemma »

lucasart wrote:[...]
- It makes no sense at all to define a piece or a square as a class. This inevitably leads to complicated and inefficient code. This is where the OOP brainwashed people go wrong.
Ops... in Satana i have a piece class. The first version of the program have engine, board, piece, move classes. In the last release, i've simplified the move class (now it is less more than a structure and doesn't have a function Execute on it) and merged board class into engine class but still i have the piece class. In my test i've seen that having a switch on the piece type, to choose the right MakeMoves, have the same speed as using virtual MakeMove funtions on the piece class.

For the rest, you're right when you say that OOP and performance are not related but wich class structure to choose is one of the programmer's choices and anything could have sense, if it helps the programmer itself.
Aleks Peshkov
Posts: 892
Joined: Sun Nov 19, 2006 9:16 pm
Location: Russia

Re: MadChess 2.0 Development

Post by Aleks Peshkov »

Declaring Square as a class allows you to write things like this with no overhead.

Code: Select all

        attack[Knight][sq] =
               sq(-2, -1) + sq(-2, +1) + sq(-1, -2) + sq(-1, +2)
             + sq(+2, +1) + sq(+2, -1) + sq(+1, +2) + sq(+1, -2);
Henk
Posts: 7220
Joined: Mon May 27, 2013 10:31 am

Re: MadChess 2.0 Development

Post by Henk »

I also don't understand how one can maintain lists for black pawns, white bishops, etcetera if you don't have a class or structure to represent a piece.

If you don't have these lists you have to iterate over their bitmap. I think that is slower than iterating over a list.
User avatar
lucasart
Posts: 3232
Joined: Mon May 31, 2010 1:29 pm
Full name: lucasart

Re: MadChess 2.0 Development

Post by lucasart »

Aleks Peshkov wrote:Declaring Square as a class allows you to write things like this with no overhead.

Code: Select all

        attack[Knight][sq] =
               sq(-2, -1) + sq(-2, +1) + sq(-1, -2) + sq(-1, +2)
             + sq(+2, +1) + sq(+2, -1) + sq(+1, +2) + sq(+1, -2);
You dont need a square class to write that. What you're writing in artificially complicated way,, is that sq(x,y) is a function taking a rank and a file and returning a bitboard.

A move class can make sense though.
Theory and practice sometimes clash. And when that happens, theory loses. Every single time.
User avatar
lucasart
Posts: 3232
Joined: Mon May 31, 2010 1:29 pm
Full name: lucasart

Re: MadChess 2.0 Development

Post by lucasart »

lucasart wrote:
Aleks Peshkov wrote:Declaring Square as a class allows you to write things like this with no overhead.

Code: Select all

        attack[Knight][sq] =
               sq(-2, -1) + sq(-2, +1) + sq(-1, -2) + sq(-1, +2)
             + sq(+2, +1) + sq(+2, -1) + sq(+1, +2) + sq(+1, -2);
You dont need a square class to write that. What you're writing in artificially complicated way,, is that sq(x,y) is a function taking a rank and a file and returning a bitboard.

A move class can make sense though.
ok, you save a bit of typing here (using a square offset ctor), but this code is written only once for bitboard initialization. How much extra typing to define all the OOP bureaucracy that allows your fancy code (ctor, offset ctor, bitboard cast, operators etc.) ?

So you have a square class. What do you do with it. Is the board going to contain an array of squares now? And how do you represent the fact that a given piece of a given color is on a square? How much OOP bureaucracy do you add to play/undo moves, when you square/piece classes? That was my point.. It's about the bigger picture, syntactic details are unimportant. piec3/square classes = wrong design. wrong design typically results in complicated and possibly inefficient code.
Theory and practice sometimes clash. And when that happens, theory loses. Every single time.
Henk
Posts: 7220
Joined: Mon May 27, 2013 10:31 am

Re: MadChess 2.0 Development

Post by Henk »

lucasart wrote:
lucasart wrote:
Aleks Peshkov wrote:Declaring Square as a class allows you to write things like this with no overhead.

Code: Select all

        attack[Knight][sq] =
               sq(-2, -1) + sq(-2, +1) + sq(-1, -2) + sq(-1, +2)
             + sq(+2, +1) + sq(+2, -1) + sq(+1, +2) + sq(+1, -2);
You dont need a square class to write that. What you're writing in artificially complicated way,, is that sq(x,y) is a function taking a rank and a file and returning a bitboard.

A move class can make sense though.
ok, you save a bit of typing here (using a square offset ctor), but this code is written only once for bitboard initialization. How much extra typing to define all the OOP bureaucracy that allows your fancy code (ctor, offset ctor, bitboard cast, operators etc.) ?

So you have a square class. What do you do with it. Is the board going to contain an array of squares now? And how do you represent the fact that a given piece of a given color is on a square? How much OOP bureaucracy do you add to play/undo moves, when you square/piece classes? That was my point.. It's about the bigger picture, syntactic details are unimportant. piec3/square classes = wrong design. wrong design typically results in complicated and possibly inefficient code.
My question is if you don't have a piece class where do you store the location of your pieces ?

Perhaps it might be beneficial to take a slightly slower evaluation for granted just to speed up do/undo move.

[By the way is it important to rewrite your program to improve speed with a factor of two. What is 70 ELO if you are at least 1000 ELO behind ]
User avatar
Evert
Posts: 2929
Joined: Sat Jan 22, 2011 12:42 am
Location: NL

Re: MadChess 2.0 Development

Post by Evert »

Henk wrote: My question is if you don't have a piece class where do you store the location of your pieces ?
Huh?
In the data-structure that represents the board state, where else?
Piece-id's and square-id's are effectively just indices referencing data tables.
Perhaps it might be beneficial to take a slightly slower evaluation for granted just to speed up do/undo move.
Depends on the individual case (you call make/unmake at least as often as eval, possibly more often), but typically the cost of make/unmake is insignificant compared to the cost of evaluation.
[By the way is it important to rewrite your program to improve speed with a factor of two. What is 70 ELO if you are at least 1000 ELO behind ]
You just answered your own question.
However, both are irrelevant if you have search bugs that need fixing first. ;)