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/>
|
<string/>
|
||||||
</property>
|
</property>
|
||||||
<property name="pixmap">
|
<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>
|
||||||
<property name="alignment">
|
<property name="alignment">
|
||||||
<set>Qt::AlignCenter</set>
|
<set>Qt::AlignCenter</set>
|
||||||
|
@ -462,7 +462,7 @@
|
||||||
</font>
|
</font>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Player1 (Black)</string>
|
<string>Player 1</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
@ -521,7 +521,7 @@
|
||||||
<string/>
|
<string/>
|
||||||
</property>
|
</property>
|
||||||
<property name="pixmap">
|
<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>
|
||||||
<property name="alignment">
|
<property name="alignment">
|
||||||
<set>Qt::AlignCenter</set>
|
<set>Qt::AlignCenter</set>
|
||||||
|
@ -543,7 +543,7 @@
|
||||||
</font>
|
</font>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Player2 (White)</string>
|
<string>Player 2</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
@ -1070,7 +1070,7 @@
|
||||||
</property>
|
</property>
|
||||||
<property name="icon">
|
<property name="icon">
|
||||||
<iconset resource="gamewindow.qrc">
|
<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>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>AI Moves First</string>
|
<string>AI Moves First</string>
|
||||||
|
@ -1085,7 +1085,7 @@
|
||||||
</property>
|
</property>
|
||||||
<property name="icon">
|
<property name="icon">
|
||||||
<iconset resource="gamewindow.qrc">
|
<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>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>AI Moves Second</string>
|
<string>AI Moves Second</string>
|
||||||
|
|
|
@ -547,8 +547,8 @@
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="gamewindow.ui" line="1089"/>
|
<location filename="gamewindow.ui" line="1089"/>
|
||||||
<source>电脑执白(R)</source>
|
<source>电脑执黑(B)</source>
|
||||||
<translation>电脑执白(R)</translation>
|
<translation>电脑执黑(B)</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="gamewindow.ui" line="1101"/>
|
<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`.
|
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).
|
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
|
enum class EndGameType : uint32_t
|
||||||
{
|
{
|
||||||
none,
|
none,
|
||||||
blackWin,
|
|
||||||
whiteWin,
|
whiteWin,
|
||||||
|
blackWin,
|
||||||
draw,
|
draw,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -48,7 +48,7 @@ Value Evaluation::value()
|
||||||
|
|
||||||
int pieceInHandDiffCount;
|
int pieceInHandDiffCount;
|
||||||
int pieceOnBoardDiffCount;
|
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();;
|
pos.piece_to_remove_count() : -pos.piece_to_remove_count();;
|
||||||
|
|
||||||
switch (pos.get_phase()) {
|
switch (pos.get_phase()) {
|
||||||
|
@ -56,10 +56,10 @@ Value Evaluation::value()
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Phase::placing:
|
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;
|
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;
|
value += VALUE_EACH_PIECE_ONBOARD * pieceOnBoardDiffCount;
|
||||||
|
|
||||||
switch (pos.get_action()) {
|
switch (pos.get_action()) {
|
||||||
|
@ -77,7 +77,7 @@ Value Evaluation::value()
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Phase::moving:
|
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
|
#ifdef EVALUATE_MOBILITY
|
||||||
value += pos.get_mobility_diff() / 5;
|
value += pos.get_mobility_diff() / 5;
|
||||||
|
@ -98,8 +98,8 @@ Value Evaluation::value()
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Phase::gameOver:
|
case Phase::gameOver:
|
||||||
if (pos.piece_on_board_count(BLACK) + pos.piece_on_board_count(WHITE) >= EFFECTIVE_SQUARE_NB) {
|
if (pos.piece_on_board_count(WHITE) + pos.piece_on_board_count(BLACK) >= EFFECTIVE_SQUARE_NB) {
|
||||||
if (rule.isBlackLoseButNotDrawWhenBoardFull) {
|
if (rule.isWhiteLoseButNotDrawWhenBoardFull) {
|
||||||
value -= VALUE_MATE;
|
value -= VALUE_MATE;
|
||||||
} else {
|
} else {
|
||||||
value = VALUE_DRAW;
|
value = VALUE_DRAW;
|
||||||
|
@ -107,12 +107,12 @@ Value Evaluation::value()
|
||||||
} else if (pos.get_action() == Action::select &&
|
} else if (pos.get_action() == Action::select &&
|
||||||
pos.is_all_surrounded(pos.side_to_move()) &&
|
pos.is_all_surrounded(pos.side_to_move()) &&
|
||||||
rule.isLoseButNotChangeSideWhenNoWay) {
|
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;
|
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;
|
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;
|
value += VALUE_MATE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -122,25 +122,25 @@ Value Evaluation::value()
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pos.side_to_move() == WHITE) {
|
if (pos.side_to_move() == BLACK) {
|
||||||
value = -value;
|
value = -value;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if EVAL_DRAW_WHEN_NOT_KNOWN_WIN_IF_MAY_FLY
|
#if EVAL_DRAW_WHEN_NOT_KNOWN_WIN_IF_MAY_FLY
|
||||||
if (pos.get_phase() == Phase::moving && rule.mayFly && !rule.hasDiagonalLines) {
|
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);
|
int piece_on_board_count_future_white = pos.piece_on_board_count(WHITE);
|
||||||
|
int piece_on_board_count_future_black = pos.piece_on_board_count(BLACK);
|
||||||
if (pos.side_to_move() == BLACK) {
|
|
||||||
piece_on_board_count_future_white -= pos.piece_to_remove_count();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pos.side_to_move() == WHITE) {
|
if (pos.side_to_move() == WHITE) {
|
||||||
piece_on_board_count_future_black -= pos.piece_to_remove_count();
|
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) {
|
if (abs(value) < VALUE_KNOWN_WIN) {
|
||||||
value = VALUE_DRAW;
|
value = VALUE_DRAW;
|
||||||
}
|
}
|
||||||
|
|
|
@ -492,7 +492,7 @@ Depth get_search_depth(const Position *pos)
|
||||||
constexpr Depth flyingDepth = 9;
|
constexpr Depth flyingDepth = 9;
|
||||||
|
|
||||||
if (pos->phase == Phase::placing) {
|
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) {
|
if (rule.piecesCount == 12) {
|
||||||
assert(0 <= index && index <= 24);
|
assert(0 <= index && index <= 24);
|
||||||
|
@ -508,8 +508,8 @@ Depth get_search_depth(const Position *pos)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pos->phase == Phase::moving) {
|
if (pos->phase == Phase::moving) {
|
||||||
const int pb = pos->count<ON_BOARD>(BLACK);
|
const int pb = pos->count<ON_BOARD>(WHITE);
|
||||||
const int pw = pos->count<ON_BOARD>(WHITE);
|
const int pw = pos->count<ON_BOARD>(BLACK);
|
||||||
|
|
||||||
const int pieces = pb + pw;
|
const int pieces = pb + pw;
|
||||||
int diff = pb - pw;
|
int diff = pb - pw;
|
||||||
|
|
|
@ -97,9 +97,9 @@ void MovePicker::score()
|
||||||
|
|
||||||
//cur->value += bannedCount; // placing phrase, place nearby ban point
|
//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 &&
|
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))) {
|
Position::is_star_square(static_cast<Square>(m))) {
|
||||||
cur->value += RATING_STAR_SQUARE;
|
cur->value += RATING_STAR_SQUARE;
|
||||||
}
|
}
|
||||||
|
|
106
src/position.cpp
106
src/position.cpp
|
@ -45,14 +45,14 @@ const string PieceToChar(Piece p)
|
||||||
return "X";
|
return "X";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (B_STONE <= p && p <= B_STONE_12) {
|
|
||||||
return "@";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (W_STONE <= p && p <= W_STONE_12) {
|
if (W_STONE <= p && p <= W_STONE_12) {
|
||||||
return "O";
|
return "O";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (B_STONE <= p && p <= B_STONE_12) {
|
||||||
|
return "@";
|
||||||
|
}
|
||||||
|
|
||||||
return "*";
|
return "*";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -62,14 +62,14 @@ Piece CharToPiece(char ch) noexcept
|
||||||
return NO_PIECE;
|
return NO_PIECE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ch == '@') {
|
|
||||||
return B_STONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ch == 'O') {
|
if (ch == 'O') {
|
||||||
return W_STONE;
|
return W_STONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ch == '@') {
|
||||||
|
return B_STONE;
|
||||||
|
}
|
||||||
|
|
||||||
if (ch == 'X') {
|
if (ch == 'X') {
|
||||||
return BAN_STONE;
|
return BAN_STONE;
|
||||||
}
|
}
|
||||||
|
@ -77,7 +77,7 @@ Piece CharToPiece(char ch) noexcept
|
||||||
return NO_PIECE;
|
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
|
} // namespace
|
||||||
|
|
||||||
|
|
||||||
|
@ -173,7 +173,7 @@ Position::Position()
|
||||||
|
|
||||||
reset();
|
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.
|
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
|
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
|
capture. This is used to determine if a draw can be claimed under the
|
||||||
fifty-move rule.
|
fifty-move rule.
|
||||||
|
|
||||||
7) Fullmove number. The number of the full move. It starts at 1, and is
|
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';
|
unsigned char token = '\0';
|
||||||
|
@ -223,7 +223,7 @@ Position &Position::set(const string &fenStr, Thread *th)
|
||||||
|
|
||||||
// 1. Piece placement
|
// 1. Piece placement
|
||||||
while ((ss >> token) && !isspace(token)) {
|
while ((ss >> token) && !isspace(token)) {
|
||||||
if (token == '@' || token == 'O' || token == 'X') {
|
if (token == 'O' || token == '@' || token == 'X') {
|
||||||
put_piece(CharToPiece(token), sq);
|
put_piece(CharToPiece(token), sq);
|
||||||
++sq;
|
++sq;
|
||||||
}
|
}
|
||||||
|
@ -234,7 +234,7 @@ Position &Position::set(const string &fenStr, Thread *th)
|
||||||
|
|
||||||
// 2. Active color
|
// 2. Active color
|
||||||
ss >> token;
|
ss >> token;
|
||||||
sideToMove = (token == 'b' ? BLACK : WHITE);
|
sideToMove = (token == 'w' ? WHITE : BLACK);
|
||||||
them = ~sideToMove; // Note: Stockfish do not need to set them
|
them = ~sideToMove; // Note: Stockfish do not need to set them
|
||||||
|
|
||||||
// 3. Phrase
|
// 3. Phrase
|
||||||
|
@ -276,10 +276,10 @@ Position &Position::set(const string &fenStr, Thread *th)
|
||||||
action = Action::none;
|
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
|
ss >> std::skipws
|
||||||
>> pieceOnBoardCount[BLACK] >> pieceInHandCount[BLACK]
|
|
||||||
>> pieceOnBoardCount[WHITE] >> pieceInHandCount[WHITE]
|
>> pieceOnBoardCount[WHITE] >> pieceInHandCount[WHITE]
|
||||||
|
>> pieceOnBoardCount[BLACK] >> pieceInHandCount[BLACK]
|
||||||
>> pieceToRemoveCount;
|
>> pieceToRemoveCount;
|
||||||
|
|
||||||
|
|
||||||
|
@ -288,7 +288,7 @@ Position &Position::set(const string &fenStr, Thread *th)
|
||||||
|
|
||||||
// Convert from fullmove starting from 1 to gamePly starting from 0,
|
// Convert from fullmove starting from 1 to gamePly starting from 0,
|
||||||
// handle also common incorrect FEN with fullmove = 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;
|
thisThread = th;
|
||||||
|
|
||||||
|
@ -363,11 +363,11 @@ const string Position::fen() const
|
||||||
|
|
||||||
ss << " ";
|
ss << " ";
|
||||||
|
|
||||||
ss << pieceOnBoardCount[BLACK] << " " << pieceInHandCount[BLACK] << " "
|
ss << pieceOnBoardCount[WHITE] << " " << pieceInHandCount[WHITE] << " "
|
||||||
<< pieceOnBoardCount[WHITE] << " " << pieceInHandCount[WHITE] << " "
|
<< pieceOnBoardCount[BLACK] << " " << pieceInHandCount[BLACK] << " "
|
||||||
<< pieceToRemoveCount << " ";
|
<< pieceToRemoveCount << " ";
|
||||||
|
|
||||||
ss << st.rule50 << " " << 1 + (gamePly - (sideToMove == WHITE)) / 2;
|
ss << st.rule50 << " " << 1 + (gamePly - (sideToMove == BLACK)) / 2;
|
||||||
|
|
||||||
return ss.str();
|
return ss.str();
|
||||||
}
|
}
|
||||||
|
@ -545,7 +545,7 @@ bool Position::reset()
|
||||||
st.rule50 = 0;
|
st.rule50 = 0;
|
||||||
|
|
||||||
phase = Phase::ready;
|
phase = Phase::ready;
|
||||||
set_side_to_move(BLACK);
|
set_side_to_move(WHITE);
|
||||||
action = Action::place;
|
action = Action::place;
|
||||||
|
|
||||||
winner = NOBODY;
|
winner = NOBODY;
|
||||||
|
@ -557,8 +557,8 @@ bool Position::reset()
|
||||||
|
|
||||||
st.key = 0;
|
st.key = 0;
|
||||||
|
|
||||||
pieceOnBoardCount[BLACK] = pieceOnBoardCount[WHITE] = 0;
|
pieceOnBoardCount[WHITE] = pieceOnBoardCount[BLACK] = 0;
|
||||||
pieceInHandCount[BLACK] = pieceInHandCount[WHITE] = rule.piecesCount;
|
pieceInHandCount[WHITE] = pieceInHandCount[BLACK] = rule.piecesCount;
|
||||||
pieceToRemoveCount = 0;
|
pieceToRemoveCount = 0;
|
||||||
|
|
||||||
MoveList<LEGAL>::create();
|
MoveList<LEGAL>::create();
|
||||||
|
@ -640,8 +640,8 @@ bool Position::put_piece(Square s, bool updateRecord)
|
||||||
currentSquare = s;
|
currentSquare = s;
|
||||||
|
|
||||||
#ifdef MUEHLE_NMM
|
#ifdef MUEHLE_NMM
|
||||||
if (pieceInHandCount[BLACK] == 0 &&
|
if (pieceInHandCount[WHITE] == 0 &&
|
||||||
pieceInHandCount[WHITE] == 0 &&
|
pieceInHandCount[BLACK] == 0 &&
|
||||||
is_all_surrounded(~sideToMove, SQ_0, s)) {
|
is_all_surrounded(~sideToMove, SQ_0, s)) {
|
||||||
set_gameover(sideToMove, GameOverReason::loseReasonNoWay);
|
set_gameover(sideToMove, GameOverReason::loseReasonNoWay);
|
||||||
//change_side_to_move();
|
//change_side_to_move();
|
||||||
|
@ -656,9 +656,9 @@ bool Position::put_piece(Square s, bool updateRecord)
|
||||||
|| is_all_in_mills(them)
|
|| is_all_in_mills(them)
|
||||||
#endif
|
#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()) {
|
if (check_if_game_is_over()) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -825,7 +825,7 @@ bool Position::remove_piece(Square s, bool updateRecord)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (phase == Phase::placing) {
|
if (phase == Phase::placing) {
|
||||||
if (pieceInHandCount[BLACK] == 0 && pieceInHandCount[WHITE] == 0) {
|
if (pieceInHandCount[WHITE] == 0 && pieceInHandCount[BLACK] == 0) {
|
||||||
phase = Phase::moving;
|
phase = Phase::moving;
|
||||||
action = Action::select;
|
action = Action::select;
|
||||||
|
|
||||||
|
@ -979,9 +979,9 @@ bool Position::check_if_game_is_over()
|
||||||
}
|
}
|
||||||
#endif // RULE_50
|
#endif // RULE_50
|
||||||
|
|
||||||
if (pieceOnBoardCount[BLACK] + pieceOnBoardCount[WHITE] >= EFFECTIVE_SQUARE_NB) {
|
if (pieceOnBoardCount[WHITE] + pieceOnBoardCount[BLACK] >= EFFECTIVE_SQUARE_NB) {
|
||||||
if (rule.isBlackLoseButNotDrawWhenBoardFull) {
|
if (rule.isWhiteLoseButNotDrawWhenBoardFull) {
|
||||||
set_gameover(WHITE, GameOverReason::loseReasonBoardIsFull);
|
set_gameover(BLACK, GameOverReason::loseReasonBoardIsFull);
|
||||||
} else {
|
} else {
|
||||||
set_gameover(DRAW, GameOverReason::drawReasonBoardIsFull);
|
set_gameover(DRAW, GameOverReason::drawReasonBoardIsFull);
|
||||||
}
|
}
|
||||||
|
@ -1005,8 +1005,8 @@ bool Position::check_if_game_is_over()
|
||||||
int Position::get_mobility_diff()
|
int Position::get_mobility_diff()
|
||||||
{
|
{
|
||||||
// TODO: Deal with rule is no ban location
|
// TODO: Deal with rule is no ban location
|
||||||
int mobilityBlack = 0;
|
|
||||||
int mobilityWhite = 0;
|
int mobilityWhite = 0;
|
||||||
|
int mobilityBlack = 0;
|
||||||
|
|
||||||
for (Square s = SQ_BEGIN; s < SQ_END; ++s) {
|
for (Square s = SQ_BEGIN; s < SQ_END; ++s) {
|
||||||
if (board[s] == NO_PIECE || board[s] == BAN_STONE) {
|
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) {
|
for (MoveDirection d = MD_BEGIN; d < MD_NB; ++d) {
|
||||||
moveSquare = static_cast<Square>(MoveList<LEGAL>::adjacentSquares[s][d]);
|
moveSquare = static_cast<Square>(MoveList<LEGAL>::adjacentSquares[s][d]);
|
||||||
if (moveSquare) {
|
if (moveSquare) {
|
||||||
if (board[moveSquare] & B_STONE) {
|
|
||||||
mobilityBlack++;
|
|
||||||
}
|
|
||||||
if (board[moveSquare] & W_STONE) {
|
if (board[moveSquare] & W_STONE) {
|
||||||
mobilityWhite++;
|
mobilityWhite++;
|
||||||
}
|
}
|
||||||
|
if (board[moveSquare] & B_STONE) {
|
||||||
|
mobilityBlack++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return mobilityBlack - mobilityWhite;
|
return mobilityWhite - mobilityBlack;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Position::remove_ban_stones()
|
void Position::remove_ban_stones()
|
||||||
|
@ -1106,34 +1106,24 @@ Color Position::color_on(Square s) const
|
||||||
bool Position::bitboard_is_ok()
|
bool Position::bitboard_is_ok()
|
||||||
{
|
{
|
||||||
#ifdef BITBOARD_DEBUG
|
#ifdef BITBOARD_DEBUG
|
||||||
Bitboard blackBB = byColorBB[BLACK];
|
|
||||||
Bitboard whiteBB = byColorBB[WHITE];
|
Bitboard whiteBB = byColorBB[WHITE];
|
||||||
|
Bitboard blackBB = byColorBB[BLACK];
|
||||||
|
|
||||||
for (Square s = SQ_BEGIN; s < SQ_END; ++s) {
|
for (Square s = SQ_BEGIN; s < SQ_END; ++s) {
|
||||||
|
|
||||||
if (empty(s))
|
if (empty(s))
|
||||||
{
|
{
|
||||||
|
if (whiteBB & (1 << s)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (blackBB & (1 << s)) {
|
if (blackBB & (1 << s)) {
|
||||||
return false;
|
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) {
|
if ((whiteBB & (1 << s)) == 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -1142,6 +1132,16 @@ bool Position::bitboard_is_ok()
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (color_of(board[s]) == BLACK) {
|
||||||
|
if ((blackBB & (1 << s)) == 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (whiteBB & (1 << s)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -1255,7 +1255,7 @@ bool Position::is_all_surrounded(Color c
|
||||||
) const
|
) const
|
||||||
{
|
{
|
||||||
// Full
|
// Full
|
||||||
if (pieceOnBoardCount[BLACK] + pieceOnBoardCount[WHITE] >= EFFECTIVE_SQUARE_NB)
|
if (pieceOnBoardCount[WHITE] + pieceOnBoardCount[BLACK] >= EFFECTIVE_SQUARE_NB)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
// Can fly
|
// Can fly
|
||||||
|
|
|
@ -52,7 +52,7 @@ struct Rule
|
||||||
|
|
||||||
// At the end of the placing phase, when the board is full,
|
// 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.
|
// 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.
|
// The player will lose if his opponent blocks them so that they cannot be moved.
|
||||||
// Change side to move if this option is disabled.
|
// Change side to move if this option is disabled.
|
||||||
|
|
|
@ -123,7 +123,7 @@ int Thread::search()
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
// TODO: Only NMM
|
// 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()) {
|
!rule.hasDiagonalLines && gameOptions.getShufflingEnabled()) {
|
||||||
const uint32_t seed = static_cast<uint32_t>(now());
|
const uint32_t seed = static_cast<uint32_t>(now());
|
||||||
std::shuffle(MoveList<LEGAL>::movePriorityList.begin(), MoveList<LEGAL>::movePriorityList.end(), std::default_random_engine(seed));
|
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 &&
|
posKey &&
|
||||||
Thread::probeEndgameHash(posKey, endgame)) {
|
Thread::probeEndgameHash(posKey, endgame)) {
|
||||||
switch (endgame.type) {
|
switch (endgame.type) {
|
||||||
case EndGameType::blackWin:
|
case EndGameType::whiteWin:
|
||||||
bestValue = VALUE_MATE;
|
bestValue = VALUE_MATE;
|
||||||
bestValue += depth;
|
bestValue += depth;
|
||||||
break;
|
break;
|
||||||
case EndGameType::whiteWin:
|
case EndGameType::blackWin:
|
||||||
bestValue = -VALUE_MATE;
|
bestValue = -VALUE_MATE;
|
||||||
bestValue -= depth;
|
bestValue -= depth;
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -283,8 +283,8 @@ void Thread::analyze(Color c)
|
||||||
const bool lose = v <= -VALUE_MATE;
|
const bool lose = v <= -VALUE_MATE;
|
||||||
const int np = v / VALUE_EACH_PIECE;
|
const int np = v / VALUE_EACH_PIECE;
|
||||||
|
|
||||||
string strUs = (c == BLACK ? "Black" : "White");
|
string strUs = (c == WHITE ? "White" : "Black");
|
||||||
string strThem = (c == BLACK ? "White" : "Black");
|
string strThem = (c == WHITE ? "Black" : "White");
|
||||||
|
|
||||||
loggerDebug("Depth: %d\n\n", originDepth);
|
loggerDebug("Depth: %d\n\n", originDepth);
|
||||||
|
|
||||||
|
@ -304,11 +304,11 @@ void Thread::analyze(Color c)
|
||||||
if (p->get_winner() == DRAW) {
|
if (p->get_winner() == DRAW) {
|
||||||
cout << "Draw" << endl;
|
cout << "Draw" << endl;
|
||||||
ndraw += 0.5; // TODO
|
ndraw += 0.5; // TODO
|
||||||
} else if (p->get_winner() == BLACK) {
|
|
||||||
cout << "Black wins" << endl;
|
|
||||||
nbwin += 0.5; // TODO
|
|
||||||
} else if (p->get_winner() == WHITE) {
|
} else if (p->get_winner() == WHITE) {
|
||||||
cout << "White wins" << endl;
|
cout << "White wins" << endl;
|
||||||
|
nbwin += 0.5; // TODO
|
||||||
|
} else if (p->get_winner() == BLACK) {
|
||||||
|
cout << "Black wins" << endl;
|
||||||
nwwin += 0.5; // TODO
|
nwwin += 0.5; // TODO
|
||||||
}
|
}
|
||||||
goto out;
|
goto out;
|
||||||
|
@ -379,10 +379,10 @@ void Thread::analyze(Color c)
|
||||||
cout << strThem << " after " << d << " moves will lead " << -np << " pieces" << endl;
|
cout << strThem << " after " << d << " moves will lead " << -np << " pieces" << endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (p->side_to_move() == BLACK) {
|
if (p->side_to_move() == WHITE) {
|
||||||
cout << "Black to move" << endl;
|
|
||||||
} else {
|
|
||||||
cout << "White to move" << endl;
|
cout << "White to move" << endl;
|
||||||
|
} else {
|
||||||
|
cout << "Black to move" << endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef QT_GUI_LIB
|
#ifndef QT_GUI_LIB
|
||||||
|
@ -427,8 +427,8 @@ string Thread::next_move()
|
||||||
if (gameOptions.isEndgameLearningEnabled()) {
|
if (gameOptions.isEndgameLearningEnabled()) {
|
||||||
if (bestvalue <= -VALUE_KNOWN_WIN) {
|
if (bestvalue <= -VALUE_KNOWN_WIN) {
|
||||||
Endgame endgame;
|
Endgame endgame;
|
||||||
endgame.type = rootPos->side_to_move() == BLACK ?
|
endgame.type = rootPos->side_to_move() == WHITE ?
|
||||||
EndGameType::whiteWin : EndGameType::blackWin;
|
EndGameType::blackWin : EndGameType::whiteWin;
|
||||||
Key endgameHash = rootPos->key(); // TODO: Do not generate hash repeatedly
|
Key endgameHash = rootPos->key(); // TODO: Do not generate hash repeatedly
|
||||||
saveEndgameHash(endgameHash, endgame);
|
saveEndgameHash(endgameHash, endgame);
|
||||||
}
|
}
|
||||||
|
|
|
@ -121,7 +121,7 @@ public:
|
||||||
Value bestvalue { VALUE_ZERO };
|
Value bestvalue { VALUE_ZERO };
|
||||||
Value lastvalue { VALUE_ZERO };
|
Value lastvalue { VALUE_ZERO };
|
||||||
|
|
||||||
Color us { BLACK };
|
Color us { WHITE };
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int timeLimit;
|
int timeLimit;
|
||||||
|
|
70
src/types.h
70
src/types.h
|
@ -131,8 +131,8 @@ enum MoveType
|
||||||
enum Color : uint8_t
|
enum Color : uint8_t
|
||||||
{
|
{
|
||||||
NOCOLOR = 0,
|
NOCOLOR = 0,
|
||||||
BLACK = 1,
|
WHITE = 1,
|
||||||
WHITE = 2,
|
BLACK = 2,
|
||||||
COLOR_NB = 3,
|
COLOR_NB = 3,
|
||||||
DRAW = 4,
|
DRAW = 4,
|
||||||
NOBODY = 8
|
NOBODY = 8
|
||||||
|
@ -252,8 +252,8 @@ enum Rating : int8_t
|
||||||
enum PieceType : uint16_t
|
enum PieceType : uint16_t
|
||||||
{
|
{
|
||||||
NO_PIECE_TYPE = 0,
|
NO_PIECE_TYPE = 0,
|
||||||
BLACK_STONE = 1,
|
WHITE_STONE = 1,
|
||||||
WHITE_STONE = 2,
|
BLACK_STONE = 2,
|
||||||
BAN = 3,
|
BAN = 3,
|
||||||
ALL_PIECES = 0,
|
ALL_PIECES = 0,
|
||||||
PIECE_TYPE_NB = 4,
|
PIECE_TYPE_NB = 4,
|
||||||
|
@ -267,33 +267,33 @@ enum Piece : uint8_t
|
||||||
NO_PIECE = 0x00,
|
NO_PIECE = 0x00,
|
||||||
BAN_STONE = 0x0F,
|
BAN_STONE = 0x0F,
|
||||||
|
|
||||||
B_STONE = 0x10,
|
W_STONE = 0x10,
|
||||||
B_STONE_1 = 0x11,
|
W_STONE_1 = 0x11,
|
||||||
B_STONE_2 = 0x12,
|
W_STONE_2 = 0x12,
|
||||||
B_STONE_3 = 0x13,
|
W_STONE_3 = 0x13,
|
||||||
B_STONE_4 = 0x14,
|
W_STONE_4 = 0x14,
|
||||||
B_STONE_5 = 0x15,
|
W_STONE_5 = 0x15,
|
||||||
B_STONE_6 = 0x16,
|
W_STONE_6 = 0x16,
|
||||||
B_STONE_7 = 0x17,
|
W_STONE_7 = 0x17,
|
||||||
B_STONE_8 = 0x18,
|
W_STONE_8 = 0x18,
|
||||||
B_STONE_9 = 0x19,
|
W_STONE_9 = 0x19,
|
||||||
B_STONE_10 = 0x1A,
|
W_STONE_10 = 0x1A,
|
||||||
B_STONE_11 = 0x1B,
|
W_STONE_11 = 0x1B,
|
||||||
B_STONE_12 = 0x1C,
|
W_STONE_12 = 0x1C,
|
||||||
|
|
||||||
W_STONE = 0x20,
|
B_STONE = 0x20,
|
||||||
W_STONE_1 = 0x21,
|
B_STONE_1 = 0x21,
|
||||||
W_STONE_2 = 0x22,
|
B_STONE_2 = 0x22,
|
||||||
W_STONE_3 = 0x23,
|
B_STONE_3 = 0x23,
|
||||||
W_STONE_4 = 0x24,
|
B_STONE_4 = 0x24,
|
||||||
W_STONE_5 = 0x25,
|
B_STONE_5 = 0x25,
|
||||||
W_STONE_6 = 0x26,
|
B_STONE_6 = 0x26,
|
||||||
W_STONE_7 = 0x27,
|
B_STONE_7 = 0x27,
|
||||||
W_STONE_8 = 0x28,
|
B_STONE_8 = 0x28,
|
||||||
W_STONE_9 = 0x29,
|
B_STONE_9 = 0x29,
|
||||||
W_STONE_10 = 0x2A,
|
B_STONE_10 = 0x2A,
|
||||||
W_STONE_11 = 0x2B,
|
B_STONE_11 = 0x2B,
|
||||||
W_STONE_12 = 0x2C,
|
B_STONE_12 = 0x2C,
|
||||||
|
|
||||||
PIECE_NB = 64, // Fix overflow
|
PIECE_NB = 64, // Fix overflow
|
||||||
};
|
};
|
||||||
|
@ -410,7 +410,7 @@ constexpr Piece make_piece(Color c)
|
||||||
|
|
||||||
constexpr Piece make_piece(Color c, PieceType pt)
|
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);
|
return make_piece(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -432,14 +432,14 @@ constexpr PieceType type_of(Piece pc)
|
||||||
return BAN;
|
return BAN;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (color_of(pc) == BLACK) {
|
|
||||||
return BLACK_STONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (color_of(pc) == WHITE) {
|
if (color_of(pc) == WHITE) {
|
||||||
return WHITE_STONE;
|
return WHITE_STONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (color_of(pc) == BLACK) {
|
||||||
|
return BLACK_STONE;
|
||||||
|
}
|
||||||
|
|
||||||
return NO_PIECE_TYPE;
|
return NO_PIECE_TYPE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -37,8 +37,8 @@ namespace
|
||||||
{
|
{
|
||||||
|
|
||||||
// FEN string of the initial position, normal mill game
|
// FEN string of the initial position, normal mill game
|
||||||
const char *StartFEN12 = "********/********/******** b p p 0 12 0 12 0 0 1";
|
const char *StartFEN12 = "********/********/******** w p p 0 12 0 12 0 0 1";
|
||||||
const char *StartFEN9 = "********/********/******** b p p 0 9 0 9 0 0 1";
|
const char *StartFEN9 = "********/********/******** w p p 0 9 0 9 0 0 1";
|
||||||
char StartFEN[BUFSIZ];
|
char StartFEN[BUFSIZ];
|
||||||
|
|
||||||
// position() is called when engine receives the "position" UCI command.
|
// position() is called when engine receives the "position" UCI command.
|
||||||
|
@ -130,7 +130,7 @@ void go(Position *pos)
|
||||||
}
|
}
|
||||||
|
|
||||||
pos->set(StartFEN, Threads.main());
|
pos->set(StartFEN, Threads.main());
|
||||||
Threads.main()->us = BLACK; // WAR
|
Threads.main()->us = WHITE; // WAR
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
|
|
|
@ -117,9 +117,9 @@ void on_mayRemoveFromMillsAlways(const Option &o)
|
||||||
rule.mayRemoveFromMillsAlways = (bool)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)
|
void on_isLoseButNotChangeSideWhenNoWay(const Option &o)
|
||||||
|
@ -181,7 +181,7 @@ void init(OptionsMap &o)
|
||||||
o["IsDefenderMoveFirst"] << Option(true, on_isDefenderMoveFirst);
|
o["IsDefenderMoveFirst"] << Option(true, on_isDefenderMoveFirst);
|
||||||
o["MayRemoveMultiple"] << Option(false, on_mayRemoveMultiple);
|
o["MayRemoveMultiple"] << Option(false, on_mayRemoveMultiple);
|
||||||
o["MayRemoveFromMillsAlways"] << Option(true, on_mayRemoveFromMillsAlways);
|
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["IsLoseButNotChangeSideWhenNoWay"] << Option(true, on_isLoseButNotChangeSideWhenNoWay);
|
||||||
o["MayFly"] << Option(false, on_mayFly);
|
o["MayFly"] << Option(false, on_mayFly);
|
||||||
o["MaxStepsLedToDraw"] << Option(50, 30, 50, on_maxStepsLedToDraw);
|
o["MaxStepsLedToDraw"] << Option(50, 30, 50, on_maxStepsLedToDraw);
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<!-- Theme applied to the Android Window while the process is starting -->
|
<!-- 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
|
<!-- Show a splash screen on the activity. Automatically removed when
|
||||||
Flutter draws its first frame -->
|
Flutter draws its first frame -->
|
||||||
<item name="android:windowBackground">@drawable/launch_background</item>
|
<item name="android:windowBackground">@drawable/launch_background</item>
|
||||||
|
@ -12,7 +13,8 @@
|
||||||
running.
|
running.
|
||||||
|
|
||||||
This Theme is only used starting with V2 of Flutter's Android embedding. -->
|
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>
|
<item name="android:windowBackground">@drawable/normal_background</item>
|
||||||
</style>
|
</style>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
@ -49,8 +49,8 @@ class Config {
|
||||||
static int boardLineColor = AppTheme.boardLineColor.value;
|
static int boardLineColor = AppTheme.boardLineColor.value;
|
||||||
static int darkBackgroundColor = AppTheme.darkBackgroundColor.value;
|
static int darkBackgroundColor = AppTheme.darkBackgroundColor.value;
|
||||||
static int boardBackgroundColor = AppTheme.boardBackgroundColor.value;
|
static int boardBackgroundColor = AppTheme.boardBackgroundColor.value;
|
||||||
static int blackPieceColor = AppTheme.blackPieceColor.value;
|
|
||||||
static int whitePieceColor = AppTheme.whitePieceColor.value;
|
static int whitePieceColor = AppTheme.whitePieceColor.value;
|
||||||
|
static int blackPieceColor = AppTheme.blackPieceColor.value;
|
||||||
|
|
||||||
// Rules
|
// Rules
|
||||||
static int piecesCount = 9;
|
static int piecesCount = 9;
|
||||||
|
@ -60,7 +60,7 @@ class Config {
|
||||||
static bool isDefenderMoveFirst = false;
|
static bool isDefenderMoveFirst = false;
|
||||||
static bool mayRemoveMultiple = false;
|
static bool mayRemoveMultiple = false;
|
||||||
static bool mayRemoveFromMillsAlways = false;
|
static bool mayRemoveFromMillsAlways = false;
|
||||||
static bool isBlackLoseButNotDrawWhenBoardFull = true;
|
static bool isWhiteLoseButNotDrawWhenBoardFull = true;
|
||||||
static bool isLoseButNotChangeSideWhenNoWay = true;
|
static bool isLoseButNotChangeSideWhenNoWay = true;
|
||||||
static bool mayFly = true;
|
static bool mayFly = true;
|
||||||
static int maxStepsLedToDraw = 50;
|
static int maxStepsLedToDraw = 50;
|
||||||
|
@ -99,10 +99,10 @@ class Config {
|
||||||
settings['DarkBackgroundColor'] ?? AppTheme.darkBackgroundColor.value;
|
settings['DarkBackgroundColor'] ?? AppTheme.darkBackgroundColor.value;
|
||||||
Config.boardBackgroundColor =
|
Config.boardBackgroundColor =
|
||||||
settings['BoardBackgroundColor'] ?? AppTheme.boardBackgroundColor.value;
|
settings['BoardBackgroundColor'] ?? AppTheme.boardBackgroundColor.value;
|
||||||
Config.blackPieceColor =
|
|
||||||
settings['BlackPieceColor'] ?? AppTheme.blackPieceColor.value;
|
|
||||||
Config.whitePieceColor =
|
Config.whitePieceColor =
|
||||||
settings['WhitePieceColor'] ?? AppTheme.whitePieceColor.value;
|
settings['WhitePieceColor'] ?? AppTheme.whitePieceColor.value;
|
||||||
|
Config.blackPieceColor =
|
||||||
|
settings['BlackPieceColor'] ?? AppTheme.blackPieceColor.value;
|
||||||
|
|
||||||
// Rules
|
// Rules
|
||||||
rule.piecesCount = Config.piecesCount = settings['PiecesCount'] ?? 9;
|
rule.piecesCount = Config.piecesCount = settings['PiecesCount'] ?? 9;
|
||||||
|
@ -118,9 +118,9 @@ class Config {
|
||||||
Config.mayRemoveMultiple = settings['MayRemoveMultiple'] ?? false;
|
Config.mayRemoveMultiple = settings['MayRemoveMultiple'] ?? false;
|
||||||
rule.mayRemoveFromMillsAlways = Config.mayRemoveFromMillsAlways =
|
rule.mayRemoveFromMillsAlways = Config.mayRemoveFromMillsAlways =
|
||||||
settings['MayRemoveFromMillsAlways'] ?? false;
|
settings['MayRemoveFromMillsAlways'] ?? false;
|
||||||
rule.isBlackLoseButNotDrawWhenBoardFull =
|
rule.isWhiteLoseButNotDrawWhenBoardFull =
|
||||||
Config.isBlackLoseButNotDrawWhenBoardFull =
|
Config.isWhiteLoseButNotDrawWhenBoardFull =
|
||||||
settings['IsBlackLoseButNotDrawWhenBoardFull'] ?? true;
|
settings['IsWhiteLoseButNotDrawWhenBoardFull'] ?? true;
|
||||||
rule.isLoseButNotChangeSideWhenNoWay =
|
rule.isLoseButNotChangeSideWhenNoWay =
|
||||||
Config.isLoseButNotChangeSideWhenNoWay =
|
Config.isLoseButNotChangeSideWhenNoWay =
|
||||||
settings['IsLoseButNotChangeSideWhenNoWay'] ?? true;
|
settings['IsLoseButNotChangeSideWhenNoWay'] ?? true;
|
||||||
|
@ -160,8 +160,8 @@ class Config {
|
||||||
settings['BoardLineColor'] = Config.boardLineColor;
|
settings['BoardLineColor'] = Config.boardLineColor;
|
||||||
settings['DarkBackgroundColor'] = Config.darkBackgroundColor;
|
settings['DarkBackgroundColor'] = Config.darkBackgroundColor;
|
||||||
settings['BoardBackgroundColor'] = Config.boardBackgroundColor;
|
settings['BoardBackgroundColor'] = Config.boardBackgroundColor;
|
||||||
settings['BlackPieceColor'] = Config.blackPieceColor;
|
|
||||||
settings['WhitePieceColor'] = Config.whitePieceColor;
|
settings['WhitePieceColor'] = Config.whitePieceColor;
|
||||||
|
settings['BlackPieceColor'] = Config.blackPieceColor;
|
||||||
|
|
||||||
// Rules
|
// Rules
|
||||||
settings['PiecesCount'] = Config.piecesCount;
|
settings['PiecesCount'] = Config.piecesCount;
|
||||||
|
@ -171,8 +171,8 @@ class Config {
|
||||||
settings['IsDefenderMoveFirst'] = Config.isDefenderMoveFirst;
|
settings['IsDefenderMoveFirst'] = Config.isDefenderMoveFirst;
|
||||||
settings['MayRemoveMultiple'] = Config.mayRemoveMultiple;
|
settings['MayRemoveMultiple'] = Config.mayRemoveMultiple;
|
||||||
settings['MayRemoveFromMillsAlways'] = Config.mayRemoveFromMillsAlways;
|
settings['MayRemoveFromMillsAlways'] = Config.mayRemoveFromMillsAlways;
|
||||||
settings['IsBlackLoseButNotDrawWhenBoardFull'] =
|
settings['IsWhiteLoseButNotDrawWhenBoardFull'] =
|
||||||
Config.isBlackLoseButNotDrawWhenBoardFull;
|
Config.isWhiteLoseButNotDrawWhenBoardFull;
|
||||||
settings['IsLoseButNotChangeSideWhenNoWay'] =
|
settings['IsLoseButNotChangeSideWhenNoWay'] =
|
||||||
Config.isLoseButNotChangeSideWhenNoWay;
|
Config.isLoseButNotChangeSideWhenNoWay;
|
||||||
settings['MayFly'] = Config.mayFly;
|
settings['MayFly'] = Config.mayFly;
|
||||||
|
|
|
@ -145,7 +145,7 @@ class NativeEngine extends Engine {
|
||||||
await send(
|
await send(
|
||||||
'setoption name MayRemoveFromMillsAlways value ${Config.mayRemoveFromMillsAlways}');
|
'setoption name MayRemoveFromMillsAlways value ${Config.mayRemoveFromMillsAlways}');
|
||||||
await send(
|
await send(
|
||||||
'setoption name IsBlackLoseButNotDrawWhenBoardFull value ${Config.isBlackLoseButNotDrawWhenBoardFull}');
|
'setoption name IsWhiteLoseButNotDrawWhenBoardFull value ${Config.isWhiteLoseButNotDrawWhenBoardFull}');
|
||||||
await send(
|
await send(
|
||||||
'setoption name IsLoseButNotChangeSideWhenNoWay value ${Config.isLoseButNotChangeSideWhenNoWay}');
|
'setoption name IsLoseButNotChangeSideWhenNoWay value ${Config.isLoseButNotChangeSideWhenNoWay}');
|
||||||
await send('setoption name MayFly value ${Config.mayFly}');
|
await send('setoption name MayFly value ${Config.mayFly}');
|
||||||
|
|
|
@ -160,12 +160,12 @@
|
||||||
"@tipToMove": {
|
"@tipToMove": {
|
||||||
"description": " to move."
|
"description": " to move."
|
||||||
},
|
},
|
||||||
"blackWin": "Player 1 win!",
|
"whiteWin": "Player 1 win!",
|
||||||
"@blackWin": {
|
"@whiteWin": {
|
||||||
"description": "Player 1 win!"
|
"description": "Player 1 win!"
|
||||||
},
|
},
|
||||||
"whiteWin": "Player 2 win!",
|
"blackWin": "Player 2 win!",
|
||||||
"@whiteWin": {
|
"@blackWin": {
|
||||||
"description": "Player 2 win!"
|
"description": "Player 2 win!"
|
||||||
},
|
},
|
||||||
"won": "Won",
|
"won": "Won",
|
||||||
|
@ -224,12 +224,12 @@
|
||||||
"@score": {
|
"@score": {
|
||||||
"description": "Score"
|
"description": "Score"
|
||||||
},
|
},
|
||||||
"black": "Player 1",
|
"white": "Player 1",
|
||||||
"@black": {
|
"@white": {
|
||||||
"description": "Player 1"
|
"description": "Player 1"
|
||||||
},
|
},
|
||||||
"white": "Player 2",
|
"black": "Player 2",
|
||||||
"@white": {
|
"@black": {
|
||||||
"description": "Player 2"
|
"description": "Player 2"
|
||||||
},
|
},
|
||||||
"loseReasonlessThanThree": " piece count is less than three.",
|
"loseReasonlessThanThree": " piece count is less than three.",
|
||||||
|
@ -488,12 +488,12 @@
|
||||||
"@mayRemoveFromMillsAlways_Detail": {
|
"@mayRemoveFromMillsAlways_Detail": {
|
||||||
"description": "mayRemoveFromMillsAlways_Detail"
|
"description": "mayRemoveFromMillsAlways_Detail"
|
||||||
},
|
},
|
||||||
"isBlackLoseButNotDrawWhenBoardFull": "Second player loses when board full",
|
"isWhiteLoseButNotDrawWhenBoardFull": "Second player loses when board full",
|
||||||
"@isBlackLoseButNotDrawWhenBoardFull": {
|
"@isWhiteLoseButNotDrawWhenBoardFull": {
|
||||||
"description": "Second player loses when board full"
|
"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.",
|
"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.",
|
||||||
"@isBlackLoseButNotDrawWhenBoardFull_Detail": {
|
"@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."
|
"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",
|
"isLoseButNotChangeSideWhenNoWay": "Lose when no legal moves",
|
||||||
|
@ -568,12 +568,12 @@
|
||||||
"@lineColor": {
|
"@lineColor": {
|
||||||
"description": "Board linecolor"
|
"description": "Board linecolor"
|
||||||
},
|
},
|
||||||
"blackPieceColor": "Player 1 piece color",
|
"whitePieceColor": "Player 1 piece color",
|
||||||
"@blackPieceColor": {
|
"@whitePieceColor": {
|
||||||
"description": "Player 1 piece color"
|
"description": "Player 1 piece color"
|
||||||
},
|
},
|
||||||
"whitePieceColor": "Player 2 piece color",
|
"blackPieceColor": "Player 2 piece color",
|
||||||
"@whitePieceColor": {
|
"@blackPieceColor": {
|
||||||
"description": "Player 2 piece color"
|
"description": "Player 2 piece color"
|
||||||
},
|
},
|
||||||
"aiIsLazy": "AI is Lazy",
|
"aiIsLazy": "AI is Lazy",
|
||||||
|
|
|
@ -40,8 +40,8 @@
|
||||||
"tipHaveThreePiecesLeft": "只剩下3颗棋子了",
|
"tipHaveThreePiecesLeft": "只剩下3颗棋子了",
|
||||||
"tipCanMoveToAnyPoint": "可飞子到任意空位",
|
"tipCanMoveToAnyPoint": "可飞子到任意空位",
|
||||||
"tipToMove": "行棋",
|
"tipToMove": "行棋",
|
||||||
"blackWin": "先手方胜",
|
"whiteWin": "先手方胜",
|
||||||
"whiteWin": "后手方胜",
|
"blackWin": "后手方胜",
|
||||||
"won": "胜",
|
"won": "胜",
|
||||||
"lost": "负",
|
"lost": "负",
|
||||||
"aborted": "中断",
|
"aborted": "中断",
|
||||||
|
@ -56,8 +56,8 @@
|
||||||
"error": "错误",
|
"error": "错误",
|
||||||
"winRate": "胜率",
|
"winRate": "胜率",
|
||||||
"score": "比分",
|
"score": "比分",
|
||||||
"black": "先手方",
|
"white": "先手方",
|
||||||
"white": "后手方",
|
"black": "后手方",
|
||||||
"loseReasonlessThanThree": "剩余棋子少于3枚。",
|
"loseReasonlessThanThree": "剩余棋子少于3枚。",
|
||||||
"loseReasonResign": "认输了。",
|
"loseReasonResign": "认输了。",
|
||||||
"loseReasonNoWay": "无路可走。",
|
"loseReasonNoWay": "无路可走。",
|
||||||
|
@ -122,8 +122,8 @@
|
||||||
"mayRemoveMultiple_Detail": "若同时形成多个三连,则形成几个三连就能吃对方几个子。",
|
"mayRemoveMultiple_Detail": "若同时形成多个三连,则形成几个三连就能吃对方几个子。",
|
||||||
"mayRemoveFromMillsAlways": "允许吃三连中的子",
|
"mayRemoveFromMillsAlways": "允许吃三连中的子",
|
||||||
"mayRemoveFromMillsAlways_Detail": "默认情况下,不能吃三连中的子,除非对方所有子都在三连中。打开此选项可解除此限制。",
|
"mayRemoveFromMillsAlways_Detail": "默认情况下,不能吃三连中的子,除非对方所有子都在三连中。打开此选项可解除此限制。",
|
||||||
"isBlackLoseButNotDrawWhenBoardFull": "当棋盘摆满时先摆子的输棋",
|
"isWhiteLoseButNotDrawWhenBoardFull": "当棋盘摆满时先摆子的输棋",
|
||||||
"isBlackLoseButNotDrawWhenBoardFull_Detail": "对于十二子棋,在摆子阶段的最后,若棋盘摆满而双方均未吃子,则先手方输棋,而非和棋。",
|
"isWhiteLoseButNotDrawWhenBoardFull_Detail": "对于十二子棋,在摆子阶段的最后,若棋盘摆满而双方均未吃子,则先手方输棋,而非和棋。",
|
||||||
"isLoseButNotChangeSideWhenNoWay": "当无路可走时输棋",
|
"isLoseButNotChangeSideWhenNoWay": "当无路可走时输棋",
|
||||||
"isLoseButNotChangeSideWhenNoWay_Detail": "走子阶段,当无路可走时输棋,而非转为由对方继续走子。",
|
"isLoseButNotChangeSideWhenNoWay_Detail": "走子阶段,当无路可走时输棋,而非转为由对方继续走子。",
|
||||||
"mayFly": "飞子",
|
"mayFly": "飞子",
|
||||||
|
@ -142,8 +142,8 @@
|
||||||
"pieceColor": "棋子颜色",
|
"pieceColor": "棋子颜色",
|
||||||
"backgroudColor": "背景颜色",
|
"backgroudColor": "背景颜色",
|
||||||
"lineColor": "线条颜色",
|
"lineColor": "线条颜色",
|
||||||
"blackPieceColor": "先手方棋子颜色",
|
"whitePieceColor": "先手方棋子颜色",
|
||||||
"whitePieceColor": "后手方棋子颜色",
|
"blackPieceColor": "后手方棋子颜色",
|
||||||
"aiIsLazy": "机器领先时懒惰",
|
"aiIsLazy": "机器领先时懒惰",
|
||||||
"isPieceCountInHandShown": "显示手中剩余棋子数",
|
"isPieceCountInHandShown": "显示手中剩余棋子数",
|
||||||
"display": "显示",
|
"display": "显示",
|
||||||
|
|
|
@ -23,7 +23,7 @@ import 'position.dart';
|
||||||
import 'types.dart';
|
import 'types.dart';
|
||||||
|
|
||||||
enum PlayerType { human, AI }
|
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 {
|
class Game {
|
||||||
static Game? _instance;
|
static Game? _instance;
|
||||||
|
@ -50,10 +50,10 @@ class Game {
|
||||||
position.init();
|
position.init();
|
||||||
_focusIndex = _blurIndex = invalidIndex;
|
_focusIndex = _blurIndex = invalidIndex;
|
||||||
moveHistory = [""];
|
moveHistory = [""];
|
||||||
sideToMove = PieceColor.black;
|
sideToMove = PieceColor.white;
|
||||||
}
|
}
|
||||||
|
|
||||||
String sideToMove = PieceColor.black;
|
String sideToMove = PieceColor.white;
|
||||||
|
|
||||||
bool? isAiToMove() {
|
bool? isAiToMove() {
|
||||||
return isAi[sideToMove];
|
return isAi[sideToMove];
|
||||||
|
@ -74,13 +74,13 @@ class Game {
|
||||||
set blurIndex(index) => _blurIndex = index;
|
set blurIndex(index) => _blurIndex = index;
|
||||||
|
|
||||||
Map<String, bool> isSearching = {
|
Map<String, bool> isSearching = {
|
||||||
PieceColor.black: false,
|
PieceColor.white: false,
|
||||||
PieceColor.white: false
|
PieceColor.black: false
|
||||||
};
|
};
|
||||||
|
|
||||||
bool aiIsSearching() {
|
bool aiIsSearching() {
|
||||||
return isSearching[PieceColor.black] == true ||
|
return isSearching[PieceColor.white] == true ||
|
||||||
isSearching[PieceColor.white] == true;
|
isSearching[PieceColor.black] == true;
|
||||||
}
|
}
|
||||||
|
|
||||||
EngineType engineType = EngineType.none;
|
EngineType engineType = EngineType.none;
|
||||||
|
@ -91,16 +91,16 @@ class Game {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case EngineType.humanVsAi:
|
case EngineType.humanVsAi:
|
||||||
case EngineType.testViaLAN:
|
case EngineType.testViaLAN:
|
||||||
isAi[PieceColor.black] = Config.aiMovesFirst;
|
isAi[PieceColor.white] = Config.aiMovesFirst;
|
||||||
isAi[PieceColor.white] = !Config.aiMovesFirst;
|
isAi[PieceColor.black] = !Config.aiMovesFirst;
|
||||||
break;
|
break;
|
||||||
case EngineType.humanVsHuman:
|
case EngineType.humanVsHuman:
|
||||||
case EngineType.humanVsLAN:
|
case EngineType.humanVsLAN:
|
||||||
case EngineType.humanVsCloud:
|
case EngineType.humanVsCloud:
|
||||||
isAi[PieceColor.black] = isAi[PieceColor.white] = false;
|
isAi[PieceColor.white] = isAi[PieceColor.black] = false;
|
||||||
break;
|
break;
|
||||||
case EngineType.aiVsAi:
|
case EngineType.aiVsAi:
|
||||||
isAi[PieceColor.black] = isAi[PieceColor.white] = true;
|
isAi[PieceColor.white] = isAi[PieceColor.black] = true;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
@ -136,7 +136,7 @@ class Game {
|
||||||
//
|
//
|
||||||
// Can regret only our turn
|
// Can regret only our turn
|
||||||
// TODO
|
// TODO
|
||||||
if (_position.side != PieceColor.white) {
|
if (_position.side != PieceColor.black) {
|
||||||
//Audios.playTone(Audios.invalidSoundId);
|
//Audios.playTone(Audios.invalidSoundId);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -174,38 +174,38 @@ class Game {
|
||||||
}
|
}
|
||||||
|
|
||||||
printStat() {
|
printStat() {
|
||||||
double blackWinRate = 0;
|
|
||||||
double whiteWinRate = 0;
|
double whiteWinRate = 0;
|
||||||
|
double blackWinRate = 0;
|
||||||
double drawRate = 0;
|
double drawRate = 0;
|
||||||
|
|
||||||
int total = position.score[PieceColor.black] +
|
int total = position.score[PieceColor.white] +
|
||||||
position.score[PieceColor.white] +
|
position.score[PieceColor.black] +
|
||||||
position.score[PieceColor.draw] ??
|
position.score[PieceColor.draw] ??
|
||||||
0;
|
0;
|
||||||
|
|
||||||
if (total == 0) {
|
if (total == 0) {
|
||||||
blackWinRate = 0;
|
|
||||||
whiteWinRate = 0;
|
whiteWinRate = 0;
|
||||||
|
blackWinRate = 0;
|
||||||
drawRate = 0;
|
drawRate = 0;
|
||||||
} else {
|
} else {
|
||||||
blackWinRate = position.score[PieceColor.black] * 100 / total ?? 0;
|
|
||||||
whiteWinRate = position.score[PieceColor.white] * 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;
|
drawRate = position.score[PieceColor.draw] * 100 / total ?? 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
String scoreInfo = "Score: " +
|
String scoreInfo = "Score: " +
|
||||||
position.score[PieceColor.black].toString() +
|
|
||||||
" : " +
|
|
||||||
position.score[PieceColor.white].toString() +
|
position.score[PieceColor.white].toString() +
|
||||||
" : " +
|
" : " +
|
||||||
|
position.score[PieceColor.black].toString() +
|
||||||
|
" : " +
|
||||||
position.score[PieceColor.draw].toString() +
|
position.score[PieceColor.draw].toString() +
|
||||||
"\ttotal: " +
|
"\ttotal: " +
|
||||||
total.toString() +
|
total.toString() +
|
||||||
"\n" +
|
"\n" +
|
||||||
blackWinRate.toString() +
|
|
||||||
"% : " +
|
|
||||||
whiteWinRate.toString() +
|
whiteWinRate.toString() +
|
||||||
"% : " +
|
"% : " +
|
||||||
|
blackWinRate.toString() +
|
||||||
|
"% : " +
|
||||||
drawRate.toString() +
|
drawRate.toString() +
|
||||||
"%" +
|
"%" +
|
||||||
"\n";
|
"\n";
|
||||||
|
|
|
@ -46,22 +46,22 @@ class Position {
|
||||||
GameRecorder? recorder;
|
GameRecorder? recorder;
|
||||||
|
|
||||||
Map<String, int> pieceInHandCount = {
|
Map<String, int> pieceInHandCount = {
|
||||||
PieceColor.black: -1,
|
PieceColor.white: -1,
|
||||||
PieceColor.white: -1
|
PieceColor.black: -1
|
||||||
};
|
};
|
||||||
Map<String, int> pieceOnBoardCount = {
|
Map<String, int> pieceOnBoardCount = {
|
||||||
PieceColor.black: 0,
|
PieceColor.white: 0,
|
||||||
PieceColor.white: 0
|
PieceColor.black: 0
|
||||||
};
|
};
|
||||||
int pieceToRemoveCount = 0;
|
int pieceToRemoveCount = 0;
|
||||||
|
|
||||||
int gamePly = 0;
|
int gamePly = 0;
|
||||||
String _sideToMove = PieceColor.black;
|
String _sideToMove = PieceColor.white;
|
||||||
|
|
||||||
StateInfo st = StateInfo();
|
StateInfo st = StateInfo();
|
||||||
|
|
||||||
String us = PieceColor.black;
|
String us = PieceColor.white;
|
||||||
String them = PieceColor.white;
|
String them = PieceColor.black;
|
||||||
String winner = PieceColor.nobody;
|
String winner = PieceColor.nobody;
|
||||||
|
|
||||||
GameOverReason gameOverReason = GameOverReason.noReason;
|
GameOverReason gameOverReason = GameOverReason.noReason;
|
||||||
|
@ -70,8 +70,8 @@ class Position {
|
||||||
Act action = Act.none;
|
Act action = Act.none;
|
||||||
|
|
||||||
Map<String, int> score = {
|
Map<String, int> score = {
|
||||||
PieceColor.black: 0,
|
|
||||||
PieceColor.white: 0,
|
PieceColor.white: 0,
|
||||||
|
PieceColor.black: 0,
|
||||||
PieceColor.draw: 0
|
PieceColor.draw: 0
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -177,7 +177,7 @@ class Position {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Active color
|
// Active color
|
||||||
ss += _sideToMove == PieceColor.black ? "b" : "w";
|
ss += _sideToMove == PieceColor.white ? "w" : "b";
|
||||||
|
|
||||||
ss += " ";
|
ss += " ";
|
||||||
|
|
||||||
|
@ -223,22 +223,22 @@ class Position {
|
||||||
|
|
||||||
ss += " ";
|
ss += " ";
|
||||||
|
|
||||||
ss += pieceOnBoardCount[PieceColor.black].toString() +
|
ss += pieceOnBoardCount[PieceColor.white].toString() +
|
||||||
" " +
|
|
||||||
pieceInHandCount[PieceColor.black].toString() +
|
|
||||||
" " +
|
|
||||||
pieceOnBoardCount[PieceColor.white].toString() +
|
|
||||||
" " +
|
" " +
|
||||||
pieceInHandCount[PieceColor.white].toString() +
|
pieceInHandCount[PieceColor.white].toString() +
|
||||||
" " +
|
" " +
|
||||||
|
pieceOnBoardCount[PieceColor.black].toString() +
|
||||||
|
" " +
|
||||||
|
pieceInHandCount[PieceColor.black].toString() +
|
||||||
|
" " +
|
||||||
pieceToRemoveCount.toString() +
|
pieceToRemoveCount.toString() +
|
||||||
" ";
|
" ";
|
||||||
|
|
||||||
int sideIsWhite = _sideToMove == PieceColor.white ? 1 : 0;
|
int sideIsBlack = _sideToMove == PieceColor.black ? 1 : 0;
|
||||||
|
|
||||||
ss += st.rule50.toString() +
|
ss += st.rule50.toString() +
|
||||||
" " +
|
" " +
|
||||||
(1 + (gamePly - sideIsWhite) ~/ 2).toString();
|
(1 + (gamePly - sideIsBlack) ~/ 2).toString();
|
||||||
|
|
||||||
return ss;
|
return ss;
|
||||||
}
|
}
|
||||||
|
@ -269,9 +269,9 @@ class Position {
|
||||||
if (move.length > "Player".length &&
|
if (move.length > "Player".length &&
|
||||||
move.substring(0, "Player".length - 1) == "Player") {
|
move.substring(0, "Player".length - 1) == "Player") {
|
||||||
if (move["Player".length] == '1') {
|
if (move["Player".length] == '1') {
|
||||||
return resign(PieceColor.black);
|
|
||||||
} else {
|
|
||||||
return resign(PieceColor.white);
|
return resign(PieceColor.white);
|
||||||
|
} else {
|
||||||
|
return resign(PieceColor.black);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -405,7 +405,7 @@ class Position {
|
||||||
st.rule50 = 0;
|
st.rule50 = 0;
|
||||||
|
|
||||||
phase = Phase.ready;
|
phase = Phase.ready;
|
||||||
setSideToMove(PieceColor.black);
|
setSideToMove(PieceColor.white);
|
||||||
action = Act.place;
|
action = Act.place;
|
||||||
|
|
||||||
winner = PieceColor.nobody;
|
winner = PieceColor.nobody;
|
||||||
|
@ -415,10 +415,10 @@ class Position {
|
||||||
|
|
||||||
st.key = 0;
|
st.key = 0;
|
||||||
|
|
||||||
pieceOnBoardCount[PieceColor.black] =
|
pieceOnBoardCount[PieceColor.white] =
|
||||||
pieceOnBoardCount[PieceColor.white] = 0;
|
pieceOnBoardCount[PieceColor.black] = 0;
|
||||||
pieceInHandCount[PieceColor.black] =
|
pieceInHandCount[PieceColor.white] =
|
||||||
pieceInHandCount[PieceColor.white] = rule.piecesCount;
|
pieceInHandCount[PieceColor.black] = rule.piecesCount;
|
||||||
pieceToRemoveCount = 0;
|
pieceToRemoveCount = 0;
|
||||||
|
|
||||||
// TODO:
|
// TODO:
|
||||||
|
@ -488,11 +488,11 @@ class Position {
|
||||||
int n = millsCount(currentSquare);
|
int n = millsCount(currentSquare);
|
||||||
|
|
||||||
if (n == 0) {
|
if (n == 0) {
|
||||||
assert(pieceInHandCount[PieceColor.black]! >= 0 &&
|
assert(pieceInHandCount[PieceColor.white]! >= 0 &&
|
||||||
pieceInHandCount[PieceColor.white]! >= 0);
|
pieceInHandCount[PieceColor.black]! >= 0);
|
||||||
|
|
||||||
if (pieceInHandCount[PieceColor.black] == 0 &&
|
if (pieceInHandCount[PieceColor.white] == 0 &&
|
||||||
pieceInHandCount[PieceColor.white] == 0) {
|
pieceInHandCount[PieceColor.black] == 0) {
|
||||||
if (checkIfGameIsOver()) {
|
if (checkIfGameIsOver()) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -643,8 +643,8 @@ class Position {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (phase == Phase.placing) {
|
if (phase == Phase.placing) {
|
||||||
if (pieceInHandCount[PieceColor.black] == 0 &&
|
if (pieceInHandCount[PieceColor.white] == 0 &&
|
||||||
pieceInHandCount[PieceColor.white] == 0) {
|
pieceInHandCount[PieceColor.black] == 0) {
|
||||||
phase = Phase.moving;
|
phase = Phase.moving;
|
||||||
action = Act.select;
|
action = Act.select;
|
||||||
|
|
||||||
|
@ -741,11 +741,11 @@ class Position {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pieceOnBoardCount[PieceColor.black]! +
|
if (pieceOnBoardCount[PieceColor.white]! +
|
||||||
pieceOnBoardCount[PieceColor.white]! >=
|
pieceOnBoardCount[PieceColor.black]! >=
|
||||||
rankNumber * fileNumber) {
|
rankNumber * fileNumber) {
|
||||||
if (rule.isBlackLoseButNotDrawWhenBoardFull) {
|
if (rule.isWhiteLoseButNotDrawWhenBoardFull) {
|
||||||
setGameOver(PieceColor.white, GameOverReason.loseReasonBoardIsFull);
|
setGameOver(PieceColor.black, GameOverReason.loseReasonBoardIsFull);
|
||||||
} else {
|
} else {
|
||||||
setGameOver(PieceColor.draw, GameOverReason.drawReasonBoardIsFull);
|
setGameOver(PieceColor.draw, GameOverReason.drawReasonBoardIsFull);
|
||||||
}
|
}
|
||||||
|
@ -906,8 +906,8 @@ class Position {
|
||||||
|
|
||||||
bool isAllSurrounded() {
|
bool isAllSurrounded() {
|
||||||
// Full
|
// Full
|
||||||
if (pieceOnBoardCount[PieceColor.black]! +
|
if (pieceOnBoardCount[PieceColor.white]! +
|
||||||
pieceOnBoardCount[PieceColor.white]! >=
|
pieceOnBoardCount[PieceColor.black]! >=
|
||||||
rankNumber * fileNumber) {
|
rankNumber * fileNumber) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -947,13 +947,13 @@ class Position {
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
int getNPiecesInHand() {
|
int getNPiecesInHand() {
|
||||||
pieceInHandCount[PieceColor.black] =
|
|
||||||
rule.piecesCount - pieceOnBoardCount[PieceColor.black]!;
|
|
||||||
pieceInHandCount[PieceColor.white] =
|
pieceInHandCount[PieceColor.white] =
|
||||||
rule.piecesCount - pieceOnBoardCount[PieceColor.white]!;
|
rule.piecesCount - pieceOnBoardCount[PieceColor.white]!;
|
||||||
|
pieceInHandCount[PieceColor.black] =
|
||||||
|
rule.piecesCount - pieceOnBoardCount[PieceColor.black]!;
|
||||||
|
|
||||||
return pieceOnBoardCount[PieceColor.black]! +
|
return pieceOnBoardCount[PieceColor.white]! +
|
||||||
pieceOnBoardCount[PieceColor.white]!;
|
pieceOnBoardCount[PieceColor.black]!;
|
||||||
}
|
}
|
||||||
|
|
||||||
void clearBoard() {
|
void clearBoard() {
|
||||||
|
@ -975,7 +975,7 @@ class Position {
|
||||||
|
|
||||||
gameOverReason = GameOverReason.noReason;
|
gameOverReason = GameOverReason.noReason;
|
||||||
phase = Phase.placing;
|
phase = Phase.placing;
|
||||||
setSideToMove(PieceColor.black);
|
setSideToMove(PieceColor.white);
|
||||||
action = Act.place;
|
action = Act.place;
|
||||||
currentSquare = 0;
|
currentSquare = 0;
|
||||||
|
|
||||||
|
@ -999,33 +999,33 @@ class Position {
|
||||||
}
|
}
|
||||||
|
|
||||||
int pieceOnBoardCountCount() {
|
int pieceOnBoardCountCount() {
|
||||||
pieceOnBoardCount[PieceColor.black] =
|
pieceOnBoardCount[PieceColor.white] =
|
||||||
pieceOnBoardCount[PieceColor.white] = 0;
|
pieceOnBoardCount[PieceColor.black] = 0;
|
||||||
|
|
||||||
for (int f = 1; f < fileExNumber; f++) {
|
for (int f = 1; f < fileExNumber; f++) {
|
||||||
for (int r = 0; r < rankNumber; r++) {
|
for (int r = 0; r < rankNumber; r++) {
|
||||||
int s = f * rankNumber + r;
|
int s = f * rankNumber + r;
|
||||||
if (board[s] == Piece.blackStone) {
|
if (board[s] == Piece.whiteStone) {
|
||||||
if (pieceOnBoardCount[PieceColor.black] != null) {
|
|
||||||
pieceOnBoardCount[PieceColor.black] =
|
|
||||||
pieceOnBoardCount[PieceColor.black]! + 1;
|
|
||||||
}
|
|
||||||
} else if (board[s] == Piece.whiteStone) {
|
|
||||||
if (pieceOnBoardCount[PieceColor.white] != null) {
|
if (pieceOnBoardCount[PieceColor.white] != null) {
|
||||||
pieceOnBoardCount[PieceColor.white] =
|
pieceOnBoardCount[PieceColor.white] =
|
||||||
pieceOnBoardCount[PieceColor.white]! + 1;
|
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 ||
|
if (pieceOnBoardCount[PieceColor.white]! > rule.piecesCount ||
|
||||||
pieceOnBoardCount[PieceColor.white]! > rule.piecesCount) {
|
pieceOnBoardCount[PieceColor.black]! > rule.piecesCount) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return pieceOnBoardCount[PieceColor.black]! +
|
return pieceOnBoardCount[PieceColor.white]! +
|
||||||
pieceOnBoardCount[PieceColor.white]!;
|
pieceOnBoardCount[PieceColor.black]!;
|
||||||
}
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
|
@ -52,7 +52,7 @@ class GameRecorder {
|
||||||
|
|
||||||
if (fullMove == 0) {
|
if (fullMove == 0) {
|
||||||
if (halfMove != null) halfMove = halfMove! + 1;
|
if (halfMove != null) halfMove = halfMove! + 1;
|
||||||
} else if (position.side != PieceColor.black) {
|
} else if (position.side != PieceColor.white) {
|
||||||
if (halfMove != null) halfMove = halfMove! + 1;
|
if (halfMove != null) halfMove = halfMove! + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,7 @@ class Rule {
|
||||||
bool isDefenderMoveFirst = false;
|
bool isDefenderMoveFirst = false;
|
||||||
bool mayRemoveMultiple = false;
|
bool mayRemoveMultiple = false;
|
||||||
bool mayRemoveFromMillsAlways = false;
|
bool mayRemoveFromMillsAlways = false;
|
||||||
bool isBlackLoseButNotDrawWhenBoardFull = true;
|
bool isWhiteLoseButNotDrawWhenBoardFull = true;
|
||||||
bool isLoseButNotChangeSideWhenNoWay = true;
|
bool isLoseButNotChangeSideWhenNoWay = true;
|
||||||
bool mayFly = true;
|
bool mayFly = true;
|
||||||
int maxStepsLedToDraw = 50;
|
int maxStepsLedToDraw = 50;
|
||||||
|
|
|
@ -131,15 +131,15 @@ enum MoveType { place, move, remove, none }
|
||||||
|
|
||||||
class PieceColor {
|
class PieceColor {
|
||||||
static const none = '*';
|
static const none = '*';
|
||||||
static const black = '@';
|
|
||||||
static const white = 'O';
|
static const white = 'O';
|
||||||
|
static const black = '@';
|
||||||
static const ban = 'X';
|
static const ban = 'X';
|
||||||
static const nobody = '-';
|
static const nobody = '-';
|
||||||
static const draw = '=';
|
static const draw = '=';
|
||||||
|
|
||||||
static String of(String piece) {
|
static String of(String piece) {
|
||||||
if (black.contains(piece)) return black;
|
|
||||||
if (white.contains(piece)) return white;
|
if (white.contains(piece)) return white;
|
||||||
|
if (black.contains(piece)) return black;
|
||||||
if (ban.contains(piece)) return ban;
|
if (ban.contains(piece)) return ban;
|
||||||
return nobody;
|
return nobody;
|
||||||
}
|
}
|
||||||
|
@ -147,8 +147,8 @@ class PieceColor {
|
||||||
static bool isSameColor(String p1, String p2) => of(p1) == of(p2);
|
static bool isSameColor(String p1, String p2) => of(p1) == of(p2);
|
||||||
|
|
||||||
static String opponent(String color) {
|
static String opponent(String color) {
|
||||||
if (color == white) return black;
|
|
||||||
if (color == black) return white;
|
if (color == black) return white;
|
||||||
|
if (color == white) return black;
|
||||||
return color;
|
return color;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -157,8 +157,8 @@ class PieceColor {
|
||||||
|
|
||||||
Map<String, int> pieceColorIndex = {
|
Map<String, int> pieceColorIndex = {
|
||||||
PieceColor.none: 0,
|
PieceColor.none: 0,
|
||||||
PieceColor.black: 1,
|
PieceColor.white: 1,
|
||||||
PieceColor.white: 2,
|
PieceColor.black: 2,
|
||||||
PieceColor.ban: 3
|
PieceColor.ban: 3
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -178,17 +178,17 @@ enum GameOverReason {
|
||||||
drawReasonBoardIsFull
|
drawReasonBoardIsFull
|
||||||
}
|
}
|
||||||
|
|
||||||
enum PieceType { none, blackStone, whiteStone, ban, count, stone }
|
enum PieceType { none, whiteStone, blackStone, ban, count, stone }
|
||||||
|
|
||||||
class Piece {
|
class Piece {
|
||||||
static const noPiece = PieceColor.none;
|
static const noPiece = PieceColor.none;
|
||||||
static const blackStone = PieceColor.black;
|
|
||||||
static const whiteStone = PieceColor.white;
|
static const whiteStone = PieceColor.white;
|
||||||
|
static const blackStone = PieceColor.black;
|
||||||
static const ban = PieceColor.ban;
|
static const ban = PieceColor.ban;
|
||||||
|
|
||||||
static bool isEmpty(String c) => noPiece.contains(c);
|
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 isWhite(String c) => whiteStone.contains(c);
|
||||||
|
static bool isBlack(String c) => blackStone.contains(c);
|
||||||
static bool isBan(String c) => ban.contains(c);
|
static bool isBan(String c) => ban.contains(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -62,7 +62,7 @@ class BoardPainter extends PiecesBasePainter {
|
||||||
|
|
||||||
if (Config.isPieceCountInHandShown) {
|
if (Config.isPieceCountInHandShown) {
|
||||||
var pieceInHandCount =
|
var pieceInHandCount =
|
||||||
Game.instance.position.pieceInHandCount[PieceColor.white];
|
Game.instance.position.pieceInHandCount[PieceColor.black];
|
||||||
|
|
||||||
var pieceInHandCountStr = "";
|
var pieceInHandCountStr = "";
|
||||||
|
|
||||||
|
|
|
@ -112,7 +112,7 @@ class PiecesPainter extends PiecesBasePainter {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Draw shadow of piece
|
// Draw shadow of piece
|
||||||
canvas.drawShadow(shadowPath, Colors.black, 2, true);
|
canvas.drawShadow(shadowPath, Colors.white, 2, true);
|
||||||
|
|
||||||
paint.style = PaintingStyle.fill;
|
paint.style = PaintingStyle.fill;
|
||||||
|
|
||||||
|
@ -130,13 +130,6 @@ class PiecesPainter extends PiecesBasePainter {
|
||||||
|
|
||||||
// Draw Border of Piece
|
// Draw Border of Piece
|
||||||
switch (pps.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:
|
case Piece.whiteStone:
|
||||||
paint.color = AppTheme.whitePieceBorderColor;
|
paint.color = AppTheme.whitePieceBorderColor;
|
||||||
canvas.drawCircle(pps.pos!, pieceRadius, paint); // For debugging
|
canvas.drawCircle(pps.pos!, pieceRadius, paint); // For debugging
|
||||||
|
@ -144,6 +137,13 @@ class PiecesPainter extends PiecesBasePainter {
|
||||||
canvas.drawCircle(pps.pos!, pieceInnerRadius, paint);
|
canvas.drawCircle(pps.pos!, pieceInnerRadius, paint);
|
||||||
blurPositionColor = Color(Config.whitePieceColor).withOpacity(0.1);
|
blurPositionColor = Color(Config.whitePieceColor).withOpacity(0.1);
|
||||||
break;
|
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:
|
case Piece.ban:
|
||||||
//print("pps.piece is Ban");
|
//print("pps.piece is Ban");
|
||||||
break;
|
break;
|
||||||
|
@ -159,17 +159,17 @@ class PiecesPainter extends PiecesBasePainter {
|
||||||
final int row = focusIndex! ~/ 7, column = focusIndex % 7;
|
final int row = focusIndex! ~/ 7, column = focusIndex % 7;
|
||||||
|
|
||||||
focusPositionColor = Color.fromARGB(
|
focusPositionColor = Color.fromARGB(
|
||||||
(Color(Config.blackPieceColor).alpha +
|
(Color(Config.whitePieceColor).alpha +
|
||||||
Color(Config.whitePieceColor).alpha) ~/
|
Color(Config.blackPieceColor).alpha) ~/
|
||||||
2,
|
2,
|
||||||
(Color(Config.blackPieceColor).red +
|
(Color(Config.whitePieceColor).red +
|
||||||
Color(Config.whitePieceColor).red) ~/
|
Color(Config.blackPieceColor).red) ~/
|
||||||
2,
|
2,
|
||||||
(Color(Config.blackPieceColor).green +
|
(Color(Config.whitePieceColor).green +
|
||||||
Color(Config.whitePieceColor).green) ~/
|
Color(Config.blackPieceColor).green) ~/
|
||||||
2,
|
2,
|
||||||
(Color(Config.blackPieceColor).blue +
|
(Color(Config.whitePieceColor).blue +
|
||||||
Color(Config.whitePieceColor).blue) ~/
|
Color(Config.blackPieceColor).blue) ~/
|
||||||
2)
|
2)
|
||||||
.withOpacity(0.5);
|
.withOpacity(0.5);
|
||||||
|
|
||||||
|
|
|
@ -93,8 +93,8 @@ class _GamePageState extends State<GamePage> with RouteAware {
|
||||||
final winner = Game.instance.position.winner;
|
final winner = Game.instance.position.winner;
|
||||||
|
|
||||||
Map<String, String> colorWinStrings = {
|
Map<String, String> colorWinStrings = {
|
||||||
PieceColor.black: S.of(context).blackWin,
|
|
||||||
PieceColor.white: S.of(context).whiteWin,
|
PieceColor.white: S.of(context).whiteWin,
|
||||||
|
PieceColor.black: S.of(context).blackWin,
|
||||||
PieceColor.draw: S.of(context).draw
|
PieceColor.draw: S.of(context).draw
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -140,8 +140,8 @@ class _GamePageState extends State<GamePage> with RouteAware {
|
||||||
// TODO
|
// TODO
|
||||||
// WAR: Fix first tap response slow when piece count changed
|
// WAR: Fix first tap response slow when piece count changed
|
||||||
if (position.phase == Phase.placing &&
|
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();
|
Game.instance.newGame();
|
||||||
|
|
||||||
if (Game.instance.isAiToMove()) {
|
if (Game.instance.isAiToMove()) {
|
||||||
|
@ -180,9 +180,9 @@ class _GamePageState extends State<GamePage> with RouteAware {
|
||||||
if (Game.instance.engineType == EngineType.humanVsAi && mounted) {
|
if (Game.instance.engineType == EngineType.humanVsAi && mounted) {
|
||||||
changeStatus(S.of(context).tipPlaced);
|
changeStatus(S.of(context).tipPlaced);
|
||||||
} else if (mounted) {
|
} else if (mounted) {
|
||||||
var side = Game.instance.sideToMove == PieceColor.black
|
var side = Game.instance.sideToMove == PieceColor.white
|
||||||
? S.of(context).white
|
? S.of(context).black
|
||||||
: S.of(context).black;
|
: S.of(context).white;
|
||||||
changeStatus(side + S.of(context).tipToMove);
|
changeStatus(side + S.of(context).tipToMove);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -279,9 +279,9 @@ class _GamePageState extends State<GamePage> with RouteAware {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (mounted) {
|
if (mounted) {
|
||||||
var them = Game.instance.sideToMove == PieceColor.black
|
var them = Game.instance.sideToMove == PieceColor.white
|
||||||
? S.of(context).white
|
? S.of(context).black
|
||||||
: S.of(context).black;
|
: S.of(context).white;
|
||||||
if (mounted) {
|
if (mounted) {
|
||||||
changeStatus(them + S.of(context).tipToMove);
|
changeStatus(them + S.of(context).tipToMove);
|
||||||
}
|
}
|
||||||
|
@ -381,9 +381,9 @@ class _GamePageState extends State<GamePage> with RouteAware {
|
||||||
mounted) {
|
mounted) {
|
||||||
if (widget.engineType == EngineType.aiVsAi) {
|
if (widget.engineType == EngineType.aiVsAi) {
|
||||||
String score =
|
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();
|
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 getGameOverReasonString(GameOverReason? reason, String? winner) {
|
||||||
//String winnerStr =
|
//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 =
|
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 = {
|
Map<GameOverReason, String> reasonMap = {
|
||||||
GameOverReason.loseReasonlessThanThree:
|
GameOverReason.loseReasonlessThanThree:
|
||||||
|
@ -496,20 +496,20 @@ class _GamePageState extends State<GamePage> with RouteAware {
|
||||||
}
|
}
|
||||||
|
|
||||||
GameResult getGameResult(var winner) {
|
GameResult getGameResult(var winner) {
|
||||||
if (isAi[PieceColor.black]! && isAi[PieceColor.white]!) {
|
if (isAi[PieceColor.white]! && isAi[PieceColor.black]!) {
|
||||||
return GameResult.none;
|
return GameResult.none;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (winner == PieceColor.black) {
|
if (winner == PieceColor.white) {
|
||||||
if (isAi[PieceColor.black]!) {
|
if (isAi[PieceColor.white]!) {
|
||||||
return GameResult.lose;
|
return GameResult.lose;
|
||||||
} else {
|
} else {
|
||||||
return GameResult.win;
|
return GameResult.win;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (winner == PieceColor.white) {
|
if (winner == PieceColor.black) {
|
||||||
if (isAi[PieceColor.white]!) {
|
if (isAi[PieceColor.black]!) {
|
||||||
return GameResult.lose;
|
return GameResult.lose;
|
||||||
} else {
|
} else {
|
||||||
return GameResult.win;
|
return GameResult.win;
|
||||||
|
@ -703,10 +703,10 @@ class _GamePageState extends State<GamePage> with RouteAware {
|
||||||
|
|
||||||
if (Game.instance.position.phase == Phase.gameOver) {
|
if (Game.instance.position.phase == Phase.gameOver) {
|
||||||
switch (Game.instance.position.winner) {
|
switch (Game.instance.position.winner) {
|
||||||
case PieceColor.black:
|
case PieceColor.white:
|
||||||
iconArrow = Icons.toggle_off_outlined;
|
iconArrow = Icons.toggle_off_outlined;
|
||||||
break;
|
break;
|
||||||
case PieceColor.white:
|
case PieceColor.black:
|
||||||
iconArrow = Icons.toggle_on_outlined;
|
iconArrow = Icons.toggle_on_outlined;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -715,10 +715,10 @@ class _GamePageState extends State<GamePage> with RouteAware {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
switch (Game.instance.sideToMove) {
|
switch (Game.instance.sideToMove) {
|
||||||
case PieceColor.black:
|
case PieceColor.white:
|
||||||
iconArrow = Icons.keyboard_arrow_left;
|
iconArrow = Icons.keyboard_arrow_left;
|
||||||
break;
|
break;
|
||||||
case PieceColor.white:
|
case PieceColor.black:
|
||||||
iconArrow = Icons.keyboard_arrow_right;
|
iconArrow = Icons.keyboard_arrow_right;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -754,11 +754,11 @@ class _GamePageState extends State<GamePage> with RouteAware {
|
||||||
"\n" +
|
"\n" +
|
||||||
S.of(context).player1 +
|
S.of(context).player1 +
|
||||||
": " +
|
": " +
|
||||||
Game.instance.position.score[PieceColor.black].toString() +
|
Game.instance.position.score[PieceColor.white].toString() +
|
||||||
"\n" +
|
"\n" +
|
||||||
S.of(context).player2 +
|
S.of(context).player2 +
|
||||||
": " +
|
": " +
|
||||||
Game.instance.position.score[PieceColor.white].toString() +
|
Game.instance.position.score[PieceColor.black].toString() +
|
||||||
"\n" +
|
"\n" +
|
||||||
S.of(context).draw +
|
S.of(context).draw +
|
||||||
": " +
|
": " +
|
||||||
|
@ -770,25 +770,25 @@ class _GamePageState extends State<GamePage> with RouteAware {
|
||||||
" " +
|
" " +
|
||||||
S.of(context).inHand +
|
S.of(context).inHand +
|
||||||
": " +
|
": " +
|
||||||
Game.instance.position.pieceInHandCount[PieceColor.black].toString() +
|
Game.instance.position.pieceInHandCount[PieceColor.white].toString() +
|
||||||
"\n" +
|
"\n" +
|
||||||
S.of(context).player2 +
|
S.of(context).player2 +
|
||||||
" " +
|
" " +
|
||||||
S.of(context).inHand +
|
S.of(context).inHand +
|
||||||
": " +
|
": " +
|
||||||
Game.instance.position.pieceInHandCount[PieceColor.white].toString() +
|
Game.instance.position.pieceInHandCount[PieceColor.black].toString() +
|
||||||
"\n" +
|
"\n" +
|
||||||
S.of(context).player1 +
|
S.of(context).player1 +
|
||||||
" " +
|
" " +
|
||||||
S.of(context).onBoard +
|
S.of(context).onBoard +
|
||||||
": " +
|
": " +
|
||||||
Game.instance.position.pieceOnBoardCount[PieceColor.black].toString() +
|
Game.instance.position.pieceOnBoardCount[PieceColor.white].toString() +
|
||||||
"\n" +
|
"\n" +
|
||||||
S.of(context).player2 +
|
S.of(context).player2 +
|
||||||
" " +
|
" " +
|
||||||
S.of(context).onBoard +
|
S.of(context).onBoard +
|
||||||
": " +
|
": " +
|
||||||
Game.instance.position.pieceOnBoardCount[PieceColor.white].toString() +
|
Game.instance.position.pieceOnBoardCount[PieceColor.black].toString() +
|
||||||
"\n";
|
"\n";
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,8 +54,8 @@ class _PersonalizationSettingsPageState
|
||||||
S.of(context).boardColor: Config.boardBackgroundColor,
|
S.of(context).boardColor: Config.boardBackgroundColor,
|
||||||
S.of(context).backgroudColor: Config.darkBackgroundColor,
|
S.of(context).backgroudColor: Config.darkBackgroundColor,
|
||||||
S.of(context).lineColor: Config.boardLineColor,
|
S.of(context).lineColor: Config.boardLineColor,
|
||||||
S.of(context).blackPieceColor: Config.blackPieceColor,
|
|
||||||
S.of(context).whitePieceColor: Config.whitePieceColor,
|
S.of(context).whitePieceColor: Config.whitePieceColor,
|
||||||
|
S.of(context).blackPieceColor: Config.blackPieceColor,
|
||||||
};
|
};
|
||||||
|
|
||||||
AlertDialog alert = AlertDialog(
|
AlertDialog alert = AlertDialog(
|
||||||
|
@ -79,10 +79,10 @@ class _PersonalizationSettingsPageState
|
||||||
Config.darkBackgroundColor = pickerColor.value;
|
Config.darkBackgroundColor = pickerColor.value;
|
||||||
} else if (colorString == S.of(context).lineColor) {
|
} else if (colorString == S.of(context).lineColor) {
|
||||||
Config.boardLineColor = pickerColor.value;
|
Config.boardLineColor = pickerColor.value;
|
||||||
} else if (colorString == S.of(context).blackPieceColor) {
|
|
||||||
Config.blackPieceColor = pickerColor.value;
|
|
||||||
} else if (colorString == S.of(context).whitePieceColor) {
|
} else if (colorString == S.of(context).whitePieceColor) {
|
||||||
Config.whitePieceColor = pickerColor.value;
|
Config.whitePieceColor = pickerColor.value;
|
||||||
|
} else if (colorString == S.of(context).blackPieceColor) {
|
||||||
|
Config.blackPieceColor = pickerColor.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
Config.save();
|
Config.save();
|
||||||
|
@ -277,16 +277,16 @@ class _PersonalizationSettingsPageState
|
||||||
ListItemDivider(),
|
ListItemDivider(),
|
||||||
SettingsListTile(
|
SettingsListTile(
|
||||||
context: context,
|
context: context,
|
||||||
titleString: S.of(context).blackPieceColor,
|
titleString: S.of(context).whitePieceColor,
|
||||||
trailingColor: Config.blackPieceColor,
|
trailingColor: Config.whitePieceColor,
|
||||||
onTap: () => showColorDialog(S.of(context).blackPieceColor),
|
onTap: () => showColorDialog(S.of(context).whitePieceColor),
|
||||||
),
|
),
|
||||||
ListItemDivider(),
|
ListItemDivider(),
|
||||||
SettingsListTile(
|
SettingsListTile(
|
||||||
context: context,
|
context: context,
|
||||||
titleString: S.of(context).whitePieceColor,
|
titleString: S.of(context).blackPieceColor,
|
||||||
trailingColor: Config.whitePieceColor,
|
trailingColor: Config.blackPieceColor,
|
||||||
onTap: () => showColorDialog(S.of(context).whitePieceColor),
|
onTap: () => showColorDialog(S.of(context).blackPieceColor),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|
|
@ -110,11 +110,11 @@ class _RuleSettingsPageState extends State<RuleSettingsPage> {
|
||||||
ListItemDivider(),
|
ListItemDivider(),
|
||||||
SettingsSwitchListTile(
|
SettingsSwitchListTile(
|
||||||
context: context,
|
context: context,
|
||||||
value: Config.isBlackLoseButNotDrawWhenBoardFull,
|
value: Config.isWhiteLoseButNotDrawWhenBoardFull,
|
||||||
onChanged: setIsBlackLoseButNotDrawWhenBoardFull,
|
onChanged: setIsWhiteLoseButNotDrawWhenBoardFull,
|
||||||
titleString: S.of(context).isBlackLoseButNotDrawWhenBoardFull,
|
titleString: S.of(context).isWhiteLoseButNotDrawWhenBoardFull,
|
||||||
subtitleString:
|
subtitleString:
|
||||||
S.of(context).isBlackLoseButNotDrawWhenBoardFull_Detail,
|
S.of(context).isWhiteLoseButNotDrawWhenBoardFull_Detail,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
@ -234,10 +234,10 @@ class _RuleSettingsPageState extends State<RuleSettingsPage> {
|
||||||
Config.save();
|
Config.save();
|
||||||
}
|
}
|
||||||
|
|
||||||
setIsBlackLoseButNotDrawWhenBoardFull(bool value) async {
|
setIsWhiteLoseButNotDrawWhenBoardFull(bool value) async {
|
||||||
setState(() {
|
setState(() {
|
||||||
rule.isBlackLoseButNotDrawWhenBoardFull =
|
rule.isWhiteLoseButNotDrawWhenBoardFull =
|
||||||
Config.isBlackLoseButNotDrawWhenBoardFull = value;
|
Config.isWhiteLoseButNotDrawWhenBoardFull = value;
|
||||||
});
|
});
|
||||||
|
|
||||||
Config.save();
|
Config.save();
|
||||||
|
|
|
@ -88,10 +88,10 @@ Game::Game(
|
||||||
|
|
||||||
#ifdef QT_GUI_LIB
|
#ifdef QT_GUI_LIB
|
||||||
// The command line of AI and controller
|
// 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)),
|
connect(aiThread[WHITE], SIGNAL(command(const string &, bool)),
|
||||||
this, SLOT(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)),
|
connect(this->gameTest, SIGNAL(command(const string &, bool)),
|
||||||
this, SLOT(command(const string &, bool)));
|
this, SLOT(command(const string &, bool)));
|
||||||
|
@ -128,8 +128,8 @@ void Game::loadSettings()
|
||||||
|
|
||||||
settings = new QSettings(SETTINGS_FILE, QSettings::IniFormat);
|
settings = new QSettings(SETTINGS_FILE, QSettings::IniFormat);
|
||||||
|
|
||||||
setEngineBlack(empty? false : settings->value("Options/BlackIsAiPlayer").toBool());
|
setEngineWhite(empty? false : settings->value("Options/WhiteIsAiPlayer").toBool());
|
||||||
setEngineWhite(empty ? true : settings->value("Options/WhiteIsAiPlayer").toBool());
|
setEngineBlack(empty ? true : settings->value("Options/BlackIsAiPlayer").toBool());
|
||||||
setFixWindowSize(empty ? false : settings->value("Options/FixWindowSize").toBool());
|
setFixWindowSize(empty ? false : settings->value("Options/FixWindowSize").toBool());
|
||||||
setSound(empty ? true : settings->value("Options/Sound").toBool());
|
setSound(empty ? true : settings->value("Options/Sound").toBool());
|
||||||
setAnimation(empty ? true : settings->value("Options/Animation").toBool());
|
setAnimation(empty ? true : settings->value("Options/Animation").toBool());
|
||||||
|
@ -217,7 +217,7 @@ void Game::gameStart()
|
||||||
|
|
||||||
void Game::gameReset()
|
void Game::gameReset()
|
||||||
{
|
{
|
||||||
while (aiThread[BLACK]->searching || aiThread[WHITE]->searching) {
|
while (aiThread[WHITE]->searching || aiThread[BLACK]->searching) {
|
||||||
loggerDebug(".");
|
loggerDebug(".");
|
||||||
QThread::msleep(100);
|
QThread::msleep(100);
|
||||||
}
|
}
|
||||||
|
@ -244,7 +244,7 @@ void Game::gameReset()
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
position.reset();
|
position.reset();
|
||||||
elapsedSeconds[BLACK] = elapsedSeconds[WHITE] = 0;
|
elapsedSeconds[WHITE] = elapsedSeconds[BLACK] = 0;
|
||||||
sideToMove = position.side_to_move();
|
sideToMove = position.side_to_move();
|
||||||
|
|
||||||
// Stop threads
|
// Stop threads
|
||||||
|
@ -269,7 +269,7 @@ void Game::gameReset()
|
||||||
|
|
||||||
for (int i = 0; i < rule.piecesCount; i++) {
|
for (int i = 0; i < rule.piecesCount; i++) {
|
||||||
// The first piece
|
// The first piece
|
||||||
md = isInverted ? PieceItem::Models::whitePiece : PieceItem::Models::blackPiece;
|
md = isInverted ? PieceItem::Models::blackPiece : PieceItem::Models::whitePiece;
|
||||||
PieceItem *newP = new PieceItem;
|
PieceItem *newP = new PieceItem;
|
||||||
newP->setModel(md);
|
newP->setModel(md);
|
||||||
newP->setPos(scene.pos_p1);
|
newP->setPos(scene.pos_p1);
|
||||||
|
@ -280,7 +280,7 @@ void Game::gameReset()
|
||||||
scene.addItem(newP);
|
scene.addItem(newP);
|
||||||
|
|
||||||
// Backhand piece
|
// Backhand piece
|
||||||
md = isInverted ? PieceItem::Models::blackPiece : PieceItem::Models::whitePiece;
|
md = isInverted ? PieceItem::Models::whitePiece : PieceItem::Models::blackPiece;
|
||||||
newP = new PieceItem;
|
newP = new PieceItem;
|
||||||
newP->setModel(md);
|
newP->setModel(md);
|
||||||
newP->setPos(scene.pos_p2);
|
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 the rule does not require timing, time1 and time2 represent the time used
|
||||||
if (timeLimit <= 0) {
|
if (timeLimit <= 0) {
|
||||||
// Clear the player's used time
|
// Clear the player's used time
|
||||||
remainingTime[BLACK] = remainingTime[WHITE] = 0;
|
remainingTime[WHITE] = remainingTime[BLACK] = 0;
|
||||||
} else {
|
} else {
|
||||||
// Set the player's remaining time to a limited time
|
// Set the player's remaining time to a limited time
|
||||||
remainingTime[BLACK] = remainingTime[WHITE] = timeLimit;
|
remainingTime[WHITE] = remainingTime[BLACK] = timeLimit;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update move history
|
// Update move history
|
||||||
|
@ -309,7 +309,7 @@ void Game::gameReset()
|
||||||
currentRow = 0;
|
currentRow = 0;
|
||||||
|
|
||||||
// Signal the main window to update the LCD display
|
// 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 time1Changed(qtime.toString("hh:mm:ss"));
|
||||||
emit time2Changed(qtime.toString("hh:mm:ss"));
|
emit time2Changed(qtime.toString("hh:mm:ss"));
|
||||||
|
|
||||||
|
@ -320,16 +320,16 @@ void Game::gameReset()
|
||||||
|
|
||||||
// Update LCD display
|
// Update LCD display
|
||||||
emit nGamesPlayedChanged(QString::number(position.gamesPlayedCount, 10));
|
emit nGamesPlayedChanged(QString::number(position.gamesPlayedCount, 10));
|
||||||
emit score1Changed(QString::number(position.score[BLACK], 10));
|
emit score1Changed(QString::number(position.score[WHITE], 10));
|
||||||
emit score2Changed(QString::number(position.score[WHITE], 10));
|
emit score2Changed(QString::number(position.score[BLACK], 10));
|
||||||
emit scoreDrawChanged(QString::number(position.score_draw, 10));
|
emit scoreDrawChanged(QString::number(position.score_draw, 10));
|
||||||
|
|
||||||
// Update winning rate LCD display
|
// 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;
|
int winningRate_1 = 0, winningRate_2 = 0, winningRate_draw = 0;
|
||||||
if (position.gamesPlayedCount != 0) {
|
if (position.gamesPlayedCount != 0) {
|
||||||
winningRate_1 = position.score[BLACK] * 10000 / position.gamesPlayedCount;
|
winningRate_1 = position.score[WHITE] * 10000 / position.gamesPlayedCount;
|
||||||
winningRate_2 = position.score[WHITE] * 10000 / position.gamesPlayedCount;
|
winningRate_2 = position.score[BLACK] * 10000 / position.gamesPlayedCount;
|
||||||
winningRate_draw = position.score_draw * 10000 / position.gamesPlayedCount;
|
winningRate_draw = position.score_draw * 10000 / position.gamesPlayedCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -353,14 +353,14 @@ void Game::setInvert(bool arg)
|
||||||
// For all pieces
|
// For all pieces
|
||||||
for (PieceItem *pieceItem : pieceList) {
|
for (PieceItem *pieceItem : pieceList) {
|
||||||
if (pieceItem) {
|
if (pieceItem) {
|
||||||
// Black -> White
|
|
||||||
if (pieceItem->getModel() == PieceItem::Models::blackPiece)
|
|
||||||
pieceItem->setModel(PieceItem::Models::whitePiece);
|
|
||||||
|
|
||||||
// White -> Black
|
// White -> Black
|
||||||
else if (pieceItem->getModel() == PieceItem::Models::whitePiece)
|
if (pieceItem->getModel() == PieceItem::Models::whitePiece)
|
||||||
pieceItem->setModel(PieceItem::Models::blackPiece);
|
pieceItem->setModel(PieceItem::Models::blackPiece);
|
||||||
|
|
||||||
|
// Black -> White
|
||||||
|
else if (pieceItem->getModel() == PieceItem::Models::blackPiece)
|
||||||
|
pieceItem->setModel(PieceItem::Models::whitePiece);
|
||||||
|
|
||||||
// Refresh checkerboard display
|
// Refresh checkerboard display
|
||||||
pieceItem->update();
|
pieceItem->update();
|
||||||
}
|
}
|
||||||
|
@ -385,7 +385,7 @@ void Game::setRule(int ruleNo, int stepLimited /*= -1*/, int timeLimited /*= 0*/
|
||||||
}
|
}
|
||||||
|
|
||||||
const int r = ruleNo;
|
const int r = ruleNo;
|
||||||
elapsedSeconds[BLACK] = elapsedSeconds[WHITE] = 0;
|
elapsedSeconds[WHITE] = elapsedSeconds[BLACK] = 0;
|
||||||
|
|
||||||
char record[64] = { 0 };
|
char record[64] = { 0 };
|
||||||
if (snprintf(record, Position::RECORD_LEN_MAX, "r%1d s%03zu t%02d", r + 1, rule.maxStepsLedToDraw, 0) <= 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)
|
void Game::setEngineWhite(bool enabled)
|
||||||
{
|
{
|
||||||
setEngine(WHITE, enabled);
|
setEngine(WHITE, enabled);
|
||||||
settings->setValue("Options/WhiteIsAiPlayer", 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)
|
void Game::setAiDepthTime(int time1, int time2)
|
||||||
{
|
{
|
||||||
stopAndWaitAiThreads();
|
stopAndWaitAiThreads();
|
||||||
|
|
||||||
aiThread[BLACK]->setAi(&position, time1);
|
aiThread[WHITE]->setAi(&position, time1);
|
||||||
aiThread[WHITE]->setAi(&position, time2);
|
aiThread[BLACK]->setAi(&position, time2);
|
||||||
|
|
||||||
startAiThreads();
|
startAiThreads();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Game::getAiDepthTime(int &time1, int &time2)
|
void Game::getAiDepthTime(int &time1, int &time2)
|
||||||
{
|
{
|
||||||
time1 = aiThread[BLACK]->getTimeLimit();
|
time1 = aiThread[WHITE]->getTimeLimit();
|
||||||
time2 = aiThread[WHITE]->getTimeLimit();
|
time2 = aiThread[BLACK]->getTimeLimit();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Game::setFixWindowSize(bool arg) noexcept
|
void Game::setFixWindowSize(bool arg) noexcept
|
||||||
|
@ -470,8 +470,8 @@ void Game::setSound(bool arg) noexcept
|
||||||
void Game::playSound(GameSound soundType, Color c)
|
void Game::playSound(GameSound soundType, Color c)
|
||||||
{
|
{
|
||||||
string soundDir = ":/sound/resources/sound/";
|
string soundDir = ":/sound/resources/sound/";
|
||||||
string sideStr = c == BLACK ? "B" : "W";
|
string sideStr = c == WHITE ? "W" : "B";
|
||||||
string oppenentStr = c == WHITE? "B" : "W";
|
string oppenentStr = c == BLACK? "W" : "B";
|
||||||
string filename;
|
string filename;
|
||||||
|
|
||||||
switch (soundType) {
|
switch (soundType) {
|
||||||
|
@ -763,7 +763,7 @@ void Game::updateTime()
|
||||||
|
|
||||||
if (timePoint >= *ourSeconds) {
|
if (timePoint >= *ourSeconds) {
|
||||||
*ourSeconds = timePoint;
|
*ourSeconds = timePoint;
|
||||||
startTime = currentTime - (elapsedSeconds[BLACK] + elapsedSeconds[WHITE]);
|
startTime = currentTime - (elapsedSeconds[WHITE] + elapsedSeconds[BLACK]);
|
||||||
} else {
|
} else {
|
||||||
*ourSeconds = currentTime - startTime - theirSeconds;
|
*ourSeconds = currentTime - startTime - theirSeconds;
|
||||||
}
|
}
|
||||||
|
@ -776,18 +776,18 @@ void Game::timerEvent(QTimerEvent *event)
|
||||||
|
|
||||||
// Player's time spent
|
// Player's time spent
|
||||||
updateTime();
|
updateTime();
|
||||||
remainingTime[BLACK] = get_elapsed_time(BLACK);
|
|
||||||
remainingTime[WHITE] = get_elapsed_time(WHITE);
|
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 the rule requires a timer, time1 and time2 indicate a countdown
|
||||||
if (timeLimit > 0) {
|
if (timeLimit > 0) {
|
||||||
// Player's remaining time
|
// Player's remaining time
|
||||||
remainingTime[BLACK] = timeLimit - remainingTime[BLACK];
|
|
||||||
remainingTime[WHITE] = timeLimit - remainingTime[WHITE];
|
remainingTime[WHITE] = timeLimit - remainingTime[WHITE];
|
||||||
|
remainingTime[BLACK] = timeLimit - remainingTime[BLACK];
|
||||||
}
|
}
|
||||||
|
|
||||||
qt1 = QTime(0, 0, 0, 0).addSecs(static_cast<int>(remainingTime[BLACK]));
|
qt1 = QTime(0, 0, 0, 0).addSecs(static_cast<int>(remainingTime[WHITE]));
|
||||||
qt2 = 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 time1Changed(qt1.toString("hh:mm:ss"));
|
||||||
emit time2Changed(qt2.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
|
// When the computer is playing chess or searching, the click is invalid
|
||||||
if (isAIsTurn() ||
|
if (isAIsTurn() ||
|
||||||
aiThread[BLACK]->searching ||
|
aiThread[WHITE]->searching ||
|
||||||
aiThread[WHITE]->searching) {
|
aiThread[BLACK]->searching) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1005,12 +1005,12 @@ bool Game::actionPiece(QPointF p)
|
||||||
gameReset();
|
gameReset();
|
||||||
gameStart();
|
gameStart();
|
||||||
|
|
||||||
if (isAiPlayer[BLACK]) {
|
|
||||||
setEngine(BLACK, true);
|
|
||||||
}
|
|
||||||
if (isAiPlayer[WHITE]) {
|
if (isAiPlayer[WHITE]) {
|
||||||
setEngine(WHITE, true);
|
setEngine(WHITE, true);
|
||||||
}
|
}
|
||||||
|
if (isAiPlayer[BLACK]) {
|
||||||
|
setEngine(BLACK, true);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
pauseThreads();
|
pauseThreads();
|
||||||
}
|
}
|
||||||
|
@ -1060,10 +1060,10 @@ bool Game::command(const string &cmd, bool update /* = true */)
|
||||||
|
|
||||||
#ifdef QT_GUI_LIB
|
#ifdef QT_GUI_LIB
|
||||||
// Prevents receiving instructions sent by threads that end late
|
// Prevents receiving instructions sent by threads that end late
|
||||||
if (sender() == aiThread[BLACK] && !isAiPlayer[BLACK])
|
if (sender() == aiThread[WHITE] && !isAiPlayer[WHITE])
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (sender() == aiThread[WHITE] && !isAiPlayer[WHITE])
|
if (sender() == aiThread[BLACK] && !isAiPlayer[BLACK])
|
||||||
return false;
|
return false;
|
||||||
#endif // QT_GUI_LIB
|
#endif // QT_GUI_LIB
|
||||||
|
|
||||||
|
@ -1170,15 +1170,15 @@ bool Game::command(const string &cmd, bool update /* = true */)
|
||||||
|
|
||||||
#ifdef TIME_STAT
|
#ifdef TIME_STAT
|
||||||
loggerDebug("Sort Time: %I64d + %I64d = %I64dms\n",
|
loggerDebug("Sort Time: %I64d + %I64d = %I64dms\n",
|
||||||
aiThread[BLACK]->sortTime, aiThread[WHITE]->sortTime,
|
aiThread[WHITE]->sortTime, aiThread[BLACK]->sortTime,
|
||||||
(aiThread[BLACK]->sortTime + aiThread[WHITE]->sortTime));
|
(aiThread[WHITE]->sortTime + aiThread[BLACK]->sortTime));
|
||||||
aiThread[BLACK]->sortTime = aiThread[WHITE]->sortTime = 0;
|
aiThread[WHITE]->sortTime = aiThread[BLACK]->sortTime = 0;
|
||||||
#endif // TIME_STAT
|
#endif // TIME_STAT
|
||||||
#ifdef CYCLE_STAT
|
#ifdef CYCLE_STAT
|
||||||
loggerDebug("Sort Cycle: %ld + %ld = %ld\n",
|
loggerDebug("Sort Cycle: %ld + %ld = %ld\n",
|
||||||
aiThread[BLACK]->sortCycle, aiThread[WHITE]->sortCycle,
|
aiThread[WHITE]->sortCycle, aiThread[BLACK]->sortCycle,
|
||||||
(aiThread[BLACK]->sortCycle + aiThread[WHITE]->sortCycle));
|
(aiThread[WHITE]->sortCycle + aiThread[BLACK]->sortCycle));
|
||||||
aiThread[BLACK]->sortCycle = aiThread[WHITE]->sortCycle = 0;
|
aiThread[WHITE]->sortCycle = aiThread[BLACK]->sortCycle = 0;
|
||||||
#endif // CYCLE_STAT
|
#endif // CYCLE_STAT
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
|
@ -1189,26 +1189,26 @@ bool Game::command(const string &cmd, bool update /* = true */)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef TRANSPOSITION_TABLE_DEBUG
|
#ifdef TRANSPOSITION_TABLE_DEBUG
|
||||||
size_t hashProbeCount_1 = aiThread[BLACK]->ttHitCount + aiThread[BLACK]->ttMissCount;
|
size_t hashProbeCount_1 = aiThread[WHITE]->ttHitCount + aiThread[WHITE]->ttMissCount;
|
||||||
size_t hashProbeCount_2 = 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",
|
loggerDebug("[key 1] probe: %llu, hit: %llu, miss: %llu, hit rate: %llu%%\n",
|
||||||
hashProbeCount_1,
|
hashProbeCount_1,
|
||||||
aiThread[BLACK]->ttHitCount,
|
aiThread[WHITE]->ttHitCount,
|
||||||
aiThread[BLACK]->ttMissCount,
|
aiThread[WHITE]->ttMissCount,
|
||||||
aiThread[BLACK]->ttHitCount * 100 / hashProbeCount_1);
|
aiThread[WHITE]->ttHitCount * 100 / hashProbeCount_1);
|
||||||
|
|
||||||
loggerDebug("[key 2] probe: %llu, hit: %llu, miss: %llu, hit rate: %llu%%\n",
|
loggerDebug("[key 2] probe: %llu, hit: %llu, miss: %llu, hit rate: %llu%%\n",
|
||||||
hashProbeCount_2,
|
hashProbeCount_2,
|
||||||
aiThread[WHITE]->ttHitCount,
|
aiThread[BLACK]->ttHitCount,
|
||||||
aiThread[WHITE]->ttMissCount,
|
aiThread[BLACK]->ttMissCount,
|
||||||
aiThread[WHITE]->ttHitCount * 100 / hashProbeCount_2);
|
aiThread[BLACK]->ttHitCount * 100 / hashProbeCount_2);
|
||||||
|
|
||||||
loggerDebug("[key +] probe: %llu, hit: %llu, miss: %llu, hit rate: %llu%%\n",
|
loggerDebug("[key +] probe: %llu, hit: %llu, miss: %llu, hit rate: %llu%%\n",
|
||||||
hashProbeCount_1 + hashProbeCount_2,
|
hashProbeCount_1 + hashProbeCount_2,
|
||||||
aiThread[BLACK]->ttHitCount + aiThread[WHITE]->ttHitCount,
|
aiThread[WHITE]->ttHitCount + aiThread[BLACK]->ttHitCount,
|
||||||
aiThread[BLACK]->ttMissCount + aiThread[WHITE]->ttMissCount,
|
aiThread[WHITE]->ttMissCount + aiThread[BLACK]->ttMissCount,
|
||||||
(aiThread[BLACK]->ttHitCount + aiThread[WHITE]->ttHitCount ) * 100 / (hashProbeCount_1 + hashProbeCount_2));
|
(aiThread[WHITE]->ttHitCount + aiThread[BLACK]->ttHitCount ) * 100 / (hashProbeCount_1 + hashProbeCount_2));
|
||||||
#endif // TRANSPOSITION_TABLE_DEBUG
|
#endif // TRANSPOSITION_TABLE_DEBUG
|
||||||
|
|
||||||
if (gameOptions.getAutoRestart()) {
|
if (gameOptions.getAutoRestart()) {
|
||||||
|
@ -1217,12 +1217,12 @@ bool Game::command(const string &cmd, bool update /* = true */)
|
||||||
gameReset();
|
gameReset();
|
||||||
gameStart();
|
gameStart();
|
||||||
|
|
||||||
if (isAiPlayer[BLACK]) {
|
|
||||||
setEngine(BLACK, true);
|
|
||||||
}
|
|
||||||
if (isAiPlayer[WHITE]) {
|
if (isAiPlayer[WHITE]) {
|
||||||
setEngine(WHITE, true);
|
setEngine(WHITE, true);
|
||||||
}
|
}
|
||||||
|
if (isAiPlayer[BLACK]) {
|
||||||
|
setEngine(BLACK, true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef MESSAGEBOX_ENABLE
|
#ifdef MESSAGEBOX_ENABLE
|
||||||
|
@ -1248,19 +1248,19 @@ bool Game::command(const string &cmd, bool update /* = true */)
|
||||||
}
|
}
|
||||||
#endif // ANALYZE_POSITION
|
#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) {
|
if (total == 0) {
|
||||||
bwinrate = 0;
|
bwinrate = 0;
|
||||||
wwinrate = 0;
|
wwinrate = 0;
|
||||||
drawrate = 0;
|
drawrate = 0;
|
||||||
} else {
|
} else {
|
||||||
bwinrate = (float)position.score[BLACK] * 100 / total;
|
bwinrate = (float)position.score[WHITE] * 100 / total;
|
||||||
wwinrate = (float)position.score[WHITE] * 100 / total;
|
wwinrate = (float)position.score[BLACK] * 100 / total;
|
||||||
drawrate = (float)position.score_draw * 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;
|
cout << fixed << setprecision(2) << bwinrate << "% : " << wwinrate << "% : " << drawrate << "%" << endl;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -1323,7 +1323,7 @@ bool Game::updateScence(Position &p)
|
||||||
piece->setSelected(false);
|
piece->setSelected(false);
|
||||||
|
|
||||||
// Convert the subscript of pieceList to the chess code of game
|
// 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;
|
int j;
|
||||||
|
|
||||||
|
@ -1354,11 +1354,11 @@ bool Game::updateScence(Position &p)
|
||||||
// If not, place the pieces outside the chessboard
|
// If not, place the pieces outside the chessboard
|
||||||
if (j == (RANK_NB) * (FILE_NB + 1)) {
|
if (j == (RANK_NB) * (FILE_NB + 1)) {
|
||||||
// Judge whether it is a removing seed or an unplaced one
|
// Judge whether it is a removing seed or an unplaced one
|
||||||
if (key & B_STONE) {
|
if (key & W_STONE) {
|
||||||
pos = (key - 0x11 < nTotalPieces / 2 - p.count<IN_HAND>(BLACK)) ?
|
pos = (key - 0x11 < nTotalPieces / 2 - p.count<IN_HAND>(WHITE)) ?
|
||||||
scene.pos_p2_g : scene.pos_p1;
|
scene.pos_p2_g : scene.pos_p1;
|
||||||
} else {
|
} 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;
|
scene.pos_p1_g : scene.pos_p2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1415,7 +1415,7 @@ bool Game::updateScence(Position &p)
|
||||||
int ipos = p.current_square();
|
int ipos = p.current_square();
|
||||||
if (ipos) {
|
if (ipos) {
|
||||||
key = board[p.current_square()];
|
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) {
|
if (ipos >= 0 && ipos < nTotalPieces) {
|
||||||
currentPiece = pieceList.at(static_cast<size_t>(ipos));
|
currentPiece = pieceList.at(static_cast<size_t>(ipos));
|
||||||
currentPiece->setSelected(true);
|
currentPiece->setSelected(true);
|
||||||
|
@ -1430,16 +1430,16 @@ bool Game::updateScence(Position &p)
|
||||||
animationGroup->start(QAbstractAnimation::DeleteWhenStopped);
|
animationGroup->start(QAbstractAnimation::DeleteWhenStopped);
|
||||||
|
|
||||||
// Update LCD display
|
// Update LCD display
|
||||||
emit score1Changed(QString::number(p.score[BLACK], 10));
|
emit score1Changed(QString::number(p.score[WHITE], 10));
|
||||||
emit score2Changed(QString::number(p.score[WHITE], 10));
|
emit score2Changed(QString::number(p.score[BLACK], 10));
|
||||||
emit scoreDrawChanged(QString::number(p.score_draw, 10));
|
emit scoreDrawChanged(QString::number(p.score_draw, 10));
|
||||||
|
|
||||||
// Update winning rate LCD display
|
// 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;
|
int winningRate_1 = 0, winningRate_2 = 0, winningRate_draw = 0;
|
||||||
if (position.gamesPlayedCount != 0) {
|
if (position.gamesPlayedCount != 0) {
|
||||||
winningRate_1 = position.score[BLACK] * 10000 / position.gamesPlayedCount;
|
winningRate_1 = position.score[WHITE] * 10000 / position.gamesPlayedCount;
|
||||||
winningRate_2 = position.score[WHITE] * 10000 / position.gamesPlayedCount;
|
winningRate_2 = position.score[BLACK] * 10000 / position.gamesPlayedCount;
|
||||||
winningRate_draw = position.score_draw * 10000 / position.gamesPlayedCount;
|
winningRate_draw = position.score_draw * 10000 / position.gamesPlayedCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1501,29 +1501,29 @@ void Game::saveScore()
|
||||||
|
|
||||||
textStream << gameTest->getKey() << endl << endl;
|
textStream << gameTest->getKey() << endl << endl;
|
||||||
|
|
||||||
if (isAiPlayer[BLACK]) {
|
|
||||||
textStream << "Black:\tAI Player" << endl;
|
|
||||||
} else {
|
|
||||||
textStream << "Black:\tHuman Player" << endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isAiPlayer[WHITE]) {
|
if (isAiPlayer[WHITE]) {
|
||||||
textStream << "White:\tAI Player" << endl;
|
textStream << "White:\tAI Player" << endl;
|
||||||
} else {
|
} else {
|
||||||
textStream << "White:\tHuman Player" << endl;
|
textStream << "White:\tHuman Player" << endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isAiPlayer[BLACK]) {
|
||||||
|
textStream << "Black:\tAI Player" << endl;
|
||||||
|
} else {
|
||||||
|
textStream << "Black:\tHuman Player" << endl;
|
||||||
|
}
|
||||||
|
|
||||||
textStream << "" << 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) {
|
if (position.gamesPlayedCount == 0) {
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
textStream << "Sum\t" + QString::number(position.gamesPlayedCount) << endl;
|
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;
|
textStream << "Draw\t" + QString::number(position.score_draw) + "\t" + QString::number(position.score_draw * 10000 / position.gamesPlayedCount) << endl;
|
||||||
|
|
||||||
out:
|
out:
|
||||||
|
@ -1539,9 +1539,9 @@ inline char Game::color_to_char(Color color)
|
||||||
inline std::string Game::char_to_string(char ch)
|
inline std::string Game::char_to_string(char ch)
|
||||||
{
|
{
|
||||||
if (ch == '1') {
|
if (ch == '1') {
|
||||||
return "黑方";
|
|
||||||
} else {
|
|
||||||
return "白方";
|
return "白方";
|
||||||
|
} else {
|
||||||
|
return "黑方";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1602,8 +1602,8 @@ void Game::setTips()
|
||||||
|
|
||||||
switch (p.phase) {
|
switch (p.phase) {
|
||||||
case Phase::ready:
|
case Phase::ready:
|
||||||
tips = "轮到" + turnStr + "落子,剩余" + std::to_string(p.pieceInHandCount[BLACK]) + "子" +
|
tips = "轮到" + turnStr + "落子,剩余" + std::to_string(p.pieceInHandCount[WHITE]) + "子" +
|
||||||
" 比分 " + to_string(p.score[BLACK]) + ":" + to_string(p.score[WHITE]) + ", 和棋 " + to_string(p.score_draw);
|
" 比分 " + to_string(p.score[WHITE]) + ":" + to_string(p.score[BLACK]) + ", 和棋 " + to_string(p.score_draw);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Phase::placing:
|
case Phase::placing:
|
||||||
|
@ -1625,11 +1625,11 @@ void Game::setTips()
|
||||||
case Phase::gameOver:
|
case Phase::gameOver:
|
||||||
appendGameOverReasonToMoveHistory();
|
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) {
|
switch (p.winner) {
|
||||||
case BLACK:
|
|
||||||
case WHITE:
|
case WHITE:
|
||||||
|
case BLACK:
|
||||||
winnerStr = char_to_string(color_to_char(p.winner));
|
winnerStr = char_to_string(color_to_char(p.winner));
|
||||||
resultStr = winnerStr + "获胜!";
|
resultStr = winnerStr + "获胜!";
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -213,13 +213,13 @@ public slots:
|
||||||
// Set edit chess state
|
// Set edit chess state
|
||||||
void setEditing(bool arg = true) noexcept;
|
void setEditing(bool arg = true) noexcept;
|
||||||
|
|
||||||
// Set black and white inversion state
|
// Set white and black inversion state
|
||||||
void setInvert(bool arg = true);
|
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
|
// 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 setEngine(Color color, bool enabled = true);
|
||||||
void setEngineBlack(bool enabled);
|
|
||||||
void setEngineWhite(bool enabled);
|
void setEngineWhite(bool enabled);
|
||||||
|
void setEngineBlack(bool enabled);
|
||||||
|
|
||||||
// Fix Window Size
|
// Fix Window Size
|
||||||
void setFixWindowSize(bool arg) noexcept;
|
void setFixWindowSize(bool arg) noexcept;
|
||||||
|
@ -288,58 +288,58 @@ public slots:
|
||||||
|
|
||||||
void threadsSetAi(Position *p)
|
void threadsSetAi(Position *p)
|
||||||
{
|
{
|
||||||
aiThread[BLACK]->setAi(p);
|
|
||||||
aiThread[WHITE]->setAi(p);
|
aiThread[WHITE]->setAi(p);
|
||||||
|
aiThread[BLACK]->setAi(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
void resetAiPlayers()
|
void resetAiPlayers()
|
||||||
{
|
{
|
||||||
isAiPlayer[BLACK] = false;
|
|
||||||
isAiPlayer[WHITE] = false;
|
isAiPlayer[WHITE] = false;
|
||||||
|
isAiPlayer[BLACK] = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void createAiThreads()
|
void createAiThreads()
|
||||||
{
|
{
|
||||||
aiThread[BLACK] = new Thread(0);
|
|
||||||
aiThread[BLACK]->us = BLACK;
|
|
||||||
|
|
||||||
aiThread[WHITE] = new Thread(0);
|
aiThread[WHITE] = new Thread(0);
|
||||||
aiThread[WHITE]->us = WHITE;
|
aiThread[WHITE]->us = WHITE;
|
||||||
|
|
||||||
|
aiThread[BLACK] = new Thread(0);
|
||||||
|
aiThread[BLACK]->us = BLACK;
|
||||||
}
|
}
|
||||||
|
|
||||||
void startAiThreads()
|
void startAiThreads()
|
||||||
{
|
{
|
||||||
if (isAiPlayer[BLACK]) {
|
|
||||||
aiThread[BLACK]->start_searching();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isAiPlayer[WHITE]) {
|
if (isAiPlayer[WHITE]) {
|
||||||
aiThread[WHITE]->start_searching();
|
aiThread[WHITE]->start_searching();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isAiPlayer[BLACK]) {
|
||||||
|
aiThread[BLACK]->start_searching();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void stopAndWaitAiThreads()
|
void stopAndWaitAiThreads()
|
||||||
{
|
{
|
||||||
if (isAiPlayer[BLACK]) {
|
|
||||||
aiThread[BLACK]->pause();
|
|
||||||
aiThread[BLACK]->wait_for_search_finished();
|
|
||||||
}
|
|
||||||
if (isAiPlayer[WHITE]) {
|
if (isAiPlayer[WHITE]) {
|
||||||
aiThread[WHITE]->pause();
|
aiThread[WHITE]->pause();
|
||||||
aiThread[WHITE]->wait_for_search_finished();
|
aiThread[WHITE]->wait_for_search_finished();
|
||||||
}
|
}
|
||||||
|
if (isAiPlayer[BLACK]) {
|
||||||
|
aiThread[BLACK]->pause();
|
||||||
|
aiThread[BLACK]->wait_for_search_finished();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void pauseThreads()
|
void pauseThreads()
|
||||||
{
|
{
|
||||||
aiThread[BLACK]->pause();
|
|
||||||
aiThread[WHITE]->pause();
|
aiThread[WHITE]->pause();
|
||||||
|
aiThread[BLACK]->pause();
|
||||||
}
|
}
|
||||||
|
|
||||||
void waitThreads()
|
void waitThreads()
|
||||||
{
|
{
|
||||||
aiThread[BLACK]->wait_for_search_finished();
|
|
||||||
aiThread[WHITE]->wait_for_search_finished();
|
aiThread[WHITE]->wait_for_search_finished();
|
||||||
|
aiThread[BLACK]->wait_for_search_finished();
|
||||||
}
|
}
|
||||||
|
|
||||||
void pauseAndWaitThreads()
|
void pauseAndWaitThreads()
|
||||||
|
@ -357,8 +357,8 @@ public slots:
|
||||||
|
|
||||||
void deleteAiThreads()
|
void deleteAiThreads()
|
||||||
{
|
{
|
||||||
delete aiThread[BLACK];
|
|
||||||
delete aiThread[WHITE];
|
delete aiThread[WHITE];
|
||||||
|
delete aiThread[BLACK];
|
||||||
}
|
}
|
||||||
|
|
||||||
// According to the signal and state of qgraphics scene, select, drop or delete the sub objects
|
// 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
|
// Is it in "Edit chess game" state
|
||||||
bool isEditing;
|
bool isEditing;
|
||||||
|
|
||||||
// Reverse black and white
|
// Reverse white and black
|
||||||
bool isInverted;
|
bool isInverted;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -191,10 +191,10 @@ void MillGameWindow::initialize()
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
connect(ui.actionEngine1_T, SIGNAL(toggled(bool)),
|
connect(ui.actionEngine1_T, SIGNAL(toggled(bool)),
|
||||||
game, SLOT(setEngineBlack(bool)));
|
game, SLOT(setEngineWhite(bool)));
|
||||||
|
|
||||||
connect(ui.actionEngine2_R, SIGNAL(toggled(bool)),
|
connect(ui.actionEngine2_R, SIGNAL(toggled(bool)),
|
||||||
game, SLOT(setEngineWhite(bool)));
|
game, SLOT(setEngineBlack(bool)));
|
||||||
|
|
||||||
connect(ui.actionFixWindowSize, SIGNAL(toggled(bool)),
|
connect(ui.actionFixWindowSize, SIGNAL(toggled(bool)),
|
||||||
game, SLOT(setFixWindowSize(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 &)));
|
connect(ui.pushButton_option, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(ctxMenu(const QPoint &)));
|
||||||
#endif /* MOBILE_APP_UI */
|
#endif /* MOBILE_APP_UI */
|
||||||
|
|
||||||
ui.actionEngine1_T->setChecked(game->isAiPlayer[BLACK]);
|
ui.actionEngine1_T->setChecked(game->isAiPlayer[WHITE]);
|
||||||
ui.actionEngine2_R->setChecked(game->isAiPlayer[WHITE]);
|
ui.actionEngine2_R->setChecked(game->isAiPlayer[BLACK]);
|
||||||
|
|
||||||
ui.actionFixWindowSize->setChecked(game->fixWindowSizeEnabled());
|
ui.actionFixWindowSize->setChecked(game->fixWindowSizeEnabled());
|
||||||
ui.actionSound_S->setChecked(game->soundEnabled());
|
ui.actionSound_S->setChecked(game->soundEnabled());
|
||||||
|
@ -588,12 +588,12 @@ void MillGameWindow::on_actionNew_N_triggered()
|
||||||
QString whoWin;
|
QString whoWin;
|
||||||
|
|
||||||
switch (game->getPosition()->get_winner()) {
|
switch (game->getPosition()->get_winner()) {
|
||||||
case BLACK:
|
|
||||||
whoWin = "Black-Win";
|
|
||||||
break;
|
|
||||||
case WHITE:
|
case WHITE:
|
||||||
whoWin = "White-Win";
|
whoWin = "White-Win";
|
||||||
break;
|
break;
|
||||||
|
case BLACK:
|
||||||
|
whoWin = "Black-Win";
|
||||||
|
break;
|
||||||
case DRAW:
|
case DRAW:
|
||||||
whoWin = "Draw";
|
whoWin = "Draw";
|
||||||
break;
|
break;
|
||||||
|
@ -712,17 +712,17 @@ void MillGameWindow::on_actionEdit_E_toggled(bool arg1)
|
||||||
|
|
||||||
void MillGameWindow::on_actionInvert_I_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) {
|
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.actionEngine1_T->setIcon(QIcon(":/icon/Resources/icon/Black.png"));
|
||||||
ui.actionEngine2_R->setIcon(QIcon(":/icon/Resources/icon/White.png"));
|
ui.actionEngine2_R->setIcon(QIcon(":/icon/Resources/icon/White.png"));
|
||||||
ui.picLabel1->setPixmap(QPixmap(":/icon/Resources/icon/Black.png"));
|
ui.picLabel1->setPixmap(QPixmap(":/icon/Resources/icon/Black.png"));
|
||||||
ui.picLabel2->setPixmap(QPixmap(":/icon/Resources/icon/White.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
|
// 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);
|
auto *label_image = new QLabel(dialog);
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
label_icon1->setPixmap(QPixmap(QString::fromUtf8(":/image/resources/image/black_piece.png")));
|
label_icon1->setPixmap(QPixmap(QString::fromUtf8(":/image/resources/image/white_piece.png")));
|
||||||
label_icon2->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_icon1->setAlignment(Qt::AlignCenter);
|
||||||
label_icon2->setAlignment(Qt::AlignCenter);
|
label_icon2->setAlignment(Qt::AlignCenter);
|
||||||
label_icon1->setFixedSize(32, 32);
|
label_icon1->setFixedSize(32, 32);
|
||||||
|
|
|
@ -82,27 +82,27 @@ void PieceItem::paint(QPainter *painter,
|
||||||
// Empty models don't draw pieces
|
// Empty models don't draw pieces
|
||||||
|
|
||||||
switch (model) {
|
switch (model) {
|
||||||
case Models::blackPiece:
|
case Models::whitePiece:
|
||||||
// If the model is black, draw black pieces
|
// If the model is white, draw white pieces
|
||||||
#ifdef MOBILE_APP_UI
|
#ifdef MOBILE_APP_UI
|
||||||
painter->setPen(Qt::NoPen);
|
painter->setPen(Qt::NoPen);
|
||||||
painter->setBrush(QColor(0, 93, 172));
|
painter->setBrush(QColor(0, 93, 172));
|
||||||
painter->drawEllipse(-size / 2, -size / 2, size, size);
|
painter->drawEllipse(-size / 2, -size / 2, size, size);
|
||||||
#else
|
#else
|
||||||
painter->drawPixmap(-size / 2, -size / 2, size, size,
|
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 */
|
#endif /* MOBILE_APP_UI */
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Models::whitePiece:
|
case Models::blackPiece:
|
||||||
// If the model is white, draw white pieces
|
// If the model is black, draw black pieces
|
||||||
#ifdef MOBILE_APP_UI
|
#ifdef MOBILE_APP_UI
|
||||||
painter->setPen(Qt::NoPen);
|
painter->setPen(Qt::NoPen);
|
||||||
painter->setBrush(QColor(231, 36, 46));
|
painter->setBrush(QColor(231, 36, 46));
|
||||||
painter->drawEllipse(-size / 2, -size / 2, size, size);
|
painter->drawEllipse(-size / 2, -size / 2, size, size);
|
||||||
#else
|
#else
|
||||||
painter->drawPixmap(-size / 2, -size / 2, size, size,
|
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 */
|
#endif /* MOBILE_APP_UI */
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -111,10 +111,10 @@ void PieceItem::paint(QPainter *painter,
|
||||||
|
|
||||||
// If the model requires the serial number to be displayed
|
// If the model requires the serial number to be displayed
|
||||||
if (showNum) {
|
if (showNum) {
|
||||||
if (model == Models::blackPiece)
|
if (model == Models::whitePiece)
|
||||||
painter->setPen(QColor(255, 255, 255));
|
painter->setPen(QColor(255, 255, 255));
|
||||||
|
|
||||||
if (model == Models::whitePiece)
|
if (model == Models::blackPiece)
|
||||||
painter->setPen(QColor(0, 0, 0));
|
painter->setPen(QColor(0, 0, 0));
|
||||||
|
|
||||||
QFont font;
|
QFont font;
|
||||||
|
|
|
@ -59,8 +59,8 @@ public:
|
||||||
enum class Models
|
enum class Models
|
||||||
{
|
{
|
||||||
noPiece = 0x1,
|
noPiece = 0x1,
|
||||||
blackPiece = 0x2,
|
whitePiece = 0x2,
|
||||||
whitePiece = 0x4,
|
blackPiece = 0x4,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum Models getModel() noexcept
|
enum Models getModel() noexcept
|
||||||
|
@ -111,7 +111,7 @@ protected:
|
||||||
private:
|
private:
|
||||||
enum Models model;
|
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 num {1};
|
||||||
|
|
||||||
int size {0};
|
int size {0};
|
||||||
|
|
Loading…
Reference in New Issue