diff --git a/src/ui/flutter/lib/common/types.dart b/src/ui/flutter/lib/common/types.dart
index 192bb0f7..eb79fa56 100644
--- a/src/ui/flutter/lib/common/types.dart
+++ b/src/ui/flutter/lib/common/types.dart
@@ -23,7 +23,7 @@ enum MoveType { place, move, remove }
enum Phase { none, ready, placing, moving, gameOver }
-enum Action { none, select, place, remove }
+enum Act { none, select, place, remove }
enum GameOverReason {
noReason,
diff --git a/src/ui/flutter/lib/mill/position.dart b/src/ui/flutter/lib/mill/position.dart
index b4e52d7e..e410f0e0 100644
--- a/src/ui/flutter/lib/mill/position.dart
+++ b/src/ui/flutter/lib/mill/position.dart
@@ -17,9 +17,12 @@
along with this program. If not, see .
*/
+import 'package:flutter/cupertino.dart';
+
import '../common/types.dart';
import '../mill/mill.dart';
import '../mill/recorder.dart';
+import '../mill/rule.dart';
class StateInfo {
/*
@@ -63,7 +66,7 @@ class Position {
GameOverReason gameOverReason = GameOverReason.noReason;
Phase phase = Phase.none;
- Action action = Action.none;
+ Act action = Act.none;
int scoreBlack = 0;
int scoreWhite = 0;
@@ -72,7 +75,9 @@ class Position {
int currentSquare;
int nPlayed = 0;
- //Move move;
+ String cmdline;
+
+ //int _move;
Position.init() {
for (var i = 0; i < _grid.length; i++) {
@@ -145,6 +150,112 @@ class Position {
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.
String fen() {
@@ -195,13 +306,13 @@ class Position {
// Action
switch (action) {
- case Action.place:
+ case Act.place:
ss += "p";
break;
- case Action.select:
+ case Act.select:
ss += "s";
break;
- case Action.remove:
+ case Act.remove:
ss += "r";
break;
default:
@@ -235,11 +346,79 @@ class Position {
return ss;
}
- void putPiece(var pt, int index) {
- _grid[index] = pt;
- _board[indexToSquare[index]] = pt;
+ /// Position::legal() tests whether a pseudo-legal move is legal
+
+ 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) {
//
if (!validateMove(from, to)) return null;
@@ -351,4 +530,237 @@ class Position {
get lastMove => _recorder.last;
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::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;
+ }
+ */
}