ZirconiumX wrote:Number 1:
Do I make my nullmove all-powerful and watch it play rubbishly in the endgame etc, or do I make my Futility Pruning all-powerful and starve nullmove of nodes?
Number 2:
Play well, and slowly, or play rubbishly, but go extremely fast.
Number 3:
Evaluation (ATM I only have PSTs, and mobility made it bring out it's queen on move 2..) or Search (Alpha-Beta, has no move ordering as I'm not sure how to implement it, Futility, Extended Futility, Limited Razoring, Nullmove, LMR, Some extensions, FHR and some other stuff)?
Number 4:
Blog (
lucichess.blogspot.com ) or Tinker?
Matthew:out
When developing Blackmail, I tried all of these things out of order. Your first priority should be to write a working (read: bug-free) search/qsearch algorithm with a working (read: bug-free) material+pst evaluation.
Don't worry about improvements such as lmr, futility, etc. until your evaluation is fairly complicated. lmr always hurt Blackmail significantly until two or three months ago, and I haven't worked on it much since because of school and work this semester. You should wait to perform some of these improvements until you start seeing your engine sacrifice pawns for positional advantage and then converting that advantage to a win. Then and only then, worry about advanced reduction/pruning methods like lmr and futility. Blackmail still does not perform razoring because it hurts very badly and does not reduce as aggressively as other engines using lmr.
Once you have your search/evaluation bug-free, work on move ordering (which I see you're doing). This includes hashtables, iid, history, killers, null move, etc. Good move ordering will improve your engine a lot more than anything else; some improvements I made to Blackmail's move ordering proved to be 200+ elo after 1000 or more games. (more than once!)
Also, don't concentrate so much on how many nodes your engine searches to a given depth, or how (un)intelligent some moves seem. Blackmail used to move d1f3 all the time in its early stages of development, so whatever it is you're doing, you're probably doing it right so far in my opinion. Instead of trying to figure out why it's doing what it's doing, you should just keep making small improvements one at a time until it's so smart you couldn't possibly understand why it's doing what it's doing. I'm the best at chess in my few circles of friends, but Blackmail has far surpassed my level of chess ability that I couldn't possibly beat it especially at fast time controls. It made all the same mistakes your engine is probably making at this point and will make in the future.
The best advice I can give is to set up Arena tournaments (or whatever gui fancies you) and test your engine against itself. Don't bother testing against some of the engines that come with the gui, they'll likely beat you so bad the results won't be useful to you. For Blackmail, I set up games at 1s/move time controls; Blackmail only supports the st and sd commands. Using sd, you may be able to beat some of the stronger engines even at your stage, but the results won't be useful. You want to see your engine searching faster and deeper just because it knows how to play better.
The very first thing I would do is to take the current version of your engine, make one .exe with only material+PST and one with material+PST+mobilty, pit them against each other in Arena using 1s time controls, and wait a day or two while they play each other. You should get about 300 games in 24 hours if there are no hiccups.
As far as documentation, I wish that I did something similar to Mediocre chess so I could remember some things, but I didn't. I would recommend doing so. When you make a change, make a post, or page in a word document and post your results if for no other reason than to know what you've tried. Keep in mind that trying something now may produce bad results, but good results later on (lmr for me, for example).
You can use my sorting code from Blackmail if you're having problems with it still. Just place this in a header file (sort.h):
Code: Select all
template <typename T> void comb_sort(T *a, int n)
{
int gap = n;
bool swapped = true;
while ( (gap > 1) || swapped ) {
if ( gap > 1 ) {
gap = (gap * 4) / 5;
}
swapped = false;
for (int i=0; i+gap<n; i++) {
if (a[i] < a[i + gap]) {
T temp = a[i];
a[i] = a[i+gap];
a[i+gap] = temp;
swapped = true;
}
}
}
}
Then use it like this. There is no need to write different sort functions for different types of things, just input the pointer to the first element in an array, and the number of items in the array:
Code: Select all
comb_sort(movestack, totalmoves);
If movestack is a struct or class, you must define a < operator for it:
Code: Select all
typedef unsigned int Move;
typedef struct MoveStack {
Move move;
int seescore;
int extensions;
int sortvalue;
} MoveStack;
//Used for sorting moves in a stack
inline bool operator< (const MoveStack &a, const MoveStack &b) { return a.sortvalue < b.sortvalue; }