From 8677f9f3222d3825aea56e48b1bc885e99cb690c Mon Sep 17 00:00:00 2001 From: Calcitem Date: Fri, 21 May 2021 23:26:56 +0800 Subject: [PATCH] flutter: Support Step forward & Take back all & Step forward all --- src/ui/flutter_app/lib/l10n/intl_en.arb | 24 ++++- src/ui/flutter_app/lib/l10n/intl_zh.arb | 7 +- src/ui/flutter_app/lib/mill/position.dart | 38 ++++++-- src/ui/flutter_app/lib/mill/recorder.dart | 87 +++++++----------- src/ui/flutter_app/lib/widgets/game_page.dart | 91 ++++++++++++++++++- 5 files changed, 175 insertions(+), 72 deletions(-) diff --git a/src/ui/flutter_app/lib/l10n/intl_en.arb b/src/ui/flutter_app/lib/l10n/intl_en.arb index 590bf7ac..e2e57bdc 100644 --- a/src/ui/flutter_app/lib/l10n/intl_en.arb +++ b/src/ui/flutter_app/lib/l10n/intl_en.arb @@ -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": { diff --git a/src/ui/flutter_app/lib/l10n/intl_zh.arb b/src/ui/flutter_app/lib/l10n/intl_zh.arb index 4a538c6d..67969a51 100644 --- a/src/ui/flutter_app/lib/l10n/intl_zh.arb +++ b/src/ui/flutter_app/lib/l10n/intl_zh.arb @@ -178,8 +178,13 @@ "undo": "悔棋", "undoOption": "悔棋", "undoOption_Detail": "允许悔棋", - "takeBack": "悔棋", + "takeBack": "回退", "takingBack": "回退中", + "waiting": "请稍等", + "stepForward": "前进", + "takeBackAll": "回退到底", + "stepForwardAll": "前进到底", + "moveNow": "立即行棋", "done": "完成", "crackMill": "不允许吃全三连", "crackMill_Detail": "若对方所有的子都在三连中, 也不允许吃子。", diff --git a/src/ui/flutter_app/lib/mill/position.dart b/src/ui/flutter_app/lib/mill/position.dart index 91590cfa..f90a233b 100644 --- a/src/ui/flutter_app/lib/mill/position.dart +++ b/src/ui/flutter_app/lib/mill/position.dart @@ -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; diff --git a/src/ui/flutter_app/lib/mill/recorder.dart b/src/ui/flutter_app/lib/mill/recorder.dart index 64a79980..5950dbee 100644 --- a/src/ui/flutter_app/lib/mill/recorder.dart +++ b/src/ui/flutter_app/lib/mill/recorder.dart @@ -23,46 +23,42 @@ import 'types.dart'; // TODO class GameRecorder { - int? halfMove, fullMove; + int cur = -1; String? lastPositionWithRemove = ""; - final _history = []; + var _history = []; - 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 getHistory() { return _history; } + void setHistory(List 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 reverseMovesToPrevRemove() { - // - List 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'; - } } diff --git a/src/ui/flutter_app/lib/widgets/game_page.dart b/src/ui/flutter_app/lib/widgets/game_page.dart index f58104b1..87a45dde 100644 --- a/src/ui/flutter_app/lib/widgets/game_page.dart +++ b/src/ui/flutter_app/lib/widgets/game_page.dart @@ -55,7 +55,7 @@ class GamePage extends StatefulWidget { class _GamePageState extends State 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 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 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 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 with RouteAware { ); } + onMoveNowButtonPressed() async { + Navigator.of(context).pop(); + /* Not implement */ + } + onInfoButtonPressed() { final analyzeText = getInfoText();