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.