flutter: position 增加代码
This commit is contained in:
parent
76435e9507
commit
0563a41392
|
@ -23,7 +23,7 @@ enum MoveType { place, move, remove }
|
||||||
|
|
||||||
enum Phase { none, ready, placing, moving, gameOver }
|
enum Phase { none, ready, placing, moving, gameOver }
|
||||||
|
|
||||||
enum Action { none, select, place, remove }
|
enum Act { none, select, place, remove }
|
||||||
|
|
||||||
enum GameOverReason {
|
enum GameOverReason {
|
||||||
noReason,
|
noReason,
|
||||||
|
|
|
@ -17,9 +17,12 @@
|
||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
|
|
||||||
import '../common/types.dart';
|
import '../common/types.dart';
|
||||||
import '../mill/mill.dart';
|
import '../mill/mill.dart';
|
||||||
import '../mill/recorder.dart';
|
import '../mill/recorder.dart';
|
||||||
|
import '../mill/rule.dart';
|
||||||
|
|
||||||
class StateInfo {
|
class StateInfo {
|
||||||
/*
|
/*
|
||||||
|
@ -63,7 +66,7 @@ class Position {
|
||||||
GameOverReason gameOverReason = GameOverReason.noReason;
|
GameOverReason gameOverReason = GameOverReason.noReason;
|
||||||
|
|
||||||
Phase phase = Phase.none;
|
Phase phase = Phase.none;
|
||||||
Action action = Action.none;
|
Act action = Act.none;
|
||||||
|
|
||||||
int scoreBlack = 0;
|
int scoreBlack = 0;
|
||||||
int scoreWhite = 0;
|
int scoreWhite = 0;
|
||||||
|
@ -72,7 +75,9 @@ class Position {
|
||||||
int currentSquare;
|
int currentSquare;
|
||||||
int nPlayed = 0;
|
int nPlayed = 0;
|
||||||
|
|
||||||
//Move move;
|
String cmdline;
|
||||||
|
|
||||||
|
//int _move;
|
||||||
|
|
||||||
Position.init() {
|
Position.init() {
|
||||||
for (var i = 0; i < _grid.length; i++) {
|
for (var i = 0; i < _grid.length; i++) {
|
||||||
|
@ -145,6 +150,112 @@ class Position {
|
||||||
|
|
||||||
bool empty(int sq) => pieceOn(sq) == Piece.noPiece;
|
bool empty(int sq) => pieceOn(sq) == Piece.noPiece;
|
||||||
|
|
||||||
|
void updateScore() {}
|
||||||
|
|
||||||
|
void setSideToMove(String color) {
|
||||||
|
_sideToMove = color;
|
||||||
|
}
|
||||||
|
|
||||||
|
String movedPiece(int move) {
|
||||||
|
return pieceOn(fromSq(move));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool selectPieceFR(int file, int rank) {
|
||||||
|
return selectPieceSQ(makeSquare(file, rank));
|
||||||
|
}
|
||||||
|
|
||||||
|
void putPiece(var pt, int index) {
|
||||||
|
_grid[index] = pt;
|
||||||
|
_board[indexToSquare[index]] = pt;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool putPieceFR(int file, int rank) {
|
||||||
|
bool ret = putPieceSQ(makeSquare(file, rank));
|
||||||
|
|
||||||
|
if (ret) {
|
||||||
|
updateScore();
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool movePieceFR(int file1, int rank1, int file2, int rank2) {
|
||||||
|
return movePieceSQ(makeSquare(file1, rank1), makeSquare(file2, rank2));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool removePieceFR(int file, int rank) {
|
||||||
|
bool ret = removePieceSQ(makeSquare(file, rank));
|
||||||
|
|
||||||
|
if (ret) {
|
||||||
|
updateScore();
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool selectPieceSQ(int sq) {
|
||||||
|
// TODO
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool putPieceSQ(int sq) {
|
||||||
|
// TODO
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool movePieceSQ(int fromSq, int toSq) {
|
||||||
|
// TODO
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool removePieceSQ(int sq) {
|
||||||
|
// TODO
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool movePiece(int fromSq, int toSq) {
|
||||||
|
if (selectPieceSQ(fromSq)) {
|
||||||
|
return putPieceSQ(toSq);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void set(String fenStr) {
|
||||||
|
/*
|
||||||
|
A FEN string defines a particular position using only the ASCII character set.
|
||||||
|
|
||||||
|
A FEN string contains six fields separated by a space. The fields are:
|
||||||
|
|
||||||
|
1) Piece placement. Each rank is described, starting
|
||||||
|
with rank 1 and ending with rank 8. Within each rank, the contents of each
|
||||||
|
square are described from file A through file C. Following the Standard
|
||||||
|
Algebraic Notation (SAN), each piece is identified by a single letter taken
|
||||||
|
from the standard English names. White pieces are designated using "O"
|
||||||
|
whilst Black uses "@". Blank uses "*". Banned uses "X".
|
||||||
|
noted using digits 1 through 8 (the number of blank squares), and "/"
|
||||||
|
separates ranks.
|
||||||
|
|
||||||
|
2) Active color. "w" means white moves next, "b" means black.
|
||||||
|
|
||||||
|
3) Phrase.
|
||||||
|
|
||||||
|
4) Action.
|
||||||
|
|
||||||
|
5) Black on board/Black in hand/White on board/White in hand/need to remove
|
||||||
|
|
||||||
|
6) Halfmove clock. This is the number of halfmoves since the last
|
||||||
|
capture. This is used to determine if a draw can be claimed under the
|
||||||
|
fifty-move rule.
|
||||||
|
|
||||||
|
7) Fullmove number. The number of the full move. It starts at 1, and is
|
||||||
|
incremented after Black's move.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/// fen() returns a FEN representation of the position.
|
/// fen() returns a FEN representation of the position.
|
||||||
|
|
||||||
String fen() {
|
String fen() {
|
||||||
|
@ -195,13 +306,13 @@ class Position {
|
||||||
|
|
||||||
// Action
|
// Action
|
||||||
switch (action) {
|
switch (action) {
|
||||||
case Action.place:
|
case Act.place:
|
||||||
ss += "p";
|
ss += "p";
|
||||||
break;
|
break;
|
||||||
case Action.select:
|
case Act.select:
|
||||||
ss += "s";
|
ss += "s";
|
||||||
break;
|
break;
|
||||||
case Action.remove:
|
case Act.remove:
|
||||||
ss += "r";
|
ss += "r";
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -235,11 +346,79 @@ class Position {
|
||||||
return ss;
|
return ss;
|
||||||
}
|
}
|
||||||
|
|
||||||
void putPiece(var pt, int index) {
|
/// Position::legal() tests whether a pseudo-legal move is legal
|
||||||
_grid[index] = pt;
|
|
||||||
_board[indexToSquare[index]] = pt;
|
bool legal(int move) {
|
||||||
|
assert(isOk(move));
|
||||||
|
|
||||||
|
String us = _sideToMove;
|
||||||
|
int fromSQ = fromSq(move);
|
||||||
|
int toSQ = toSq(move);
|
||||||
|
|
||||||
|
if (fromSQ == toSQ) {
|
||||||
|
return false; // TODO: Same with is_ok(m)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (phase == Phase.moving && typeOf(move) != MoveType.remove) {
|
||||||
|
if (movedPiece(move) != us) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Add more
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Position::pseudo_legal() takes a random move and tests whether the move is
|
||||||
|
/// pseudo legal. It is used to validate moves from TT that can be corrupted
|
||||||
|
/// due to SMP concurrent access or hash position key aliasing.
|
||||||
|
|
||||||
|
bool pseudoLegal(int move) {
|
||||||
|
// TODO
|
||||||
|
return legal(move);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
/// Position::do_move() makes a move, and saves all information necessary
|
||||||
|
/// to a StateInfo object. The move is assumed to be legal. Pseudo-legal
|
||||||
|
/// moves should be filtered out before this function is called.
|
||||||
|
|
||||||
|
void doMove(int move) {
|
||||||
|
bool ret = false;
|
||||||
|
|
||||||
|
MoveType mt = typeOf(move);
|
||||||
|
|
||||||
|
switch (mt) {
|
||||||
|
case MoveType.remove:
|
||||||
|
// Reset rule 50 counter
|
||||||
|
rule50 = 0;
|
||||||
|
ret = removePiece(toSq(move));
|
||||||
|
break;
|
||||||
|
case MoveType.move:
|
||||||
|
ret = movePiece(fromSq(move), toSq(move));
|
||||||
|
break;
|
||||||
|
case MoveType.place:
|
||||||
|
ret = putPieceSQ(toSq(move));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ret) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Increment ply counters. In particular, rule50 will be reset to zero later on
|
||||||
|
// in case of a capture.
|
||||||
|
++gamePly;
|
||||||
|
++rule50;
|
||||||
|
++pliesFromNull;
|
||||||
|
|
||||||
|
_move = move;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
String doMove(int from, int to) {
|
String doMove(int from, int to) {
|
||||||
//
|
//
|
||||||
if (!validateMove(from, to)) return null;
|
if (!validateMove(from, to)) return null;
|
||||||
|
@ -351,4 +530,237 @@ class Position {
|
||||||
get lastMove => _recorder.last;
|
get lastMove => _recorder.last;
|
||||||
|
|
||||||
get lastCapturedPosition => _recorder.lastCapturedPosition;
|
get lastCapturedPosition => _recorder.lastCapturedPosition;
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
int piecesOnBoardCount() {
|
||||||
|
pieceCountOnBoardBlack = pieceCountOnBoardWhite = 0;
|
||||||
|
|
||||||
|
for (int f = 1; f < 3 + 2; f++) {
|
||||||
|
for (int r = 0; r < 8; r++) {
|
||||||
|
int s = f * 8 + r;
|
||||||
|
if (_board[s] == Piece.blackStone) {
|
||||||
|
pieceCountOnBoardBlack++;
|
||||||
|
} else if (_board[s] == Piece.whiteStone) {
|
||||||
|
pieceCountOnBoardBlack++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pieceCountOnBoardBlack > rule.nTotalPiecesEachSide ||
|
||||||
|
pieceCountOnBoardWhite > rule.nTotalPiecesEachSide) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return pieceCountOnBoardBlack + pieceCountOnBoardWhite;
|
||||||
|
}
|
||||||
|
|
||||||
|
int piecesInHandCount() {
|
||||||
|
pieceCountInHandBlack = rule.nTotalPiecesEachSide - pieceCountOnBoardBlack;
|
||||||
|
pieceCountInHandWhite = rule.nTotalPiecesEachSide - pieceCountOnBoardWhite;
|
||||||
|
|
||||||
|
return pieceCountOnBoardBlack + pieceCountOnBoardWhite;
|
||||||
|
}
|
||||||
|
|
||||||
|
int setPosition(Rule newRule) {
|
||||||
|
rule = newRule;
|
||||||
|
|
||||||
|
gamePly = 0;
|
||||||
|
rule50 = 0;
|
||||||
|
|
||||||
|
phase = Phase.ready;
|
||||||
|
setSideToMove(Color.black);
|
||||||
|
action = Act.place;
|
||||||
|
|
||||||
|
for (int i = 0; i < _grid.length; i++) _grid[i] = Piece.noPiece;
|
||||||
|
|
||||||
|
for (int i = 0; i < _board.length; i++) _board[i] = Piece.noPiece;
|
||||||
|
|
||||||
|
if (piecesOnBoardCount() == -1) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
piecesInHandCount();
|
||||||
|
pieceCountNeedRemove = 0;
|
||||||
|
|
||||||
|
winner = Color.unknown;
|
||||||
|
|
||||||
|
currentSquare = 0;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool reset() {
|
||||||
|
gamePly = 0;
|
||||||
|
rule50 = 0;
|
||||||
|
|
||||||
|
phase = Phase.ready;
|
||||||
|
setSideToMove(Color.black);
|
||||||
|
action = Act.place;
|
||||||
|
|
||||||
|
winner = Color.unknown;
|
||||||
|
gameOverReason = GameOverReason.noReason;
|
||||||
|
|
||||||
|
for (int i = 0; i < _grid.length; i++) _grid[i] = Piece.noPiece;
|
||||||
|
|
||||||
|
for (int i = 0; i < _board.length; i++) _board[i] = Piece.noPiece;
|
||||||
|
|
||||||
|
pieceCountOnBoardBlack = pieceCountOnBoardWhite = 0;
|
||||||
|
pieceCountInHandBlack = pieceCountInHandWhite = rule.nTotalPiecesEachSide;
|
||||||
|
pieceCountNeedRemove = 0;
|
||||||
|
|
||||||
|
currentSquare = 0;
|
||||||
|
int i = 0; // TODO: rule
|
||||||
|
|
||||||
|
cmdline = "r" +
|
||||||
|
(i + 1).toString() +
|
||||||
|
" " +
|
||||||
|
"s" +
|
||||||
|
rule.maxStepsLedToDraw.toString() +
|
||||||
|
" t" +
|
||||||
|
0.toString();
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool start() {
|
||||||
|
gameOverReason = GameOverReason.noReason;
|
||||||
|
|
||||||
|
switch (phase) {
|
||||||
|
case Phase.placing:
|
||||||
|
case Phase.moving:
|
||||||
|
return false;
|
||||||
|
case Phase.gameOver:
|
||||||
|
reset();
|
||||||
|
continue ready;
|
||||||
|
ready:
|
||||||
|
case Phase.ready:
|
||||||
|
phase = Phase.placing;
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
bool putPiece(int sq)
|
||||||
|
{
|
||||||
|
String piece = Piece.noPiece;
|
||||||
|
String us = _sideToMove;
|
||||||
|
|
||||||
|
if (phase == Phase.gameOver ||
|
||||||
|
action != Act.place ||
|
||||||
|
sq < 0 || sq >= 31 || _board[sq] != Piece.noPiece) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (phase == Phase.ready) {
|
||||||
|
start();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (phase == Phase.placing) {
|
||||||
|
piece = _sideToMove;
|
||||||
|
if (_sideToMove == Color.black) {
|
||||||
|
pieceCountInHandBlack--;
|
||||||
|
pieceCountOnBoardBlack++;
|
||||||
|
}
|
||||||
|
else if (_sideToMove == Color.white) {
|
||||||
|
pieceCountInHandWhite--;
|
||||||
|
pieceCountOnBoardWhite++;
|
||||||
|
}
|
||||||
|
|
||||||
|
_board[sq]= piece;
|
||||||
|
_grid[squareToIndex[sq]] = piece;
|
||||||
|
|
||||||
|
cmdline = "(" + fileOf(sq).toString() + "," + rankOf(sq).toString() + ")";
|
||||||
|
|
||||||
|
currentSquare = sq;
|
||||||
|
|
||||||
|
int n = addMills(currentSquare);
|
||||||
|
|
||||||
|
if (n == 0) {
|
||||||
|
assert(pieceCountInHandBlack >= 0 && pieceCountInHandWhite >= 0);
|
||||||
|
|
||||||
|
if (pieceCountInHandBlack == 0 && pieceCountInHandWhite == 0) {
|
||||||
|
if (checkGameOverCondition()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
phase = Phase.moving;
|
||||||
|
action = Act.select;
|
||||||
|
|
||||||
|
if (rule.hasBannedLocations) {
|
||||||
|
removeBanStones();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!rule.isDefenderMoveFirst) {
|
||||||
|
changeSideToMove();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (checkGameOverCondition()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
changeSideToMove();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
pieceCountNeedRemove = rule.allowRemoveMultiPiecesWhenCloseMultiMill ? n : 1;
|
||||||
|
action = Act.remove;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if (phase == Phase.moving) {
|
||||||
|
|
||||||
|
if (checkGameOverCondition()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if illegal
|
||||||
|
if (pieceCountOnBoard[sideToMove] > rule->nPiecesAtLeast ||
|
||||||
|
!rule->allowFlyWhenRemainThreePieces) {
|
||||||
|
int md;
|
||||||
|
|
||||||
|
for (md = 0; md < MD_NB; md++) {
|
||||||
|
if (s == MoveList<LEGAL>::moveTable[currentSquare][md])
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// not in moveTable
|
||||||
|
if (md == MD_NB) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (updateCmdlist) {
|
||||||
|
sprintf(cmdline, "(%1u,%1u)->(%1u,%1u)",
|
||||||
|
file_of(currentSquare), rank_of(currentSquare),
|
||||||
|
file_of(s), rank_of(s));
|
||||||
|
st.rule50++;
|
||||||
|
}
|
||||||
|
|
||||||
|
board[s] = board[currentSquare];
|
||||||
|
|
||||||
|
board[currentSquare] = NO_PIECE;
|
||||||
|
|
||||||
|
currentSquare = s;
|
||||||
|
int n = add_mills(currentSquare);
|
||||||
|
|
||||||
|
// midgame
|
||||||
|
if (n == 0) {
|
||||||
|
action = ACTION_SELECT;
|
||||||
|
change_side_to_move();
|
||||||
|
|
||||||
|
if (check_gameover_condition()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
pieceCountNeedRemove = rule->allowRemoveMultiPiecesWhenCloseMultiMill ? n : 1;
|
||||||
|
update_key_misc();
|
||||||
|
action = ACTION_REMOVE;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
assert(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue