parent
10c4fe1c47
commit
564de203ac
|
@ -30,7 +30,7 @@ jobs:
|
|||
run: flutter --version
|
||||
|
||||
- name: Install dependencies
|
||||
run: cd src/ui/flutter; flutter pub get
|
||||
run: cd src/ui/flutter; flutter pub get; flutter pub global activate intl_utils; flutter --no-color pub global run intl_utils:generate
|
||||
|
||||
# Uncomment this step to verify the use of 'dart format' on each commit.
|
||||
# - name: Verify formatting
|
||||
|
|
|
@ -230,7 +230,6 @@ Value search(Position *pos, Sanmill::Stack<Position> &ss, Depth depth, Depth ori
|
|||
#endif
|
||||
|
||||
#ifdef ENDGAME_LEARNING
|
||||
// 检索残局库
|
||||
Endgame endgame;
|
||||
|
||||
if (gameOptions.getLearnEndgameEnabled() &&
|
||||
|
@ -269,7 +268,7 @@ Value search(Position *pos, Sanmill::Stack<Position> &ss, Depth depth, Depth ori
|
|||
bestValue = probeVal;
|
||||
|
||||
#if 0
|
||||
// TODO: 有必要针对深度微调 value?
|
||||
// TODO: Need adjust value?
|
||||
if (position->turn == BLACK)
|
||||
bestValue += tte.depth - depth;
|
||||
else
|
||||
|
|
|
@ -18,5 +18,237 @@
|
|||
"humanVsCloud": "Human Vs Cloud",
|
||||
"@humanVsCloud": {
|
||||
"description": "Human Vs Cloud"
|
||||
},
|
||||
"gameRecord": "Game Record",
|
||||
"@gameRecord": {
|
||||
"description": "Game Record"
|
||||
},
|
||||
"noGameRecord": "No record",
|
||||
"@noGameRecord": {
|
||||
"description": "No record"
|
||||
},
|
||||
"ok": "OK",
|
||||
"@ok": {
|
||||
"description": "OK"
|
||||
},
|
||||
"cancel": "Cancel",
|
||||
"@cancel": {
|
||||
"description": "Cancel"
|
||||
},
|
||||
"daSanQi": "Da San Qi",
|
||||
"@daSanQi": {
|
||||
"description": "Da San Qi"
|
||||
},
|
||||
"copyright": "Copyright © 2019-2020 The Sanmill Authors",
|
||||
"@copyright": {
|
||||
"description": "Copyright"
|
||||
},
|
||||
"gameWarning": "",
|
||||
"@gameWarning": {
|
||||
"description": "Game Warning"
|
||||
},
|
||||
"tipSelectWrong": "Select wrong piece",
|
||||
"@tipSelectWrong": {
|
||||
"description": "Select wrong piece"
|
||||
},
|
||||
"tipPlace": "Please place",
|
||||
"@tipPlace": {
|
||||
"description": "Please place"
|
||||
},
|
||||
"tipBanPlace": "Cannot place here",
|
||||
"@tipBanPlace": {
|
||||
"description": "Cannot place here"
|
||||
},
|
||||
"tipPlaced": "Placed",
|
||||
"@tipPlaced": {
|
||||
"description": "Placed"
|
||||
},
|
||||
"tipRemove": "Please remove",
|
||||
"@tipRemove": {
|
||||
"description": "Please remove"
|
||||
},
|
||||
"tipBanRemove": "Cannot remove",
|
||||
"@tipBanRemove": {
|
||||
"description": "Cannot remove"
|
||||
},
|
||||
"tipRemoved": "Removed",
|
||||
"@tipRemoved": {
|
||||
"description": "Removed"
|
||||
},
|
||||
"tipMove": "Please move",
|
||||
"@tipMove": {
|
||||
"description": "Please move"
|
||||
},
|
||||
"blackWin": "Black win",
|
||||
"@blackWin": {
|
||||
"description": "Black win"
|
||||
},
|
||||
"whiteWin": "White win",
|
||||
"@whiteWin": {
|
||||
"description": "White win"
|
||||
},
|
||||
"draw": "Draw",
|
||||
"@draw": {
|
||||
"description": "Draw"
|
||||
},
|
||||
"thinking": "Thinking ...",
|
||||
"@thinking": {
|
||||
"description": "Thinking ..."
|
||||
},
|
||||
"newGame": "New Game",
|
||||
"@newGame": {
|
||||
"description": "New Game"
|
||||
},
|
||||
"restartGame": "Restart Game?",
|
||||
"@restartGame": {
|
||||
"description": "Restart Game?"
|
||||
},
|
||||
"gameStarted": "Game started, please place",
|
||||
"@gameStarted": {
|
||||
"description": "Game started, please place"
|
||||
},
|
||||
"analyzing": "Analyzing ...",
|
||||
"@analyzing": {
|
||||
"description": "Analyzing ..."
|
||||
},
|
||||
"error": "Error",
|
||||
"@error": {
|
||||
"description": "Error"
|
||||
},
|
||||
"winRate": "Win Rate",
|
||||
"@winRate": {
|
||||
"description": "Win Rate"
|
||||
},
|
||||
"score": "Score",
|
||||
"@score": {
|
||||
"description": "Score"
|
||||
},
|
||||
"black": "Black",
|
||||
"@black": {
|
||||
"description": "Black"
|
||||
},
|
||||
"white": "White",
|
||||
"@white": {
|
||||
"description": "White"
|
||||
},
|
||||
"loseReasonlessThanThree": " piece count is less than three.",
|
||||
"@loseReasonlessThanThree": {
|
||||
"description": " piece count is less than three."
|
||||
},
|
||||
"loseReasonResign": " resign.",
|
||||
"@loseReasonResign": {
|
||||
"description": " resign."
|
||||
},
|
||||
"loseReasonNoWay": " is no way to go.",
|
||||
"@loseReasonNoWay": {
|
||||
"description": " is no way to go."
|
||||
},
|
||||
"loseReasonBoardIsFull": "The board is full, no way to go.",
|
||||
"@loseReasonBoardIsFull": {
|
||||
"description": "The board is full, no way to go."
|
||||
},
|
||||
"loseReasonTimeOver": "Time Over",
|
||||
"@loseReasonTimeOver": {
|
||||
"description": "Time Over"
|
||||
},
|
||||
"drawReasonRule50": "Rule50",
|
||||
"@drawReasonRule50": {
|
||||
"description": "Rule50"
|
||||
},
|
||||
"drawReasonBoardIsFull": "Draw, because the board is full",
|
||||
"@drawReasonBoardIsFull": {
|
||||
"description": "Draw, because the board is full"
|
||||
},
|
||||
"drawReasonThreefoldRepetition": "Draw, because three fold repetition.",
|
||||
"@drawReasonThreefoldRepetition": {
|
||||
"description": "Draw, because three fold repetition."
|
||||
},
|
||||
"gameOverUnknownReason": "Game Over! Unknown reason.",
|
||||
"@gameOverUnknownReason": {
|
||||
"description": "Game Over! Unknown reason."
|
||||
},
|
||||
"youWin": "You win! Congratulations!",
|
||||
"@youWin": {
|
||||
"description": "You win! Congratulations!"
|
||||
},
|
||||
"youLose": "You Lose!",
|
||||
"@youLose": {
|
||||
"description": "You Lose!"
|
||||
},
|
||||
"regret": "Regret",
|
||||
"@regret": {
|
||||
"description": "Regret"
|
||||
},
|
||||
"analyze": "Analyze",
|
||||
"@analyze": {
|
||||
"description": "Analyze"
|
||||
},
|
||||
"playerName": "Player Name",
|
||||
"@playerName": {
|
||||
"description": "Player Name"
|
||||
},
|
||||
"about": "About",
|
||||
"@about": {
|
||||
"description": "About"
|
||||
},
|
||||
"version": "Version",
|
||||
"@version": {
|
||||
"description": "Version"
|
||||
},
|
||||
"releaseBaseOn": "Release base On GPLv3",
|
||||
"@releaseBaseOn": {
|
||||
"description": "Release base On GPLv3"
|
||||
},
|
||||
"webSite": "Website",
|
||||
"@webSite": {
|
||||
"description": "Web Site"
|
||||
},
|
||||
"whatsNew": "What's New",
|
||||
"@whatsNew": {
|
||||
"description": "What's New"
|
||||
},
|
||||
"fastUpdateChannel": "Fast Update Channel",
|
||||
"@fastUpdateChannel": {
|
||||
"description": "Fast Update Channel"
|
||||
},
|
||||
"thanks": "Thanks",
|
||||
"@thanks": {
|
||||
"description": "Thanks"
|
||||
},
|
||||
"thankWho": "Thanks to following programmers and teams:",
|
||||
"@thankWho": {
|
||||
"description": "Thank who"
|
||||
},
|
||||
"stockfish": "Stockfish - UCI chess engine",
|
||||
"@stockfish": {
|
||||
"description": "Stockfish - UCI chess engine"
|
||||
},
|
||||
"chessRoad": "ChessRoad by He Zhaoyun",
|
||||
"@chessRoad": {
|
||||
"description": "ChessRoad"
|
||||
},
|
||||
"nineChess": "NineChess by liuweilhy",
|
||||
"@nineChess": {
|
||||
"description": "NineChess"
|
||||
},
|
||||
"settings": "Settings",
|
||||
"@settings": {
|
||||
"description": "Settings"
|
||||
},
|
||||
"level": "Level",
|
||||
"@level": {
|
||||
"description": "Level"
|
||||
},
|
||||
"sound": "Sound",
|
||||
"@sound": {
|
||||
"description": "Sound"
|
||||
},
|
||||
"tone": "Tone",
|
||||
"@tone": {
|
||||
"description": "Tone"
|
||||
},
|
||||
"leaderBoard": "Leader Board",
|
||||
"@leaderBoard": {
|
||||
"description": "Leader Board"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,5 +3,63 @@
|
|||
"humanVsAi": "人机对战",
|
||||
"humanVsHuman": "双人对战",
|
||||
"aiVsAi": "机器对战",
|
||||
"humanVsCloud": "挑战云端"
|
||||
"humanVsCloud": "挑战云端",
|
||||
"gameRecord": "棋谱",
|
||||
"noGameRecord": "暂无招法",
|
||||
"ok": "好的",
|
||||
"cancel": "取消",
|
||||
"daSanQi": "打三棋",
|
||||
"copyright": "版权所有 © 2019-2020 The Sanmill Authors",
|
||||
"gameWarning": " 健康游戏忠告\n抵制不良游戏,拒绝盗版游戏。\n注意自我保护,谨防受骗上当。\n适度游戏益脑,沉迷游戏伤身。\n合理安排时间,享受健康生活。",
|
||||
"tipSelectWrong": "选择的子不对",
|
||||
"tipPlace": "请落子",
|
||||
"tipBanPlace": "不能落在此处",
|
||||
"tipPlaced": "已落子",
|
||||
"tipRemove": "请吃子",
|
||||
"tipBanRemove": "不能吃这颗子",
|
||||
"tipRemoved": "已吃子",
|
||||
"tipMove": "请走子",
|
||||
"blackWin": "黑方胜",
|
||||
"whiteWin": "白方胜",
|
||||
"draw": "和棋",
|
||||
"thinking": "对方思考中...",
|
||||
"newGame": "新局",
|
||||
"restartGame": "重新开局?",
|
||||
"gameStarted": "游戏开始 请落子",
|
||||
"analyzing": "正在分析局面...",
|
||||
"error": "错误",
|
||||
"winRate": "胜率",
|
||||
"score": "分数",
|
||||
"black": "黑方",
|
||||
"white": "白方",
|
||||
"loseReasonlessThanThree": "剩余棋子少于3枚。",
|
||||
"loseReasonResign": "认输了。",
|
||||
"loseReasonNoWay": "被闷杀。",
|
||||
"loseReasonBoardIsFull": "因棋盘摆满而无路可走。",
|
||||
"loseReasonTimeOver": "超时判负。",
|
||||
"drawReasonRule50": "连续超过50步未吃子,判和。",
|
||||
"drawReasonBoardIsFull": "棋盘摆满,无路可走,判和。",
|
||||
"drawReasonThreefoldRepetition": "三次重复局面和。",
|
||||
"gameOverUnknownReason": "游戏结束,原因未知!",
|
||||
"youWin": "恭喜你赢了",
|
||||
"youLose": "你输了",
|
||||
"regret": "悔棋",
|
||||
"analyze": "分析",
|
||||
"playerName": "棋手姓名",
|
||||
"about": "关于",
|
||||
"version": "版本",
|
||||
"releaseBaseOn": "依照 GPLv3 协议发布",
|
||||
"webSite": "官方网站",
|
||||
"whatsNew": "新版变化",
|
||||
"fastUpdateChannel": "快速更新通道",
|
||||
"thanks": "Thanks",
|
||||
"thankWho": "直棋 离不开以下人员的无私贡献,感激不尽!\n代码贡献者: Calcitem\n开源库: 所基于的开源库太多,难以罗列,在这里仅列出主要的几项,同时也感谢其他默默无闻为开源事业做出贡献的人们:'",
|
||||
"stockfish": "Stockfish - UCI 国际象棋引擎",
|
||||
"chessRoad": "ChessRoad (棋路) by He Zhaoyun",
|
||||
"nineChess": "NineChess (九联棋) by liuweilhy",
|
||||
"settings": "设置",
|
||||
"level": "游戏难度",
|
||||
"sound": "Sound",
|
||||
"tone": "提示音效",
|
||||
"leaderBoard": "排行榜"
|
||||
}
|
|
@ -30,7 +30,6 @@ class Game {
|
|||
|
||||
String sideToMove = Color.black;
|
||||
|
||||
// 是否黑白反转
|
||||
bool isColorInverted;
|
||||
|
||||
Map<String, bool> isAi = {Color.black: false, Color.white: true};
|
||||
|
@ -44,28 +43,20 @@ class Game {
|
|||
position.start();
|
||||
}
|
||||
|
||||
// 是否有落子动画
|
||||
bool hasAnimation;
|
||||
|
||||
// 动画持续时间
|
||||
int durationTime;
|
||||
int animationDurationTime;
|
||||
|
||||
// 是否有落子音效
|
||||
static bool hasSound = true;
|
||||
|
||||
// 是否必败时认输
|
||||
bool resignIfMostLose = false;
|
||||
|
||||
// 是否自动交换先后手
|
||||
bool isAutoChangeFirstMove = false;
|
||||
|
||||
// AI 是否为先手
|
||||
bool isAiFirstMove = false;
|
||||
|
||||
// 规则号
|
||||
int ruleIndex;
|
||||
|
||||
// 提示语
|
||||
String tips;
|
||||
|
||||
List<String> moveHistory = [""];
|
||||
|
@ -111,7 +102,7 @@ class Game {
|
|||
|
||||
bool regret({moves = 2}) {
|
||||
//
|
||||
// 轮到自己走棋的时候,才能悔棋
|
||||
// Can regret only our turn
|
||||
// TODO
|
||||
if (_position.side != Color.white) {
|
||||
//Audios.playTone('invalid.mp3');
|
||||
|
@ -120,7 +111,7 @@ class Game {
|
|||
|
||||
var regretted = false;
|
||||
|
||||
/// 悔棋一回合(两步),才能撤回自己上一次的动棋
|
||||
/// Regret 2 step
|
||||
|
||||
for (var i = 0; i < moves; i++) {
|
||||
//
|
||||
|
@ -164,7 +155,6 @@ class Game {
|
|||
int total;
|
||||
double blackWinRate, whiteWinRate, drawRate;
|
||||
|
||||
// 如果未开局则开局
|
||||
if (position.phase == Phase.ready) {
|
||||
start();
|
||||
}
|
||||
|
|
|
@ -52,7 +52,6 @@ int makeSquare(int file, int rank) {
|
|||
return (file << 3) + rank - 1;
|
||||
}
|
||||
|
||||
/// 对战结果:未决、赢、输、和
|
||||
enum GameResult { pending, win, lose, draw }
|
||||
|
||||
class Color {
|
||||
|
@ -119,7 +118,7 @@ class Move {
|
|||
|
||||
MoveType type;
|
||||
|
||||
// 这一步走完后的 FEN 记数,用于悔棋时恢复 FEN 步数 Counter
|
||||
// Used to restore fen step conter when regreting
|
||||
String counterMarks;
|
||||
|
||||
parse() {
|
||||
|
@ -163,10 +162,10 @@ class Move {
|
|||
parse();
|
||||
}
|
||||
|
||||
/// 引擎返回的招法用是如此表示的,例如:
|
||||
/// 落子:(1,2)
|
||||
/// 吃子:-(1,2)
|
||||
/// 走子:(3,1)->(2,1)
|
||||
/// Format:
|
||||
/// Place: (1,2)
|
||||
/// Remove: -(1,2)
|
||||
/// Move: (3,1)->(2,1)
|
||||
|
||||
Move.set(String move) {
|
||||
this.move = move;
|
||||
|
|
|
@ -1464,7 +1464,7 @@ class Position {
|
|||
|
||||
if (lastMove.removed != Piece.noPiece) {
|
||||
//
|
||||
// 查找上一个吃子局面(或开局),NativeEngine 需要
|
||||
// Find last remove position (or opening), NativeEngine need
|
||||
final tempPosition = Position.clone(this);
|
||||
|
||||
final moves = recorder.reverseMovesToPrevRemove();
|
||||
|
|
|
@ -20,10 +20,9 @@
|
|||
import 'mill.dart';
|
||||
import 'position.dart';
|
||||
import 'types.dart';
|
||||
import 'package:sanmill/generated/l10n.dart';
|
||||
|
||||
class GameRecorder {
|
||||
//
|
||||
// 无吃子步数、总回合数
|
||||
int halfMove, fullMove;
|
||||
String lastPositionWithRemove;
|
||||
final _history = <Move>[];
|
||||
|
@ -99,7 +98,7 @@ class GameRecorder {
|
|||
}
|
||||
|
||||
if (manualText.isEmpty) {
|
||||
manualText = '<暂无招法>';
|
||||
manualText = "";
|
||||
}
|
||||
|
||||
return manualText;
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
*/
|
||||
|
||||
class Rule {
|
||||
String name = "打三棋";
|
||||
String name = "Da San Qi";
|
||||
String description;
|
||||
int nTotalPiecesEachSide = 12; // 9 or 12
|
||||
int nPiecesAtLeast = 3; // Default is 3
|
||||
|
|
|
@ -44,7 +44,7 @@ class PiecesPainter extends PiecesBasePainter {
|
|||
this.blurIndex = Move.invalidMove,
|
||||
}) : super(width: width) {
|
||||
//
|
||||
pieceWidth = squareWidth * 0.9; // 棋子大小
|
||||
pieceWidth = squareWidth * 0.9; // size of square
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -56,7 +56,6 @@ class PiecesPainter extends PiecesBasePainter {
|
|||
gridWidth: gridWidth,
|
||||
squareWidth: squareWidth,
|
||||
pieceWidth: pieceWidth,
|
||||
// 棋子放在线上中央
|
||||
offsetX: Board.padding + squareWidth / 2,
|
||||
offsetY: Board.padding + Board.digitsHeight + squareWidth / 2,
|
||||
focusIndex: focusIndex,
|
||||
|
@ -66,7 +65,6 @@ class PiecesPainter extends PiecesBasePainter {
|
|||
|
||||
@override
|
||||
bool shouldRepaint(CustomPainter oldDelegate) {
|
||||
// 每次重建 Painter 时都要重画
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -89,11 +87,12 @@ class PiecesPainter extends PiecesBasePainter {
|
|||
final shadowPath = Path();
|
||||
final piecesToDraw = <PiecePaintPair>[];
|
||||
|
||||
// 在棋盘上画棋子
|
||||
// Draw pieces on board
|
||||
for (var row = 0; row < 7; row++) {
|
||||
for (var col = 0; col < 7; col++) {
|
||||
//
|
||||
final piece = position.pieceOnGrid(row * 7 + col); // 初始状态无棋子
|
||||
final piece =
|
||||
position.pieceOnGrid(row * 7 + col); // No Pieces when initial
|
||||
|
||||
if (piece == Piece.noPiece) continue;
|
||||
|
||||
|
@ -107,7 +106,7 @@ class PiecesPainter extends PiecesBasePainter {
|
|||
}
|
||||
}
|
||||
|
||||
// 棋子下绘制阴影
|
||||
// Draw shadow of piece
|
||||
canvas.drawShadow(shadowPath, Colors.black, 2, true);
|
||||
|
||||
paint.style = PaintingStyle.fill;
|
||||
|
@ -122,19 +121,19 @@ class PiecesPainter extends PiecesBasePainter {
|
|||
|
||||
piecesToDraw.forEach((pps) {
|
||||
var pieceRadius = pieceWidth / 2;
|
||||
var pieceInnerRadius = pieceRadius * 0.99; // 决定棋子外圈有宽
|
||||
var pieceInnerRadius = pieceRadius * 0.99;
|
||||
|
||||
// 绘制棋子边界
|
||||
// Draw Border of Piece
|
||||
switch (pps.piece) {
|
||||
case Piece.blackStone:
|
||||
paint.color = UIColors.blackPieceBorderColor;
|
||||
canvas.drawCircle(pps.pos, pieceRadius, paint); // 临时调试用
|
||||
canvas.drawCircle(pps.pos, pieceRadius, paint); // For debugging
|
||||
paint.color = UIColors.blackPieceColor;
|
||||
canvas.drawCircle(pps.pos, pieceInnerRadius, paint);
|
||||
break;
|
||||
case Piece.whiteStone:
|
||||
paint.color = UIColors.whitePieceBorderColor;
|
||||
canvas.drawCircle(pps.pos, pieceRadius, paint); // 临时调试用
|
||||
canvas.drawCircle(pps.pos, pieceRadius, paint); // For debugging
|
||||
paint.color = UIColors.whitePieceColor;
|
||||
canvas.drawCircle(pps.pos, pieceInnerRadius, paint);
|
||||
break;
|
||||
|
|
|
@ -52,7 +52,7 @@ class Player extends RankItem {
|
|||
final playerInfoJson = profile['_rank-player-info'] ?? '{}';
|
||||
final values = jsonDecode(playerInfoJson);
|
||||
|
||||
name = values['name'] ?? '无名英雄';
|
||||
name = values['name'] ?? 'Anonymous';
|
||||
winCloudEngine = values['win_cloud_engine'] ?? 0;
|
||||
winAi = values['win_ai'] ?? 0;
|
||||
}
|
||||
|
|
|
@ -26,19 +26,19 @@ class RankItem {
|
|||
int winCloudEngine, winAi;
|
||||
|
||||
RankItem(Map<String, dynamic> values) {
|
||||
name = values['name'] ?? '无名英雄';
|
||||
name = values['name'] ?? 'Anonymous';
|
||||
winCloudEngine = values['win_cloud_engine'] ?? 0;
|
||||
winAi = values['win_ai'] ?? 0;
|
||||
}
|
||||
|
||||
RankItem.empty() {
|
||||
name = '无名英雄';
|
||||
name = 'Anonymous';
|
||||
winCloudEngine = 0;
|
||||
winAi = 0;
|
||||
}
|
||||
|
||||
RankItem.mock() {
|
||||
name = '我是英雄';
|
||||
name = 'I am a hero';
|
||||
winCloudEngine = 3;
|
||||
winAi = 12;
|
||||
}
|
||||
|
|
|
@ -20,57 +20,37 @@
|
|||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
// Toast 显示位置控制
|
||||
enum ToastPostion { top, center, bottom }
|
||||
|
||||
class Toast {
|
||||
// toast靠它加到屏幕上
|
||||
static OverlayEntry _overlayEntry;
|
||||
// toast是否正在showing
|
||||
static bool _showing = false;
|
||||
// 开启一个新toast的当前时间,用于对比是否已经展示了足够时间
|
||||
static DateTime _startedTime;
|
||||
// 提示内容
|
||||
static String _msg;
|
||||
// toast显示时间
|
||||
static int _showTime;
|
||||
// 背景颜色
|
||||
static Color _bgColor;
|
||||
// 文本颜色
|
||||
static Color _textColor;
|
||||
// 文字大小
|
||||
static double _textSize;
|
||||
// 显示位置
|
||||
static ToastPostion _toastPosition;
|
||||
// 左右边距
|
||||
static double _pdHorizontal;
|
||||
// 上下边距
|
||||
static double _pdVertical;
|
||||
|
||||
static void toast(
|
||||
BuildContext context, {
|
||||
// 显示的文本
|
||||
String msg,
|
||||
// 显示的时间 单位毫秒
|
||||
int showTime = 1000,
|
||||
// 显示的背景
|
||||
int showTimeMs = 1000,
|
||||
Color bgColor = Colors.black,
|
||||
// 显示的文本颜色
|
||||
Color textColor = Colors.white,
|
||||
// 显示的文字大小
|
||||
double textSize = 16.0,
|
||||
// 显示的位置
|
||||
ToastPostion position = ToastPostion.center,
|
||||
// 文字水平方向的内边距
|
||||
double pdHorizontal = 20.0,
|
||||
// 文字垂直方向的内边距
|
||||
double pdVertical = 10.0,
|
||||
}) async {
|
||||
assert(msg != null);
|
||||
|
||||
_msg = msg;
|
||||
_startedTime = DateTime.now();
|
||||
_showTime = showTime;
|
||||
_showTime = showTimeMs;
|
||||
_bgColor = bgColor;
|
||||
_textColor = textColor;
|
||||
_textSize = textSize;
|
||||
|
@ -78,18 +58,13 @@ class Toast {
|
|||
_pdHorizontal = pdHorizontal;
|
||||
_pdVertical = pdVertical;
|
||||
|
||||
// 获取OverlayState
|
||||
OverlayState overlayState = Overlay.of(context);
|
||||
|
||||
_showing = true;
|
||||
|
||||
if (_overlayEntry == null) {
|
||||
//
|
||||
// OverlayEntry负责构建布局
|
||||
// 通过OverlayEntry将构建的布局插入到整个布局的最上层
|
||||
_overlayEntry = OverlayEntry(
|
||||
builder: (BuildContext context) => Positioned(
|
||||
// top值,可以改变这个值来改变toast在屏幕中的位置
|
||||
top: buildToastPosition(context),
|
||||
child: Container(
|
||||
alignment: Alignment.center,
|
||||
|
@ -97,7 +72,7 @@ class Toast {
|
|||
child: Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 40.0),
|
||||
child: AnimatedOpacity(
|
||||
opacity: _showing ? 1.0 : 0.0, // 目标透明度
|
||||
opacity: _showing ? 1.0 : 0.0,
|
||||
duration: _showing
|
||||
? Duration(milliseconds: 100)
|
||||
: Duration(milliseconds: 400),
|
||||
|
@ -107,18 +82,15 @@ class Toast {
|
|||
),
|
||||
);
|
||||
|
||||
// 插入到整个布局的最上层
|
||||
overlayState.insert(_overlayEntry);
|
||||
//
|
||||
} else {
|
||||
// 重新绘制UI,类似setState
|
||||
// Redraw UI, like setState
|
||||
_overlayEntry.markNeedsBuild();
|
||||
}
|
||||
|
||||
// 等待时间
|
||||
await Future.delayed(Duration(milliseconds: _showTime));
|
||||
|
||||
// 2 秒后 到底消失不消失
|
||||
if (DateTime.now().difference(_startedTime).inMilliseconds >= _showTime) {
|
||||
_showing = false;
|
||||
_overlayEntry.markNeedsBuild();
|
||||
|
@ -128,7 +100,6 @@ class Toast {
|
|||
}
|
||||
}
|
||||
|
||||
// toast 绘制
|
||||
static _buildToastWidget() {
|
||||
return Center(
|
||||
child: Card(
|
||||
|
@ -143,7 +114,6 @@ class Toast {
|
|||
);
|
||||
}
|
||||
|
||||
// 设置toast位置
|
||||
static buildToastPosition(context) {
|
||||
//
|
||||
var backResult;
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:sanmill/style/colors.dart';
|
||||
import 'package:sanmill/generated/l10n.dart';
|
||||
|
||||
class EditPage extends StatefulWidget {
|
||||
//
|
||||
|
@ -65,7 +66,7 @@ class _EditPageState extends State<EditPage> {
|
|||
title: Text(widget.title, style: TextStyle(fontFamily: '')),
|
||||
actions: <Widget>[
|
||||
FlatButton(
|
||||
child: Text('确定',
|
||||
child: Text(S.of(context).ok,
|
||||
style: TextStyle(fontFamily: '', color: Colors.white)),
|
||||
onPressed: () => onSubmit(_textController.text),
|
||||
)
|
||||
|
|
|
@ -66,21 +66,21 @@ class _GamePageState extends State<GamePage> {
|
|||
switch (winner) {
|
||||
case Color.nobody:
|
||||
if (Game.shared.position.phase == Phase.placing) {
|
||||
changeStatus('请摆子');
|
||||
changeStatus(S.of(context).tipPlace);
|
||||
} else if (Game.shared.position.phase == Phase.moving) {
|
||||
changeStatus('请走子');
|
||||
changeStatus(S.of(context).tipMove);
|
||||
}
|
||||
break;
|
||||
case Color.black:
|
||||
changeStatus('黑方胜');
|
||||
changeStatus(S.of(context).blackWin);
|
||||
gotWin();
|
||||
break;
|
||||
case Color.white:
|
||||
changeStatus('白方胜');
|
||||
changeStatus(S.of(context).whiteWin);
|
||||
gotLose();
|
||||
break;
|
||||
case Color.draw:
|
||||
changeStatus('和棋');
|
||||
changeStatus(S.of(context).draw);
|
||||
gotDraw();
|
||||
break;
|
||||
}
|
||||
|
@ -91,82 +91,71 @@ class _GamePageState extends State<GamePage> {
|
|||
|
||||
int sq = indexToSquare[index];
|
||||
|
||||
// 点击非落子点,不执行
|
||||
if (sq == null) {
|
||||
print("putPiece skip index: $index");
|
||||
return;
|
||||
}
|
||||
|
||||
// AI 走棋或正在搜索时,点击无效
|
||||
if (Game.shared.isAiToMove() || Game.shared.aiIsSearching()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 如果未开局则开局
|
||||
if (position.phase == Phase.ready) {
|
||||
Game.shared.start();
|
||||
}
|
||||
|
||||
// 判断执行选子、落子或去子
|
||||
bool ret = false;
|
||||
|
||||
switch (position.action) {
|
||||
case Act.place:
|
||||
if (position.putPiece(sq)) {
|
||||
if (position.action == Act.remove) {
|
||||
// 播放成三音效
|
||||
//Audios.playTone('mill.mp3');
|
||||
changeStatus('请吃子');
|
||||
changeStatus(S.of(context).tipRemove);
|
||||
} else {
|
||||
// 播放移动棋子音效
|
||||
//Audios.playTone('put.mp3');
|
||||
changeStatus('已落子');
|
||||
changeStatus(S.of(context).tipPlaced);
|
||||
}
|
||||
ret = true;
|
||||
print("putPiece: [$sq]");
|
||||
break;
|
||||
} else {
|
||||
print("putPiece: skip [$sq]");
|
||||
changeStatus('不能落在此处');
|
||||
changeStatus(S.of(context).tipBanPlace);
|
||||
}
|
||||
|
||||
// 如果移子不成功,尝试重新选子,这里不break
|
||||
// If cannot move, retry select, do not break
|
||||
//[[fallthrough]];
|
||||
continue select;
|
||||
select:
|
||||
case Act.select:
|
||||
if (position.selectPiece(sq)) {
|
||||
// 播放选子音效
|
||||
//Audios.playTone('select.mp3');
|
||||
Game.shared.select(index);
|
||||
ret = true;
|
||||
print("selectPiece: [$sq]");
|
||||
changeStatus('请落子');
|
||||
changeStatus(S.of(context).tipPlace);
|
||||
} else {
|
||||
// 播放禁止音效
|
||||
//Audios.playTone('banned.mp3');
|
||||
print("selectPiece: skip [$sq]");
|
||||
changeStatus('选择的子不对');
|
||||
changeStatus(S.of(context).tipSelectWrong);
|
||||
}
|
||||
break;
|
||||
|
||||
case Act.remove:
|
||||
if (position.removePiece(sq)) {
|
||||
// 播放音效
|
||||
//Audios.playTone('remove.mp3');
|
||||
ret = true;
|
||||
print("removePiece: [$sq]");
|
||||
changeStatus('已吃子');
|
||||
changeStatus(S.of(context).tipRemoved);
|
||||
} else {
|
||||
// 播放禁止音效
|
||||
//Audios.playTone('banned.mp3');
|
||||
print("removePiece: skip [$sq]");
|
||||
changeStatus('不能吃这个子');
|
||||
changeStatus(S.of(context).tipBanRemove);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
// 如果是结局状态,不做任何响应
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -185,11 +174,8 @@ class _GamePageState extends State<GamePage> {
|
|||
Move m = Move(position.cmdline);
|
||||
position.recorder.moveIn(m, position);
|
||||
|
||||
// 发信号更新状态栏
|
||||
setState(() {});
|
||||
|
||||
// AI设置
|
||||
// 如果还未决出胜负
|
||||
if (position.winner == Color.nobody) {
|
||||
engineToGo();
|
||||
} else {
|
||||
|
@ -208,7 +194,7 @@ class _GamePageState extends State<GamePage> {
|
|||
// TODO
|
||||
while (Game.shared.position.winner == Color.nobody &&
|
||||
Game.shared.position.sideToMove() == Color.white) {
|
||||
changeStatus('对方思考中...');
|
||||
changeStatus(S.of(context).thinking);
|
||||
|
||||
final response = await widget.engine.search(Game.shared.position);
|
||||
|
||||
|
@ -229,7 +215,7 @@ class _GamePageState extends State<GamePage> {
|
|||
confirm() {
|
||||
Navigator.of(context).pop();
|
||||
Game.shared.newGame();
|
||||
changeStatus('游戏开始 请摆子');
|
||||
changeStatus(S.of(context).gameStarted);
|
||||
|
||||
if (Game.shared.isAiToMove()) {
|
||||
print("New Game: AI's turn.");
|
||||
|
@ -243,11 +229,13 @@ class _GamePageState extends State<GamePage> {
|
|||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return AlertDialog(
|
||||
title: Text('新局?', style: TextStyle(color: UIColors.primaryColor)),
|
||||
content: SingleChildScrollView(child: Text('重新开局?')),
|
||||
title: Text(S.of(context).newGame,
|
||||
style: TextStyle(color: UIColors.primaryColor)),
|
||||
content:
|
||||
SingleChildScrollView(child: Text(S.of(context).restartGame)),
|
||||
actions: <Widget>[
|
||||
FlatButton(child: Text('确定'), onPressed: confirm),
|
||||
FlatButton(child: Text('取消'), onPressed: cancel),
|
||||
FlatButton(child: Text(S.of(context).ok), onPressed: confirm),
|
||||
FlatButton(child: Text(S.of(context).cancel), onPressed: cancel),
|
||||
],
|
||||
);
|
||||
},
|
||||
|
@ -256,12 +244,14 @@ class _GamePageState extends State<GamePage> {
|
|||
|
||||
analyzePosition() async {
|
||||
//
|
||||
Toast.toast(context, msg: '正在分析局面...', position: ToastPostion.bottom);
|
||||
Toast.toast(context,
|
||||
msg: S.of(context).analyzing, position: ToastPostion.bottom);
|
||||
|
||||
setState(() => _searching = true);
|
||||
|
||||
try {} catch (e) {
|
||||
Toast.toast(context, msg: '错误: $e', position: ToastPostion.bottom);
|
||||
Toast.toast(context,
|
||||
msg: S.of(context).error + ": $e", position: ToastPostion.bottom);
|
||||
} finally {
|
||||
setState(() => _searching = false);
|
||||
}
|
||||
|
@ -279,8 +269,8 @@ class _GamePageState extends State<GamePage> {
|
|||
children.add(
|
||||
ListTile(
|
||||
title: Text(item.moveName, style: TextStyle(fontSize: 18)),
|
||||
subtitle: Text('胜率:${item.winRate}%'),
|
||||
trailing: Text('分数:${item.score}'),
|
||||
subtitle: Text(S.of(context).winRate + ": ${item.winRate}%"),
|
||||
trailing: Text(S.of(context).score + ": ${item.score}'"),
|
||||
onTap: () => callback(item),
|
||||
),
|
||||
);
|
||||
|
@ -300,39 +290,38 @@ class _GamePageState extends State<GamePage> {
|
|||
|
||||
String getGameOverReasonString(GameOverReason reason, String winner) {
|
||||
String loseReasonStr;
|
||||
String winnerStr = winner == Color.black ? "黑方" : "白方";
|
||||
String loserStr = winner == Color.black ? "白方" : "黑方";
|
||||
String winnerStr =
|
||||
winner == Color.black ? S.of(context).black : S.of(context).white;
|
||||
String loserStr =
|
||||
winner == Color.black ? S.of(context).white : S.of(context).black;
|
||||
|
||||
switch (Game.shared.position.gameOverReason) {
|
||||
case GameOverReason.loseReasonlessThanThree:
|
||||
loseReasonStr = "$loserStr剩余棋子少于3枚。";
|
||||
loseReasonStr = loserStr + S.of(context).loseReasonlessThanThree;
|
||||
break;
|
||||
case GameOverReason.loseReasonResign:
|
||||
loseReasonStr = "$loserStr认输了。";
|
||||
loseReasonStr = loserStr + S.of(context).loseReasonResign;
|
||||
break;
|
||||
case GameOverReason.loseReasonNoWay:
|
||||
loseReasonStr = "$loserStr被闷杀。";
|
||||
loseReasonStr = loserStr + S.of(context).loseReasonNoWay;
|
||||
break;
|
||||
case GameOverReason.loseReasonBoardIsFull:
|
||||
loseReasonStr = "棋盘摆满,$loserStr无路可走。";
|
||||
loseReasonStr = loserStr + S.of(context).loseReasonBoardIsFull;
|
||||
break;
|
||||
case GameOverReason.loseReasonTimeOver:
|
||||
loseReasonStr = "$loserStr超时判负。";
|
||||
loseReasonStr = loserStr + S.of(context).loseReasonTimeOver;
|
||||
break;
|
||||
case GameOverReason.drawReasonRule50:
|
||||
loseReasonStr = "连续超过50步未吃子,判和。";
|
||||
break;
|
||||
case GameOverReason.drawReasonRule50:
|
||||
loseReasonStr = "连续超过50步未吃子,判和。";
|
||||
loseReasonStr = S.of(context).drawReasonRule50;
|
||||
break;
|
||||
case GameOverReason.drawReasonBoardIsFull:
|
||||
loseReasonStr = "棋盘摆满,无路可走,判和。";
|
||||
loseReasonStr = S.of(context).drawReasonBoardIsFull;
|
||||
break;
|
||||
case GameOverReason.drawReasonThreefoldRepetition:
|
||||
loseReasonStr = "三次重复局面和。";
|
||||
loseReasonStr = S.of(context).drawReasonThreefoldRepetition;
|
||||
break;
|
||||
default:
|
||||
loseReasonStr = "未知原因,棋局结束。";
|
||||
loseReasonStr = S.of(context).gameOverUnknownReason;
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -349,13 +338,14 @@ class _GamePageState extends State<GamePage> {
|
|||
barrierDismissible: false,
|
||||
builder: (BuildContext context) {
|
||||
return AlertDialog(
|
||||
title: Text('恭喜你赢了', style: TextStyle(color: UIColors.primaryColor)),
|
||||
title: Text(S.of(context).youWin,
|
||||
style: TextStyle(color: UIColors.primaryColor)),
|
||||
content: Text(getGameOverReasonString(
|
||||
Game.shared.position.gameOverReason,
|
||||
Game.shared.position.winner)),
|
||||
actions: <Widget>[
|
||||
FlatButton(
|
||||
child: Text('好的'),
|
||||
child: Text(S.of(context).ok),
|
||||
onPressed: () => Navigator.of(context).pop()),
|
||||
],
|
||||
);
|
||||
|
@ -378,13 +368,14 @@ class _GamePageState extends State<GamePage> {
|
|||
barrierDismissible: false,
|
||||
builder: (BuildContext context) {
|
||||
return AlertDialog(
|
||||
title: Text('你输了', style: TextStyle(color: UIColors.primaryColor)),
|
||||
title: Text(S.of(context).youLose,
|
||||
style: TextStyle(color: UIColors.primaryColor)),
|
||||
content: Text(getGameOverReasonString(
|
||||
Game.shared.position.gameOverReason,
|
||||
Game.shared.position.winner)),
|
||||
actions: <Widget>[
|
||||
FlatButton(
|
||||
child: Text('好的'),
|
||||
child: Text(S.of(context).ok),
|
||||
onPressed: () => Navigator.of(context).pop()),
|
||||
],
|
||||
);
|
||||
|
@ -401,13 +392,14 @@ class _GamePageState extends State<GamePage> {
|
|||
barrierDismissible: false,
|
||||
builder: (BuildContext context) {
|
||||
return AlertDialog(
|
||||
title: Text('和棋', style: TextStyle(color: UIColors.primaryColor)),
|
||||
title: Text(S.of(context).draw,
|
||||
style: TextStyle(color: UIColors.primaryColor)),
|
||||
content: Text(getGameOverReasonString(
|
||||
Game.shared.position.gameOverReason,
|
||||
Game.shared.position.winner)),
|
||||
actions: <Widget>[
|
||||
FlatButton(
|
||||
child: Text('好的'),
|
||||
child: Text(S.of(context).ok),
|
||||
onPressed: () => Navigator.of(context).pop()),
|
||||
],
|
||||
);
|
||||
|
@ -417,7 +409,7 @@ class _GamePageState extends State<GamePage> {
|
|||
|
||||
void calcScreenPaddingH() {
|
||||
//
|
||||
// 当屏幕的纵横比小于16/9时,限制棋盘的宽度
|
||||
// when screen's height/width rate is less than 16/9, limit witdh of board
|
||||
final windowSize = MediaQuery.of(context).size;
|
||||
double height = windowSize.height, width = windowSize.width;
|
||||
|
||||
|
@ -511,10 +503,12 @@ class _GamePageState extends State<GamePage> {
|
|||
padding: EdgeInsets.symmetric(vertical: 2),
|
||||
child: Row(children: <Widget>[
|
||||
Expanded(child: SizedBox()),
|
||||
FlatButton(child: Text('新局', style: buttonStyle), onPressed: newGame),
|
||||
FlatButton(
|
||||
child: Text(S.of(context).newGame, style: buttonStyle),
|
||||
onPressed: newGame),
|
||||
Expanded(child: SizedBox()),
|
||||
FlatButton(
|
||||
child: Text('悔棋', style: buttonStyle),
|
||||
child: Text(S.of(context).regret, style: buttonStyle),
|
||||
onPressed: () {
|
||||
Game.shared.regret(steps: 2);
|
||||
setState(() {});
|
||||
|
@ -522,7 +516,7 @@ class _GamePageState extends State<GamePage> {
|
|||
),
|
||||
Expanded(child: SizedBox()),
|
||||
FlatButton(
|
||||
child: Text('分析', style: buttonStyle),
|
||||
child: Text(S.of(context).analyze, style: buttonStyle),
|
||||
onPressed: _searching ? null : analyzePosition,
|
||||
),
|
||||
Expanded(child: SizedBox()),
|
||||
|
@ -571,12 +565,13 @@ class _GamePageState extends State<GamePage> {
|
|||
barrierDismissible: false,
|
||||
builder: (BuildContext context) {
|
||||
return AlertDialog(
|
||||
title: Text('棋谱', style: TextStyle(color: UIColors.primaryColor)),
|
||||
title: Text(S.of(context).gameRecord,
|
||||
style: TextStyle(color: UIColors.primaryColor)),
|
||||
content:
|
||||
SingleChildScrollView(child: Text(text, style: manualStyle)),
|
||||
actions: <Widget>[
|
||||
FlatButton(
|
||||
child: Text('好的'),
|
||||
child: Text(S.of(context).ok),
|
||||
onPressed: () => Navigator.of(context).pop(),
|
||||
),
|
||||
],
|
||||
|
|
|
@ -135,15 +135,10 @@ class _MainMenuState extends State<MainMenu> with TickerProviderStateMixin {
|
|||
onPressed: () => navigateTo(GamePage(EngineType.aiVsAi)),
|
||||
),
|
||||
Expanded(child: SizedBox()),
|
||||
Text(
|
||||
' 健康游戏忠告\n'
|
||||
'抵制不良游戏,拒绝盗版游戏。\n'
|
||||
'注意自我保护,谨防受骗上当。\n'
|
||||
'适度游戏益脑,沉迷游戏伤身。\n'
|
||||
'合理安排时间,享受健康生活。',
|
||||
Text(S.of(context).gameWarning,
|
||||
style: TextStyle(color: Colors.black54, fontSize: 16)),
|
||||
Expanded(child: SizedBox()),
|
||||
Text('Copyright © 2019-2020 The Sanmill Authors',
|
||||
Text(S.of(context).copyright,
|
||||
style: TextStyle(color: Colors.black54, fontSize: 16)),
|
||||
Expanded(child: SizedBox()),
|
||||
],
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:package_info/package_info.dart';
|
||||
import 'package:sanmill/common/config.dart';
|
||||
import 'package:sanmill/generated/l10n.dart';
|
||||
import 'package:sanmill/services/audios.dart';
|
||||
import 'package:sanmill/services/player.dart';
|
||||
import 'package:sanmill/style/colors.dart';
|
||||
|
@ -70,7 +71,7 @@ class _SettingsPageState extends State<SettingsPage> {
|
|||
SizedBox(height: 10),
|
||||
RadioListTile(
|
||||
activeColor: UIColors.primaryColor,
|
||||
title: Text('初级'),
|
||||
title: Text('L1'),
|
||||
groupValue: Config.thinkingTime,
|
||||
value: 5000,
|
||||
onChanged: callback,
|
||||
|
@ -78,7 +79,7 @@ class _SettingsPageState extends State<SettingsPage> {
|
|||
Divider(),
|
||||
RadioListTile(
|
||||
activeColor: UIColors.primaryColor,
|
||||
title: Text('中级'),
|
||||
title: Text('L2'),
|
||||
groupValue: Config.thinkingTime,
|
||||
value: 15000,
|
||||
onChanged: callback,
|
||||
|
@ -86,7 +87,7 @@ class _SettingsPageState extends State<SettingsPage> {
|
|||
Divider(),
|
||||
RadioListTile(
|
||||
activeColor: UIColors.primaryColor,
|
||||
title: Text('高级'),
|
||||
title: Text('L3'),
|
||||
groupValue: Config.thinkingTime,
|
||||
value: 30000,
|
||||
onChanged: callback,
|
||||
|
@ -126,8 +127,8 @@ class _SettingsPageState extends State<SettingsPage> {
|
|||
//
|
||||
final newName = await Navigator.of(context).push(
|
||||
MaterialPageRoute(
|
||||
builder: (context) =>
|
||||
EditPage('棋手姓名', initValue: Player.shared.name)),
|
||||
builder: (context) => EditPage(S.of(context).playerName,
|
||||
initValue: Player.shared.name)),
|
||||
);
|
||||
|
||||
if (newName != null) nameChanged(newName);
|
||||
|
@ -156,16 +157,18 @@ class _SettingsPageState extends State<SettingsPage> {
|
|||
context: context,
|
||||
barrierDismissible: false,
|
||||
builder: (context) => AlertDialog(
|
||||
title: Text('关于「直棋 」', style: TextStyle(color: UIColors.primaryColor)),
|
||||
title: Text(S.of(context).about + S.of(context).appName,
|
||||
style: TextStyle(color: UIColors.primaryColor)),
|
||||
content: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
SizedBox(height: 5),
|
||||
Text('版本: $_version', style: TextStyle(fontFamily: '')),
|
||||
Text(S.of(context).version + ": $_version",
|
||||
style: TextStyle(fontFamily: '')),
|
||||
SizedBox(height: 15),
|
||||
InkWell(
|
||||
child: Text('依照 GPLv3 协议发布',
|
||||
child: Text(S.of(context).releaseBaseOn,
|
||||
style: TextStyle(
|
||||
fontFamily: '',
|
||||
color: Colors.blue,
|
||||
|
@ -175,7 +178,7 @@ class _SettingsPageState extends State<SettingsPage> {
|
|||
),
|
||||
SizedBox(height: 15),
|
||||
InkWell(
|
||||
child: Text('官方网站',
|
||||
child: Text(S.of(context).webSite,
|
||||
style: TextStyle(
|
||||
fontFamily: '',
|
||||
color: Colors.blue,
|
||||
|
@ -183,7 +186,7 @@ class _SettingsPageState extends State<SettingsPage> {
|
|||
onTap: () => _launchURL('https://github.com/calcitem/Sanmill'),
|
||||
),
|
||||
InkWell(
|
||||
child: Text('新版变化',
|
||||
child: Text(S.of(context).whatsNew,
|
||||
style: TextStyle(
|
||||
fontFamily: '',
|
||||
color: Colors.blue,
|
||||
|
@ -192,7 +195,7 @@ class _SettingsPageState extends State<SettingsPage> {
|
|||
'https://github.com/calcitem/Sanmill/commits/master'),
|
||||
),
|
||||
InkWell(
|
||||
child: Text('快速更新通道',
|
||||
child: Text(S.of(context).fastUpdateChannel,
|
||||
style: TextStyle(
|
||||
fontFamily: '',
|
||||
color: Colors.blue,
|
||||
|
@ -202,16 +205,13 @@ class _SettingsPageState extends State<SettingsPage> {
|
|||
),
|
||||
SizedBox(height: 15),
|
||||
InkWell(
|
||||
child: Text('致谢'),
|
||||
child: Text(S.of(context).thanks),
|
||||
),
|
||||
InkWell(
|
||||
child: Text('直棋 离不开以下人员的无私贡献,感激不尽!\n'
|
||||
'代码贡献者: Calcitem\n'
|
||||
'开源库: '
|
||||
'所基于的开源库太多,难以罗列,在这里仅列出主要的几项,同时也感谢其他默默无闻为开源事业做出贡献的人们:'),
|
||||
child: Text(S.of(context).thankWho),
|
||||
),
|
||||
InkWell(
|
||||
child: Text('Stockfish - UCI chess engine',
|
||||
child: Text(S.of(context).stockfish,
|
||||
style: TextStyle(
|
||||
fontFamily: '',
|
||||
color: Colors.blue,
|
||||
|
@ -220,7 +220,7 @@ class _SettingsPageState extends State<SettingsPage> {
|
|||
_launchURL('https://github.com/official-stockfish/Stockfish'),
|
||||
),
|
||||
InkWell(
|
||||
child: Text('ChessRoad (棋路) by He Zhaoyun',
|
||||
child: Text(S.of(context).chessRoad,
|
||||
style: TextStyle(
|
||||
fontFamily: '',
|
||||
color: Colors.blue,
|
||||
|
@ -228,7 +228,7 @@ class _SettingsPageState extends State<SettingsPage> {
|
|||
onTap: () => _launchURL('https://github.com/hezhaoyun/chessroad'),
|
||||
),
|
||||
InkWell(
|
||||
child: Text('NineChess (九联棋) by liuweilhy',
|
||||
child: Text(S.of(context).nineChess,
|
||||
style: TextStyle(
|
||||
fontFamily: '',
|
||||
color: Colors.blue,
|
||||
|
@ -239,7 +239,8 @@ class _SettingsPageState extends State<SettingsPage> {
|
|||
),
|
||||
actions: <Widget>[
|
||||
FlatButton(
|
||||
child: Text('好的'), onPressed: () => Navigator.of(context).pop()),
|
||||
child: Text(S.of(context).ok),
|
||||
onPressed: () => Navigator.of(context).pop()),
|
||||
],
|
||||
),
|
||||
);
|
||||
|
@ -254,14 +255,14 @@ class _SettingsPageState extends State<SettingsPage> {
|
|||
|
||||
return Scaffold(
|
||||
backgroundColor: UIColors.lightBackgroundColor,
|
||||
appBar: AppBar(title: Text('设置')),
|
||||
appBar: AppBar(title: Text(S.of(context).settings)),
|
||||
body: SingleChildScrollView(
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
const SizedBox(height: 10.0),
|
||||
Text("人机难度", style: headerStyle),
|
||||
Text(S.of(context).level, style: headerStyle),
|
||||
const SizedBox(height: 10.0),
|
||||
Card(
|
||||
color: UIColors.boardBackgroundColor,
|
||||
|
@ -270,14 +271,14 @@ class _SettingsPageState extends State<SettingsPage> {
|
|||
child: Column(
|
||||
children: <Widget>[
|
||||
ListTile(
|
||||
title: Text("游戏难度", style: itemStyle),
|
||||
title: Text(S.of(context).level, style: itemStyle),
|
||||
trailing:
|
||||
Row(mainAxisSize: MainAxisSize.min, children: <Widget>[
|
||||
Text(Config.thinkingTime <= 5000
|
||||
? '初级'
|
||||
? 'L1'
|
||||
: Config.thinkingTime <= 15000
|
||||
? '中级'
|
||||
: '高级'),
|
||||
? 'L2'
|
||||
: 'L3'),
|
||||
Icon(Icons.keyboard_arrow_right,
|
||||
color: UIColors.secondaryColor),
|
||||
]),
|
||||
|
@ -287,7 +288,7 @@ class _SettingsPageState extends State<SettingsPage> {
|
|||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
Text("声音", style: headerStyle),
|
||||
Text(S.of(context).sound, style: headerStyle),
|
||||
Card(
|
||||
color: UIColors.boardBackgroundColor,
|
||||
margin: const EdgeInsets.symmetric(vertical: 10),
|
||||
|
@ -296,28 +297,28 @@ class _SettingsPageState extends State<SettingsPage> {
|
|||
SwitchListTile(
|
||||
activeColor: UIColors.primaryColor,
|
||||
value: Config.bgmEnabled,
|
||||
title: Text("背景音乐", style: itemStyle),
|
||||
title: Text(S.of(context).sound, style: itemStyle),
|
||||
onChanged: switchMusic,
|
||||
),
|
||||
_buildDivider(),
|
||||
SwitchListTile(
|
||||
activeColor: UIColors.primaryColor,
|
||||
value: Config.toneEnabled,
|
||||
title: Text("提示音效", style: itemStyle),
|
||||
title: Text(S.of(context).tone, style: itemStyle),
|
||||
onChanged: switchTone,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
Text("排行榜", style: headerStyle),
|
||||
Text(S.of(context).leaderBoard, style: headerStyle),
|
||||
Card(
|
||||
color: UIColors.boardBackgroundColor,
|
||||
margin: const EdgeInsets.symmetric(vertical: 10),
|
||||
child: Column(
|
||||
children: <Widget>[
|
||||
ListTile(
|
||||
title: Text("棋手姓名", style: itemStyle),
|
||||
title: Text(S.of(context).playerName, style: itemStyle),
|
||||
trailing:
|
||||
Row(mainAxisSize: MainAxisSize.min, children: <Widget>[
|
||||
Text(Player.shared.name),
|
||||
|
@ -330,14 +331,15 @@ class _SettingsPageState extends State<SettingsPage> {
|
|||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
Text("关于", style: headerStyle),
|
||||
Text(S.of(context).about, style: headerStyle),
|
||||
Card(
|
||||
color: UIColors.boardBackgroundColor,
|
||||
margin: const EdgeInsets.symmetric(vertical: 10),
|
||||
child: Column(
|
||||
children: <Widget>[
|
||||
ListTile(
|
||||
title: Text("关于「直棋」", style: itemStyle),
|
||||
title: Text(S.of(context).about + S.of(context).appName,
|
||||
style: itemStyle),
|
||||
trailing:
|
||||
Row(mainAxisSize: MainAxisSize.min, children: <Widget>[
|
||||
Text(_version ?? ''),
|
||||
|
|
Loading…
Reference in New Issue