Skip to content

Commit

Permalink
Merge pull request #2 from Tearth/v2.0-dev
Browse files Browse the repository at this point in the history
v2.0 (Darkness), 19.10.2020
  • Loading branch information
Tearth authored Oct 19, 2020
2 parents d208cb6 + 5ef14c6 commit a7fe9d7
Show file tree
Hide file tree
Showing 135 changed files with 3,504 additions and 1,331 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -349,3 +349,4 @@ MigrationBackup/
.ionide/
/cloc.exe
/cloc.bat
/Cosette.Arbiter/settings.json
28 changes: 26 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,28 @@
# Version 1.0 (Aqua), 19-09-2020
* Initial version
# Version 2.0 (Darkness), 19.10.2020
- Added fifty-move rule detection
- Added new evaluation functions: pawn shield, bishop pair, doubled rooks, a rook on open file
- Added "evaluate" command to get FEN position evaluation
- Added ability to postpone moves generation before PV move check
- Added evaluation hash table
- Added Arbiter app to speed up the process of testing engine
- Added support for UCI's winc and binc
- Fixed PV node detection
- Fixed invalid detection of passing pawns
- Fixed invalid best move when a search has been aborted
- Fixed static exchange evaluation - in rare cases the table was returning an invalid score
- Improved method of probing piece type at the specified field
- Improved time management - now allocated time depends on the moves count
- Improved move ordering: castling and better promotions are now prioritized
- Improved transposition tables: entries are now smaller, have proper checkmate scores (relative to position) and are used between moves (aging)
- Redefined and reduced the size of Move structure (from 4 bytes to 2 bytes)
- Reduced size of transposition table entry (from 16 bytes to 12 bytes), evaluation hash table entry (from 8 bytes to 4 bytes) and pawn hash table entry (from 8 bytes to 4 bytes)
- Optimized printing UCI output
- Adjusted move ordering scores
- Updated .NET Core runtime version to 3.1.403

Estimated strength: 1950 ELO

# Version 1.0 (Aqua), 19.09.2020
- Initial version

Estimated strength: 1900 ELO
20 changes: 20 additions & 0 deletions Cosette.Arbiter.Tests/Cosette.Arbiter.Tests.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>

<IsPackable>false</IsPackable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.6.0" />
<PackageReference Include="xunit" Version="2.4.0" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.0" />
<PackageReference Include="coverlet.collector" Version="1.2.0" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\Cosette.Arbiter\Cosette.Arbiter.csproj" />
</ItemGroup>

</Project>
33 changes: 33 additions & 0 deletions Cosette.Arbiter.Tests/HashKeyTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
using System;
using System.Collections.Generic;
using Cosette.Arbiter.Book;
using Xunit;

namespace Cosette.Arbiter.Tests
{
public class HashKeyTests
{
[Theory]
[InlineData(new string[] { }, 5060803636482931868)]
[InlineData(new[] { "e2e4" }, 9384546495678726550)]
[InlineData(new[] { "e2e4", "d7d5" }, 528813709611831216)]
[InlineData(new[] { "e2e4", "d7d5", "e4e5", }, 7363297126586722772)]
[InlineData(new[] { "e2e4", "d7d5", "e4e5", "f7f5" }, 2496273314520498040)]
[InlineData(new[] { "e2e4", "d7d5", "e4e5", "f7f5", "e1e2" }, 7289745035295343297)]
[InlineData(new[] { "e2e4", "d7d5", "e4e5", "f7f5", "e1e2", "e8f7" }, 71445182323015129)]
[InlineData(new[] { "a2a4", "b7b5", "h2h4", "b5b4", "c2c4" }, 4359805404264691255)]
[InlineData(new[] { "a2a4", "b7b5", "h2h4", "b5b4", "c2c4", "b4c3", "a1a3" }, 6647202560273257824)]
public void HashKey_FromInitialPosition(string[] moves, ulong expectedHashKey)
{
var polyglotBoard = new PolyglotBoard();
polyglotBoard.InitDefaultState();

foreach (var move in moves)
{
polyglotBoard.MakeMove(move);
}

Assert.Equal(expectedHashKey, polyglotBoard.CalculateHash());
}
}
}
17 changes: 17 additions & 0 deletions Cosette.Arbiter/Book/CastlingFlags.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
using System;

namespace Cosette.Arbiter.Book
{
[Flags]
public enum CastlingFlags
{
None = 0,
WhiteShort = 1,
WhiteLong = 2,
BlackShort = 4,
BlackLong = 8,
WhiteCastling = WhiteShort | WhiteLong,
BlackCastling = BlackShort | BlackLong,
Everything = WhiteShort | WhiteLong | BlackShort | BlackLong
}
}
8 changes: 8 additions & 0 deletions Cosette.Arbiter/Book/ColorType.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
namespace Cosette.Arbiter.Book
{
public enum ColorType
{
White,
Black
}
}
19 changes: 19 additions & 0 deletions Cosette.Arbiter/Book/PieceType.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
namespace Cosette.Arbiter.Book
{
public enum PieceType
{
None = -1,
BlackPawn,
WhitePawn,
BlackKnight,
WhiteKnight,
BlackBishop,
WhiteBishop,
BlackRook,
WhiteRook,
BlackQueen,
WhiteQueen,
BlackKing,
WhiteKing
}
}
211 changes: 211 additions & 0 deletions Cosette.Arbiter/Book/PolyglotBoard.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,211 @@
using System;

namespace Cosette.Arbiter.Book
{
public class PolyglotBoard
{
private PieceType[,] _state;
private CastlingFlags _castlingFlags;
private ColorType _colorToMove;
private int _enPassantFile;

public PolyglotBoard()
{
_state = new PieceType[8,8];
_castlingFlags = CastlingFlags.Everything;
_colorToMove = ColorType.White;
_enPassantFile = -1;
}

public void InitDefaultState()
{
for (var file = 0; file < 8; file++)
{
for (var rank = 0; rank < 8; rank++)
{
_state[file, rank] = PieceType.None;
}
}

_state[0, 0] = PieceType.WhiteRook;
_state[1, 0] = PieceType.WhiteKnight;
_state[2, 0] = PieceType.WhiteBishop;
_state[3, 0] = PieceType.WhiteQueen;
_state[4, 0] = PieceType.WhiteKing;
_state[5, 0] = PieceType.WhiteBishop;
_state[6, 0] = PieceType.WhiteKnight;
_state[7, 0] = PieceType.WhiteRook;

_state[0, 1] = PieceType.WhitePawn;
_state[1, 1] = PieceType.WhitePawn;
_state[2, 1] = PieceType.WhitePawn;
_state[3, 1] = PieceType.WhitePawn;
_state[4, 1] = PieceType.WhitePawn;
_state[5, 1] = PieceType.WhitePawn;
_state[6, 1] = PieceType.WhitePawn;
_state[7, 1] = PieceType.WhitePawn;

_state[0, 6] = PieceType.BlackPawn;
_state[1, 6] = PieceType.BlackPawn;
_state[2, 6] = PieceType.BlackPawn;
_state[3, 6] = PieceType.BlackPawn;
_state[4, 6] = PieceType.BlackPawn;
_state[5, 6] = PieceType.BlackPawn;
_state[6, 6] = PieceType.BlackPawn;
_state[7, 6] = PieceType.BlackPawn;

_state[0, 7] = PieceType.BlackRook;
_state[1, 7] = PieceType.BlackKnight;
_state[2, 7] = PieceType.BlackBishop;
_state[3, 7] = PieceType.BlackQueen;
_state[4, 7] = PieceType.BlackKing;
_state[5, 7] = PieceType.BlackBishop;
_state[6, 7] = PieceType.BlackKnight;
_state[7, 7] = PieceType.BlackRook;
}

public void MakeMove(string move)
{
var (fromFile, fromRank) = (move[0] - 'a', move[1] - '1');
var (toFile, toRank) = (move[2] - 'a', move[3] - '1');
var pieceType = _state[fromFile, fromRank];
var oldEnPassant = _enPassantFile;

// Pieces
_state[toFile, toRank] = _state[fromFile, fromRank];
_state[fromFile, fromRank] = PieceType.None;
_enPassantFile = -1;

// Castling
if (pieceType == PieceType.WhiteKing)
{
_castlingFlags &= ~CastlingFlags.WhiteCastling;

if (Math.Abs(fromFile - toFile) == 2)
{
// Short castling
if (fromFile < toFile)
{
_state[7, 0] = PieceType.None;
_state[5, 0] = PieceType.WhiteRook;
}
// Long castling
else
{
_state[0, 0] = PieceType.None;
_state[3, 0] = PieceType.WhiteRook;
}
}
}
else if (pieceType == PieceType.BlackKing)
{
_castlingFlags &= ~CastlingFlags.BlackCastling;

if (Math.Abs(fromFile - toFile) == 2)
{
// Short castling
if (fromFile < toFile)
{
_state[7, 7] = PieceType.None;
_state[5, 7] = PieceType.BlackRook;
}
// Long castling
else
{
_state[0, 7] = PieceType.None;
_state[3, 7] = PieceType.BlackRook;
}
}
}
else if (pieceType == PieceType.WhiteRook && fromFile == 0 && fromRank == 0)
{
_castlingFlags &= ~CastlingFlags.WhiteLong;
}
else if (pieceType == PieceType.WhiteRook && fromFile == 7 && fromRank == 0)
{
_castlingFlags &= ~CastlingFlags.WhiteShort;
}
else if (pieceType == PieceType.BlackRook && fromFile == 0 && fromRank == 7)
{
_castlingFlags &= ~CastlingFlags.BlackLong;
}
else if (pieceType == PieceType.BlackRook && fromFile == 7 && fromRank == 7)
{
_castlingFlags &= ~CastlingFlags.BlackShort;
}

// En passant
if (pieceType == PieceType.WhitePawn || pieceType == PieceType.BlackPawn)
{
if (Math.Abs(fromRank - toRank) == 2)
{
var targetPieceType = _colorToMove == ColorType.White ? PieceType.BlackPawn : PieceType.WhitePawn;
if (toFile > 0 && _state[toFile - 1, toRank] == targetPieceType ||
toFile < 7 && _state[toFile + 1, toRank] == targetPieceType)
{
_enPassantFile = toFile;
}
}
else if (Math.Abs(fromFile - toFile) == 1 && toFile == oldEnPassant)
{
if (_colorToMove == ColorType.White)
{
_state[toFile, toRank - 1] = PieceType.None;
}
else if (_colorToMove == ColorType.Black)
{
_state[toFile, toRank + 1] = PieceType.None;
}
}
}

// Color
_colorToMove = _colorToMove == ColorType.White ? ColorType.Black : ColorType.White;
}

public ulong CalculateHash()
{
ulong result = 0;

for (var file = 0; file < 8; file++)
{
for (var rank = 0; rank < 8; rank++)
{
if (_state[file, rank] != PieceType.None)
{
result ^= PolyglotConstants.Keys[64 * (int)_state[file, rank] + 8 * rank + file];
}
}
}

if ((_castlingFlags & CastlingFlags.WhiteShort) != 0)
{
result ^= PolyglotConstants.Keys[768];
}
if ((_castlingFlags & CastlingFlags.WhiteLong) != 0)
{
result ^= PolyglotConstants.Keys[769];
}
if ((_castlingFlags & CastlingFlags.BlackShort) != 0)
{
result ^= PolyglotConstants.Keys[770];
}
if ((_castlingFlags & CastlingFlags.BlackLong) != 0)
{
result ^= PolyglotConstants.Keys[771];
}

if (_enPassantFile != -1)
{
result ^= PolyglotConstants.Keys[772 + _enPassantFile];
}

if (_colorToMove == ColorType.White)
{
result ^= PolyglotConstants.Keys[780];
}

return result;
}
}
}
Loading

0 comments on commit a7fe9d7

Please sign in to comment.