views:

507

answers:

9

ok, so i have been working on my chess program for a while and i am beginning to hit a wall. i have done all of the standard optimizations (negascout, iterative deepening, killer moves, history heuristic, quiescent search, pawn position evaluation, some search extensions) and i'm all out of ideas!

i am looking to make it multi-threaded soon, and that should give me a good boost in performance, but aside from that are there any other nifty tricks you guys have come across? i have considered switching to MDF(f), but i have heard it is a hassle and isn't really worth it.

what i would be most interested in is some kind of learning algorithm, but i don't know if anyone has done that effectively with a chess program yet.

also, would switching to a bit board be significant? i currently am using 0x88.

A: 

Assuming "history heuristic" involves some sort of database of past moves, a learning algorithm isn't going to give you much more unless it plays a lot of games against the same player. You can probably achieve more by classifying a player and tweaking the selection of moves from your historic database.

Draemon
currently, my history heuristic just keeps the history from one running of the program to the next. i guess i will make that persistent and have separate tables for each player i play.
twolfe18
In that case why not use a database of previous moves (eg high profile games have moves listed on the web) categorised by skill, aggression, etc - that gives you a lot of valuable data.
Draemon
well, i think to really get any benefit, you need a huge amount of moves before any improvement is noticed (depends on your weighting heuristic though). if you consider the amount of lines possible in a game, a few games worth of moves probably wont help too much.
twolfe18
A: 

It's been a long time since I've done any programming on any chess program, but at the time, bit boards did give a real improvement. Other than that I can't give you much advise. Do you only evaluate the position of pawns? Some (slight) bonuses for position or mobility of some key pieces may be in order.

I'm not certain what type of thing you would like it to learn however...

Thorarin
+2  A: 

I know that one improvement that was talked about at the AI courses in university where having a huge database of finishing moves. So having a precalculated database for games with only a small number of figures left. So that if you hit a near end positioning in your search you stop the search and take a precalculated value that improves your search results like extra deepening that you can do for important/critique moves without much computation time spend. I think it also comes with a change in heuristics in a late game state but I'm not a chess player so I don't know the dynamics of game finishing.

Janusz
A: 

As far as tips, I know large gains can be found in optimizing your move generation routines before any eval functions. Making that function as tight as possible can give you 10% or more in nodes/sec improvement.

If you're moving to bitboards, do some digging on rec.games.chess.computer archives for some of Dr. Robert Hyatts old posts about Crafty (pretty sure he doesn't post anymore). Or grab the latest copy from his FTP and start digging. I'm pretty sure it would be a significant shift for you though.

Tom
+1  A: 
  • Transposition Table
  • Opening Book
  • End Game Table Bases
  • Improved Static Board Evaluation for Leaf Nodes
  • Bitboards for Raw Speed
FogleBird
A: 

Be warned, getting game search right in a threaded environment can be a royal pain (I've tried it). It can be done, but from some literature searching I did a while back, it's extremely hard to get any speed boost at all out of it.

BCS
+10  A: 

Over the last year of development of my chess engine (www.chessbin.com), much of the time has been spent optimizing my code to allow for better and faster move searching. Over that time I have learned a few tricks that I would like to share with you.

Measuring Performance

Essentially you can improve your performance in two ways:

  • Evaluate your nodes faster
  • Search fewer nodes to come up with the same answer

Your first problem in code optimization will be measurement. How do you know you have really made a difference? In order to help you with this problem you will need to make sure you can record some statistics during your move search. The ones I capture in my chess engine are:

  • Time it took for the search to complete.
  • Number of nodes searched

This will allow you to benchmark and test your changes. The best way to approach testing is to create several save games from the opening position, middle game and the end game. Record the time and number of nodes searched for black and white. After making any changes I usually perform tests against the above mentioned save games to see if I have made improvements in the above two matrices: number of nodes searched or speed.

To complicate things further, after making a code change you might run your engine 3 times and get 3 different results each time. Let’s say that your chess engine found the best move in 9, 10 and 11 seconds. That is a spread of about 20%. So did you improve your engine by 10%-20% or was it just varied load on your pc. How do you know? To fight this I have added methods that will allow my engine to play against itself, it will make moves for both white and black. This way you can test not just the time variance over one move, but a series of as many as 50 moves over the course of the game. If last time the game took 10 minutes and now it takes 9, you probably improved your engine by 10%. Running the test again should confirm this.

Finding Performance Gains

Now that we know how to measure performance gains lets discuss how to identify potential performance gains.

If you are in a .NET environment then the .NET profiler will be your friend. If you have a Visual Studio for Developers edition it comes built in for free, however there are other third party tools you can use. This tool has saved me hours of work as it will tell you where your engine is spending most of its time and allow you to concentrate on your trouble spots. If you do not have a profiler tool you may have to somehow log the time stamps as your engine goes through different steps. I do not suggest this. In this case a good profiler is worth its weight in gold. Red Gate ANTS Profiler is expensive but the best one I have ever tried. If you can’t afford one, at least use it for their 14 day trial.

Your profiler will surly identify things for you, however here are some small lessons I have learned working with C#:

  • Make everything private
  • Whatever you can’t make private, make it sealed
  • Make as many methods static as possible.
  • Don’t make your methods chatty, one long method is better than 4 smaller ones.
  • Chess board stored as an array [8][8] is slower then an array of [64]
  • Replace int with byte where possible.
  • Return from your methods as early as possible.
  • Stacks are better than lists
  • Arrays are better than stacks and lists.
  • If you can define the size of the list before you populate it.
  • Casting, boxing, un-boxing is evil.

Further Performance Gains:

I find move generation and ordering is extremely important. However here is the problem as I see it. If you evaluate the score of each move before you sort and run Alpha Beta, you will be able to optimize your move ordering such that you will get extremely quick Alpha Beta cutoffs. This is because you will be able to mostly try the best move first. However the time you have spent evaluating each move will be wasted. For example you might have evaluated the score on 20 moves, sort your moves try the first 2 and received a cut-off on move number 2. In theory the time you have spent on the other 18 moves was wasted.

On the other hand if you do a lighter and much faster evaluation say just captures, your sort will not be that good and you will have to search more nodes (up to 60% more). On the other hand you would not do a heavy evaluation on every possible move. As a whole this approach is usually faster.

Finding this perfect balance between having enough information for a good sort and not doing extra work on moves you will not use, will allow you to find huge gains in your search algorithm. Furthermore if you choose the poorer sort approach you will want to first to a shallower search say to ply 3, sort your move before you go into the deeper search (this is often called Iterative Deepening). This will significantly improve your sort and allow you to search much fewer moves.

Adam Berent
+1 awesome answer, but one small nitpick: `If you can define the size of the list before you populate it.` ... what?
RCIX
He probably meant that if you can define the size beforehand, you should.
jasonh
List<byte> = new List<byte>(100)
Adam Berent
+1  A: 

Answering an old question.

Assuming you already have a working transposition table.

Late Move Reduction. That gave my program about 100 elo points and it is very simple to implement.

In my experience, unless your implementation is very inefficient, then the actual board representation (0x88, bitboard, etc.) is not that important.

Although you can criple you chess engine with bad performance, a lightning fast move generator in itself is not going to make a program good.

The search tricks used and the evaluation function are the overwhelming factors determining overall strength.

And the most important parts, by far, of the evaluation are Material, Passed pawns, King Safety and Pawn Structure.

The most important parts of the search are: Null Move Pruning, Check Extension and Late Move reduction.

Your program can come a long, long way, on these simple techniques alone!

Jesper Nielsen
A: 

Its quite an old question, I was just searching questions on chess and found this one unanswered. Well it may not be of any help to you now, but may prove helpful to other users.

I didn't see null move pruning, transposition tables.. are you using them? They would give you a big boost...

One thing that gave me a big boost was minimizing conditional branching... Alot of things can be precomputed. Search for such opportunities.

Most modern PCs have multiple cores so it would be a good idea making it multithreading. You don't necessarily need to go MDF(f) for that.

I wont suggest moving your code to bitboard. Its simply too much work. Even though bitboards could give a boost on 64 bit machines.

Finally and most importantly chess literature dominates any optimizations we may use. optimization is too much work. Look at open source chess engines, particularly crafty and fruit/toga. Fruit used to be open source initially.

Umair Ahmed