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.