Skip to content

Commit

Permalink
Chess input representation v2.8 (#125)
Browse files Browse the repository at this point in the history
* added material count feature
* added get_plane_statistics.ipynb
* added C++ implementation for inputs 2.8
* added C++ unit tests
  • Loading branch information
QueensGambit authored May 30, 2021
1 parent 4872f78 commit d4c45d2
Show file tree
Hide file tree
Showing 6 changed files with 254 additions and 22 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
@project: CrazyAra
@author: queensgambit
Input representation for chess v2.1.
Input representation for chess v2.8.
This presentation avoids potential overfitting and bias, e.g. no color information, no move counter, no progress counter
and adds features which are hard for the CNN to extract, e.g. material info, number legal moves, checkerboard,
opposite color bishops.
Expand All @@ -25,11 +25,12 @@
CHANNEL_IS_960 = 19
CHANNEL_PIECE_MASK = 20
CHANNEL_CHECKERBOARD = 22
CHANNEL_MATERIAL = 23
CHANNEL_MATERIAL_DIFF = 23
CHANNEL_OPP_BISHOPS = 28
CHANNEL_CHECKERS = 29
CHANNEL_CHECK_MOVES = 30
CHANNEL_MOBILITY = 32
CHANNEL_MATERIAL_COUNT = 33


def board_to_planes(board: chess.Board, normalize=True, last_moves=None):
Expand Down Expand Up @@ -84,13 +85,14 @@ def board_to_planes(board: chess.Board, normalize=True, last_moves=None):
Checkers | 1 | Indicates all pieces giving check |
Checking Moves | 2 | Indicates all checking moves (from sq, to sq) |
Mobility | 1 | Indicates the number of legal moves
P1 Material Count | 5 | (pieces are ordered: PAWN, KNIGHT, BISHOP, ROOK, QUEEN), normalized with 8 |
---
13 planes
18 planes
The total number of planes is calculated as follows:
# --------------
13 + 4 + 2 + 1 + 13
Total: 33 planes
13 + 4 + 2 + 1 + 18
Total: 38 planes
:param board: Board handle (Python-chess object)
:param normalize: True if the inputs shall be normalized to the range [0.-1.]
Expand Down Expand Up @@ -193,10 +195,10 @@ def board_to_planes(board: chess.Board, normalize=True, last_moves=None):
# Channel: 23 - 27
# Relative material difference (negative if less pieces than opponent and positive if more)
# iterate over all pieces except the king
assert(channel == CHANNEL_MATERIAL)
assert(channel == CHANNEL_MATERIAL_DIFF)
for piece_type in chess.PIECE_TYPES[:-1]:
matt_diff = len(board.pieces(piece_type, me)) - len(board.pieces(piece_type, you))
planes[channel, :, :] = matt_diff / NORMALIZE_PIECE_NUMBER if normalize else matt_diff
material_count = len(board.pieces(piece_type, me)) - len(board.pieces(piece_type, you))
planes[channel, :, :] = material_count / NORMALIZE_PIECE_NUMBER if normalize else material_count
channel += 1

# Channel: 28
Expand Down Expand Up @@ -236,6 +238,14 @@ def board_to_planes(board: chess.Board, normalize=True, last_moves=None):
planes[channel, :, :] = len(my_legal_moves) / NORMALIZE_MOBILITY if normalize else len(my_legal_moves)
channel += 1

# Channel: 33
# Material
assert(channel == CHANNEL_MATERIAL_COUNT)
for piece_type in chess.PIECE_TYPES[:-1]:
material_count = len(board.pieces(piece_type, me))
planes[channel, :, :] = material_count / NORMALIZE_PIECE_NUMBER if normalize else material_count
channel += 1

assert channel == NB_CHANNELS_TOTAL
return planes

Expand Down Expand Up @@ -329,10 +339,14 @@ def normalize_input_planes(planes):
:param planes: Input planes representation
:return: The normalized planes
"""
channel = CHANNEL_MATERIAL
channel = CHANNEL_MATERIAL_DIFF
for _ in chess.PIECE_TYPES[:-1]:
planes[channel, :, :] /= NORMALIZE_PIECE_NUMBER
channel += 1
planes[CHANNEL_MOBILITY, :, :] /= NORMALIZE_MOBILITY
channel = CHANNEL_MATERIAL_COUNT
for _ in chess.PIECE_TYPES[:-1]:
planes[channel, :, :] /= NORMALIZE_PIECE_NUMBER
channel += 1

return planes
2 changes: 1 addition & 1 deletion DeepCrazyhouse/src/domain/variants/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@
if VERSION == 1:
NB_CHANNELS_POS = 15
else: # VERSION == 2
NB_CHANNELS_POS = 12 + 1 + 13 # 12 pieces + 1 en-passant and 13 auxiliary
NB_CHANNELS_POS = 12 + 1 + 18 # 13 # 12 pieces + 1 en-passant and 13 auxiliary
if VERSION == 1:
NB_CHANNELS_CONST = 7
else: # VERSION == 2
Expand Down
129 changes: 129 additions & 0 deletions DeepCrazyhouse/src/preprocessing/get_plane_statistics.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Get Plane Statistics (Unit-Test Preparation)\n",
"\n",
"* file: get_plane_statistics.ipynb\n",
"* brief: Allows investigating the board planes and their statistics. These can later be used e.g. for unit-tests.\n",
"\n",
"* author: QueensGambit\n",
"* contact: johannes.czech@cs.tu-darmstadt.de\n",
"* versions:\n",
" * 2021-05-30 initial version"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"%load_ext autoreload\n",
"%autoreload 2\n",
"%reload_ext autoreload"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import sys, os\n",
"sys.path.insert(0,'../../../')\n",
"import os\n",
"import sys\n",
"import chess\n",
"import logging\n",
"from DeepCrazyhouse.src.preprocessing.pgn_to_planes_converter import PGN2PlanesConverter\n",
"from DeepCrazyhouse.src.runtime.color_logger import enable_color_logging\n",
"from DeepCrazyhouse.src.domain.variants.input_representation import board_to_planes, get_planes_statistics\n",
"enable_color_logging()\n",
"logging.getLogger().setLevel(logging.WARNING)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"b = chess.Board(\"r3k1nr/pbp4p/p2p2pb/4P3/3P4/N2q1n2/PPP2PPP/5K1R w kq - 0 14\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"get_planes_statistics(b, True, [])"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"b = chess.Board()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"b.push_uci(\"e2e4\")\n",
"b.push_uci(\"c7c5\")\n",
"b.push_uci(\"d2d3\")\n",
"b.push_uci(\"a7a6\")\n",
"b.push_uci(\"e4e5\")\n",
"b.push_uci(\"d7d5\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"b"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"get_planes_statistics(b, False, [chess.Move.from_uci(\"d7d5\")])"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.7.6"
}
},
"nbformat": 4,
"nbformat_minor": 4
}
5 changes: 3 additions & 2 deletions engine/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,9 @@ if (MODE_CHESS)
project(ClassicAra CXX)
add_definitions(-DMODE_CHESS)
add_definitions(-DMCTS_TB_SUPPORT)
add_definitions(-DVERSION=1)
# add_definitions(-DVERSION=2)
# add_definitions(-DVERSION=1)
add_definitions(-DVERSION=2)
add_definitions(-DSUB_VERSION=8)
endif()

if (MODE_LICHESS)
Expand Down
43 changes: 34 additions & 9 deletions engine/src/environments/chess_related/inputrepresentation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -375,18 +375,31 @@ inline void set_mobility(PlaneData& p, const vector<Action>& legalMoves)
p.set_plane_to_value<true>(p.normalize ? legalMoves.size() / StateConstants::NORMALIZE_MOBILITY() : legalMoves.size());
}

inline void set_opposite_bishops(PlaneData& p) {
inline void set_opposite_bishops(PlaneData& p)
{
if (p.pos->opposite_bishops()) {
p.set_plane_to_one<false>();
}
++p.currentChannel;
}

inline void set_material_count(PlaneData& p)
{
float relativeCount = p.pos->count<PAWN>(p.me());
p.set_plane_to_value<true>(p.normalize ? relativeCount / StateConstants::NORMALIZE_PIECE_NUMBER() : relativeCount);
relativeCount = p.pos->count<KNIGHT>(p.me());
p.set_plane_to_value<true>(p.normalize ? relativeCount / StateConstants::NORMALIZE_PIECE_NUMBER() : relativeCount);
relativeCount = p.pos->count<BISHOP>(p.me());
p.set_plane_to_value<true>(p.normalize ? relativeCount / StateConstants::NORMALIZE_PIECE_NUMBER() : relativeCount);
relativeCount = p.pos->count<ROOK>(p.me());
p.set_plane_to_value<true>(p.normalize ? relativeCount / StateConstants::NORMALIZE_PIECE_NUMBER() : relativeCount);
relativeCount = p.pos->count<QUEEN>(p.me());
p.set_plane_to_value<true>(p.normalize ? relativeCount / StateConstants::NORMALIZE_PIECE_NUMBER() : relativeCount);
}

#ifdef MODE_CHESS
void board_to_planes_v_2_7(const Board *pos, bool normalize, float *inputPlanes, const vector<Action>& legalMoves)
inline void board_to_planes_v_2_7(PlaneData& planeData, const vector<Action>& legalMoves)
{
// Fill in the piece positions
PlaneData planeData(pos, inputPlanes, normalize);
set_plane_pieces(planeData);
set_plane_ep_square(planeData);
assert(planeData.currentChannel == StateConstants::NB_CHANNELS_POS());
Expand All @@ -403,20 +416,32 @@ void board_to_planes_v_2_7(const Board *pos, bool normalize, float *inputPlanes,
set_checkers(planeData);
set_check_moves(planeData, legalMoves);
set_mobility(planeData, legalMoves);
assert(planeData.currentChannel == StateConstants::NB_CHANNELS_TOTAL());
}

inline void board_to_planes_v_2_8(PlaneData& planeData, const vector<Action>& legalMoves)
{
board_to_planes_v_2_7(planeData, legalMoves);
set_material_count(planeData);
}

#endif

void board_to_planes(const Board *pos, size_t boardRepetition, bool normalize, float *inputPlanes, const vector<Action>& legalMoves)
{
#if VERSION == 2
board_to_planes_v_2_7(pos, normalize, inputPlanes, legalMoves);
return;
#endif
// Fill in the piece positions
// Iterate over both color starting with WHITE
PlaneData planeData(pos, inputPlanes, normalize);

#if VERSION == 2
#if SUB_VERSION == 7
board_to_planes_v_2_7(planeData, legalMoves);
#elif SUB_VERSION == 8
board_to_planes_v_2_8(planeData, legalMoves);
#endif
assert(planeData.currentChannel == StateConstants::NB_CHANNELS_TOTAL());
return;
#endif

// (I) Set the pieces for both players
set_plane_pieces(planeData);

Expand Down
Loading

0 comments on commit d4c45d2

Please sign in to comment.