538 lines
13 KiB
C++
538 lines
13 KiB
C++
/*
|
|
This file is part of Sanmill.
|
|
Copyright (C) 2019-2021 The Sanmill developers (see AUTHORS file)
|
|
|
|
Sanmill is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
Sanmill is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#ifndef TYPES_H_INCLUDED
|
|
#define TYPES_H_INCLUDED
|
|
|
|
#include "config.h"
|
|
|
|
/// When compiling with provided Makefile (e.g. for Linux and OSX), configuration
|
|
/// is done automatically. To get started type 'make help'.
|
|
///
|
|
/// When Makefile is not used (e.g. with Microsoft Visual Studio) some switches
|
|
/// need to be set manually:
|
|
///
|
|
/// -DNDEBUG | Disable debugging mode. Always use this for release.
|
|
///
|
|
/// -DNO_PREFETCH | Disable use of prefetch asm-instruction. You may need this to
|
|
/// | run on some very old machines.
|
|
///
|
|
/// -DUSE_POPCNT | Add runtime support for use of popcnt asm-instruction. Works
|
|
/// | only in 64-bit mode and requires hardware with popcnt support.
|
|
///
|
|
/// -DUSE_PEXT | Add runtime support for use of pext asm-instruction. Works
|
|
/// | only in 64-bit mode and requires hardware with pext support.
|
|
|
|
#include <cassert>
|
|
#include <cctype>
|
|
#include <climits>
|
|
#include <cstdint>
|
|
#include <cstdlib>
|
|
#include <algorithm>
|
|
|
|
#if defined(_MSC_VER)
|
|
// Disable some silly and noisy warning from MSVC compiler
|
|
#pragma warning(disable: 4127) // Conditional expression is constant
|
|
#pragma warning(disable: 4146) // Unary minus operator applied to unsigned type
|
|
#pragma warning(disable: 4800) // Forcing value to bool 'true' or 'false'
|
|
#endif
|
|
|
|
/// Predefined macros hell:
|
|
///
|
|
/// __GNUC__ Compiler is gcc, Clang or Intel on Linux
|
|
/// __INTEL_COMPILER Compiler is Intel
|
|
/// _MSC_VER Compiler is MSVC or Intel on Windows
|
|
/// _WIN32 Building on Windows (any)
|
|
/// _WIN64 Building on Windows 64 bit
|
|
|
|
#if defined(__GNUC__ ) && (__GNUC__ < 9 || (__GNUC__ == 9 && __GNUC_MINOR__ <= 2)) && defined(_WIN32) && !defined(__clang__)
|
|
#define ALIGNAS_ON_STACK_VARIABLES_BROKEN
|
|
#endif
|
|
|
|
#define ASSERT_ALIGNED(ptr, alignment) assert(reinterpret_cast<uintptr_t>(ptr) % alignment == 0)
|
|
|
|
#if defined(_WIN64) && defined(_MSC_VER) // No Makefile used
|
|
# include <intrin.h> // Microsoft header for _BitScanForward64()
|
|
# define IS_64BIT
|
|
#endif
|
|
|
|
#if defined(USE_POPCNT) && (defined(__INTEL_COMPILER) || defined(_MSC_VER))
|
|
# include <nmmintrin.h> // Intel and Microsoft header for _mm_popcnt_u64()
|
|
#endif
|
|
|
|
#if !defined(NO_PREFETCH) && (defined(__INTEL_COMPILER) || defined(_MSC_VER))
|
|
# include <xmmintrin.h> // Intel and Microsoft header for _mm_prefetch()
|
|
#endif
|
|
|
|
#if defined(USE_PEXT)
|
|
# include <immintrin.h> // Header for _pext_u64() intrinsic
|
|
# define pext(b, m) _pext_u64(b, m)
|
|
#else
|
|
# define pext(b, m) 0
|
|
#endif
|
|
|
|
#ifdef USE_POPCNT
|
|
constexpr bool HasPopCnt = true;
|
|
#else
|
|
constexpr bool HasPopCnt = false;
|
|
#endif
|
|
|
|
#ifdef USE_PEXT
|
|
constexpr bool HasPext = true;
|
|
#else
|
|
constexpr bool HasPext = false;
|
|
#endif
|
|
|
|
#ifdef IS_64BIT
|
|
constexpr bool Is64Bit = true;
|
|
#else
|
|
constexpr bool Is64Bit = false;
|
|
#endif
|
|
|
|
#ifdef TRANSPOSITION_TABLE_64BIT_KEY
|
|
typedef uint64_t Key;
|
|
#else
|
|
typedef uint32_t Key;
|
|
#endif /* TRANSPOSITION_TABLE_64BIT_KEY */
|
|
|
|
typedef uint32_t Bitboard;
|
|
|
|
constexpr int MAX_MOVES = 64;
|
|
constexpr int MAX_PLY = 48;
|
|
|
|
|
|
|
|
enum Move : int32_t
|
|
{
|
|
MOVE_NONE,
|
|
MOVE_NULL = 65
|
|
};
|
|
|
|
enum MoveType
|
|
{
|
|
MOVETYPE_PLACE,
|
|
MOVETYPE_MOVE,
|
|
MOVETYPE_REMOVE
|
|
};
|
|
|
|
enum Color : uint8_t
|
|
{
|
|
NOCOLOR = 0,
|
|
BLACK = 1,
|
|
WHITE = 2,
|
|
COLOR_NB = 3,
|
|
DRAW = 4,
|
|
NOBODY = 8
|
|
};
|
|
|
|
enum class Phase : uint16_t
|
|
{
|
|
none,
|
|
ready,
|
|
placing, // Placing men on vacant points
|
|
moving, // Moving men to adjacent points or
|
|
// (optional) Moving men to any vacant point when the player has been reduced to three men
|
|
gameOver
|
|
};
|
|
|
|
// enum class that represents an action that one player can take when it's
|
|
// his turn at the board. The can be on of the following:
|
|
// - select a piece on the board;
|
|
// - place a piece on the board;
|
|
// - move a piece on the board:
|
|
// - slide a piece between two adjacent locations;
|
|
// - 'jump' a piece to any empty location if the player has less than
|
|
// three pieces and mayFly is |true|;
|
|
// - remove an opponent's piece after successfully closing a mill;
|
|
enum class Action : uint16_t
|
|
{
|
|
none,
|
|
select,
|
|
place,
|
|
remove
|
|
};
|
|
|
|
enum class GameOverReason
|
|
{
|
|
noReason,
|
|
|
|
// A player wins by reducing the opponent to two pieces
|
|
// (where they could no longer form mills and thus be unable to win)
|
|
loseReasonlessThanThree,
|
|
|
|
// A player wins by leaving them without a legal move.
|
|
loseReasonNoWay,
|
|
loseReasonBoardIsFull,
|
|
|
|
loseReasonResign,
|
|
loseReasonTimeOver,
|
|
drawReasonThreefoldRepetition,
|
|
drawReasonRule50,
|
|
drawReasonBoardIsFull,
|
|
};
|
|
|
|
enum Bound : uint8_t
|
|
{
|
|
BOUND_NONE,
|
|
BOUND_UPPER,
|
|
BOUND_LOWER,
|
|
BOUND_EXACT = BOUND_UPPER | BOUND_LOWER
|
|
};
|
|
|
|
enum Value : int8_t
|
|
{
|
|
VALUE_ZERO = 0,
|
|
VALUE_DRAW = 0,
|
|
VALUE_KNOWN_WIN = 20,
|
|
VALUE_UNIQUE = 60,
|
|
VALUE_MATE = 80,
|
|
VALUE_INFINITE = 125,
|
|
VALUE_UNKNOWN = INT8_MIN,
|
|
VALUE_NONE = VALUE_UNKNOWN,
|
|
|
|
VALUE_TB_WIN_IN_MAX_PLY = VALUE_MATE - 2 * MAX_PLY,
|
|
VALUE_TB_LOSS_IN_MAX_PLY = -VALUE_TB_WIN_IN_MAX_PLY,
|
|
VALUE_MATE_IN_MAX_PLY = VALUE_MATE - MAX_PLY,
|
|
VALUE_MATED_IN_MAX_PLY = -VALUE_MATE_IN_MAX_PLY,
|
|
|
|
StoneValue = 5,
|
|
VALUE_EACH_PIECE = StoneValue,
|
|
VALUE_EACH_PIECE_INHAND = VALUE_EACH_PIECE,
|
|
VALUE_EACH_PIECE_ONBOARD = VALUE_EACH_PIECE,
|
|
VALUE_EACH_PIECE_PLACING_NEEDREMOVE = VALUE_EACH_PIECE,
|
|
VALUE_EACH_PIECE_MOVING_NEEDREMOVE = VALUE_EACH_PIECE,
|
|
|
|
VALUE_MTDF_WINDOW = VALUE_EACH_PIECE,
|
|
VALUE_PVS_WINDOW = VALUE_EACH_PIECE,
|
|
|
|
VALUE_PLACING_WINDOW = VALUE_EACH_PIECE_PLACING_NEEDREMOVE + (VALUE_EACH_PIECE_ONBOARD - VALUE_EACH_PIECE_INHAND) + 1,
|
|
VALUE_MOVING_WINDOW = VALUE_EACH_PIECE_MOVING_NEEDREMOVE + 1,
|
|
|
|
};
|
|
|
|
enum Rating : int8_t
|
|
{
|
|
RATING_ZERO = 0,
|
|
|
|
RATING_BLOCK_ONE_MILL = 10,
|
|
RATING_ONE_MILL = 11,
|
|
|
|
RATING_STAR_SQUARE = 11,
|
|
|
|
RATING_BLOCK_TWO_MILLS = RATING_BLOCK_ONE_MILL * 2,
|
|
RATING_TWO_MILLS = RATING_ONE_MILL * 2,
|
|
|
|
RATING_BLOCK_THREE_MILLS = RATING_BLOCK_ONE_MILL * 3,
|
|
RATING_THREE_MILLS = RATING_ONE_MILL * 3,
|
|
|
|
RATING_REMOVE_ONE_MILL = RATING_ONE_MILL,
|
|
RATING_REMOVE_TWO_MILLS = RATING_TWO_MILLS,
|
|
RATING_REMOVE_THREE_MILLS = RATING_THREE_MILLS,
|
|
|
|
RATING_REMOVE_THEIR_ONE_MILL = -RATING_REMOVE_ONE_MILL,
|
|
RATING_REMOVE_THEIR_TWO_MILLS = -RATING_REMOVE_TWO_MILLS,
|
|
RATING_REMOVE_THEIR_THREE_MILLS = -RATING_REMOVE_THREE_MILLS,
|
|
|
|
RATING_TT = 100,
|
|
RATING_MAX = INT8_MAX,
|
|
};
|
|
|
|
enum PieceType : uint16_t
|
|
{
|
|
NO_PIECE_TYPE = 0,
|
|
BLACK_STONE = 1,
|
|
WHITE_STONE = 2,
|
|
BAN = 3,
|
|
ALL_PIECES = 0,
|
|
PIECE_TYPE_NB = 4,
|
|
|
|
IN_HAND = 0x10,
|
|
ON_BOARD = 0x20,
|
|
};
|
|
|
|
enum Piece : uint8_t
|
|
{
|
|
NO_PIECE = 0x00,
|
|
BAN_STONE = 0x0F,
|
|
|
|
B_STONE = 0x10,
|
|
B_STONE_1 = 0x11,
|
|
B_STONE_2 = 0x12,
|
|
B_STONE_3 = 0x13,
|
|
B_STONE_4 = 0x14,
|
|
B_STONE_5 = 0x15,
|
|
B_STONE_6 = 0x16,
|
|
B_STONE_7 = 0x17,
|
|
B_STONE_8 = 0x18,
|
|
B_STONE_9 = 0x19,
|
|
B_STONE_10 = 0x1A,
|
|
B_STONE_11 = 0x1B,
|
|
B_STONE_12 = 0x1C,
|
|
|
|
W_STONE = 0x20,
|
|
W_STONE_1 = 0x21,
|
|
W_STONE_2 = 0x22,
|
|
W_STONE_3 = 0x23,
|
|
W_STONE_4 = 0x24,
|
|
W_STONE_5 = 0x25,
|
|
W_STONE_6 = 0x26,
|
|
W_STONE_7 = 0x27,
|
|
W_STONE_8 = 0x28,
|
|
W_STONE_9 = 0x29,
|
|
W_STONE_10 = 0x2A,
|
|
W_STONE_11 = 0x2B,
|
|
W_STONE_12 = 0x2C,
|
|
|
|
PIECE_NB = 64, // Fix overflow
|
|
};
|
|
|
|
constexpr Value PieceValue = StoneValue;
|
|
|
|
using Depth = int8_t;
|
|
|
|
enum : int
|
|
{
|
|
DEPTH_NONE = 0, // TODO: -6,
|
|
DEPTH_OFFSET = DEPTH_NONE
|
|
};
|
|
|
|
enum Square : int
|
|
{
|
|
SQ_0 = 0, SQ_1 = 1, SQ_2 = 2, SQ_3 = 3, SQ_4 = 4, SQ_5 = 5, SQ_6 = 6, SQ_7 = 7,
|
|
SQ_8 = 8, SQ_9 = 9, SQ_10 = 10, SQ_11 = 11, SQ_12 = 12, SQ_13 = 13, SQ_14 = 14, SQ_15 = 15,
|
|
SQ_16 = 16, SQ_17 = 17, SQ_18 = 18, SQ_19 = 19, SQ_20 = 20, SQ_21 = 21, SQ_22 = 22, SQ_23 = 23,
|
|
SQ_24 = 24, SQ_25 = 25, SQ_26 = 26, SQ_27 = 27, SQ_28 = 28, SQ_29 = 29, SQ_30 = 30, SQ_31 = 31,
|
|
|
|
SQ_A1 = 8, SQ_A2 = 9, SQ_A3 = 10, SQ_A4 = 11, SQ_A5 = 12, SQ_A6 = 13, SQ_A7 = 14, SQ_A8 = 15,
|
|
SQ_B1 = 16, SQ_B2 = 17, SQ_B3 = 18, SQ_B4 = 19, SQ_B5 = 20, SQ_B6 = 21, SQ_B7 = 22, SQ_B8 = 23,
|
|
SQ_C1 = 24, SQ_C2 = 25, SQ_C3 = 26, SQ_C4 = 27, SQ_C5 = 28, SQ_C6 = 29, SQ_C7 = 30, SQ_C8 = 31,
|
|
|
|
SQ_32 = 32, SQ_33 = 33, SQ_34 = 34, SQ_35 = 35, SQ_36 = 36, SQ_37 = 37, SQ_38 = 38, SQ_39 = 39,
|
|
|
|
SQ_NONE = 0,
|
|
|
|
EFFECTIVE_SQUARE_NB = 24, // The board consists of a grid with twenty-four intersections or points.
|
|
|
|
SQUARE_ZERO = 0,
|
|
SQUARE_NB = 40,
|
|
|
|
SQ_BEGIN = SQ_8,
|
|
SQ_END = SQ_32
|
|
};
|
|
|
|
enum MoveDirection : int
|
|
{
|
|
MD_CLOCKWISE = 0,
|
|
MD_BEGIN = MD_CLOCKWISE,
|
|
MD_ANTICLOCKWISE = 1,
|
|
MD_INWARD = 2,
|
|
MD_OUTWARD = 3,
|
|
MD_NB = 4
|
|
};
|
|
|
|
enum LineDirection : int
|
|
{
|
|
LD_HORIZONTAL = 0,
|
|
LD_VERTICAL = 1,
|
|
LD_SLASH = 2,
|
|
LD_NB = 3
|
|
};
|
|
|
|
enum File : int
|
|
{
|
|
FILE_A = 1, FILE_B, FILE_C, FILE_NB = 3
|
|
};
|
|
|
|
enum Rank : int
|
|
{
|
|
RANK_1 = 1, RANK_2, RANK_3, RANK_4, RANK_5, RANK_6, RANK_7, RANK_8, RANK_NB = 8
|
|
};
|
|
|
|
|
|
#if 0
|
|
/// Score enum stores a middlegame and an endgame value in a single integer (enum).
|
|
/// The least significant 16 bits are used to store the middlegame value and the
|
|
/// upper 16 bits are used to store the endgame value. We have to take care to
|
|
/// avoid left-shifting a signed int to avoid undefined behavior.
|
|
enum Score : int
|
|
{
|
|
SCORE_ZERO
|
|
};
|
|
#endif
|
|
|
|
|
|
#define ENABLE_BASE_OPERATORS_ON(T) \
|
|
constexpr T operator+(T d1, int d2) { return T(int(d1) + d2); } \
|
|
constexpr T operator-(T d1, int d2) { return T(int(d1) - d2); } \
|
|
constexpr T operator-(T d) { return T(-int(d)); } \
|
|
inline T& operator+=(T& d1, int d2) { return d1 = d1 + d2; } \
|
|
inline T& operator-=(T& d1, int d2) { return d1 = d1 - d2; }
|
|
|
|
#define ENABLE_INCR_OPERATORS_ON(T) \
|
|
inline T& operator++(T& d) { return d = T(int(d) + 1); } \
|
|
inline T& operator--(T& d) { return d = T(int(d) - 1); }
|
|
|
|
#define ENABLE_FULL_OPERATORS_ON(T) \
|
|
ENABLE_BASE_OPERATORS_ON(T) \
|
|
constexpr T operator*(int i, T d) noexcept { return T(i * int(d)); } \
|
|
constexpr T operator*(T d, int i) noexcept { return T(int(d) * i); } \
|
|
constexpr T operator/(T d, int i) noexcept { return T(int(d) / i); } \
|
|
constexpr int operator/(T d1, T d2) noexcept { return int(d1) / int(d2); } \
|
|
inline T& operator*=(T& d, int i) noexcept { return d = T(int(d) * i); } \
|
|
inline T& operator/=(T& d, int i) noexcept { return d = T(int(d) / i); }
|
|
|
|
ENABLE_FULL_OPERATORS_ON(Value)
|
|
|
|
ENABLE_INCR_OPERATORS_ON(Piece)
|
|
ENABLE_INCR_OPERATORS_ON(PieceType)
|
|
ENABLE_INCR_OPERATORS_ON(Square)
|
|
ENABLE_INCR_OPERATORS_ON(File)
|
|
ENABLE_INCR_OPERATORS_ON(Rank)
|
|
ENABLE_INCR_OPERATORS_ON(MoveDirection)
|
|
|
|
#undef ENABLE_FULL_OPERATORS_ON
|
|
#undef ENABLE_INCR_OPERATORS_ON
|
|
#undef ENABLE_BASE_OPERATORS_ON
|
|
|
|
constexpr Color operator~(Color c)
|
|
{
|
|
return Color(c ^ 3); // Toggle color
|
|
}
|
|
|
|
// constexpr Piece operator~(Piece p)
|
|
// {
|
|
// return Piece(p ^ 8); // Swap color of piece
|
|
// }
|
|
|
|
constexpr Square make_square(File f, Rank r)
|
|
{
|
|
return Square((f << 3) + r - 1);
|
|
}
|
|
|
|
constexpr Piece make_piece(Color c)
|
|
{
|
|
return Piece(c << 4);
|
|
}
|
|
|
|
constexpr Piece make_piece(Color c, PieceType pt)
|
|
{
|
|
if (pt == BLACK_STONE || pt == WHITE_STONE) {
|
|
return make_piece(c);
|
|
}
|
|
|
|
if (pt == BAN) {
|
|
return BAN_STONE;
|
|
}
|
|
|
|
return NO_PIECE;
|
|
}
|
|
|
|
constexpr Color color_of(Piece pc)
|
|
{
|
|
return Color(pc >> 4);
|
|
}
|
|
|
|
constexpr PieceType type_of(Piece pc)
|
|
{
|
|
if (pc == BAN_STONE) {
|
|
return BAN;
|
|
}
|
|
|
|
if (color_of(pc) == BLACK) {
|
|
return BLACK_STONE;
|
|
}
|
|
|
|
if (color_of(pc) == WHITE) {
|
|
return WHITE_STONE;
|
|
}
|
|
|
|
return NO_PIECE_TYPE;
|
|
}
|
|
|
|
constexpr bool is_ok(Square s)
|
|
{
|
|
return s == SQ_NONE || (s >= SQ_BEGIN && s < SQ_END); // TODO: SQ_NONE?
|
|
}
|
|
|
|
constexpr File file_of(Square s)
|
|
{
|
|
return File(s >> 3);
|
|
}
|
|
|
|
constexpr Rank rank_of(Square s)
|
|
{
|
|
return Rank((s & 0x07) + 1);
|
|
}
|
|
|
|
constexpr Square from_sq(Move m)
|
|
{
|
|
if (m < 0)
|
|
m = (Move)-m;
|
|
|
|
return static_cast<Square>(m >> 8);
|
|
}
|
|
|
|
constexpr Square to_sq(Move m)
|
|
{
|
|
if (m < 0)
|
|
m = (Move)-m;
|
|
|
|
return Square(m & 0x00FF);
|
|
}
|
|
|
|
constexpr int from_to(Move m)
|
|
{
|
|
#if 0
|
|
return m & 0xFFF;
|
|
#endif
|
|
return m & 0xFFFF; // TODO
|
|
}
|
|
|
|
constexpr MoveType type_of(Move m)
|
|
{
|
|
if (m < 0) {
|
|
return MOVETYPE_REMOVE;
|
|
} else if (m & 0x1f00) {
|
|
return MOVETYPE_MOVE;
|
|
}
|
|
|
|
return MOVETYPE_PLACE; // m & 0x00ff
|
|
}
|
|
|
|
constexpr Move make_move(Square from, Square to)
|
|
{
|
|
return Move((from << 8) + to);
|
|
}
|
|
|
|
constexpr Move reverse_move(Move m)
|
|
{
|
|
return make_move(to_sq(m), from_sq(m));
|
|
}
|
|
|
|
constexpr bool is_ok(Move m)
|
|
{
|
|
return from_sq(m) != to_sq(m); // Catch MOVE_NULL and MOVE_NONE
|
|
}
|
|
|
|
/// Based on a congruential pseudo random number generator
|
|
constexpr Key make_key(uint64_t seed) {
|
|
return Key(seed * 6364136223846793005ULL + 1442695040888963407ULL);
|
|
}
|
|
|
|
#endif // #ifndef TYPES_H_INCLUDED
|