Indicate white pieces as player one and black as player two

Thanks Matt Littlewood!
This commit is contained in:
Calcitem 2021-05-14 22:24:43 +08:00
parent 7e40f0dec7
commit c2af00c10d
35 changed files with 464 additions and 462 deletions

View File

@ -440,7 +440,7 @@
<string/>
</property>
<property name="pixmap">
<pixmap resource="gamewindow.qrc">:/icon/resources/icon/Black.png</pixmap>
<pixmap resource="gamewindow.qrc">:/icon/resources/icon/White.png</pixmap>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
@ -462,7 +462,7 @@
</font>
</property>
<property name="text">
<string>Player1 (Black)</string>
<string>Player 1</string>
</property>
</widget>
</item>
@ -521,7 +521,7 @@
<string/>
</property>
<property name="pixmap">
<pixmap resource="gamewindow.qrc">:/icon/resources/icon/White.png</pixmap>
<pixmap resource="gamewindow.qrc">:/icon/resources/icon/Black.png</pixmap>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
@ -543,7 +543,7 @@
</font>
</property>
<property name="text">
<string>Player2 (White)</string>
<string>Player 2</string>
</property>
</widget>
</item>
@ -1070,7 +1070,7 @@
</property>
<property name="icon">
<iconset resource="gamewindow.qrc">
<normaloff>:/icon/resources/icon/Black.png</normaloff>:/icon/resources/icon/Black.png</iconset>
<normaloff>:/icon/resources/icon/White.png</normaloff>:/icon/resources/icon/White.png</iconset>
</property>
<property name="text">
<string>AI Moves First</string>
@ -1085,7 +1085,7 @@
</property>
<property name="icon">
<iconset resource="gamewindow.qrc">
<normaloff>:/icon/resources/icon/White.png</normaloff>:/icon/resources/icon/White.png</iconset>
<normaloff>:/icon/resources/icon/Black.png</normaloff>:/icon/resources/icon/Black.png</iconset>
</property>
<property name="text">
<string>AI Moves Second</string>

View File

@ -547,8 +547,8 @@
</message>
<message>
<location filename="gamewindow.ui" line="1089"/>
<source>(R)</source>
<translation>(R)</translation>
<source>(B)</source>
<translation>(B)</translation>
</message>
<message>
<location filename="gamewindow.ui" line="1101"/>

View File

@ -34,9 +34,9 @@ Following is some information about the algorithms and data structures used by S
The mill game board in Sanmill is represented by an array of `24` squares (points), laid out so that square `A1` has the value `8` and square `C8` has the value `31`.
Each square contains `SQ_NONE` if it is empty, or a piece identifier if it is occupied. Black pieces have identifier values between `B_STONE_1` and `B_STONE_12`, while White pieces have values between `W_STONE_1` and `W_STONE_12`. A special value (`BAN_STONE`) is used to represent a square that is banned.
Each square contains `SQ_NONE` if it is empty, or a piece identifier if it is occupied. White pieces have identifier values between `W_STONE_1` and `W_STONE_12`, while Black pieces have values between `B_STONE_1` and `B_STONE_12`. A special value (`BAN_STONE`) is used to represent a square that is banned.
The Board class also maintains several "bit boards" or quantities that that hold 32 bits. The Bitboard class in the source encapsulates a bit board. For example, the occupied bit board has one bit set for every piece that is on the board (there are actually three such bit boards, one for Black, one for White, and one for Ban).
The Board class also maintains several "bit boards" or quantities that that hold 32 bits. The Bitboard class in the source encapsulates a bit board. For example, the occupied bit board has one bit set for every piece that is on the board (there are actually three such bit boards, one for White, one for Black, and one for Ban).
Each type of piece has its own bit board that has one bit set for each piece of that type (for example, there is a `byTypeBB[BAN]` Bitboard to hold ban locations).

View File

@ -36,8 +36,8 @@ static const int SAVE_ENDGAME_EVERY_N_GAMES = 256;
enum class EndGameType : uint32_t
{
none,
blackWin,
whiteWin,
blackWin,
draw,
};

View File

@ -48,7 +48,7 @@ Value Evaluation::value()
int pieceInHandDiffCount;
int pieceOnBoardDiffCount;
int pieceToRemoveCount = (pos.side_to_move() == BLACK) ?
int pieceToRemoveCount = (pos.side_to_move() == WHITE) ?
pos.piece_to_remove_count() : -pos.piece_to_remove_count();;
switch (pos.get_phase()) {
@ -56,10 +56,10 @@ Value Evaluation::value()
break;
case Phase::placing:
pieceInHandDiffCount = pos.piece_in_hand_count(BLACK) - pos.piece_in_hand_count(WHITE);
pieceInHandDiffCount = pos.piece_in_hand_count(WHITE) - pos.piece_in_hand_count(BLACK);
value += VALUE_EACH_PIECE_INHAND * pieceInHandDiffCount;
pieceOnBoardDiffCount = pos.piece_on_board_count(BLACK) - pos.piece_on_board_count(WHITE);
pieceOnBoardDiffCount = pos.piece_on_board_count(WHITE) - pos.piece_on_board_count(BLACK);
value += VALUE_EACH_PIECE_ONBOARD * pieceOnBoardDiffCount;
switch (pos.get_action()) {
@ -77,7 +77,7 @@ Value Evaluation::value()
break;
case Phase::moving:
value = (pos.piece_on_board_count(BLACK) - pos.piece_on_board_count(WHITE)) * VALUE_EACH_PIECE_ONBOARD;
value = (pos.piece_on_board_count(WHITE) - pos.piece_on_board_count(BLACK)) * VALUE_EACH_PIECE_ONBOARD;
#ifdef EVALUATE_MOBILITY
value += pos.get_mobility_diff() / 5;
@ -98,8 +98,8 @@ Value Evaluation::value()
break;
case Phase::gameOver:
if (pos.piece_on_board_count(BLACK) + pos.piece_on_board_count(WHITE) >= EFFECTIVE_SQUARE_NB) {
if (rule.isBlackLoseButNotDrawWhenBoardFull) {
if (pos.piece_on_board_count(WHITE) + pos.piece_on_board_count(BLACK) >= EFFECTIVE_SQUARE_NB) {
if (rule.isWhiteLoseButNotDrawWhenBoardFull) {
value -= VALUE_MATE;
} else {
value = VALUE_DRAW;
@ -107,12 +107,12 @@ Value Evaluation::value()
} else if (pos.get_action() == Action::select &&
pos.is_all_surrounded(pos.side_to_move()) &&
rule.isLoseButNotChangeSideWhenNoWay) {
const Value delta = pos.side_to_move() == BLACK ? -VALUE_MATE : VALUE_MATE;
const Value delta = pos.side_to_move() == WHITE ? -VALUE_MATE : VALUE_MATE;
value += delta;
}
else if (pos.piece_on_board_count(BLACK) < rule.piecesAtLeastCount) {
else if (pos.piece_on_board_count(WHITE) < rule.piecesAtLeastCount) {
value -= VALUE_MATE;
} else if (pos.piece_on_board_count(WHITE) < rule.piecesAtLeastCount) {
} else if (pos.piece_on_board_count(BLACK) < rule.piecesAtLeastCount) {
value += VALUE_MATE;
}
@ -122,25 +122,25 @@ Value Evaluation::value()
break;
}
if (pos.side_to_move() == WHITE) {
if (pos.side_to_move() == BLACK) {
value = -value;
}
#if EVAL_DRAW_WHEN_NOT_KNOWN_WIN_IF_MAY_FLY
if (pos.get_phase() == Phase::moving && rule.mayFly && !rule.hasDiagonalLines) {
int piece_on_board_count_future_black = pos.piece_on_board_count(BLACK);
int piece_on_board_count_future_white = pos.piece_on_board_count(WHITE);
if (pos.side_to_move() == BLACK) {
piece_on_board_count_future_white -= pos.piece_to_remove_count();
}
int piece_on_board_count_future_black = pos.piece_on_board_count(BLACK);
if (pos.side_to_move() == WHITE) {
piece_on_board_count_future_black -= pos.piece_to_remove_count();
}
if (pos.side_to_move() == BLACK) {
piece_on_board_count_future_white -= pos.piece_to_remove_count();
}
if (piece_on_board_count_future_white == 3 || piece_on_board_count_future_black == 3) {
if (piece_on_board_count_future_black == 3 || piece_on_board_count_future_white == 3) {
if (abs(value) < VALUE_KNOWN_WIN) {
value = VALUE_DRAW;
}

View File

@ -492,7 +492,7 @@ Depth get_search_depth(const Position *pos)
constexpr Depth flyingDepth = 9;
if (pos->phase == Phase::placing) {
const int index = rule.piecesCount * 2 - pos->count<IN_HAND>(BLACK) - pos->count<IN_HAND>(WHITE);
const int index = rule.piecesCount * 2 - pos->count<IN_HAND>(WHITE) - pos->count<IN_HAND>(BLACK);
if (rule.piecesCount == 12) {
assert(0 <= index && index <= 24);
@ -508,8 +508,8 @@ Depth get_search_depth(const Position *pos)
}
if (pos->phase == Phase::moving) {
const int pb = pos->count<ON_BOARD>(BLACK);
const int pw = pos->count<ON_BOARD>(WHITE);
const int pb = pos->count<ON_BOARD>(WHITE);
const int pw = pos->count<ON_BOARD>(BLACK);
const int pieces = pb + pw;
int diff = pb - pw;

View File

@ -97,9 +97,9 @@ void MovePicker::score()
//cur->value += bannedCount; // placing phrase, place nearby ban point
// for 12 men's morris (has diagonal), white 2nd move place star point is as important as close mill (TODO)
// for 12 men's morris (has diagonal), black 2nd move place star point is as important as close mill (TODO)
if (rule.hasDiagonalLines &&
pos.count<ON_BOARD>(WHITE) < 2 && // patch: only when white 2nd move
pos.count<ON_BOARD>(BLACK) < 2 && // patch: only when black 2nd move
Position::is_star_square(static_cast<Square>(m))) {
cur->value += RATING_STAR_SQUARE;
}

View File

@ -45,14 +45,14 @@ const string PieceToChar(Piece p)
return "X";
}
if (B_STONE <= p && p <= B_STONE_12) {
return "@";
}
if (W_STONE <= p && p <= W_STONE_12) {
return "O";
}
if (B_STONE <= p && p <= B_STONE_12) {
return "@";
}
return "*";
}
@ -62,14 +62,14 @@ Piece CharToPiece(char ch) noexcept
return NO_PIECE;
}
if (ch == '@') {
return B_STONE;
}
if (ch == 'O') {
return W_STONE;
}
if (ch == '@') {
return B_STONE;
}
if (ch == 'X') {
return BAN_STONE;
}
@ -77,7 +77,7 @@ Piece CharToPiece(char ch) noexcept
return NO_PIECE;
}
constexpr PieceType PieceTypes[] = { NO_PIECE_TYPE, BLACK_STONE, WHITE_STONE, BAN };
constexpr PieceType PieceTypes[] = { NO_PIECE_TYPE, WHITE_STONE, BLACK_STONE, BAN };
} // namespace
@ -173,7 +173,7 @@ Position::Position()
reset();
score[BLACK] = score[WHITE] = score_draw = gamesPlayedCount = 0;
score[WHITE] = score[BLACK] = score_draw = gamesPlayedCount = 0;
}
@ -203,14 +203,14 @@ Position &Position::set(const string &fenStr, Thread *th)
4) Action.
5) Black on board/Black in hand/White on board/White in hand/need to remove
5) White on board/White in hand/Black on board/Black in hand/need to remove
6) Halfmove clock. This is the number of halfmoves since the last
capture. This is used to determine if a draw can be claimed under the
fifty-move rule.
7) Fullmove number. The number of the full move. It starts at 1, and is
incremented after Black's move.
incremented after White's move.
*/
unsigned char token = '\0';
@ -223,7 +223,7 @@ Position &Position::set(const string &fenStr, Thread *th)
// 1. Piece placement
while ((ss >> token) && !isspace(token)) {
if (token == '@' || token == 'O' || token == 'X') {
if (token == 'O' || token == '@' || token == 'X') {
put_piece(CharToPiece(token), sq);
++sq;
}
@ -234,7 +234,7 @@ Position &Position::set(const string &fenStr, Thread *th)
// 2. Active color
ss >> token;
sideToMove = (token == 'b' ? BLACK : WHITE);
sideToMove = (token == 'w' ? WHITE : BLACK);
them = ~sideToMove; // Note: Stockfish do not need to set them
// 3. Phrase
@ -276,10 +276,10 @@ Position &Position::set(const string &fenStr, Thread *th)
action = Action::none;
}
// 5. Black on board / Black in hand / White on board / White in hand / need to remove
// 5. White on board / White in hand / Black on board / Black in hand / need to remove
ss >> std::skipws
>> pieceOnBoardCount[BLACK] >> pieceInHandCount[BLACK]
>> pieceOnBoardCount[WHITE] >> pieceInHandCount[WHITE]
>> pieceOnBoardCount[BLACK] >> pieceInHandCount[BLACK]
>> pieceToRemoveCount;
@ -288,7 +288,7 @@ Position &Position::set(const string &fenStr, Thread *th)
// Convert from fullmove starting from 1 to gamePly starting from 0,
// handle also common incorrect FEN with fullmove = 0.
gamePly = std::max(2 * (gamePly - 1), 0) + (sideToMove == WHITE);
gamePly = std::max(2 * (gamePly - 1), 0) + (sideToMove == BLACK);
thisThread = th;
@ -363,11 +363,11 @@ const string Position::fen() const
ss << " ";
ss << pieceOnBoardCount[BLACK] << " " << pieceInHandCount[BLACK] << " "
<< pieceOnBoardCount[WHITE] << " " << pieceInHandCount[WHITE] << " "
ss << pieceOnBoardCount[WHITE] << " " << pieceInHandCount[WHITE] << " "
<< pieceOnBoardCount[BLACK] << " " << pieceInHandCount[BLACK] << " "
<< pieceToRemoveCount << " ";
ss << st.rule50 << " " << 1 + (gamePly - (sideToMove == WHITE)) / 2;
ss << st.rule50 << " " << 1 + (gamePly - (sideToMove == BLACK)) / 2;
return ss.str();
}
@ -545,7 +545,7 @@ bool Position::reset()
st.rule50 = 0;
phase = Phase::ready;
set_side_to_move(BLACK);
set_side_to_move(WHITE);
action = Action::place;
winner = NOBODY;
@ -557,8 +557,8 @@ bool Position::reset()
st.key = 0;
pieceOnBoardCount[BLACK] = pieceOnBoardCount[WHITE] = 0;
pieceInHandCount[BLACK] = pieceInHandCount[WHITE] = rule.piecesCount;
pieceOnBoardCount[WHITE] = pieceOnBoardCount[BLACK] = 0;
pieceInHandCount[WHITE] = pieceInHandCount[BLACK] = rule.piecesCount;
pieceToRemoveCount = 0;
MoveList<LEGAL>::create();
@ -640,8 +640,8 @@ bool Position::put_piece(Square s, bool updateRecord)
currentSquare = s;
#ifdef MUEHLE_NMM
if (pieceInHandCount[BLACK] == 0 &&
pieceInHandCount[WHITE] == 0 &&
if (pieceInHandCount[WHITE] == 0 &&
pieceInHandCount[BLACK] == 0 &&
is_all_surrounded(~sideToMove, SQ_0, s)) {
set_gameover(sideToMove, GameOverReason::loseReasonNoWay);
//change_side_to_move();
@ -656,9 +656,9 @@ bool Position::put_piece(Square s, bool updateRecord)
|| is_all_in_mills(them)
#endif
) {
assert(pieceInHandCount[BLACK] >= 0 && pieceInHandCount[WHITE] >= 0);
assert(pieceInHandCount[WHITE] >= 0 && pieceInHandCount[BLACK] >= 0);
if (pieceInHandCount[BLACK] == 0 && pieceInHandCount[WHITE] == 0) {
if (pieceInHandCount[WHITE] == 0 && pieceInHandCount[BLACK] == 0) {
if (check_if_game_is_over()) {
return true;
}
@ -825,7 +825,7 @@ bool Position::remove_piece(Square s, bool updateRecord)
}
if (phase == Phase::placing) {
if (pieceInHandCount[BLACK] == 0 && pieceInHandCount[WHITE] == 0) {
if (pieceInHandCount[WHITE] == 0 && pieceInHandCount[BLACK] == 0) {
phase = Phase::moving;
action = Action::select;
@ -979,9 +979,9 @@ bool Position::check_if_game_is_over()
}
#endif // RULE_50
if (pieceOnBoardCount[BLACK] + pieceOnBoardCount[WHITE] >= EFFECTIVE_SQUARE_NB) {
if (rule.isBlackLoseButNotDrawWhenBoardFull) {
set_gameover(WHITE, GameOverReason::loseReasonBoardIsFull);
if (pieceOnBoardCount[WHITE] + pieceOnBoardCount[BLACK] >= EFFECTIVE_SQUARE_NB) {
if (rule.isWhiteLoseButNotDrawWhenBoardFull) {
set_gameover(BLACK, GameOverReason::loseReasonBoardIsFull);
} else {
set_gameover(DRAW, GameOverReason::drawReasonBoardIsFull);
}
@ -1005,8 +1005,8 @@ bool Position::check_if_game_is_over()
int Position::get_mobility_diff()
{
// TODO: Deal with rule is no ban location
int mobilityBlack = 0;
int mobilityWhite = 0;
int mobilityBlack = 0;
for (Square s = SQ_BEGIN; s < SQ_END; ++s) {
if (board[s] == NO_PIECE || board[s] == BAN_STONE) {
@ -1014,18 +1014,18 @@ int Position::get_mobility_diff()
for (MoveDirection d = MD_BEGIN; d < MD_NB; ++d) {
moveSquare = static_cast<Square>(MoveList<LEGAL>::adjacentSquares[s][d]);
if (moveSquare) {
if (board[moveSquare] & B_STONE) {
mobilityBlack++;
}
if (board[moveSquare] & W_STONE) {
mobilityWhite++;
}
if (board[moveSquare] & B_STONE) {
mobilityBlack++;
}
}
}
}
}
return mobilityBlack - mobilityWhite;
return mobilityWhite - mobilityBlack;
}
void Position::remove_ban_stones()
@ -1106,34 +1106,24 @@ Color Position::color_on(Square s) const
bool Position::bitboard_is_ok()
{
#ifdef BITBOARD_DEBUG
Bitboard blackBB = byColorBB[BLACK];
Bitboard whiteBB = byColorBB[WHITE];
Bitboard blackBB = byColorBB[BLACK];
for (Square s = SQ_BEGIN; s < SQ_END; ++s) {
if (empty(s))
{
if (whiteBB & (1 << s)) {
return false;
}
if (blackBB & (1 << s)) {
return false;
}
if (whiteBB & (1 << s)) {
return false;
}
}
if (color_of(board[s]) == BLACK)
if (color_of(board[s]) == WHITE)
{
if ((blackBB & (1 << s)) == 0) {
return false;
}
if (whiteBB & (1 << s)) {
return false;
}
}
if (color_of(board[s]) == WHITE) {
if ((whiteBB & (1 << s)) == 0) {
return false;
}
@ -1142,6 +1132,16 @@ bool Position::bitboard_is_ok()
return false;
}
}
if (color_of(board[s]) == BLACK) {
if ((blackBB & (1 << s)) == 0) {
return false;
}
if (whiteBB & (1 << s)) {
return false;
}
}
}
#endif
@ -1255,7 +1255,7 @@ bool Position::is_all_surrounded(Color c
) const
{
// Full
if (pieceOnBoardCount[BLACK] + pieceOnBoardCount[WHITE] >= EFFECTIVE_SQUARE_NB)
if (pieceOnBoardCount[WHITE] + pieceOnBoardCount[BLACK] >= EFFECTIVE_SQUARE_NB)
return true;
// Can fly

View File

@ -52,7 +52,7 @@ struct Rule
// At the end of the placing phase, when the board is full,
// the side that places first loses the game, otherwise, the game is a draw.
bool isBlackLoseButNotDrawWhenBoardFull;
bool isWhiteLoseButNotDrawWhenBoardFull;
// The player will lose if his opponent blocks them so that they cannot be moved.
// Change side to move if this option is disabled.

View File

@ -123,7 +123,7 @@ int Thread::search()
#if 0
// TODO: Only NMM
if (rootPos->piece_on_board_count(BLACK) + rootPos->piece_on_board_count(WHITE) <= 1 &&
if (rootPos->piece_on_board_count(WHITE) + rootPos->piece_on_board_count(BLACK) <= 1 &&
!rule.hasDiagonalLines && gameOptions.getShufflingEnabled()) {
const uint32_t seed = static_cast<uint32_t>(now());
std::shuffle(MoveList<LEGAL>::movePriorityList.begin(), MoveList<LEGAL>::movePriorityList.end(), std::default_random_engine(seed));
@ -255,11 +255,11 @@ Value search(Position *pos, Sanmill::Stack<Position> &ss, Depth depth, Depth ori
posKey &&
Thread::probeEndgameHash(posKey, endgame)) {
switch (endgame.type) {
case EndGameType::blackWin:
case EndGameType::whiteWin:
bestValue = VALUE_MATE;
bestValue += depth;
break;
case EndGameType::whiteWin:
case EndGameType::blackWin:
bestValue = -VALUE_MATE;
bestValue -= depth;
break;

View File

@ -283,8 +283,8 @@ void Thread::analyze(Color c)
const bool lose = v <= -VALUE_MATE;
const int np = v / VALUE_EACH_PIECE;
string strUs = (c == BLACK ? "Black" : "White");
string strThem = (c == BLACK ? "White" : "Black");
string strUs = (c == WHITE ? "White" : "Black");
string strThem = (c == WHITE ? "Black" : "White");
loggerDebug("Depth: %d\n\n", originDepth);
@ -304,11 +304,11 @@ void Thread::analyze(Color c)
if (p->get_winner() == DRAW) {
cout << "Draw" << endl;
ndraw += 0.5; // TODO
} else if (p->get_winner() == BLACK) {
cout << "Black wins" << endl;
nbwin += 0.5; // TODO
} else if (p->get_winner() == WHITE) {
cout << "White wins" << endl;
nbwin += 0.5; // TODO
} else if (p->get_winner() == BLACK) {
cout << "Black wins" << endl;
nwwin += 0.5; // TODO
}
goto out;
@ -379,10 +379,10 @@ void Thread::analyze(Color c)
cout << strThem << " after " << d << " moves will lead " << -np << " pieces" << endl;
}
if (p->side_to_move() == BLACK) {
cout << "Black to move" << endl;
} else {
if (p->side_to_move() == WHITE) {
cout << "White to move" << endl;
} else {
cout << "Black to move" << endl;
}
#ifndef QT_GUI_LIB
@ -427,8 +427,8 @@ string Thread::next_move()
if (gameOptions.isEndgameLearningEnabled()) {
if (bestvalue <= -VALUE_KNOWN_WIN) {
Endgame endgame;
endgame.type = rootPos->side_to_move() == BLACK ?
EndGameType::whiteWin : EndGameType::blackWin;
endgame.type = rootPos->side_to_move() == WHITE ?
EndGameType::blackWin : EndGameType::whiteWin;
Key endgameHash = rootPos->key(); // TODO: Do not generate hash repeatedly
saveEndgameHash(endgameHash, endgame);
}

View File

@ -121,7 +121,7 @@ public:
Value bestvalue { VALUE_ZERO };
Value lastvalue { VALUE_ZERO };
Color us { BLACK };
Color us { WHITE };
private:
int timeLimit;

View File

@ -131,8 +131,8 @@ enum MoveType
enum Color : uint8_t
{
NOCOLOR = 0,
BLACK = 1,
WHITE = 2,
WHITE = 1,
BLACK = 2,
COLOR_NB = 3,
DRAW = 4,
NOBODY = 8
@ -252,8 +252,8 @@ enum Rating : int8_t
enum PieceType : uint16_t
{
NO_PIECE_TYPE = 0,
BLACK_STONE = 1,
WHITE_STONE = 2,
WHITE_STONE = 1,
BLACK_STONE = 2,
BAN = 3,
ALL_PIECES = 0,
PIECE_TYPE_NB = 4,
@ -267,33 +267,33 @@ 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 = 0x10,
W_STONE_1 = 0x11,
W_STONE_2 = 0x12,
W_STONE_3 = 0x13,
W_STONE_4 = 0x14,
W_STONE_5 = 0x15,
W_STONE_6 = 0x16,
W_STONE_7 = 0x17,
W_STONE_8 = 0x18,
W_STONE_9 = 0x19,
W_STONE_10 = 0x1A,
W_STONE_11 = 0x1B,
W_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,
B_STONE = 0x20,
B_STONE_1 = 0x21,
B_STONE_2 = 0x22,
B_STONE_3 = 0x23,
B_STONE_4 = 0x24,
B_STONE_5 = 0x25,
B_STONE_6 = 0x26,
B_STONE_7 = 0x27,
B_STONE_8 = 0x28,
B_STONE_9 = 0x29,
B_STONE_10 = 0x2A,
B_STONE_11 = 0x2B,
B_STONE_12 = 0x2C,
PIECE_NB = 64, // Fix overflow
};
@ -410,7 +410,7 @@ constexpr Piece make_piece(Color c)
constexpr Piece make_piece(Color c, PieceType pt)
{
if (pt == BLACK_STONE || pt == WHITE_STONE) {
if (pt == WHITE_STONE || pt == BLACK_STONE) {
return make_piece(c);
}
@ -432,14 +432,14 @@ constexpr PieceType type_of(Piece pc)
return BAN;
}
if (color_of(pc) == BLACK) {
return BLACK_STONE;
}
if (color_of(pc) == WHITE) {
return WHITE_STONE;
}
if (color_of(pc) == BLACK) {
return BLACK_STONE;
}
return NO_PIECE_TYPE;
}

View File

@ -37,8 +37,8 @@ namespace
{
// FEN string of the initial position, normal mill game
const char *StartFEN12 = "********/********/******** b p p 0 12 0 12 0 0 1";
const char *StartFEN9 = "********/********/******** b p p 0 9 0 9 0 0 1";
const char *StartFEN12 = "********/********/******** w p p 0 12 0 12 0 0 1";
const char *StartFEN9 = "********/********/******** w p p 0 9 0 9 0 0 1";
char StartFEN[BUFSIZ];
// position() is called when engine receives the "position" UCI command.
@ -130,7 +130,7 @@ void go(Position *pos)
}
pos->set(StartFEN, Threads.main());
Threads.main()->us = BLACK; // WAR
Threads.main()->us = WHITE; // WAR
break;
}
#else

View File

@ -117,9 +117,9 @@ void on_mayRemoveFromMillsAlways(const Option &o)
rule.mayRemoveFromMillsAlways = (bool)o;
}
void on_isBlackLoseButNotDrawWhenBoardFull(const Option &o)
void on_isWhiteLoseButNotDrawWhenBoardFull(const Option &o)
{
rule.isBlackLoseButNotDrawWhenBoardFull = (bool)o;
rule.isWhiteLoseButNotDrawWhenBoardFull = (bool)o;
}
void on_isLoseButNotChangeSideWhenNoWay(const Option &o)
@ -181,7 +181,7 @@ void init(OptionsMap &o)
o["IsDefenderMoveFirst"] << Option(true, on_isDefenderMoveFirst);
o["MayRemoveMultiple"] << Option(false, on_mayRemoveMultiple);
o["MayRemoveFromMillsAlways"] << Option(true, on_mayRemoveFromMillsAlways);
o["IsBlackLoseButNotDrawWhenBoardFull"] << Option(true, on_isBlackLoseButNotDrawWhenBoardFull);
o["IsWhiteLoseButNotDrawWhenBoardFull"] << Option(true, on_isWhiteLoseButNotDrawWhenBoardFull);
o["IsLoseButNotChangeSideWhenNoWay"] << Option(true, on_isLoseButNotChangeSideWhenNoWay);
o["MayFly"] << Option(false, on_mayFly);
o["MaxStepsLedToDraw"] << Option(50, 30, 50, on_maxStepsLedToDraw);

View File

@ -1,7 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- Theme applied to the Android Window while the process is starting -->
<style name="LaunchTheme" parent="@android:style/Theme.Black.NoTitleBar">
<style name="LaunchTheme"
parent="@android:style/Theme.Black.NoTitleBar">
<!-- Show a splash screen on the activity. Automatically removed when
Flutter draws its first frame -->
<item name="android:windowBackground">@drawable/launch_background</item>
@ -12,7 +13,8 @@
running.
This Theme is only used starting with V2 of Flutter's Android embedding. -->
<style name="NormalTheme" parent="@android:style/Theme.Black.NoTitleBar">
<style name="NormalTheme"
parent="@android:style/Theme.Black.NoTitleBar">
<item name="android:windowBackground">@drawable/normal_background</item>
</style>
</resources>

View File

@ -49,8 +49,8 @@ class Config {
static int boardLineColor = AppTheme.boardLineColor.value;
static int darkBackgroundColor = AppTheme.darkBackgroundColor.value;
static int boardBackgroundColor = AppTheme.boardBackgroundColor.value;
static int blackPieceColor = AppTheme.blackPieceColor.value;
static int whitePieceColor = AppTheme.whitePieceColor.value;
static int blackPieceColor = AppTheme.blackPieceColor.value;
// Rules
static int piecesCount = 9;
@ -60,7 +60,7 @@ class Config {
static bool isDefenderMoveFirst = false;
static bool mayRemoveMultiple = false;
static bool mayRemoveFromMillsAlways = false;
static bool isBlackLoseButNotDrawWhenBoardFull = true;
static bool isWhiteLoseButNotDrawWhenBoardFull = true;
static bool isLoseButNotChangeSideWhenNoWay = true;
static bool mayFly = true;
static int maxStepsLedToDraw = 50;
@ -99,10 +99,10 @@ class Config {
settings['DarkBackgroundColor'] ?? AppTheme.darkBackgroundColor.value;
Config.boardBackgroundColor =
settings['BoardBackgroundColor'] ?? AppTheme.boardBackgroundColor.value;
Config.blackPieceColor =
settings['BlackPieceColor'] ?? AppTheme.blackPieceColor.value;
Config.whitePieceColor =
settings['WhitePieceColor'] ?? AppTheme.whitePieceColor.value;
Config.blackPieceColor =
settings['BlackPieceColor'] ?? AppTheme.blackPieceColor.value;
// Rules
rule.piecesCount = Config.piecesCount = settings['PiecesCount'] ?? 9;
@ -118,9 +118,9 @@ class Config {
Config.mayRemoveMultiple = settings['MayRemoveMultiple'] ?? false;
rule.mayRemoveFromMillsAlways = Config.mayRemoveFromMillsAlways =
settings['MayRemoveFromMillsAlways'] ?? false;
rule.isBlackLoseButNotDrawWhenBoardFull =
Config.isBlackLoseButNotDrawWhenBoardFull =
settings['IsBlackLoseButNotDrawWhenBoardFull'] ?? true;
rule.isWhiteLoseButNotDrawWhenBoardFull =
Config.isWhiteLoseButNotDrawWhenBoardFull =
settings['IsWhiteLoseButNotDrawWhenBoardFull'] ?? true;
rule.isLoseButNotChangeSideWhenNoWay =
Config.isLoseButNotChangeSideWhenNoWay =
settings['IsLoseButNotChangeSideWhenNoWay'] ?? true;
@ -160,8 +160,8 @@ class Config {
settings['BoardLineColor'] = Config.boardLineColor;
settings['DarkBackgroundColor'] = Config.darkBackgroundColor;
settings['BoardBackgroundColor'] = Config.boardBackgroundColor;
settings['BlackPieceColor'] = Config.blackPieceColor;
settings['WhitePieceColor'] = Config.whitePieceColor;
settings['BlackPieceColor'] = Config.blackPieceColor;
// Rules
settings['PiecesCount'] = Config.piecesCount;
@ -171,8 +171,8 @@ class Config {
settings['IsDefenderMoveFirst'] = Config.isDefenderMoveFirst;
settings['MayRemoveMultiple'] = Config.mayRemoveMultiple;
settings['MayRemoveFromMillsAlways'] = Config.mayRemoveFromMillsAlways;
settings['IsBlackLoseButNotDrawWhenBoardFull'] =
Config.isBlackLoseButNotDrawWhenBoardFull;
settings['IsWhiteLoseButNotDrawWhenBoardFull'] =
Config.isWhiteLoseButNotDrawWhenBoardFull;
settings['IsLoseButNotChangeSideWhenNoWay'] =
Config.isLoseButNotChangeSideWhenNoWay;
settings['MayFly'] = Config.mayFly;

View File

@ -145,7 +145,7 @@ class NativeEngine extends Engine {
await send(
'setoption name MayRemoveFromMillsAlways value ${Config.mayRemoveFromMillsAlways}');
await send(
'setoption name IsBlackLoseButNotDrawWhenBoardFull value ${Config.isBlackLoseButNotDrawWhenBoardFull}');
'setoption name IsWhiteLoseButNotDrawWhenBoardFull value ${Config.isWhiteLoseButNotDrawWhenBoardFull}');
await send(
'setoption name IsLoseButNotChangeSideWhenNoWay value ${Config.isLoseButNotChangeSideWhenNoWay}');
await send('setoption name MayFly value ${Config.mayFly}');

View File

@ -160,12 +160,12 @@
"@tipToMove": {
"description": " to move."
},
"blackWin": "Player 1 win!",
"@blackWin": {
"whiteWin": "Player 1 win!",
"@whiteWin": {
"description": "Player 1 win!"
},
"whiteWin": "Player 2 win!",
"@whiteWin": {
"blackWin": "Player 2 win!",
"@blackWin": {
"description": "Player 2 win!"
},
"won": "Won",
@ -224,12 +224,12 @@
"@score": {
"description": "Score"
},
"black": "Player 1",
"@black": {
"white": "Player 1",
"@white": {
"description": "Player 1"
},
"white": "Player 2",
"@white": {
"black": "Player 2",
"@black": {
"description": "Player 2"
},
"loseReasonlessThanThree": " piece count is less than three.",
@ -488,12 +488,12 @@
"@mayRemoveFromMillsAlways_Detail": {
"description": "mayRemoveFromMillsAlways_Detail"
},
"isBlackLoseButNotDrawWhenBoardFull": "Second player loses when board full",
"@isBlackLoseButNotDrawWhenBoardFull": {
"isWhiteLoseButNotDrawWhenBoardFull": "Second player loses when board full",
"@isWhiteLoseButNotDrawWhenBoardFull": {
"description": "Second player loses when board full"
},
"isBlackLoseButNotDrawWhenBoardFull_Detail": "At the end of the placing phase, when the board is full, the side that places first loses the game, otherwise, the game is a draw.",
"@isBlackLoseButNotDrawWhenBoardFull_Detail": {
"isWhiteLoseButNotDrawWhenBoardFull_Detail": "At the end of the placing phase, when the board is full, the side that places first loses the game, otherwise, the game is a draw.",
"@isWhiteLoseButNotDrawWhenBoardFull_Detail": {
"description": "At the end of the placing phase, when the board is full, the side that places first loses the game, otherwise, the game is a draw."
},
"isLoseButNotChangeSideWhenNoWay": "Lose when no legal moves",
@ -568,12 +568,12 @@
"@lineColor": {
"description": "Board linecolor"
},
"blackPieceColor": "Player 1 piece color",
"@blackPieceColor": {
"whitePieceColor": "Player 1 piece color",
"@whitePieceColor": {
"description": "Player 1 piece color"
},
"whitePieceColor": "Player 2 piece color",
"@whitePieceColor": {
"blackPieceColor": "Player 2 piece color",
"@blackPieceColor": {
"description": "Player 2 piece color"
},
"aiIsLazy": "AI is Lazy",

View File

@ -40,8 +40,8 @@
"tipHaveThreePiecesLeft": "只剩下3颗棋子了",
"tipCanMoveToAnyPoint": "可飞子到任意空位",
"tipToMove": "行棋",
"blackWin": "先手方胜",
"whiteWin": "后手方胜",
"whiteWin": "先手方胜",
"blackWin": "后手方胜",
"won": "胜",
"lost": "负",
"aborted": "中断",
@ -56,8 +56,8 @@
"error": "错误",
"winRate": "胜率",
"score": "比分",
"black": "先手方",
"white": "后手方",
"white": "先手方",
"black": "后手方",
"loseReasonlessThanThree": "剩余棋子少于3枚。",
"loseReasonResign": "认输了。",
"loseReasonNoWay": "无路可走。",
@ -122,8 +122,8 @@
"mayRemoveMultiple_Detail": "若同时形成多个三连,则形成几个三连就能吃对方几个子。",
"mayRemoveFromMillsAlways": "允许吃三连中的子",
"mayRemoveFromMillsAlways_Detail": "默认情况下,不能吃三连中的子,除非对方所有子都在三连中。打开此选项可解除此限制。",
"isBlackLoseButNotDrawWhenBoardFull": "当棋盘摆满时先摆子的输棋",
"isBlackLoseButNotDrawWhenBoardFull_Detail": "对于十二子棋,在摆子阶段的最后,若棋盘摆满而双方均未吃子,则先手方输棋,而非和棋。",
"isWhiteLoseButNotDrawWhenBoardFull": "当棋盘摆满时先摆子的输棋",
"isWhiteLoseButNotDrawWhenBoardFull_Detail": "对于十二子棋,在摆子阶段的最后,若棋盘摆满而双方均未吃子,则先手方输棋,而非和棋。",
"isLoseButNotChangeSideWhenNoWay": "当无路可走时输棋",
"isLoseButNotChangeSideWhenNoWay_Detail": "走子阶段,当无路可走时输棋,而非转为由对方继续走子。",
"mayFly": "飞子",
@ -142,8 +142,8 @@
"pieceColor": "棋子颜色",
"backgroudColor": "背景颜色",
"lineColor": "线条颜色",
"blackPieceColor": "先手方棋子颜色",
"whitePieceColor": "后手方棋子颜色",
"whitePieceColor": "先手方棋子颜色",
"blackPieceColor": "后手方棋子颜色",
"aiIsLazy": "机器领先时懒惰",
"isPieceCountInHandShown": "显示手中剩余棋子数",
"display": "显示",

View File

@ -23,7 +23,7 @@ import 'position.dart';
import 'types.dart';
enum PlayerType { human, AI }
Map<String, bool> isAi = {PieceColor.black: false, PieceColor.white: true};
Map<String, bool> isAi = {PieceColor.white: false, PieceColor.black: true};
class Game {
static Game? _instance;
@ -50,10 +50,10 @@ class Game {
position.init();
_focusIndex = _blurIndex = invalidIndex;
moveHistory = [""];
sideToMove = PieceColor.black;
sideToMove = PieceColor.white;
}
String sideToMove = PieceColor.black;
String sideToMove = PieceColor.white;
bool? isAiToMove() {
return isAi[sideToMove];
@ -74,13 +74,13 @@ class Game {
set blurIndex(index) => _blurIndex = index;
Map<String, bool> isSearching = {
PieceColor.black: false,
PieceColor.white: false
PieceColor.white: false,
PieceColor.black: false
};
bool aiIsSearching() {
return isSearching[PieceColor.black] == true ||
isSearching[PieceColor.white] == true;
return isSearching[PieceColor.white] == true ||
isSearching[PieceColor.black] == true;
}
EngineType engineType = EngineType.none;
@ -91,16 +91,16 @@ class Game {
switch (type) {
case EngineType.humanVsAi:
case EngineType.testViaLAN:
isAi[PieceColor.black] = Config.aiMovesFirst;
isAi[PieceColor.white] = !Config.aiMovesFirst;
isAi[PieceColor.white] = Config.aiMovesFirst;
isAi[PieceColor.black] = !Config.aiMovesFirst;
break;
case EngineType.humanVsHuman:
case EngineType.humanVsLAN:
case EngineType.humanVsCloud:
isAi[PieceColor.black] = isAi[PieceColor.white] = false;
isAi[PieceColor.white] = isAi[PieceColor.black] = false;
break;
case EngineType.aiVsAi:
isAi[PieceColor.black] = isAi[PieceColor.white] = true;
isAi[PieceColor.white] = isAi[PieceColor.black] = true;
break;
default:
break;
@ -136,7 +136,7 @@ class Game {
//
// Can regret only our turn
// TODO
if (_position.side != PieceColor.white) {
if (_position.side != PieceColor.black) {
//Audios.playTone(Audios.invalidSoundId);
return false;
}
@ -174,38 +174,38 @@ class Game {
}
printStat() {
double blackWinRate = 0;
double whiteWinRate = 0;
double blackWinRate = 0;
double drawRate = 0;
int total = position.score[PieceColor.black] +
position.score[PieceColor.white] +
int total = position.score[PieceColor.white] +
position.score[PieceColor.black] +
position.score[PieceColor.draw] ??
0;
if (total == 0) {
blackWinRate = 0;
whiteWinRate = 0;
blackWinRate = 0;
drawRate = 0;
} else {
blackWinRate = position.score[PieceColor.black] * 100 / total ?? 0;
whiteWinRate = position.score[PieceColor.white] * 100 / total ?? 0;
blackWinRate = position.score[PieceColor.black] * 100 / total ?? 0;
drawRate = position.score[PieceColor.draw] * 100 / total ?? 0;
}
String scoreInfo = "Score: " +
position.score[PieceColor.black].toString() +
" : " +
position.score[PieceColor.white].toString() +
" : " +
position.score[PieceColor.black].toString() +
" : " +
position.score[PieceColor.draw].toString() +
"\ttotal: " +
total.toString() +
"\n" +
blackWinRate.toString() +
"% : " +
whiteWinRate.toString() +
"% : " +
blackWinRate.toString() +
"% : " +
drawRate.toString() +
"%" +
"\n";

View File

@ -46,22 +46,22 @@ class Position {
GameRecorder? recorder;
Map<String, int> pieceInHandCount = {
PieceColor.black: -1,
PieceColor.white: -1
PieceColor.white: -1,
PieceColor.black: -1
};
Map<String, int> pieceOnBoardCount = {
PieceColor.black: 0,
PieceColor.white: 0
PieceColor.white: 0,
PieceColor.black: 0
};
int pieceToRemoveCount = 0;
int gamePly = 0;
String _sideToMove = PieceColor.black;
String _sideToMove = PieceColor.white;
StateInfo st = StateInfo();
String us = PieceColor.black;
String them = PieceColor.white;
String us = PieceColor.white;
String them = PieceColor.black;
String winner = PieceColor.nobody;
GameOverReason gameOverReason = GameOverReason.noReason;
@ -70,8 +70,8 @@ class Position {
Act action = Act.none;
Map<String, int> score = {
PieceColor.black: 0,
PieceColor.white: 0,
PieceColor.black: 0,
PieceColor.draw: 0
};
@ -177,7 +177,7 @@ class Position {
}
// Active color
ss += _sideToMove == PieceColor.black ? "b" : "w";
ss += _sideToMove == PieceColor.white ? "w" : "b";
ss += " ";
@ -223,22 +223,22 @@ class Position {
ss += " ";
ss += pieceOnBoardCount[PieceColor.black].toString() +
" " +
pieceInHandCount[PieceColor.black].toString() +
" " +
pieceOnBoardCount[PieceColor.white].toString() +
ss += pieceOnBoardCount[PieceColor.white].toString() +
" " +
pieceInHandCount[PieceColor.white].toString() +
" " +
pieceOnBoardCount[PieceColor.black].toString() +
" " +
pieceInHandCount[PieceColor.black].toString() +
" " +
pieceToRemoveCount.toString() +
" ";
int sideIsWhite = _sideToMove == PieceColor.white ? 1 : 0;
int sideIsBlack = _sideToMove == PieceColor.black ? 1 : 0;
ss += st.rule50.toString() +
" " +
(1 + (gamePly - sideIsWhite) ~/ 2).toString();
(1 + (gamePly - sideIsBlack) ~/ 2).toString();
return ss;
}
@ -269,9 +269,9 @@ class Position {
if (move.length > "Player".length &&
move.substring(0, "Player".length - 1) == "Player") {
if (move["Player".length] == '1') {
return resign(PieceColor.black);
} else {
return resign(PieceColor.white);
} else {
return resign(PieceColor.black);
}
}
@ -405,7 +405,7 @@ class Position {
st.rule50 = 0;
phase = Phase.ready;
setSideToMove(PieceColor.black);
setSideToMove(PieceColor.white);
action = Act.place;
winner = PieceColor.nobody;
@ -415,10 +415,10 @@ class Position {
st.key = 0;
pieceOnBoardCount[PieceColor.black] =
pieceOnBoardCount[PieceColor.white] = 0;
pieceInHandCount[PieceColor.black] =
pieceInHandCount[PieceColor.white] = rule.piecesCount;
pieceOnBoardCount[PieceColor.white] =
pieceOnBoardCount[PieceColor.black] = 0;
pieceInHandCount[PieceColor.white] =
pieceInHandCount[PieceColor.black] = rule.piecesCount;
pieceToRemoveCount = 0;
// TODO:
@ -488,11 +488,11 @@ class Position {
int n = millsCount(currentSquare);
if (n == 0) {
assert(pieceInHandCount[PieceColor.black]! >= 0 &&
pieceInHandCount[PieceColor.white]! >= 0);
assert(pieceInHandCount[PieceColor.white]! >= 0 &&
pieceInHandCount[PieceColor.black]! >= 0);
if (pieceInHandCount[PieceColor.black] == 0 &&
pieceInHandCount[PieceColor.white] == 0) {
if (pieceInHandCount[PieceColor.white] == 0 &&
pieceInHandCount[PieceColor.black] == 0) {
if (checkIfGameIsOver()) {
return true;
}
@ -643,8 +643,8 @@ class Position {
}
if (phase == Phase.placing) {
if (pieceInHandCount[PieceColor.black] == 0 &&
pieceInHandCount[PieceColor.white] == 0) {
if (pieceInHandCount[PieceColor.white] == 0 &&
pieceInHandCount[PieceColor.black] == 0) {
phase = Phase.moving;
action = Act.select;
@ -741,11 +741,11 @@ class Position {
return true;
}
if (pieceOnBoardCount[PieceColor.black]! +
pieceOnBoardCount[PieceColor.white]! >=
if (pieceOnBoardCount[PieceColor.white]! +
pieceOnBoardCount[PieceColor.black]! >=
rankNumber * fileNumber) {
if (rule.isBlackLoseButNotDrawWhenBoardFull) {
setGameOver(PieceColor.white, GameOverReason.loseReasonBoardIsFull);
if (rule.isWhiteLoseButNotDrawWhenBoardFull) {
setGameOver(PieceColor.black, GameOverReason.loseReasonBoardIsFull);
} else {
setGameOver(PieceColor.draw, GameOverReason.drawReasonBoardIsFull);
}
@ -906,8 +906,8 @@ class Position {
bool isAllSurrounded() {
// Full
if (pieceOnBoardCount[PieceColor.black]! +
pieceOnBoardCount[PieceColor.white]! >=
if (pieceOnBoardCount[PieceColor.white]! +
pieceOnBoardCount[PieceColor.black]! >=
rankNumber * fileNumber) {
return true;
}
@ -947,13 +947,13 @@ class Position {
///////////////////////////////////////////////////////////////////////////////
int getNPiecesInHand() {
pieceInHandCount[PieceColor.black] =
rule.piecesCount - pieceOnBoardCount[PieceColor.black]!;
pieceInHandCount[PieceColor.white] =
rule.piecesCount - pieceOnBoardCount[PieceColor.white]!;
pieceInHandCount[PieceColor.black] =
rule.piecesCount - pieceOnBoardCount[PieceColor.black]!;
return pieceOnBoardCount[PieceColor.black]! +
pieceOnBoardCount[PieceColor.white]!;
return pieceOnBoardCount[PieceColor.white]! +
pieceOnBoardCount[PieceColor.black]!;
}
void clearBoard() {
@ -975,7 +975,7 @@ class Position {
gameOverReason = GameOverReason.noReason;
phase = Phase.placing;
setSideToMove(PieceColor.black);
setSideToMove(PieceColor.white);
action = Act.place;
currentSquare = 0;
@ -999,33 +999,33 @@ class Position {
}
int pieceOnBoardCountCount() {
pieceOnBoardCount[PieceColor.black] =
pieceOnBoardCount[PieceColor.white] = 0;
pieceOnBoardCount[PieceColor.white] =
pieceOnBoardCount[PieceColor.black] = 0;
for (int f = 1; f < fileExNumber; f++) {
for (int r = 0; r < rankNumber; r++) {
int s = f * rankNumber + r;
if (board[s] == Piece.blackStone) {
if (pieceOnBoardCount[PieceColor.black] != null) {
pieceOnBoardCount[PieceColor.black] =
pieceOnBoardCount[PieceColor.black]! + 1;
}
} else if (board[s] == Piece.whiteStone) {
if (board[s] == Piece.whiteStone) {
if (pieceOnBoardCount[PieceColor.white] != null) {
pieceOnBoardCount[PieceColor.white] =
pieceOnBoardCount[PieceColor.white]! + 1;
}
} else if (board[s] == Piece.blackStone) {
if (pieceOnBoardCount[PieceColor.black] != null) {
pieceOnBoardCount[PieceColor.black] =
pieceOnBoardCount[PieceColor.black]! + 1;
}
}
}
}
if (pieceOnBoardCount[PieceColor.black]! > rule.piecesCount ||
pieceOnBoardCount[PieceColor.white]! > rule.piecesCount) {
if (pieceOnBoardCount[PieceColor.white]! > rule.piecesCount ||
pieceOnBoardCount[PieceColor.black]! > rule.piecesCount) {
return -1;
}
return pieceOnBoardCount[PieceColor.black]! +
pieceOnBoardCount[PieceColor.white]!;
return pieceOnBoardCount[PieceColor.white]! +
pieceOnBoardCount[PieceColor.black]!;
}
///////////////////////////////////////////////////////////////////////////////

View File

@ -52,7 +52,7 @@ class GameRecorder {
if (fullMove == 0) {
if (halfMove != null) halfMove = halfMove! + 1;
} else if (position.side != PieceColor.black) {
} else if (position.side != PieceColor.white) {
if (halfMove != null) halfMove = halfMove! + 1;
}

View File

@ -26,7 +26,7 @@ class Rule {
bool isDefenderMoveFirst = false;
bool mayRemoveMultiple = false;
bool mayRemoveFromMillsAlways = false;
bool isBlackLoseButNotDrawWhenBoardFull = true;
bool isWhiteLoseButNotDrawWhenBoardFull = true;
bool isLoseButNotChangeSideWhenNoWay = true;
bool mayFly = true;
int maxStepsLedToDraw = 50;

View File

@ -131,15 +131,15 @@ enum MoveType { place, move, remove, none }
class PieceColor {
static const none = '*';
static const black = '@';
static const white = 'O';
static const black = '@';
static const ban = 'X';
static const nobody = '-';
static const draw = '=';
static String of(String piece) {
if (black.contains(piece)) return black;
if (white.contains(piece)) return white;
if (black.contains(piece)) return black;
if (ban.contains(piece)) return ban;
return nobody;
}
@ -147,8 +147,8 @@ class PieceColor {
static bool isSameColor(String p1, String p2) => of(p1) == of(p2);
static String opponent(String color) {
if (color == white) return black;
if (color == black) return white;
if (color == white) return black;
return color;
}
@ -157,8 +157,8 @@ class PieceColor {
Map<String, int> pieceColorIndex = {
PieceColor.none: 0,
PieceColor.black: 1,
PieceColor.white: 2,
PieceColor.white: 1,
PieceColor.black: 2,
PieceColor.ban: 3
};
@ -178,17 +178,17 @@ enum GameOverReason {
drawReasonBoardIsFull
}
enum PieceType { none, blackStone, whiteStone, ban, count, stone }
enum PieceType { none, whiteStone, blackStone, ban, count, stone }
class Piece {
static const noPiece = PieceColor.none;
static const blackStone = PieceColor.black;
static const whiteStone = PieceColor.white;
static const blackStone = PieceColor.black;
static const ban = PieceColor.ban;
static bool isEmpty(String c) => noPiece.contains(c);
static bool isBlack(String c) => blackStone.contains(c);
static bool isWhite(String c) => whiteStone.contains(c);
static bool isBlack(String c) => blackStone.contains(c);
static bool isBan(String c) => ban.contains(c);
}

View File

@ -62,7 +62,7 @@ class BoardPainter extends PiecesBasePainter {
if (Config.isPieceCountInHandShown) {
var pieceInHandCount =
Game.instance.position.pieceInHandCount[PieceColor.white];
Game.instance.position.pieceInHandCount[PieceColor.black];
var pieceInHandCountStr = "";

View File

@ -112,7 +112,7 @@ class PiecesPainter extends PiecesBasePainter {
}
// Draw shadow of piece
canvas.drawShadow(shadowPath, Colors.black, 2, true);
canvas.drawShadow(shadowPath, Colors.white, 2, true);
paint.style = PaintingStyle.fill;
@ -130,13 +130,6 @@ class PiecesPainter extends PiecesBasePainter {
// Draw Border of Piece
switch (pps.piece) {
case Piece.blackStone:
paint.color = AppTheme.blackPieceBorderColor;
canvas.drawCircle(pps.pos!, pieceRadius, paint); // For debugging
paint.color = Color(Config.blackPieceColor);
canvas.drawCircle(pps.pos!, pieceInnerRadius, paint);
blurPositionColor = Color(Config.blackPieceColor).withOpacity(0.1);
break;
case Piece.whiteStone:
paint.color = AppTheme.whitePieceBorderColor;
canvas.drawCircle(pps.pos!, pieceRadius, paint); // For debugging
@ -144,6 +137,13 @@ class PiecesPainter extends PiecesBasePainter {
canvas.drawCircle(pps.pos!, pieceInnerRadius, paint);
blurPositionColor = Color(Config.whitePieceColor).withOpacity(0.1);
break;
case Piece.blackStone:
paint.color = AppTheme.blackPieceBorderColor;
canvas.drawCircle(pps.pos!, pieceRadius, paint); // For debugging
paint.color = Color(Config.blackPieceColor);
canvas.drawCircle(pps.pos!, pieceInnerRadius, paint);
blurPositionColor = Color(Config.blackPieceColor).withOpacity(0.1);
break;
case Piece.ban:
//print("pps.piece is Ban");
break;
@ -159,17 +159,17 @@ class PiecesPainter extends PiecesBasePainter {
final int row = focusIndex! ~/ 7, column = focusIndex % 7;
focusPositionColor = Color.fromARGB(
(Color(Config.blackPieceColor).alpha +
Color(Config.whitePieceColor).alpha) ~/
(Color(Config.whitePieceColor).alpha +
Color(Config.blackPieceColor).alpha) ~/
2,
(Color(Config.blackPieceColor).red +
Color(Config.whitePieceColor).red) ~/
(Color(Config.whitePieceColor).red +
Color(Config.blackPieceColor).red) ~/
2,
(Color(Config.blackPieceColor).green +
Color(Config.whitePieceColor).green) ~/
(Color(Config.whitePieceColor).green +
Color(Config.blackPieceColor).green) ~/
2,
(Color(Config.blackPieceColor).blue +
Color(Config.whitePieceColor).blue) ~/
(Color(Config.whitePieceColor).blue +
Color(Config.blackPieceColor).blue) ~/
2)
.withOpacity(0.5);

View File

@ -93,8 +93,8 @@ class _GamePageState extends State<GamePage> with RouteAware {
final winner = Game.instance.position.winner;
Map<String, String> colorWinStrings = {
PieceColor.black: S.of(context).blackWin,
PieceColor.white: S.of(context).whiteWin,
PieceColor.black: S.of(context).blackWin,
PieceColor.draw: S.of(context).draw
};
@ -140,8 +140,8 @@ class _GamePageState extends State<GamePage> with RouteAware {
// TODO
// WAR: Fix first tap response slow when piece count changed
if (position.phase == Phase.placing &&
position.pieceOnBoardCount[PieceColor.black] == 0 &&
position.pieceOnBoardCount[PieceColor.white] == 0) {
position.pieceOnBoardCount[PieceColor.white] == 0 &&
position.pieceOnBoardCount[PieceColor.black] == 0) {
Game.instance.newGame();
if (Game.instance.isAiToMove()) {
@ -180,9 +180,9 @@ class _GamePageState extends State<GamePage> with RouteAware {
if (Game.instance.engineType == EngineType.humanVsAi && mounted) {
changeStatus(S.of(context).tipPlaced);
} else if (mounted) {
var side = Game.instance.sideToMove == PieceColor.black
? S.of(context).white
: S.of(context).black;
var side = Game.instance.sideToMove == PieceColor.white
? S.of(context).black
: S.of(context).white;
changeStatus(side + S.of(context).tipToMove);
}
}
@ -279,9 +279,9 @@ class _GamePageState extends State<GamePage> with RouteAware {
}
} else {
if (mounted) {
var them = Game.instance.sideToMove == PieceColor.black
? S.of(context).white
: S.of(context).black;
var them = Game.instance.sideToMove == PieceColor.white
? S.of(context).black
: S.of(context).white;
if (mounted) {
changeStatus(them + S.of(context).tipToMove);
}
@ -381,9 +381,9 @@ class _GamePageState extends State<GamePage> with RouteAware {
mounted) {
if (widget.engineType == EngineType.aiVsAi) {
String score =
Game.instance.position.score[PieceColor.black].toString() +
Game.instance.position.score[PieceColor.white].toString() +
" : " +
Game.instance.position.score[PieceColor.white].toString() +
Game.instance.position.score[PieceColor.black].toString() +
" : " +
Game.instance.position.score[PieceColor.draw].toString();
@ -460,9 +460,9 @@ class _GamePageState extends State<GamePage> with RouteAware {
String getGameOverReasonString(GameOverReason? reason, String? winner) {
//String winnerStr =
// winner == Color.black ? S.of(context).black : S.of(context).white;
// winner == Color.white ? S.of(context).white : S.of(context).black;
String loserStr =
winner == PieceColor.black ? S.of(context).white : S.of(context).black;
winner == PieceColor.white ? S.of(context).black : S.of(context).white;
Map<GameOverReason, String> reasonMap = {
GameOverReason.loseReasonlessThanThree:
@ -496,20 +496,20 @@ class _GamePageState extends State<GamePage> with RouteAware {
}
GameResult getGameResult(var winner) {
if (isAi[PieceColor.black]! && isAi[PieceColor.white]!) {
if (isAi[PieceColor.white]! && isAi[PieceColor.black]!) {
return GameResult.none;
}
if (winner == PieceColor.black) {
if (isAi[PieceColor.black]!) {
if (winner == PieceColor.white) {
if (isAi[PieceColor.white]!) {
return GameResult.lose;
} else {
return GameResult.win;
}
}
if (winner == PieceColor.white) {
if (isAi[PieceColor.white]!) {
if (winner == PieceColor.black) {
if (isAi[PieceColor.black]!) {
return GameResult.lose;
} else {
return GameResult.win;
@ -703,10 +703,10 @@ class _GamePageState extends State<GamePage> with RouteAware {
if (Game.instance.position.phase == Phase.gameOver) {
switch (Game.instance.position.winner) {
case PieceColor.black:
case PieceColor.white:
iconArrow = Icons.toggle_off_outlined;
break;
case PieceColor.white:
case PieceColor.black:
iconArrow = Icons.toggle_on_outlined;
break;
default:
@ -715,10 +715,10 @@ class _GamePageState extends State<GamePage> with RouteAware {
}
} else {
switch (Game.instance.sideToMove) {
case PieceColor.black:
case PieceColor.white:
iconArrow = Icons.keyboard_arrow_left;
break;
case PieceColor.white:
case PieceColor.black:
iconArrow = Icons.keyboard_arrow_right;
break;
default:
@ -754,11 +754,11 @@ class _GamePageState extends State<GamePage> with RouteAware {
"\n" +
S.of(context).player1 +
": " +
Game.instance.position.score[PieceColor.black].toString() +
Game.instance.position.score[PieceColor.white].toString() +
"\n" +
S.of(context).player2 +
": " +
Game.instance.position.score[PieceColor.white].toString() +
Game.instance.position.score[PieceColor.black].toString() +
"\n" +
S.of(context).draw +
": " +
@ -770,25 +770,25 @@ class _GamePageState extends State<GamePage> with RouteAware {
" " +
S.of(context).inHand +
": " +
Game.instance.position.pieceInHandCount[PieceColor.black].toString() +
Game.instance.position.pieceInHandCount[PieceColor.white].toString() +
"\n" +
S.of(context).player2 +
" " +
S.of(context).inHand +
": " +
Game.instance.position.pieceInHandCount[PieceColor.white].toString() +
Game.instance.position.pieceInHandCount[PieceColor.black].toString() +
"\n" +
S.of(context).player1 +
" " +
S.of(context).onBoard +
": " +
Game.instance.position.pieceOnBoardCount[PieceColor.black].toString() +
Game.instance.position.pieceOnBoardCount[PieceColor.white].toString() +
"\n" +
S.of(context).player2 +
" " +
S.of(context).onBoard +
": " +
Game.instance.position.pieceOnBoardCount[PieceColor.white].toString() +
Game.instance.position.pieceOnBoardCount[PieceColor.black].toString() +
"\n";
return ret;
}

View File

@ -54,8 +54,8 @@ class _PersonalizationSettingsPageState
S.of(context).boardColor: Config.boardBackgroundColor,
S.of(context).backgroudColor: Config.darkBackgroundColor,
S.of(context).lineColor: Config.boardLineColor,
S.of(context).blackPieceColor: Config.blackPieceColor,
S.of(context).whitePieceColor: Config.whitePieceColor,
S.of(context).blackPieceColor: Config.blackPieceColor,
};
AlertDialog alert = AlertDialog(
@ -79,10 +79,10 @@ class _PersonalizationSettingsPageState
Config.darkBackgroundColor = pickerColor.value;
} else if (colorString == S.of(context).lineColor) {
Config.boardLineColor = pickerColor.value;
} else if (colorString == S.of(context).blackPieceColor) {
Config.blackPieceColor = pickerColor.value;
} else if (colorString == S.of(context).whitePieceColor) {
Config.whitePieceColor = pickerColor.value;
} else if (colorString == S.of(context).blackPieceColor) {
Config.blackPieceColor = pickerColor.value;
}
Config.save();
@ -277,16 +277,16 @@ class _PersonalizationSettingsPageState
ListItemDivider(),
SettingsListTile(
context: context,
titleString: S.of(context).blackPieceColor,
trailingColor: Config.blackPieceColor,
onTap: () => showColorDialog(S.of(context).blackPieceColor),
titleString: S.of(context).whitePieceColor,
trailingColor: Config.whitePieceColor,
onTap: () => showColorDialog(S.of(context).whitePieceColor),
),
ListItemDivider(),
SettingsListTile(
context: context,
titleString: S.of(context).whitePieceColor,
trailingColor: Config.whitePieceColor,
onTap: () => showColorDialog(S.of(context).whitePieceColor),
titleString: S.of(context).blackPieceColor,
trailingColor: Config.blackPieceColor,
onTap: () => showColorDialog(S.of(context).blackPieceColor),
),
],
),

View File

@ -110,11 +110,11 @@ class _RuleSettingsPageState extends State<RuleSettingsPage> {
ListItemDivider(),
SettingsSwitchListTile(
context: context,
value: Config.isBlackLoseButNotDrawWhenBoardFull,
onChanged: setIsBlackLoseButNotDrawWhenBoardFull,
titleString: S.of(context).isBlackLoseButNotDrawWhenBoardFull,
value: Config.isWhiteLoseButNotDrawWhenBoardFull,
onChanged: setIsWhiteLoseButNotDrawWhenBoardFull,
titleString: S.of(context).isWhiteLoseButNotDrawWhenBoardFull,
subtitleString:
S.of(context).isBlackLoseButNotDrawWhenBoardFull_Detail,
S.of(context).isWhiteLoseButNotDrawWhenBoardFull_Detail,
),
],
),
@ -234,10 +234,10 @@ class _RuleSettingsPageState extends State<RuleSettingsPage> {
Config.save();
}
setIsBlackLoseButNotDrawWhenBoardFull(bool value) async {
setIsWhiteLoseButNotDrawWhenBoardFull(bool value) async {
setState(() {
rule.isBlackLoseButNotDrawWhenBoardFull =
Config.isBlackLoseButNotDrawWhenBoardFull = value;
rule.isWhiteLoseButNotDrawWhenBoardFull =
Config.isWhiteLoseButNotDrawWhenBoardFull = value;
});
Config.save();

View File

@ -88,10 +88,10 @@ Game::Game(
#ifdef QT_GUI_LIB
// The command line of AI and controller
connect(aiThread[BLACK], SIGNAL(command(const string &, bool)),
this, SLOT(command(const string &, bool)));
connect(aiThread[WHITE], SIGNAL(command(const string &, bool)),
this, SLOT(command(const string &, bool)));
connect(aiThread[BLACK], SIGNAL(command(const string &, bool)),
this, SLOT(command(const string &, bool)));
connect(this->gameTest, SIGNAL(command(const string &, bool)),
this, SLOT(command(const string &, bool)));
@ -128,8 +128,8 @@ void Game::loadSettings()
settings = new QSettings(SETTINGS_FILE, QSettings::IniFormat);
setEngineBlack(empty? false : settings->value("Options/BlackIsAiPlayer").toBool());
setEngineWhite(empty ? true : settings->value("Options/WhiteIsAiPlayer").toBool());
setEngineWhite(empty? false : settings->value("Options/WhiteIsAiPlayer").toBool());
setEngineBlack(empty ? true : settings->value("Options/BlackIsAiPlayer").toBool());
setFixWindowSize(empty ? false : settings->value("Options/FixWindowSize").toBool());
setSound(empty ? true : settings->value("Options/Sound").toBool());
setAnimation(empty ? true : settings->value("Options/Animation").toBool());
@ -217,7 +217,7 @@ void Game::gameStart()
void Game::gameReset()
{
while (aiThread[BLACK]->searching || aiThread[WHITE]->searching) {
while (aiThread[WHITE]->searching || aiThread[BLACK]->searching) {
loggerDebug(".");
QThread::msleep(100);
}
@ -244,7 +244,7 @@ void Game::gameReset()
#endif
position.reset();
elapsedSeconds[BLACK] = elapsedSeconds[WHITE] = 0;
elapsedSeconds[WHITE] = elapsedSeconds[BLACK] = 0;
sideToMove = position.side_to_move();
// Stop threads
@ -269,7 +269,7 @@ void Game::gameReset()
for (int i = 0; i < rule.piecesCount; i++) {
// The first piece
md = isInverted ? PieceItem::Models::whitePiece : PieceItem::Models::blackPiece;
md = isInverted ? PieceItem::Models::blackPiece : PieceItem::Models::whitePiece;
PieceItem *newP = new PieceItem;
newP->setModel(md);
newP->setPos(scene.pos_p1);
@ -280,7 +280,7 @@ void Game::gameReset()
scene.addItem(newP);
// Backhand piece
md = isInverted ? PieceItem::Models::blackPiece : PieceItem::Models::whitePiece;
md = isInverted ? PieceItem::Models::whitePiece : PieceItem::Models::blackPiece;
newP = new PieceItem;
newP->setModel(md);
newP->setPos(scene.pos_p2);
@ -296,10 +296,10 @@ void Game::gameReset()
// If the rule does not require timing, time1 and time2 represent the time used
if (timeLimit <= 0) {
// Clear the player's used time
remainingTime[BLACK] = remainingTime[WHITE] = 0;
remainingTime[WHITE] = remainingTime[BLACK] = 0;
} else {
// Set the player's remaining time to a limited time
remainingTime[BLACK] = remainingTime[WHITE] = timeLimit;
remainingTime[WHITE] = remainingTime[BLACK] = timeLimit;
}
// Update move history
@ -309,7 +309,7 @@ void Game::gameReset()
currentRow = 0;
// Signal the main window to update the LCD display
const QTime qtime = QTime(0, 0, 0, 0).addSecs(static_cast<int>(remainingTime[BLACK]));
const QTime qtime = QTime(0, 0, 0, 0).addSecs(static_cast<int>(remainingTime[WHITE]));
emit time1Changed(qtime.toString("hh:mm:ss"));
emit time2Changed(qtime.toString("hh:mm:ss"));
@ -320,16 +320,16 @@ void Game::gameReset()
// Update LCD display
emit nGamesPlayedChanged(QString::number(position.gamesPlayedCount, 10));
emit score1Changed(QString::number(position.score[BLACK], 10));
emit score2Changed(QString::number(position.score[WHITE], 10));
emit score1Changed(QString::number(position.score[WHITE], 10));
emit score2Changed(QString::number(position.score[BLACK], 10));
emit scoreDrawChanged(QString::number(position.score_draw, 10));
// Update winning rate LCD display
position.gamesPlayedCount = position.score[BLACK] + position.score[WHITE] + position.score_draw;
position.gamesPlayedCount = position.score[WHITE] + position.score[BLACK] + position.score_draw;
int winningRate_1 = 0, winningRate_2 = 0, winningRate_draw = 0;
if (position.gamesPlayedCount != 0) {
winningRate_1 = position.score[BLACK] * 10000 / position.gamesPlayedCount;
winningRate_2 = position.score[WHITE] * 10000 / position.gamesPlayedCount;
winningRate_1 = position.score[WHITE] * 10000 / position.gamesPlayedCount;
winningRate_2 = position.score[BLACK] * 10000 / position.gamesPlayedCount;
winningRate_draw = position.score_draw * 10000 / position.gamesPlayedCount;
}
@ -353,14 +353,14 @@ void Game::setInvert(bool arg)
// For all pieces
for (PieceItem *pieceItem : pieceList) {
if (pieceItem) {
// Black -> White
if (pieceItem->getModel() == PieceItem::Models::blackPiece)
pieceItem->setModel(PieceItem::Models::whitePiece);
// White -> Black
else if (pieceItem->getModel() == PieceItem::Models::whitePiece)
if (pieceItem->getModel() == PieceItem::Models::whitePiece)
pieceItem->setModel(PieceItem::Models::blackPiece);
// Black -> White
else if (pieceItem->getModel() == PieceItem::Models::blackPiece)
pieceItem->setModel(PieceItem::Models::whitePiece);
// Refresh checkerboard display
pieceItem->update();
}
@ -385,7 +385,7 @@ void Game::setRule(int ruleNo, int stepLimited /*= -1*/, int timeLimited /*= 0*/
}
const int r = ruleNo;
elapsedSeconds[BLACK] = elapsedSeconds[WHITE] = 0;
elapsedSeconds[WHITE] = elapsedSeconds[BLACK] = 0;
char record[64] = { 0 };
if (snprintf(record, Position::RECORD_LEN_MAX, "r%1d s%03zu t%02d", r + 1, rule.maxStepsLedToDraw, 0) <= 0) {
@ -414,32 +414,32 @@ void Game::setEngine(Color color, bool enabled)
}
}
void Game::setEngineBlack(bool enabled)
{
setEngine(BLACK, enabled);
settings->setValue("Options/BlackIsAiPlayer", enabled);
}
void Game::setEngineWhite(bool enabled)
{
setEngine(WHITE, enabled);
settings->setValue("Options/WhiteIsAiPlayer", enabled);
}
void Game::setEngineBlack(bool enabled)
{
setEngine(BLACK, enabled);
settings->setValue("Options/BlackIsAiPlayer", enabled);
}
void Game::setAiDepthTime(int time1, int time2)
{
stopAndWaitAiThreads();
aiThread[BLACK]->setAi(&position, time1);
aiThread[WHITE]->setAi(&position, time2);
aiThread[WHITE]->setAi(&position, time1);
aiThread[BLACK]->setAi(&position, time2);
startAiThreads();
}
void Game::getAiDepthTime(int &time1, int &time2)
{
time1 = aiThread[BLACK]->getTimeLimit();
time2 = aiThread[WHITE]->getTimeLimit();
time1 = aiThread[WHITE]->getTimeLimit();
time2 = aiThread[BLACK]->getTimeLimit();
}
void Game::setFixWindowSize(bool arg) noexcept
@ -470,8 +470,8 @@ void Game::setSound(bool arg) noexcept
void Game::playSound(GameSound soundType, Color c)
{
string soundDir = ":/sound/resources/sound/";
string sideStr = c == BLACK ? "B" : "W";
string oppenentStr = c == WHITE? "B" : "W";
string sideStr = c == WHITE ? "W" : "B";
string oppenentStr = c == BLACK? "W" : "B";
string filename;
switch (soundType) {
@ -763,7 +763,7 @@ void Game::updateTime()
if (timePoint >= *ourSeconds) {
*ourSeconds = timePoint;
startTime = currentTime - (elapsedSeconds[BLACK] + elapsedSeconds[WHITE]);
startTime = currentTime - (elapsedSeconds[WHITE] + elapsedSeconds[BLACK]);
} else {
*ourSeconds = currentTime - startTime - theirSeconds;
}
@ -776,18 +776,18 @@ void Game::timerEvent(QTimerEvent *event)
// Player's time spent
updateTime();
remainingTime[BLACK] = get_elapsed_time(BLACK);
remainingTime[WHITE] = get_elapsed_time(WHITE);
remainingTime[BLACK] = get_elapsed_time(BLACK);
// If the rule requires a timer, time1 and time2 indicate a countdown
if (timeLimit > 0) {
// Player's remaining time
remainingTime[BLACK] = timeLimit - remainingTime[BLACK];
remainingTime[WHITE] = timeLimit - remainingTime[WHITE];
remainingTime[BLACK] = timeLimit - remainingTime[BLACK];
}
qt1 = QTime(0, 0, 0, 0).addSecs(static_cast<int>(remainingTime[BLACK]));
qt2 = QTime(0, 0, 0, 0).addSecs(static_cast<int>(remainingTime[WHITE]));
qt1 = QTime(0, 0, 0, 0).addSecs(static_cast<int>(remainingTime[WHITE]));
qt2 = QTime(0, 0, 0, 0).addSecs(static_cast<int>(remainingTime[BLACK]));
emit time1Changed(qt1.toString("hh:mm:ss"));
emit time2Changed(qt2.toString("hh:mm:ss"));
@ -852,8 +852,8 @@ bool Game::actionPiece(QPointF p)
// When the computer is playing chess or searching, the click is invalid
if (isAIsTurn() ||
aiThread[BLACK]->searching ||
aiThread[WHITE]->searching) {
aiThread[WHITE]->searching ||
aiThread[BLACK]->searching) {
return false;
}
@ -1005,12 +1005,12 @@ bool Game::actionPiece(QPointF p)
gameReset();
gameStart();
if (isAiPlayer[BLACK]) {
setEngine(BLACK, true);
}
if (isAiPlayer[WHITE]) {
setEngine(WHITE, true);
}
if (isAiPlayer[BLACK]) {
setEngine(BLACK, true);
}
} else {
pauseThreads();
}
@ -1060,10 +1060,10 @@ bool Game::command(const string &cmd, bool update /* = true */)
#ifdef QT_GUI_LIB
// Prevents receiving instructions sent by threads that end late
if (sender() == aiThread[BLACK] && !isAiPlayer[BLACK])
if (sender() == aiThread[WHITE] && !isAiPlayer[WHITE])
return false;
if (sender() == aiThread[WHITE] && !isAiPlayer[WHITE])
if (sender() == aiThread[BLACK] && !isAiPlayer[BLACK])
return false;
#endif // QT_GUI_LIB
@ -1170,15 +1170,15 @@ bool Game::command(const string &cmd, bool update /* = true */)
#ifdef TIME_STAT
loggerDebug("Sort Time: %I64d + %I64d = %I64dms\n",
aiThread[BLACK]->sortTime, aiThread[WHITE]->sortTime,
(aiThread[BLACK]->sortTime + aiThread[WHITE]->sortTime));
aiThread[BLACK]->sortTime = aiThread[WHITE]->sortTime = 0;
aiThread[WHITE]->sortTime, aiThread[BLACK]->sortTime,
(aiThread[WHITE]->sortTime + aiThread[BLACK]->sortTime));
aiThread[WHITE]->sortTime = aiThread[BLACK]->sortTime = 0;
#endif // TIME_STAT
#ifdef CYCLE_STAT
loggerDebug("Sort Cycle: %ld + %ld = %ld\n",
aiThread[BLACK]->sortCycle, aiThread[WHITE]->sortCycle,
(aiThread[BLACK]->sortCycle + aiThread[WHITE]->sortCycle));
aiThread[BLACK]->sortCycle = aiThread[WHITE]->sortCycle = 0;
aiThread[WHITE]->sortCycle, aiThread[BLACK]->sortCycle,
(aiThread[WHITE]->sortCycle + aiThread[BLACK]->sortCycle));
aiThread[WHITE]->sortCycle = aiThread[BLACK]->sortCycle = 0;
#endif // CYCLE_STAT
#if 0
@ -1189,26 +1189,26 @@ bool Game::command(const string &cmd, bool update /* = true */)
#endif
#ifdef TRANSPOSITION_TABLE_DEBUG
size_t hashProbeCount_1 = aiThread[BLACK]->ttHitCount + aiThread[BLACK]->ttMissCount;
size_t hashProbeCount_2 = aiThread[WHITE]->ttHitCount + aiThread[WHITE]->ttMissCount;
size_t hashProbeCount_1 = aiThread[WHITE]->ttHitCount + aiThread[WHITE]->ttMissCount;
size_t hashProbeCount_2 = aiThread[BLACK]->ttHitCount + aiThread[BLACK]->ttMissCount;
loggerDebug("[key 1] probe: %llu, hit: %llu, miss: %llu, hit rate: %llu%%\n",
hashProbeCount_1,
aiThread[BLACK]->ttHitCount,
aiThread[BLACK]->ttMissCount,
aiThread[BLACK]->ttHitCount * 100 / hashProbeCount_1);
aiThread[WHITE]->ttHitCount,
aiThread[WHITE]->ttMissCount,
aiThread[WHITE]->ttHitCount * 100 / hashProbeCount_1);
loggerDebug("[key 2] probe: %llu, hit: %llu, miss: %llu, hit rate: %llu%%\n",
hashProbeCount_2,
aiThread[WHITE]->ttHitCount,
aiThread[WHITE]->ttMissCount,
aiThread[WHITE]->ttHitCount * 100 / hashProbeCount_2);
aiThread[BLACK]->ttHitCount,
aiThread[BLACK]->ttMissCount,
aiThread[BLACK]->ttHitCount * 100 / hashProbeCount_2);
loggerDebug("[key +] probe: %llu, hit: %llu, miss: %llu, hit rate: %llu%%\n",
hashProbeCount_1 + hashProbeCount_2,
aiThread[BLACK]->ttHitCount + aiThread[WHITE]->ttHitCount,
aiThread[BLACK]->ttMissCount + aiThread[WHITE]->ttMissCount,
(aiThread[BLACK]->ttHitCount + aiThread[WHITE]->ttHitCount ) * 100 / (hashProbeCount_1 + hashProbeCount_2));
aiThread[WHITE]->ttHitCount + aiThread[BLACK]->ttHitCount,
aiThread[WHITE]->ttMissCount + aiThread[BLACK]->ttMissCount,
(aiThread[WHITE]->ttHitCount + aiThread[BLACK]->ttHitCount ) * 100 / (hashProbeCount_1 + hashProbeCount_2));
#endif // TRANSPOSITION_TABLE_DEBUG
if (gameOptions.getAutoRestart()) {
@ -1217,12 +1217,12 @@ bool Game::command(const string &cmd, bool update /* = true */)
gameReset();
gameStart();
if (isAiPlayer[BLACK]) {
setEngine(BLACK, true);
}
if (isAiPlayer[WHITE]) {
setEngine(WHITE, true);
}
if (isAiPlayer[BLACK]) {
setEngine(BLACK, true);
}
}
#ifdef MESSAGEBOX_ENABLE
@ -1248,19 +1248,19 @@ bool Game::command(const string &cmd, bool update /* = true */)
}
#endif // ANALYZE_POSITION
total = position.score[BLACK] + position.score[WHITE] + position.score_draw;
total = position.score[WHITE] + position.score[BLACK] + position.score_draw;
if (total == 0) {
bwinrate = 0;
wwinrate = 0;
drawrate = 0;
} else {
bwinrate = (float)position.score[BLACK] * 100 / total;
wwinrate = (float)position.score[WHITE] * 100 / total;
bwinrate = (float)position.score[WHITE] * 100 / total;
wwinrate = (float)position.score[BLACK] * 100 / total;
drawrate = (float)position.score_draw * 100 / total;
}
cout << "Score: " << position.score[BLACK] << " : " << position.score[WHITE] << " : " << position.score_draw << "\ttotal: " << total << endl;
cout << "Score: " << position.score[WHITE] << " : " << position.score[BLACK] << " : " << position.score_draw << "\ttotal: " << total << endl;
cout << fixed << setprecision(2) << bwinrate << "% : " << wwinrate << "% : " << drawrate << "%" << endl;
return true;
@ -1323,7 +1323,7 @@ bool Game::updateScence(Position &p)
piece->setSelected(false);
// Convert the subscript of pieceList to the chess code of game
key = (i % 2) ? (i / 2 + W_STONE_1) : (i / 2 + B_STONE_1);
key = (i % 2) ? (i / 2 + B_STONE_1) : (i / 2 + W_STONE_1);
int j;
@ -1354,11 +1354,11 @@ bool Game::updateScence(Position &p)
// If not, place the pieces outside the chessboard
if (j == (RANK_NB) * (FILE_NB + 1)) {
// Judge whether it is a removing seed or an unplaced one
if (key & B_STONE) {
pos = (key - 0x11 < nTotalPieces / 2 - p.count<IN_HAND>(BLACK)) ?
if (key & W_STONE) {
pos = (key - 0x11 < nTotalPieces / 2 - p.count<IN_HAND>(WHITE)) ?
scene.pos_p2_g : scene.pos_p1;
} else {
pos = (key - 0x21 < nTotalPieces / 2 - p.count<IN_HAND>(WHITE)) ?
pos = (key - 0x21 < nTotalPieces / 2 - p.count<IN_HAND>(BLACK)) ?
scene.pos_p1_g : scene.pos_p2;
}
@ -1415,7 +1415,7 @@ bool Game::updateScence(Position &p)
int ipos = p.current_square();
if (ipos) {
key = board[p.current_square()];
ipos = (key & B_STONE) ? (key - B_STONE_1) * 2 : (key - W_STONE_1) * 2 + 1;
ipos = (key & W_STONE) ? (key - W_STONE_1) * 2 : (key - B_STONE_1) * 2 + 1;
if (ipos >= 0 && ipos < nTotalPieces) {
currentPiece = pieceList.at(static_cast<size_t>(ipos));
currentPiece->setSelected(true);
@ -1430,16 +1430,16 @@ bool Game::updateScence(Position &p)
animationGroup->start(QAbstractAnimation::DeleteWhenStopped);
// Update LCD display
emit score1Changed(QString::number(p.score[BLACK], 10));
emit score2Changed(QString::number(p.score[WHITE], 10));
emit score1Changed(QString::number(p.score[WHITE], 10));
emit score2Changed(QString::number(p.score[BLACK], 10));
emit scoreDrawChanged(QString::number(p.score_draw, 10));
// Update winning rate LCD display
position.gamesPlayedCount = position.score[BLACK] + position.score[WHITE] + position.score_draw;
position.gamesPlayedCount = position.score[WHITE] + position.score[BLACK] + position.score_draw;
int winningRate_1 = 0, winningRate_2 = 0, winningRate_draw = 0;
if (position.gamesPlayedCount != 0) {
winningRate_1 = position.score[BLACK] * 10000 / position.gamesPlayedCount;
winningRate_2 = position.score[WHITE] * 10000 / position.gamesPlayedCount;
winningRate_1 = position.score[WHITE] * 10000 / position.gamesPlayedCount;
winningRate_2 = position.score[BLACK] * 10000 / position.gamesPlayedCount;
winningRate_draw = position.score_draw * 10000 / position.gamesPlayedCount;
}
@ -1501,29 +1501,29 @@ void Game::saveScore()
textStream << gameTest->getKey() << endl << endl;
if (isAiPlayer[BLACK]) {
textStream << "Black:\tAI Player" << endl;
} else {
textStream << "Black:\tHuman Player" << endl;
}
if (isAiPlayer[WHITE]) {
textStream << "White:\tAI Player" << endl;
} else {
textStream << "White:\tHuman Player" << endl;
}
if (isAiPlayer[BLACK]) {
textStream << "Black:\tAI Player" << endl;
} else {
textStream << "Black:\tHuman Player" << endl;
}
textStream << "" << endl;
position.gamesPlayedCount = position.score[BLACK] + position.score[WHITE] + position.score_draw;
position.gamesPlayedCount = position.score[WHITE] + position.score[BLACK] + position.score_draw;
if (position.gamesPlayedCount == 0) {
goto out;
}
textStream << "Sum\t" + QString::number(position.gamesPlayedCount) << endl;
textStream << "Black\t" + QString::number(position.score[BLACK]) + "\t" + QString::number(position.score[BLACK] * 10000 / position.gamesPlayedCount) << endl;
textStream << "White\t" + QString::number(position.score[WHITE]) + "\t" + QString::number(position.score[WHITE] * 10000 / position.gamesPlayedCount) << endl;
textStream << "White\t" + QString::number(position.score[WHITE]) + "\t" + QString::number(position.score[WHITE] * 10000 / position.gamesPlayedCount) << endl;
textStream << "Black\t" + QString::number(position.score[BLACK]) + "\t" + QString::number(position.score[BLACK] * 10000 / position.gamesPlayedCount) << endl;
textStream << "Draw\t" + QString::number(position.score_draw) + "\t" + QString::number(position.score_draw * 10000 / position.gamesPlayedCount) << endl;
out:
@ -1539,9 +1539,9 @@ inline char Game::color_to_char(Color color)
inline std::string Game::char_to_string(char ch)
{
if (ch == '1') {
return "黑方";
} else {
return "白方";
} else {
return "黑方";
}
}
@ -1602,8 +1602,8 @@ void Game::setTips()
switch (p.phase) {
case Phase::ready:
tips = "轮到" + turnStr + "落子,剩余" + std::to_string(p.pieceInHandCount[BLACK]) + "" +
" 比分 " + to_string(p.score[BLACK]) + ":" + to_string(p.score[WHITE]) + ", 和棋 " + to_string(p.score_draw);
tips = "轮到" + turnStr + "落子,剩余" + std::to_string(p.pieceInHandCount[WHITE]) + "" +
" 比分 " + to_string(p.score[WHITE]) + ":" + to_string(p.score[BLACK]) + ", 和棋 " + to_string(p.score_draw);
break;
case Phase::placing:
@ -1625,11 +1625,11 @@ void Game::setTips()
case Phase::gameOver:
appendGameOverReasonToMoveHistory();
scoreStr = "比分 " + to_string(p.score[BLACK]) + " : " + to_string(p.score[WHITE]) + ", 和棋 " + to_string(p.score_draw);
scoreStr = "比分 " + to_string(p.score[WHITE]) + " : " + to_string(p.score[BLACK]) + ", 和棋 " + to_string(p.score_draw);
switch (p.winner) {
case BLACK:
case WHITE:
case BLACK:
winnerStr = char_to_string(color_to_char(p.winner));
resultStr = winnerStr + "获胜!";
break;

View File

@ -213,13 +213,13 @@ public slots:
// Set edit chess state
void setEditing(bool arg = true) noexcept;
// Set black and white inversion state
// Set white and black inversion state
void setInvert(bool arg = true);
// If Id is 1, let the computer take the lead; if Id is 2, let the computer take the second place
void setEngine(Color color, bool enabled = true);
void setEngineBlack(bool enabled);
void setEngineWhite(bool enabled);
void setEngineBlack(bool enabled);
// Fix Window Size
void setFixWindowSize(bool arg) noexcept;
@ -288,58 +288,58 @@ public slots:
void threadsSetAi(Position *p)
{
aiThread[BLACK]->setAi(p);
aiThread[WHITE]->setAi(p);
aiThread[BLACK]->setAi(p);
}
void resetAiPlayers()
{
isAiPlayer[BLACK] = false;
isAiPlayer[WHITE] = false;
isAiPlayer[BLACK] = false;
}
void createAiThreads()
{
aiThread[BLACK] = new Thread(0);
aiThread[BLACK]->us = BLACK;
aiThread[WHITE] = new Thread(0);
aiThread[WHITE]->us = WHITE;
aiThread[BLACK] = new Thread(0);
aiThread[BLACK]->us = BLACK;
}
void startAiThreads()
{
if (isAiPlayer[BLACK]) {
aiThread[BLACK]->start_searching();
}
if (isAiPlayer[WHITE]) {
aiThread[WHITE]->start_searching();
}
if (isAiPlayer[BLACK]) {
aiThread[BLACK]->start_searching();
}
}
void stopAndWaitAiThreads()
{
if (isAiPlayer[BLACK]) {
aiThread[BLACK]->pause();
aiThread[BLACK]->wait_for_search_finished();
}
if (isAiPlayer[WHITE]) {
aiThread[WHITE]->pause();
aiThread[WHITE]->wait_for_search_finished();
}
if (isAiPlayer[BLACK]) {
aiThread[BLACK]->pause();
aiThread[BLACK]->wait_for_search_finished();
}
}
void pauseThreads()
{
aiThread[BLACK]->pause();
aiThread[WHITE]->pause();
aiThread[BLACK]->pause();
}
void waitThreads()
{
aiThread[BLACK]->wait_for_search_finished();
aiThread[WHITE]->wait_for_search_finished();
aiThread[BLACK]->wait_for_search_finished();
}
void pauseAndWaitThreads()
@ -357,8 +357,8 @@ public slots:
void deleteAiThreads()
{
delete aiThread[BLACK];
delete aiThread[WHITE];
delete aiThread[BLACK];
}
// According to the signal and state of qgraphics scene, select, drop or delete the sub objects
@ -427,7 +427,7 @@ private:
// Is it in "Edit chess game" state
bool isEditing;
// Reverse black and white
// Reverse white and black
bool isInverted;
public:

View File

@ -191,10 +191,10 @@ void MillGameWindow::initialize()
#endif
connect(ui.actionEngine1_T, SIGNAL(toggled(bool)),
game, SLOT(setEngineBlack(bool)));
game, SLOT(setEngineWhite(bool)));
connect(ui.actionEngine2_R, SIGNAL(toggled(bool)),
game, SLOT(setEngineWhite(bool)));
game, SLOT(setEngineBlack(bool)));
connect(ui.actionFixWindowSize, SIGNAL(toggled(bool)),
game, SLOT(setFixWindowSize(bool)));
@ -382,8 +382,8 @@ void MillGameWindow::initialize()
connect(ui.pushButton_option, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(ctxMenu(const QPoint &)));
#endif /* MOBILE_APP_UI */
ui.actionEngine1_T->setChecked(game->isAiPlayer[BLACK]);
ui.actionEngine2_R->setChecked(game->isAiPlayer[WHITE]);
ui.actionEngine1_T->setChecked(game->isAiPlayer[WHITE]);
ui.actionEngine2_R->setChecked(game->isAiPlayer[BLACK]);
ui.actionFixWindowSize->setChecked(game->fixWindowSizeEnabled());
ui.actionSound_S->setChecked(game->soundEnabled());
@ -588,12 +588,12 @@ void MillGameWindow::on_actionNew_N_triggered()
QString whoWin;
switch (game->getPosition()->get_winner()) {
case BLACK:
whoWin = "Black-Win";
break;
case WHITE:
whoWin = "White-Win";
break;
case BLACK:
whoWin = "Black-Win";
break;
case DRAW:
whoWin = "Draw";
break;
@ -712,17 +712,17 @@ void MillGameWindow::on_actionEdit_E_toggled(bool arg1)
void MillGameWindow::on_actionInvert_I_toggled(bool arg1)
{
// If black and white are reversed
// If white and black are reversed
if (arg1) {
ui.actionEngine1_T->setIcon(QIcon(":/icon/Resources/icon/White.png"));
ui.actionEngine2_R->setIcon(QIcon(":/icon/Resources/icon/Black.png"));
ui.picLabel1->setPixmap(QPixmap(":/icon/Resources/icon/White.png"));
ui.picLabel2->setPixmap(QPixmap(":/icon/Resources/icon/Black.png"));
} else {
ui.actionEngine1_T->setIcon(QIcon(":/icon/Resources/icon/Black.png"));
ui.actionEngine2_R->setIcon(QIcon(":/icon/Resources/icon/White.png"));
ui.picLabel1->setPixmap(QPixmap(":/icon/Resources/icon/Black.png"));
ui.picLabel2->setPixmap(QPixmap(":/icon/Resources/icon/White.png"));
} else {
ui.actionEngine1_T->setIcon(QIcon(":/icon/Resources/icon/White.png"));
ui.actionEngine2_R->setIcon(QIcon(":/icon/Resources/icon/Black.png"));
ui.picLabel1->setPixmap(QPixmap(":/icon/Resources/icon/White.png"));
ui.picLabel2->setPixmap(QPixmap(":/icon/Resources/icon/Black.png"));
}
// Let the controller change the color of the pieces
@ -988,8 +988,8 @@ void MillGameWindow::on_actionAbout_A_triggered()
auto *label_image = new QLabel(dialog);
#if 0
label_icon1->setPixmap(QPixmap(QString::fromUtf8(":/image/resources/image/black_piece.png")));
label_icon2->setPixmap(QPixmap(QString::fromUtf8(":/image/resources/image/white_piece.png")));
label_icon1->setPixmap(QPixmap(QString::fromUtf8(":/image/resources/image/white_piece.png")));
label_icon2->setPixmap(QPixmap(QString::fromUtf8(":/image/resources/image/black_piece.png")));
label_icon1->setAlignment(Qt::AlignCenter);
label_icon2->setAlignment(Qt::AlignCenter);
label_icon1->setFixedSize(32, 32);

View File

@ -82,27 +82,27 @@ void PieceItem::paint(QPainter *painter,
// Empty models don't draw pieces
switch (model) {
case Models::blackPiece:
// If the model is black, draw black pieces
case Models::whitePiece:
// If the model is white, draw white pieces
#ifdef MOBILE_APP_UI
painter->setPen(Qt::NoPen);
painter->setBrush(QColor(0, 93, 172));
painter->drawEllipse(-size / 2, -size / 2, size, size);
#else
painter->drawPixmap(-size / 2, -size / 2, size, size,
QPixmap(":/image/resources/image/black_piece.png"));
QPixmap(":/image/resources/image/white_piece.png"));
#endif /* MOBILE_APP_UI */
break;
case Models::whitePiece:
// If the model is white, draw white pieces
case Models::blackPiece:
// If the model is black, draw black pieces
#ifdef MOBILE_APP_UI
painter->setPen(Qt::NoPen);
painter->setBrush(QColor(231, 36, 46));
painter->drawEllipse(-size / 2, -size / 2, size, size);
#else
painter->drawPixmap(-size / 2, -size / 2, size, size,
QPixmap(":/image/resources/image/white_piece.png"));
QPixmap(":/image/resources/image/black_piece.png"));
#endif /* MOBILE_APP_UI */
break;
default:
@ -111,10 +111,10 @@ void PieceItem::paint(QPainter *painter,
// If the model requires the serial number to be displayed
if (showNum) {
if (model == Models::blackPiece)
if (model == Models::whitePiece)
painter->setPen(QColor(255, 255, 255));
if (model == Models::whitePiece)
if (model == Models::blackPiece)
painter->setPen(QColor(0, 0, 0));
QFont font;

View File

@ -59,8 +59,8 @@ public:
enum class Models
{
noPiece = 0x1,
blackPiece = 0x2,
whitePiece = 0x4,
whitePiece = 0x2,
blackPiece = 0x4,
};
enum Models getModel() noexcept
@ -111,7 +111,7 @@ protected:
private:
enum Models model;
// Piece number, black and white all start from 1
// Piece number, white and black all start from 1
int num {1};
int size {0};