The middlegame PST for kings seems to be wrong, it seems to favor moving the king to higher ranks instead of discouraging that.
I do not understand your MvvLvaScores[][] array. First thing is, it has a lot of redundancy by being a 13x13 array while you only need 6x6 (or 7x7). You never have captures of friendly pieces, and White takes Black can be handled with the same data as Black takes White if you use abs(). Next point, MVV/LVA means "most valuable victim/least valuable aggressor" and is usually implemented differently: all moves capturing a piece of type X should be scored higher than all captures of pieces with a lower value than X, and for two captures of the same piece type the move with the lower-valued moving piece should come first. A possible formula would be:
mvvLvaScore(move) = 6 * type_of_captured_piece(move) - type_of_moving_piece(move)
if the piece type is in the range [1 .. 6]. The factor "6" can of course be any number >= 6.
What about the raw speed of this engine? For instance, your move ordering implementation appears to be quite slow since you calculate the ordering scores for each moves within the comparison operator so you calculate it many times for the same move. What about making the ordering score a member of the move and calculating it only once?
There should be a better way (and maybe even one that is more "C++") than always accessing information related to pieces like this throughout the whole code:
Code: Select all
SOME_ARRAY[position.board[square] + PieceShift]
where PieceShift is 6 and board[square] is the piece type in the range { -6 .. +6 }. I could imagine some accessor methods of the position class, for instance:
Code: Select all
unsigned int Position::pieceIndex(Sq s) const { return board[s] + PieceShift; } // returns a number in [0 .. 12]
Piece Position::pieceType(Sq s) const { return std::abs(board[s]); } // returns a number in [0 .. 6]
Color Position::color(Sq s) const { return Colors[pieceIndex(s)]; }
I wonder why you set the hash move as killer move, I can imagine a negative impact on the quality of your move ordering.
I also wonder why you check for "king capture" within the move loop even though you also have an explicit legality check when making a move so that you can never reach a position where the enemy king can be captured. Furthermore, when ignoring that redundancy, the correct score for a position where the king can be captured should be higher than MATE-ply in my opinion since a "mated" position where all pseudo-legal moves lead to capturing the king would already have occurred one ply earlier.
If you would like to know why this engine is so weak I would suggest to disable all pruning code and test that against the original version. Maybe the problem is somewhere within the pruning?
Maybe, as a 2000 lines c++ code, it may also become an entry point for beginners.
Not sure whether a 2-days work is always suitable for that purpose

Once you know there are no serious bugs and it has an acceptable strength then go for it, otherwise I suggest first to fix the code before proposing it to beginners.