Author: Sune Fischer
Date: 00:16:19 08/16/04
Go up one level in this thread
On August 16, 2004 at 00:04:08, Russell Reagan wrote:
>>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.
I'd like to see Bjarne write an open source chess program :)
>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 would not, actually. If there is a bug it's about finding it as soon as
possible. A crash will tell you instantly if something is wrong :)
Unfortunately not all bugs cause crashes.
>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) { ... }
Agreed, so you use something like sq.IsEmpty()?
I wonder how much of such abuse a compiler can handle :)
>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.
I think this would be very inefficient, I do checks incrementally.
I figured since you need to know at every node anyway for move generation, there
is a good reason to do it incrementally.
>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..."
What I meant was making the member function const, like this
int Board::Eval(...) const;
The advantage is that you still have full access to all variables, as opposed to
a non-member that will have to uses accessers.
I find that it's too much trouble to write e.g.
int OtherClass::Eval(Board * B) {
if (B->GetWhiteRooks() & ....)
}
it really does not improve readability, IMO, it only clutters the code.
Of course you could replace that call with macros, but I think we both would
dislike that solution.
Now compare the above with
int Board::Eval(...) const {
if (white_rooks & ...)
}
Not even a member selection operator needed! :)
It's my personal preference that the latter is more readable and that
readability in this case outweighs the tiny risk it may involve.
>>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...
I'd suggest that you should rather focus on getting good move ordering than a
speedy generation, generation won't be a bottleneck anyway.
-S.
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.