Henk wrote:Sven Schüle wrote:Henk wrote:In my current implementation I did not do table look-ups near the leaves just to make sure it would not become a performance bottleneck.
Why should a hash table lookup that helps to avoid searching again many subtrees, and/or helps to improve move ordering, become a performance bottleneck?
EDIT: here I assume your remark was about TT lookup, since you previously wrote that your current implementation does not include a pawn hash table.
Perhaps it doesn't but I wanted to make sure it certainly does not. Also I was focusing on nodes/second because Skipper was five times slower than fairy-max.
I suggest not to focus on nodes per second. Your engine will never reach any reasonable strength as long as your strategy is to focus on nodes per second.
Here is what I suggest you should focus on, basically in this order (although steps 5 and 6 might be interchangeable, don't worry).
1. Focus on having no bugs.
2. Focus on still having no bugs

Especially make sure to start based on a 100% correct board representation, make/unmake, move generator, attack calculation and other very basic routines. ASSERT, Perft and others are your friends ...
3. Start with a very simple and very fast evaluation with just material, a roughly reasonable piece-square table and maybe a simple passed pawn eval. Ideally material and PST eval are calculated incrementally during makeMove() so that the actual evalution function is really minimal in the beginning. Keep this version of eval until you have a really fast and decent search (i.e., after step 7 further down is completed). It is definitely possible to reach ELO 2200 or even much more with a simple eval combined with a strong search. A world-class engine needs a decent evaluation, of course, but ELO 2200 doesn't.
Also use tapered eval to be well prepared for endgame evaluation (especially important for kings).
4. Implement a simple and obviously correct basic alpha-beta search with quiescence search, MVV/LVA-based move ordering, and iterative deepening, where the best move of the previous iteration is always searched first. The initial search code should not take significantly more than about 100 lines of code (depending on the programming language, of course).
5. Add a transposition hash table. Use it for TT pruning first, then for move ordering as well.
6. Add a simple and obviously working implementation of nullmove pruning.
7. Improve the search step by step while still keeping the very simple evaluation. Take care not to introduce new bugs. Watch the branching factor and time-to-depth instead of NPS.
Test really a lot, invest much more time in testing than in changing the code. Search features to be added step by step may include PVS, IID, LMR, killer move, history heuristic, "delta pruning", mate distance pruning, SEE (to skip losing captures in QS), nullmove verification, and many others. Don't add two of them at once, only add the next one after ensuring that the previous one has definitely improved the engine (otherwise leave it out!) and no new bugs were introduced.
8. Now you should have an engine with an effective branching factor lower than, say, 4.0 (should be even less), and with a strength above ELO 2000 at least (should be even more). Now it might be time to do any of the following steps, ideally in this order:
a) Add evaluation features, one at a time. When adding pawn structure evaluation it may make sense to also add a pawn hash table.
b) Tune evaluation parameters.
c) Take care about speed, in terms of nodes per second.
That should be sufficient to make progress.