flutter: Support Step forward & Take back all & Step forward all

This commit is contained in:
Calcitem 2021-05-21 23:26:56 +08:00
parent 8c1e8c2ba0
commit 8677f9f322
5 changed files with 175 additions and 72 deletions

View File

@ -720,9 +720,29 @@
"@takingBack": {
"description": "Taking back..."
},
"done": "done.",
"waiting": "Waiting...",
"@waiting": {
"description": "Waiting..."
},
"stepForward": "Step forward",
"@stepForward": {
"description": "Step forward"
},
"takeBackAll": "Take back all",
"@takeBackAll": {
"description": "Take back all"
},
"stepForwardAll": "Step forward all",
"@stepForwardAll": {
"description": "Step forward all"
},
"moveNow": "Move now",
"@moveNow": {
"description": "Move now"
},
"done": "Done.",
"@done": {
"description": "done."
"description": "Done."
},
"crackMill": "Crack-mill",
"@crackMill": {

View File

@ -178,8 +178,13 @@
"undo": "悔棋",
"undoOption": "悔棋",
"undoOption_Detail": "允许悔棋",
"takeBack": "悔棋",
"takeBack": "回退",
"takingBack": "回退中",
"waiting": "请稍等",
"stepForward": "前进",
"takeBackAll": "回退到底",
"stepForwardAll": "前进到底",
"moveNow": "立即行棋",
"done": "完成",
"crackMill": "不允许吃全三连",
"crackMill_Detail": "若对方所有的子都在三连中, 也不允许吃子。",

View File

@ -1035,11 +1035,15 @@ class Position {
///////////////////////////////////////////////////////////////////////////////
void takeBack() async {
print("TODO: Take back");
void _gotoHistory(int moveIndex) async {
if (recorder == null) {
print("[TakeBack] recorder is null.");
print("[goto] recorder is null.");
return;
}
var history = recorder!.getHistory();
if (moveIndex < -1 || history.length <= moveIndex) {
print("[goto] moveIndex is out of range.");
return;
}
@ -1049,17 +1053,35 @@ class Position {
Game.instance.engineType = EngineType.humanVsHuman;
Game.instance.setWhoIsAi(EngineType.humanVsHuman);
var history = recorder!.getHistory();
var historyBack = history;
await Game.instance.newGame();
for (var i = 0; i < history.length - 1; i++) {
for (var i = 0; i <= moveIndex; i++) {
Game.instance.doMove(history[i].move);
}
// Restore context
Game.instance.engineType = engineTypeBackup;
Game.instance.setWhoIsAi(engineTypeBackup);
recorder!.setHistory(historyBack);
recorder!.cur = moveIndex;
}
void takeBack() async {
_gotoHistory(recorder!.cur - 1);
}
void stepForward() async {
_gotoHistory(recorder!.cur + 1);
}
void takeBackAll() async {
_gotoHistory(-1);
}
void stepForwardAll() async {
_gotoHistory(recorder!.getHistory().length - 1);
}
String movesSinceLastRemove() {
@ -1099,10 +1121,6 @@ class Position {
get side => _sideToMove;
get halfMove => recorder!.halfMove;
get fullMove => recorder!.fullMove;
get lastMove => recorder!.last;
get lastPositionWithRemove => recorder!.lastPositionWithRemove;

View File

@ -23,46 +23,42 @@ import 'types.dart';
// TODO
class GameRecorder {
int? halfMove, fullMove;
int cur = -1;
String? lastPositionWithRemove = "";
final _history = <Move>[];
var _history = <Move>[];
GameRecorder(
{this.halfMove = 0, this.fullMove = 0, this.lastPositionWithRemove});
GameRecorder.fromCounterMarks(String marks) {
//
var segments = marks.split(' ');
if (segments.length != 2) {
throw 'Error: Invalid Counter Marks: $marks';
}
halfMove = int.parse(segments[0]);
fullMove = int.parse(segments[1]);
if (halfMove == null || fullMove == null) {
throw 'Error: Invalid Counter Marks: $marks';
}
}
GameRecorder({this.cur = -1, this.lastPositionWithRemove});
List<Move> getHistory() {
return _history;
}
void setHistory(List<Move> newHistory) {
_history = newHistory;
}
void jumpToHead() {
cur = 0;
}
void jumpToTail() {
cur = _history.length - 1;
}
void clear() {
_history.clear();
cur = 0;
}
void prune() {
if (cur == _history.length - 1) {
return;
}
_history.removeRange(cur + 1, _history.length);
}
void moveIn(Move move, Position position) {
//
if (move.type == MoveType.remove) {
halfMove = 0;
} else {
if (halfMove != null) halfMove = halfMove! + 1;
}
if (fullMove == 0) {
if (halfMove != null) halfMove = halfMove! + 1;
} else if (position.side != PieceColor.white) {
if (halfMove != null) halfMove = halfMove! + 1;
}
if (_history.length > 0) {
if (_history[_history.length - 1].move == move.move) {
//assert(false);
@ -72,6 +68,7 @@ class GameRecorder {
}
_history.add(move);
cur++;
if (move.type == MoveType.remove) {
lastPositionWithRemove = position.fen();
@ -85,24 +82,16 @@ class GameRecorder {
get last => _history.isEmpty ? null : _history.last;
List<Move> reverseMovesToPrevRemove() {
//
List<Move> moves = [];
Move moveAt(int index) => _history[index];
for (var i = _history.length - 1; i >= 0; i--) {
if (_history[i].type == MoveType.remove) break;
moves.add(_history[i]);
}
return moves;
}
get movesCount => _history.length;
String buildMoveHistoryText({cols = 2}) {
var moveHistoryText = '';
int k = 1;
String num = "";
for (var i = 0; i < _history.length; i++) {
for (var i = 0; i <= cur; i++) {
if (Config.standardNotationEnabled) {
if (k % cols == 1) {
num = "${(k + 1) ~/ 2}. ";
@ -112,8 +101,7 @@ class GameRecorder {
} else {
num = "";
}
if (i + 1 < _history.length &&
_history[i + 1].type == MoveType.remove) {
if (i + 1 <= cur && _history[i + 1].type == MoveType.remove) {
moveHistoryText +=
'$num${_history[i].notation}${_history[i + 1].notation} ';
i++;
@ -138,13 +126,4 @@ class GameRecorder {
return moveHistoryText;
}
Move moveAt(int index) => _history[index];
get movesCount => _history.length;
@override
String toString() {
return '$halfMove $fullMove';
}
}

View File

@ -55,7 +55,7 @@ class GamePage extends StatefulWidget {
class _GamePageState extends State<GamePage> with RouteAware {
String? _tip = '';
bool isReady = false;
bool isTakingBack = false;
bool isGoingToHistory = false;
late Timer timer;
final String tag = "[game_page]";
@ -357,6 +357,7 @@ class _GamePageState extends State<GamePage> with RouteAware {
//position.move = m;
Move m = Move(position.record);
position.recorder.prune();
position.recorder.moveIn(m, position);
setState(() {});
@ -491,6 +492,36 @@ class _GamePageState extends State<GamePage> with RouteAware {
SizedBox(height: AppTheme.sizedBoxHeight),
ListItemDivider(),
SizedBox(height: AppTheme.sizedBoxHeight),
SimpleDialogOption(
child: Text(
S.of(context).stepForward,
style: AppTheme.simpleDialogOptionTextStyle,
),
onPressed: onStepForwardButtonPressed,
),
SizedBox(height: AppTheme.sizedBoxHeight),
ListItemDivider(),
SizedBox(height: AppTheme.sizedBoxHeight),
SimpleDialogOption(
child: Text(
S.of(context).takeBackAll,
style: AppTheme.simpleDialogOptionTextStyle,
),
onPressed: onTakeBackAllButtonPressed,
),
SizedBox(height: AppTheme.sizedBoxHeight),
ListItemDivider(),
SizedBox(height: AppTheme.sizedBoxHeight),
SimpleDialogOption(
child: Text(
S.of(context).stepForwardAll,
style: AppTheme.simpleDialogOptionTextStyle,
),
onPressed: onStepForwardAllButtonPressed,
),
SizedBox(height: AppTheme.sizedBoxHeight),
ListItemDivider(),
SizedBox(height: AppTheme.sizedBoxHeight),
SimpleDialogOption(
child: Text(
S.of(context).moveList,
@ -498,27 +529,72 @@ class _GamePageState extends State<GamePage> with RouteAware {
),
onPressed: onMoveListButtonPressed,
),
/*
SizedBox(height: AppTheme.sizedBoxHeight),
ListItemDivider(),
SizedBox(height: AppTheme.sizedBoxHeight),
SimpleDialogOption(
child: Text(
S.of(context).moveNow,
style: AppTheme.simpleDialogOptionTextStyle,
),
onPressed: onMoveNowButtonPressed,
),
*/
],
);
},
);
}
onGotoHistoryButtonsPressed(var func) async {
Navigator.of(context).pop();
if (mounted) {
showTip(S.of(context).waiting);
}
if (isGoingToHistory) {
print("[TakeBack] Is going to history, ignore Take Back button press.");
return;
}
isGoingToHistory = true;
await func;
isGoingToHistory = false;
if (mounted) {
showTip(S.of(context).done);
}
}
onTakeBackButtonPressed() async {
onGotoHistoryButtonsPressed(Game.instance.position.takeBack());
}
onStepForwardButtonPressed() async {
onGotoHistoryButtonsPressed(Game.instance.position.stepForward());
}
onTakeBackAllButtonPressed() async {
onGotoHistoryButtonsPressed(Game.instance.position.takeBackAll());
}
onStepForwardAllButtonPressed() async {
Navigator.of(context).pop();
if (mounted) {
showTip(S.of(context).takingBack);
}
if (isTakingBack) {
if (isGoingToHistory) {
print("[TakeBack] Is taking back, ignore Take Back button press.");
return;
}
isTakingBack = true;
await Game.instance.position.takeBack();
isTakingBack = false;
isGoingToHistory = true;
await Game.instance.position.stepForwardAll();
isGoingToHistory = false;
//Audios.playTone(Audios.placeSoundId);
@ -564,6 +640,11 @@ class _GamePageState extends State<GamePage> with RouteAware {
);
}
onMoveNowButtonPressed() async {
Navigator.of(context).pop();
/* Not implement */
}
onInfoButtonPressed() {
final analyzeText = getInfoText();