MadChess 2.0 Beta Build 038 (Killer Moves)

I added killer moves to MadChess 2.0 Beta. Killer moves are quiet moves (not captures or pawn promotions) that cause a beta cutoff. Two killer moves are saved for each ply. They are searched immediately after captures and pawn promotions.

public class KillerMoves
{
private readonly Board _board;
private readonly KillerMove[][] _killerMoves;
public KillerMoves(Board Board, int MaxDepth)
{
_board = Board;
_killerMoves = new KillerMove[MaxDepth + 1][];
for (int depth = 0; depth <= MaxDepth; depth++)
{
_killerMoves[depth] = new KillerMove[2];
_killerMoves[depth][0] = new KillerMove(Piece.None, Square.Illegal);
_killerMoves[depth][1] = new KillerMove(Piece.None, Square.Illegal);
}
}
public int GetValue(int Depth, uint Move)
{
if (Equals(_killerMoves[Depth][0], Move))
{
return 2;
}
return Equals(_killerMoves[Depth][1], Move) ? 1 : 0;
}
public void UpdateValue(int Depth, uint Move)
{
if (Equals(_killerMoves[Depth][0], Move))
{
// Move already is the best killer move.
return;
}
// Shift killer moves.
_killerMoves[Depth][1] = _killerMoves[Depth][0];
// Update killer move.
_killerMoves[Depth][0].Piece = _board.CurrentPosition.Squares[MadChess.Move.From(Move)];
_killerMoves[Depth][0].ToSquare = MadChess.Move.To(Move);
}
private bool Equals(KillerMove KillerMove, uint Move)
{
return (KillerMove.Piece == _board.CurrentPosition.Squares[MadChess.Move.From(Move)]) &&
(KillerMove.ToSquare == MadChess.Move.To(Move));
}
}

if (score >= Beta)
{
// Position is not the result of best play by both players.
if (quietMove)
{
// Update killer moves.
_killerMoves.UpdateValue(Depth, move);
}
// Update best move cache.
UpdateBestMoveCache(Depth, Horizon, move, score, Alpha, Beta);
// Beta cutoff
return Beta;
}
public uint GetNextMove(uint[] Moves, int Depth, int CandidateMoveNumber, out int MoveIndex)
{
for (int moveIndex = 0; moveIndex < _board.CurrentPosition.MoveIndex; moveIndex++)
{
uint move = Moves[moveIndex];
if (move != 0u)
{
if (CandidateMoveNumber == 0)
{
// Prioritize killer moves.
int killer = _killerMoves.GetValue(Depth, move);
Move.SetKiller(ref move, killer);
}
// TODO: Prioritize by move history.
}
}
// Find highest priority unplayed move.
uint nextMove = 0u;
MoveIndex = 0;
for (int moveIndex = 0; moveIndex < _board.CurrentPosition.MoveIndex; moveIndex++)
{
uint move = Moves[moveIndex];
if (!Move.Played(move))
{
// Move has not been played.
if (move > nextMove)
{
nextMove = move;
MoveIndex = moveIndex;
}
}
}
return nextMove;
}
view raw Search.cs hosted with ❤ by GitHub

This added 61 Elo to the playing strength of MadChess 2.0 Beta.

MadChess 2.0                   2065 :    800 (+396,=136,-268),  58.0 %

vs.                                 :  games (   +,   =,   -),   (%) :   Diff,  SD, CFS (%)
BikJump v2.01                       :    100 (  36,  21,  43),  46.5 :    -26,  11,    0.8
Matheus-2.3                         :    100 (  40,  20,  40),  50.0 :     -7,  11,   27.3
Monarch 1.7                         :    100 (  38,  19,  43),  47.5 :    +14,  11,   90.3
BigLion 2.23w                       :    100 (  49,  15,  36),  56.5 :    +44,  12,  100.0
Sharper 0.17                        :    100 (  61,   5,  34),  63.5 :    +60,  11,  100.0
Faile 1.4                           :    100 (  52,  23,  25),  63.5 :    +85,  11,  100.0
Jabba13032012                       :    100 (  62,  14,  24),  69.0 :   +117,  11,  100.0
Roce 0.0390                         :    100 (  58,  19,  23),  67.5 :   +182,  11,  100.0
Feature Category Date Rev1 WAC2 Elo Rating3 Improvement
Killer Moves Search 2015 Jan 03 38 275 2065 +61
Futility Pruning Search 2014 Dec 29 37 256 2004 +54
Null Move
Quiescence Recaptures
Search 2014 Dec 28 34 242 1950 +46
King Safety Evaluation 2014 Dec 24 32 225 1904 +27
Piece Mobility Evaluation 2014 Dec 16 29 225 1877 +64
Draw By Repetition Bug Evaluation 2014 Dec 10 27 225 1813 +47
Passed Pawns Evaluation 2014 Dec 09 26 225 1766 +72
Time Management Search 2014 Dec 08 25 231 1694 +24
Delay Move Generation
Aspiration Window Bug
Search 2014 Dec 02 23 231 1670 +44
MVV / LVA Move Order
Draw By Insufficient Material
Move List Overflow Bug
Search 2014 Dec 01 22 235 1626 +30
Tapered Evaluation
MG and EG Piece Location
Evaluation 2014 Nov 29 21 234 1596 +107
Alpha / Beta Negamax
Aspiration Windows
Quiescence, Hash
Material, Piece Squares
Baseline 2014 Nov 25 20 236 1489
  1. Subversion source code revision
  2. Win At Chess position test, 3 seconds per position
  3. Bullet chess, 2 min / game + 1 sec / move

Banks 50th Amateur Series Division 7

MadChess 1.4 participated in Graham Banks’ 50th amateur tournament in division 7.

                                  1    2    3    4    5    6    7    8    9    0    1    2    
1   Gibbon 2.60a 64-bit           **** 0001 0½½0 1½1½ 1½01 ½01½ 011½ 1111 ½111 1110 ½111 1½½1  29.0/44
2   FireFly 2.7.0 64-bit          1110 **** 0011 0½½½ ½0½1 01½½ 1111 101½ 1011 ½111 0½1½ 1½10  28.0/44
3   Fischerle 0.9.60 64-bit       1½½1 1100 **** ½1½½ ½0½1 1010 1010 ½110 ½011 ½00½ ½101 11½1  25.5/44  551.50
4   Orion 0.2 64-bit              0½0½ 1½½½ ½0½½ **** 01½0 0110 0½½0 ½½1½ 1011 1½1½ 11½1 1111  25.5/44  517.25
5   EveAnn 1.71a                  0½10 ½1½0 ½1½0 10½1 **** 011½ ½111 1101 1½0½ 00½1 ½½½½ 0½11  25.0/44
6   MadChess 1.4 64-bit           ½10½ 10½½ 0101 1001 100½ **** 1½00 1½1½ 0½11 1½½1 1½½½ 10½0  23.5/44
7   Carballo 0.8                  100½ 0000 0101 1½½1 ½000 0½11 **** ½01½ 1½½½ ½½01 0110 ½½01  20.0/44  426.75
8   MangoPaolaAjedrez 4.1         0000 010½ ½001 ½½0½ 0010 0½0½ ½10½ **** 11½1 001½ ½½11 111½  20.0/44  400.75
9   Absolute Zero 2.4.0.0 64-bit  ½000 0100 ½100 0100 0½1½ 1½00 0½½½ 00½0 **** 1½11 1½1½ 0111  19.0/44
10  Protej 0.5.8c                 0001 ½000 ½11½ 0½0½ 11½0 0½½0 ½½10 110½ 0½00 **** ½010 ½100  17.0/44  377.75
11  Exacto 0.e 64-bit             ½000 1½0½ ½010 00½0 ½½½½ 0½½½ 1001 ½½00 0½0½ ½101 **** 110½  17.0/44  364.50
12  NGplay 9.86 64-bit            0½½0 0½01 00½0 0000 1½00 01½1 ½½10 000½ 1000 ½011 001½ ****  14.5/44

Games

MadChess 2.0 Beta Build 037 (Futility Pruning)

I added futility pruning to MadChess 2.0 Beta. In the main search, for non-capture moves, if the static score plus the futility margin is less than alpha, the move is considered too weak and is skipped. In the quiescence search, for capture moves, if the static score plus the material value of the captured piece plus the futility margin is less than alpha, the move is considered too weak and is skipped. The futility margin depends on the distance to the horizon, and is subject to other constraints, illustrated in the code below.

To Horizon Futility Margin (centipawns)
<1 (Quiescence Search) 100
1 150
2 250
3 400
4 600
>4 Not Futile

// Create search parameters.
_aspirationWindows = new[] {50, 200, 500};
_futilityMargins = new[] {100, 150, 250, 400, 600};
// Search
// Determine if move is legal.
if (_board.IsMoveLegal(ref move))
{
// Move is legal.
legalMoveNumber++;
if (Depth == 0)
{
// Update root move.
_rootMove = move;
_rootMoveNumber = legalMoveNumber;
}
}
else
{
// Move is illegal.
// Mark move as played.
Move.SetPlayed(ref move, true);
moves[moveIndex] = move;
// Skip illegal move.
continue;
}
if (IsMoveFutile(Depth, Horizon, move, legalMoveNumber, staticScore, Alpha, Beta))
{
// Move is futile.
// Mark move as played.
Move.SetPlayed(ref move, true);
moves[moveIndex] = move;
// Skip move.
continue;
}
// ...
private bool IsMoveFutile(int Depth, int Horizon, uint Move, int LegalMoveNumber, int StaticScore,
int Alpha, int Beta)
{
if (Depth == 0)
{
// Root move is not futile.
return false;
}
if (LegalMoveNumber == 1)
{
// First move is not futile.
return false;
}
if (_board.CurrentPosition.KingInCheck)
{
// Move when king is in check is not futile.
return false;
}
if (MadChess.Move.IsCheck(Move))
{
// Check is not futile.
return false;
}
int fromSquare = MadChess.Move.From(Move);
byte piece = _board.CurrentPosition.Squares[fromSquare];
byte pawn;
int rank;
if (_board.CurrentPosition.WhiteMove)
{
pawn = Piece.WhitePawn;
rank = _board.WhiteRanks[fromSquare];
}
else
{
pawn = Piece.BlackPawn;
rank = _board.BlackRanks[fromSquare];
}
if ((piece == pawn) && (rank >= 6))
{
// Pawn push or promotion is not futile.
return false;
}
if ((Math.Abs(Alpha) >= Score.Checkmate) || (Math.Abs(Beta) >= Score.Checkmate))
{
// Move under threat of checkmate is not futile.
return false;
}
int toHorizon = Horizon - Depth;
byte captureVictim = MadChess.Move.CaptureVictim(Move);
if ((toHorizon > 0) && (MadChess.Move.CaptureVictim(Move) != Piece.None))
{
// Capture in main search is not futile.
return false;
}
if (toHorizon >= _futilityMargins.Length)
{
// Move far from search horizon is not futile.
return false;
}
// Determine futility margin.
int futilityMargin = toHorizon <= 0 ? _futilityMargins[0] : _futilityMargins[toHorizon];
if (futilityMargin == 0)
{
// Futility margin not enabled.
return false;
}
int materialValueCapturedPiece;
switch (captureVictim)
{
case Piece.Pawn:
materialValueCapturedPiece = Evaluation.PawnMaterialScore;
break;
case Piece.Knight:
materialValueCapturedPiece = Evaluation.KnightMaterialScore;
break;
case Piece.Bishop:
materialValueCapturedPiece = Evaluation.BishopMaterialScore;
break;
case Piece.Rook:
materialValueCapturedPiece = Evaluation.RookMaterialScore;
break;
case Piece.Queen:
materialValueCapturedPiece = Evaluation.QueenMaterialScore;
break;
default:
materialValueCapturedPiece = 0;
break;
}
bool couldPassAlpha = ((StaticScore + materialValueCapturedPiece + futilityMargin) > Alpha);
return !couldPassAlpha;
}

This added 54 Elo to the playing strength of MadChess 2.0 Beta.

MadChess 2.0                   2004 :    800 (+322,=144,-334),  49.3 %

vs.                                 :  games (   +,   =,   -),   (%) :   Diff,  SD, CFS (%)
BikJump v2.01                       :    100 (  18,  18,  64),  27.0 :    -98,  12,    0.0
Matheus-2.3                         :    100 (  28,  17,  55),  36.5 :    -75,  11,    0.0
Monarch 1.7                         :    100 (  26,  16,  58),  34.0 :    -54,  13,    0.0
BigLion 2.23w                       :    100 (  45,  11,  44),  50.5 :    -17,  10,    5.6
Sharper 0.17                        :    100 (  50,  13,  37),  56.5 :     -1,  12,   46.4
Faile 1.4                           :    100 (  42,  32,  26),  58.0 :    +24,  10,   98.8
Jabba13032012                       :    100 (  54,  22,  24),  65.0 :    +58,  11,  100.0
Roce 0.0390                         :    100 (  59,  15,  26),  66.5 :   +123,  11,  100.0
Feature Category Date Rev1 WAC2 Elo Rating3 Improvement
Futility Pruning Search 2014 Dec 29 37 256 2004 +54
Null Move
Quiescence Recaptures
Search 2014 Dec 28 34 242 1950 +46
King Safety Evaluation 2014 Dec 24 32 225 1904 +27
Piece Mobility Evaluation 2014 Dec 16 29 225 1877 +64
Draw By Repetition Bug Evaluation 2014 Dec 10 27 225 1813 +47
Passed Pawns Evaluation 2014 Dec 09 26 225 1766 +72
Time Management Search 2014 Dec 08 25 231 1694 +24
Delay Move Generation
Aspiration Window Bug
Search 2014 Dec 02 23 231 1670 +44
MVV / LVA Move Order
Draw By Insufficient Material
Move List Overflow Bug
Search 2014 Dec 01 22 235 1626 +30
Tapered Evaluation
MG and EG Piece Location
Evaluation 2014 Nov 29 21 234 1596 +107
Alpha / Beta Negamax
Aspiration Windows
Quiescence, Hash
Material, Piece Squares
Baseline 2014 Nov 25 20 236 1489
  1. Subversion source code revision
  2. Win At Chess position test, 3 seconds per position
  3. Bullet chess, 2 min / game + 1 sec / move

MadChess 2.0 Beta Build 034 (Null Move)

I added null move search to MadChess 2.0 Beta. In addition, I limited the quiescence search to recaptures if the distance from the horizon is four or more moves. If the king is in check, all moves are searched. If not, and the distance from the horizon is four or more moves, only recaptures are searched (captures of the last piece that moved).

private const int _quietSearchRecaptureDepth = 4;
private const int _nullMoveHorizonReduction = 2;
if (toHorizon <= 0)
{
// Search for a quiet position.
return GetQuietScore(Square.Illegal, Depth, Depth, OriginalHorizon, Alpha, Beta);
}
// Get static score.
int staticScore = _evaluation.GetMaterialScore();
if (NullMove && IsNullMoveAllowed(Depth, Horizon, staticScore, Beta))
{
// Null move is allowed.
// Search null move.
if (SearchNullMove(Depth, Horizon, OriginalHorizon, Beta))
{
// Enemy is unable to capitalize on position even if player forfeits right to move.
// While forfeiting right to move is illegal, this indicates position is strong.
// Position is not the result of best play by both players.
// Update best move cache.
UpdateBestMoveCache(Depth, Horizon, 0u, Beta, Alpha, Beta);
// Beta cutoff.
return Beta;
}
}
private bool IsNullMoveAllowed(int Depth, int Horizon, int StaticScore, int Beta)
{
// Null move may be allowed.
if (Depth == 0)
{
// Do not attempt null move at the root.
return false;
}
if ((Horizon - Depth) <= _nullMoveHorizonReduction)
{
// Do not attempt null move near search horizon.
return false;
}
if (StaticScore < Beta)
{
// Do not attempt null move if static score is less than beta.
return false;
}
if (_board.CurrentPosition.KingInCheck)
{
// Do not attempt null move if king is in check.
return false;
}
// Do not attempt null move if side to move has one minor or major piece or less.
int minorAndMajorPieces = _board.CurrentPosition.WhiteMove ? _board.CurrentPosition.WhiteMinorPieces +
_board.CurrentPosition.WhiteMajorPieces :
_board.CurrentPosition.BlackMinorPieces + _board.CurrentPosition.BlackMajorPieces;
return minorAndMajorPieces > 1;
}
private bool SearchNullMove(int Depth, int Horizon, int OriginalHorizon, int Beta)
{
// Get move horizon.
int moveHorizon = Horizon - _nullMoveHorizonReduction;
// Play null move.
_board.PlayNullMove();
// Search with zero alpha / beta window.
int score = -GetDynamicScore(Depth + 1, moveHorizon, OriginalHorizon, false, -Beta, -Beta + 1);
// Undo null move.
_board.UndoMove();
return score >= Beta;
}

int fromHorizon = Depth - Horizon;
if (searchOnlyCaptures && (fromHorizon >= _quietSearchRecaptureDepth) && (RecaptureSquare != Square.Illegal))
{
// Generate recaptures.
_board.GenerateCaptures(RecaptureSquare);
}
else
{
// Generate moves.
_board.GenerateMoves(searchOnlyCaptures);
}
// Sort moves.
SortMovesByPriority(_board.CurrentPosition.Moves, 0, _board.CurrentPosition.MoveIndex - 1, true, 0ul, Depth);

These enhancements added 46 Elo to the playing strength of MadChess 2.0 Beta.

MadChess 2.0                   1950 :    800 (+271,=150,-379),  43.3 %

vs.                                 :  games (   +,   =,   -),   (%) :   Diff,  SD, CFS (%)
BikJump v2.01                       :    100 (  23,  20,  57),  33.0 :   -132,  12,    0.0
Matheus-2.3                         :    100 (  27,  17,  56),  35.5 :   -114,  12,    0.0
Monarch 1.7                         :    100 (  22,  17,  61),  30.5 :    -95,  13,    0.0
BigLion 2.23w                       :    100 (  27,  20,  53),  37.0 :    -64,  11,    0.0
Faile 1.4                           :    100 (  36,  27,  37),  49.5 :    -50,  10,    0.0
Sharper 0.17                        :    100 (  46,  15,  39),  53.5 :    -37,  12,    0.1
Jabba13032012                       :    100 (  48,   9,  43),  52.5 :    +16,  11,   92.1
Roce 0.0390                         :    100 (  42,  25,  33),  54.5 :    +90,  11,  100.0
Feature Category Date Rev1 WAC2 Elo Rating3 Improvement
Null Move
Quiescence Recaptures
Search 2014 Dec 28 34 242 1950 +46
King Safety Evaluation 2014 Dec 24 32 225 1904 +27
Piece Mobility Evaluation 2014 Dec 16 29 225 1877 +64
Draw By Repetition Bug Evaluation 2014 Dec 10 27 225 1813 +47
Passed Pawns Evaluation 2014 Dec 09 26 225 1766 +72
Time Management Search 2014 Dec 08 25 231 1694 +24
Delay Move Generation
Aspiration Window Bug
Search 2014 Dec 02 23 231 1670 +44
MVV / LVA Move Order
Draw By Insufficient Material
Move List Overflow Bug
Search 2014 Dec 01 22 235 1626 +30
Tapered Evaluation
MG and EG Piece Location
Evaluation 2014 Nov 29 21 234 1596 +107
Alpha / Beta Negamax
Aspiration Windows
Quiescence, Hash
Material, Piece Squares
Baseline 2014 Nov 25 20 236 1489
  1. Subversion source code revision
  2. Win At Chess position test, 3 seconds per position
  3. Bullet chess, 2 min / game + 1 sec / move

MadChess 2.0 Beta Build 032 (King Safety)

I added king safety evaluation to MadChess 2.0 Beta. Defects in king protection (missing pawn shield, semi-open files adjacent to king, squares near king attacked by enemy pieces) are counted, then used as an index into a non-linear piece coordination table.

private const int _kingSafetyMissingPawn = 2;
private const int _kingSafetySemiOpenFile = 4;
private const int _kingSafetyMinorAttackOuterRing = 1;
private const int _kingSafetyMinorAttackInnerRing = 2;
private const int _kingSafetyMajorAttackOuterRing = 1;
private const int _kingSafetyMajorAttackInnerRing = 3;
private readonly int[] = new[] {0, 0, 1, 2, 4, 6, 9, 12, 16, 20, 25, 30, 36, 42, 49, 56, 64, 72, 81,
90,100, 110, 121, 132, 144, 156, 169, 182, 196, 210, 225, 240, 256}; // 0.25 * x Pow 2
// Bishops, for example. Code for other pieces is similar.
case Piece.WhiteBishop:
_whiteBishops++;
materialScore += _bishopMaterialScore;
mgLocationScore += _whiteBishopMgLocationScores[square];
egLocationScore += _whiteBishopEgLocationScores[square];
_board.CountBishopMovesAndKingAttacks(square, pieceMin, pieceMax, out moves, out kingAttacksOuterRing,
out kingAttacksInnerRing);
mgPieceMobility += _bishopMgMobility[moves];
egPieceMobility += _bishopEgMobility[moves];
whitePieceCoordination += (kingAttacksOuterRing * _kingSafetyMinorAttackOuterRing) + (kingAttacksInnerRing
* _kingSafetyMinorAttackInnerRing);
break;
public void CountBishopMovesAndKingAttacks(int Square, byte OwnPieceMin, byte OwnPieceMax, out int Moves,
out int KingAttacksOuterRing, out int KingAttacksInnerRing)
{
Moves = 0;
KingAttacksOuterRing = 0;
KingAttacksInnerRing = 0;
int kingSquare = OwnPieceMin == Piece.WhitePawn ? CurrentPosition.BlackKingSquare :
int kingAttackSquare;
CurrentPosition.WhiteKingSquare;
int kingAttackSquare;
foreach (int direction in _bishopDirections)
{
int otherSquare = Square;
while (true)
{
otherSquare = _squareIndices[otherSquare][direction];
if (otherSquare == MadChess.Square.Illegal)
{
// Illegal square
break;
}
byte otherPiece = CurrentPosition.Squares[otherSquare];
if (otherPiece == Piece.None)
{
// Empty square
Moves++;
kingAttackSquare = _kingAttackSquares[kingSquare][otherSquare];
switch (kingAttackSquare)
{
case KingAttackSquare.OuterRing:
KingAttacksOuterRing++;
break;
case KingAttackSquare.InnerRing:
KingAttacksInnerRing++;
break;
}
}
else if ((otherPiece >= OwnPieceMin) && (otherPiece <= OwnPieceMax))
{
// Own piece
break;
}
else
{
// Enemy piece
Moves++;
kingAttackSquare = _kingAttackSquares[kingSquare][otherSquare];
switch (kingAttackSquare)
{
case KingAttackSquare.OuterRing:
KingAttacksOuterRing++;
break;
case KingAttackSquare.InnerRing:
KingAttacksInnerRing++;
break;
}
break;
}
}
}
}
private int EvaluateKingSafety(int WhitePieceCoordination, int BlackPieceCoordination)
{
// Count pawns missing from squares in front of white king.
int missingPawns = _board.CountMissingPawnShield(true);
BlackPieceCoordination += missingPawns * _kingSafetyMissingPawn;
// Count pawns missing from squares in front of black king.
missingPawns = _board.CountMissingPawnShield(false);
WhitePieceCoordination += missingPawns * _kingSafetyMissingPawn;
// Count semi-open files adjacent to white king.
int minFile = Math.Max(_board.Files[_board.CurrentPosition.WhiteKingSquare] - 1, 1);
int maxFile = Math.Min(_board.Files[_board.CurrentPosition.WhiteKingSquare] + 1, 8);
int semiOpenFiles = 0;
for (int file = minFile; file <= maxFile; file++)
{
if (_whiteMostAdvancedPawns[file] == 0)
{
semiOpenFiles++;
}
}
BlackPieceCoordination += semiOpenFiles * _kingSafetySemiOpenFile;
// Count semi-open files adjacent to black king.
minFile = Math.Max(_board.Files[_board.CurrentPosition.BlackKingSquare] - 1, 1);
maxFile = Math.Min(_board.Files[_board.CurrentPosition.BlackKingSquare] + 1, 8);
semiOpenFiles = 0;
for (int file = minFile; file <= maxFile; file++)
{
if (_blackMostAdvancedPawns[file] == 0)
{
semiOpenFiles++;
}
}
WhitePieceCoordination += semiOpenFiles * _kingSafetySemiOpenFile;
// White piece coordination negatively impacts black king safety.
int index = Math.Min(WhitePieceCoordination, _kingSafetyPieceCoordination.Length - 1);
int blackKingSafety = -_kingSafetyPieceCoordination[index];
// Black piece coordination negatively impacts white king safety.
index = Math.Min(BlackPieceCoordination, _kingSafetyPieceCoordination.Length - 1);
int whiteKingSafety = -_kingSafetyPieceCoordination[index];
return whiteKingSafety - blackKingSafety;
}

It took me several attempts to calibrate the weights and the non-linear penalty, but eventually I found an improvement. This added 27 Elo to the playing strength of MadChess 2.0 Beta.

MadChess 2.0                   1904 :    800 (+233,=127,-440),  37.1 %

vs.                                 :  games (   +,   =,   -),   (%) :   Diff,  SD, CFS (%)
BikJump v2.01                       :    100 (   6,  18,  76),  15.0 :   -190,  12,    0.0
Matheus-2.3                         :    100 (  17,  18,  65),  26.0 :   -165,  12,    0.0
Monarch 1.7                         :    100 (  18,  15,  67),  25.5 :   -142,  13,    0.0
BigLion 2.23w                       :    100 (  29,  16,  55),  37.0 :   -107,  12,    0.0
Faile 1.4                           :    100 (  33,  19,  48),  42.5 :    -96,  10,    0.0
Sharper 0.17                        :    100 (  32,  18,  50),  41.0 :    -87,  12,    0.0
Jabba13032012                       :    100 (  46,   8,  46),  50.0 :    -28,  11,    0.5
Roce 0.0390                         :    100 (  52,  15,  33),  59.5 :    +49,  11,  100.0
Feature Category Date Rev1 WAC2 Elo Rating3 Improvement
King Safety Evaluation 2014 Dec 24 32 225 1904 +27
Piece Mobility Evaluation 2014 Dec 16 29 225 1877 +64
Draw By Repetition Bug Evaluation 2014 Dec 10 27 225 1813 +47
Passed Pawns Evaluation 2014 Dec 09 26 225 1766 +72
Time Management Search 2014 Dec 08 25 231 1694 +24
Delay Move Generation
Aspiration Window Bug
Search 2014 Dec 02 23 231 1670 +44
MVV / LVA Move Order
Draw By Insufficient Material
Move List Overflow Bug
Search 2014 Dec 01 22 235 1626 +30
Tapered Evaluation
MG and EG Piece Location
Evaluation 2014 Nov 29 21 234 1596 +107
Alpha / Beta Negamax
Aspiration Windows
Quiescence, Hash
Material, Piece Squares
Baseline 2014 Nov 25 20 236 1489
  1. Subversion source code revision
  2. Win At Chess position test, 3 seconds per position
  3. Bullet chess, 2 min / game + 1 sec / move