flutter: Add posKey and zobrist

And do some refactor.
This commit is contained in:
Calcitem 2021-04-17 11:52:33 +08:00
parent 4753276f42
commit adf331811b
3 changed files with 314 additions and 41 deletions

View File

@ -24,8 +24,10 @@ import 'package:sanmill/services/audios.dart';
import 'mills.dart';
import 'types.dart';
import 'zobrist.dart';
int repetition = 0;
late List<int> posKeyHistory;
class StateInfo {
// Copied when making a move
@ -233,11 +235,11 @@ class Position {
pieceToRemoveCount.toString() +
" ";
int sideIsBlack = _sideToMove == PieceColor.black ? 1 : 0;
int sideIsWhite = _sideToMove == PieceColor.white ? 1 : 0;
ss += st.rule50.toString() +
" " +
(1 + (gamePly - sideIsBlack) ~/ 2).toString();
(1 + (gamePly - sideIsWhite) ~/ 2).toString();
return ss;
}
@ -339,7 +341,42 @@ class Position {
return true;
}
// TODO: THREEFOLD_REPETITION
bool hasRepeated(List<Position> ss) {
for (int i = posKeyHistory.length - 2; i >= 0; i--) {
if (st.key == posKeyHistory[i]) {
return true;
}
}
int size = ss.length;
for (int i = size - 1; i >= 0; i--) {
if (ss[i].move.type == MoveType.remove) {
break;
}
if (st.key == ss[i].st.key) {
return true;
}
}
return false;
}
/// hasGameCycle() tests if the position has a move which draws by repetition.
bool hasGameCycle() {
for (var i in posKeyHistory) {
if (st.key == i) {
repetition++;
if (repetition == 3) {
repetition = 0;
return true;
}
}
}
return false;
}
///////////////////////////////////////////////////////////////////////////////
@ -368,6 +405,10 @@ class Position {
pieceInHandCount[PieceColor.white] = rule.piecesCount;
pieceToRemoveCount = 0;
// TODO:
// MoveList<LEGAL>::create();
// create_mill_table();
currentSquare = 0;
record = "";
@ -424,6 +465,8 @@ class Position {
record = "(" + fileOf(s).toString() + "," + rankOf(s).toString() + ")";
updateKey(s);
currentSquare = s;
int n = millsCount(currentSquare);
@ -459,6 +502,7 @@ class Position {
Audios.playTone('place.mp3');
} else {
pieceToRemoveCount = rule.mayRemoveMultiple ? n : 1;
updateKeyMisc();
action = Act.remove;
Game.instance.focusIndex = squareToIndex[s] ?? invalidIndex;
Audios.playTone('mill.mp3');
@ -497,6 +541,9 @@ class Position {
st.rule50++;
board[s] = _grid[squareToIndex[s]!] = board[currentSquare];
updateKey(s);
revertKey(currentSquare);
board[currentSquare] =
_grid[squareToIndex[currentSquare]!] = Piece.noPiece;
@ -516,6 +563,7 @@ class Position {
}
} else {
pieceToRemoveCount = rule.mayRemoveMultiple ? n : 1;
updateKeyMisc();
action = Act.remove;
Game.instance.focusIndex = squareToIndex[s] ?? invalidIndex;
Audios.playTone('mill.mp3');
@ -543,11 +591,14 @@ class Position {
return false;
}
revertKey(s);
Audios.playTone('remove.mp3');
if (rule.hasBannedLocations && phase == Phase.placing) {
// Remove and put ban
board[s] = _grid[squareToIndex[s]!] = Piece.ban;
updateKey(s);
} else {
// Remove only
board[s] = _grid[squareToIndex[s]!] = Piece.noPiece;
@ -569,6 +620,7 @@ class Position {
currentSquare = 0;
pieceToRemoveCount--;
updateKeyMisc();
if (pieceToRemoveCount > 0) {
return true;
@ -629,6 +681,10 @@ class Position {
return true;
}
String getWinner() {
return winner;
}
void setGameOver(String w, GameOverReason reason) {
phase = Phase.gameOver;
gameOverReason = reason;
@ -677,9 +733,7 @@ class Position {
return true;
}
bool isNoWay = isAllSurrounded();
//print("phase = $phase, action = $action, isAllSurrounded = $isNoWay");
if (phase == Phase.moving && action == Act.select && isNoWay) {
if (phase == Phase.moving && action == Act.select && isAllSurrounded()) {
if (rule.isLoseButNotChangeSideWhenNoWay) {
setGameOver(
PieceColor.opponent(sideToMove()), GameOverReason.loseReasonNoWay);
@ -704,6 +758,7 @@ class Position {
if (board[s] == Piece.ban) {
board[s] = _grid[squareToIndex[s]!] = Piece.noPiece;
revertKey(s);
}
}
}
@ -711,46 +766,38 @@ class Position {
void setSideToMove(String color) {
_sideToMove = color;
us = _sideToMove;
them = PieceColor.opponent(us);
//us = color;
them = PieceColor.opponent(_sideToMove);
}
void changeSideToMove() {
them = _sideToMove;
_sideToMove = PieceColor.opponent(_sideToMove);
setSideToMove(PieceColor.opponent(_sideToMove));
st.key ^= Zobrist.side;
print("$_sideToMove to move.");
}
int pieceOnBoardCountCount() {
pieceOnBoardCount[PieceColor.black] =
pieceOnBoardCount[PieceColor.white] = 0;
int updateKey(int s) {
String pieceType = colorOn(s);
for (int f = 1; f < fileExNumber; f++) {
for (int r = 0; r < rankNumber; r++) {
int s = f * rankNumber + r;
if (board[s] == Piece.blackStone) {
if (pieceOnBoardCount[PieceColor.black] != null) {
pieceOnBoardCount[PieceColor.black] =
pieceOnBoardCount[PieceColor.black]! + 1;
}
} else if (board[s] == Piece.whiteStone) {
if (pieceOnBoardCount[PieceColor.white] != null) {
pieceOnBoardCount[PieceColor.white] =
pieceOnBoardCount[PieceColor.white]! + 1;
}
}
}
}
st.key ^= Zobrist.psq[pieceColorIndex[pieceType]!][s];
if (pieceOnBoardCount[PieceColor.black]! > rule.piecesCount ||
pieceOnBoardCount[PieceColor.white]! > rule.piecesCount) {
return -1;
}
return pieceOnBoardCount[PieceColor.black]! +
pieceOnBoardCount[PieceColor.white]!;
return st.key;
}
int revertKey(int s) {
return updateKey(s);
}
int updateKeyMisc() {
st.key = st.key << Zobrist.KEY_MISC_BIT >> Zobrist.KEY_MISC_BIT;
st.key |= (pieceToRemoveCount) << (32 - Zobrist.KEY_MISC_BIT);
return st.key;
}
///////////////////////////////////////////////////////////////////////////////
String colorOn(int sq) {
return board[sq];
}
@ -837,8 +884,6 @@ class Position {
return true;
}
// TODO: surrounded_pieces_count
bool isAllSurrounded() {
// Full
if (pieceOnBoardCount[PieceColor.black]! +
@ -879,6 +924,8 @@ class Position {
return (s == 16 || s == 18 || s == 20 || s == 22);
}
///////////////////////////////////////////////////////////////////////////////
int getNPiecesInHand() {
pieceInHandCount[PieceColor.black] =
rule.piecesCount - pieceOnBoardCount[PieceColor.black]!;
@ -931,8 +978,34 @@ class Position {
return -1;
}
String getWinner() {
return winner;
int pieceOnBoardCountCount() {
pieceOnBoardCount[PieceColor.black] =
pieceOnBoardCount[PieceColor.white] = 0;
for (int f = 1; f < fileExNumber; f++) {
for (int r = 0; r < rankNumber; r++) {
int s = f * rankNumber + r;
if (board[s] == Piece.blackStone) {
if (pieceOnBoardCount[PieceColor.black] != null) {
pieceOnBoardCount[PieceColor.black] =
pieceOnBoardCount[PieceColor.black]! + 1;
}
} else if (board[s] == Piece.whiteStone) {
if (pieceOnBoardCount[PieceColor.white] != null) {
pieceOnBoardCount[PieceColor.white] =
pieceOnBoardCount[PieceColor.white]! + 1;
}
}
}
}
if (pieceOnBoardCount[PieceColor.black]! > rule.piecesCount ||
pieceOnBoardCount[PieceColor.white]! > rule.piecesCount) {
return -1;
}
return pieceOnBoardCount[PieceColor.black]! +
pieceOnBoardCount[PieceColor.white]!;
}
///////////////////////////////////////////////////////////////////////////////

View File

@ -155,6 +155,13 @@ class PieceColor {
String operator -(String c) => opponent(c);
}
Map<String, int> pieceColorIndex = {
PieceColor.none: 0,
PieceColor.black: 1,
PieceColor.white: 2,
PieceColor.ban: 3
};
enum Phase { none, ready, placing, moving, gameOver }
enum Act { none, select, place, remove }
@ -234,7 +241,7 @@ enum LineDirection { horizontal, vertical, slash }
const lineDirectionNumber = 3;
enum File { A, B, C }
enum File { none, A, B, C }
const fileNumber = 3;
const fileExNumber = fileNumber + 2;

View File

@ -0,0 +1,193 @@
/*
This file is part of Sanmill.
Copyright (C) 2019-2021 The Sanmill developers (see AUTHORS file)
Sanmill is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Sanmill is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
class Zobrist {
static const int KEY_MISC_BIT = 2;
static var psq = [
[
0x4E421A,
0x3962FF,
0x6DB6EE,
0x219AE1,
0x1F3DE2,
0xD9AACB,
0xD51733,
0xD3F9EA,
0xF5A7BB,
0xDC4109,
0xEE4319,
0x7CDA7A,
0xFD7B4D,
0x4138BE,
0xCCBB2D,
0xDA6097,
0x06D827,
0xCBC16C,
0x46F125,
0xE29F22,
0xCAAB94,
0x5B02DB,
0x877CD6,
0x35E438,
0x49FDAE,
0xE68314,
0xBE1664,
0x1F49D3,
0x50F5B1,
0x149AAF,
0xF509B9,
0x47AEB5,
0x18E993,
0x76BB4F,
0xFE1739,
0xF87B87,
0x0A8CD2,
0x630C6B,
0x88F5B4,
0x0A583E,
],
[
0xA0128E,
0x6F2251,
0x51E99D,
0x6D35BF,
0x66D6D9,
0x87D366,
0x75A57A,
0x534FC4,
0x1FE34B,
0xAD6FB0,
0xE5679D,
0xF88AFF,
0x0462DA,
0x4BDE96,
0xF28912,
0x10537E,
0x26D8EA,
0x37E6E7,
0x0871D9,
0xCD5F4F,
0xF4AFA1,
0x44A51B,
0x772656,
0x8B7965,
0xD8F17D,
0x80F3D7,
0x6B6206,
0x19B8BB,
0xFBC229,
0x0FCAB4,
0xFD7374,
0xA647B9,
0x296A8D,
0xA3D742,
0x624D6D,
0x459FD4,
0xCE8C26,
0x965448,
0x410171,
0x1EDD7A,
],
[
0x1FCF95,
0xA5634E,
0x21976A,
0x32902D,
0x55A27C,
0x49EC5F,
0x0176A1,
0xCAAAEF,
0x145886,
0xB4C808,
0x0153EE,
0x7D78DF,
0xE9C3C5,
0x66B7A6,
0x3CD930,
0xDBBA23,
0xF19841,
0x6BEFDF,
0xB979FE,
0xBA4D06,
0x96AECF,
0x33B96E,
0x76A99C,
0x1B8762,
0x747B20,
0x0DEC24,
0xA4E632,
0xBA2442,
0x59C91B,
0x41482D,
0xF2CD39,
0x30E9C1,
0x6B156D,
0xC7F191,
0x012D36,
0xC66B36,
0x631560,
0xA891FC,
0xF6C8AC,
0xD80B94,
],
[
0xF641E9,
0xF164BF,
0x2DBE4C,
0xE2A40C,
0x53FA06,
0x4F3117,
0x0ACA70,
0x2C72F5,
0xC81047,
0x4B76AE,
0xEB55C8,
0x0DB6EF,
0x7F57AB,
0x22D060,
0x390554,
0xDE9A43,
0x6583AF,
0x41D141,
0x9CBF92,
0x7E528F,
0x2BEFA1,
0x5C5FDC,
0x4DDAFA,
0x7C98A1,
0x65A13B,
0x2953BF,
0x8769A8,
0xE6DCA1,
0xD01A6E,
0xBCD935,
0x175659,
0xAD5A73,
0xB04E7D,
0x815F53,
0x12469A,
0xB2F25C,
0x564E4B,
0xD19437,
0xA4F63C,
0x7169E5,
]
];
static int side = 0x201906;
}