Indicate white pieces as player one and black as player two
Thanks Matt Littlewood!
This commit is contained in:
parent
7e40f0dec7
commit
c2af00c10d
|
@ -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>
|
||||
|
|
|
@ -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"/>
|
||||
|
|
|
@ -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).
|
||||
|
||||
|
|
|
@ -36,8 +36,8 @@ static const int SAVE_ENDGAME_EVERY_N_GAMES = 256;
|
|||
enum class EndGameType : uint32_t
|
||||
{
|
||||
none,
|
||||
blackWin,
|
||||
whiteWin,
|
||||
blackWin,
|
||||
draw,
|
||||
};
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
106
src/position.cpp
106
src/position.cpp
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -121,7 +121,7 @@ public:
|
|||
Value bestvalue { VALUE_ZERO };
|
||||
Value lastvalue { VALUE_ZERO };
|
||||
|
||||
Color us { BLACK };
|
||||
Color us { WHITE };
|
||||
|
||||
private:
|
||||
int timeLimit;
|
||||
|
|
70
src/types.h
70
src/types.h
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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}');
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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": "显示",
|
||||
|
|
|
@ -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";
|
||||
|
|
|
@ -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]!;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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 = "";
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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};
|
||||
|
|
Loading…
Reference in New Issue