Computer Chess Club Archives


Search

Terms

Messages

Subject: Re: c,c++5,c#.

Author: Russell Reagan

Date: 21:04:08 08/15/04

Go up one level in this thread


On August 15, 2004 at 10:46:51, Sune Fischer wrote:

>If you use rotated bitboards you'll perhaps note that move_piece(from,to) can be
>optimized for captures since you don't need to set rotated bits on the to-square
>(except for e.p.).
>So lifting pieces off the board and setting them back down can be optimized if
>you do it all in one go.
>
>Little things like that made me realize that wrapping things in tiny methods
>weren't going to be easy without a cost.

I thought about that, but I decide that I would take the small speed hit in this
instance for reasons explained below. I also have hope that the optimizer will
take a sequence of function calls and perform the optimization you mentioned,
removing any redundant work. If not now, maybe in a few years as optimizers
continue to improve.

>I think that your access functions can still be called from anywhere to do
>something which would corrupt, so it's not really a guarantee.

That isn't the main reason I use a class for this. There are two main goals. One
is to establish and maintain an invariant. The other is to make that class as
minimal as possible to protect encapsulation. I'll give you links to the
articles that led me to adopt this approach.

http://www.artima.com/intv/goldilocks.html
This one is an interview with Bjarne Stroustrup. He talks about using a class as
a means to establish and maintain an invariant, and minimizing member functions
to increase the level of encapsulation.

http://www.cuj.com/documents/s=8042/cuj0002meyers/
This is an article my Scott Meyers. This one addresses the encapsulation issue.

If you've read those and understand why and how I would create a board class the
way I have, then maybe my explanation will make more sense.

In my chess program, going back to the board example, I have created a class
that establishes an invariant (all of the bitboards or piece lists are in sync
with the board array), and I maintain that invariant. I then provide efficient
access to the things that other parts of the program will need (bitboards, piece
lists, etc.), and lastly I don't add any member functions that don't need to be
member functions.

Example 1: I may accidentally call add_piece() somewhere in the program, but the
board remains valid. I'd rather the board remain valid and play an inferior move
(or even an illegal move) than just crash. I'm also much less likely to
accidentally call a function like add_piece() than I am to make a typo like: if
(board[sq] = empty) { ... }

Example 2: If I need to find out if my king is in check, I'd make that a
non-member function. I provide efficient access to my board's data and write a
non-member function. My data is never at risk.

You mentioned making board a const when passing it to a non-member function.
That is true, and it minimizes my advantage quite a bit, but I can also do that
in addition to my approach, and I have some extra safety nets while you have to
always remember to make it const. I will always prefer to rely on the compiler
and put it out of my mind than to always remind myself, "Don't forget to make it
const..."

>Wow, over 50? You have more experience than me then :)

Let's just say that I probably have more experience at writing perft calculators
that don't work correctly all of the time :) This new approach I've taken is
working much better than my many previous failed attempts. Pretty much every one
of these failed attempts was due to premature optimization. It really is as
deadly as they say...



This page took 0 seconds to execute

Last modified: Thu, 15 Apr 21 08:11:13 -0700

Current Computer Chess Club Forums at Talkchess. This site by Sean Mintz.