diff --git a/src/ui/flutter/lib/common/misc.dart b/src/ui/flutter/lib/common/algorithm.dart similarity index 99% rename from src/ui/flutter/lib/common/misc.dart rename to src/ui/flutter/lib/common/algorithm.dart index 8f12475d..7a6e5e2b 100644 --- a/src/ui/flutter/lib/common/misc.dart +++ b/src/ui/flutter/lib/common/algorithm.dart @@ -20,7 +20,6 @@ abs(value) => value > 0 ? value : -value; int binarySearch(List array, int start, int end, int key) { - // if (start > end) return -1; if (array[start] == key) return start; diff --git a/src/ui/flutter/lib/common/config.dart b/src/ui/flutter/lib/common/config.dart index 995028da..702ea4bd 100644 --- a/src/ui/flutter/lib/common/config.dart +++ b/src/ui/flutter/lib/common/config.dart @@ -20,29 +20,26 @@ import 'profile.dart'; class Config { - // static bool bgmEnabled = false; static bool toneEnabled = true; - static int stepTime = 5000; + static int thinkingTime = 5000; static Future loadProfile() async { - // final profile = await Profile.shared(); Config.bgmEnabled = profile['bgm-enabled'] ?? false; Config.toneEnabled = profile['tone-enabled'] ?? true; - Config.stepTime = profile['step-time'] ?? 5000; + Config.thinkingTime = profile['thinking-time'] ?? 5000; return true; } static Future save() async { - // final profile = await Profile.shared(); profile['bgm-enabled'] = Config.bgmEnabled; profile['tone-enabled'] = Config.toneEnabled; - profile['step-time'] = Config.stepTime; + profile['thinking-time'] = Config.thinkingTime; profile.commit(); diff --git a/src/ui/flutter/lib/common/profile.dart b/src/ui/flutter/lib/common/profile.dart index fbd7867a..30ff2db7 100644 --- a/src/ui/flutter/lib/common/profile.dart +++ b/src/ui/flutter/lib/common/profile.dart @@ -23,18 +23,16 @@ import 'dart:io'; import 'package:path_provider/path_provider.dart'; class Profile { - // - static const DefaultFileName = 'default-profile.json'; + static const defaultFileName = 'default-profile.json'; static Profile _shared; File _file; Map _values = {}; static shared() async { - // if (_shared == null) { _shared = Profile(); - await _shared._load(DefaultFileName); + await _shared._load(defaultFileName); } return _shared; @@ -45,7 +43,6 @@ class Profile { operator []=(String key, dynamic value) => _values[key] = value; Future commit() async { - // _file.create(recursive: true); try { @@ -60,7 +57,6 @@ class Profile { } Future _load(String fileName) async { - // final docDir = await getApplicationDocumentsDirectory(); _file = File('${docDir.path}/$fileName'); diff --git a/src/ui/flutter/lib/engine/analysis.dart b/src/ui/flutter/lib/engine/analyze.dart similarity index 65% rename from src/ui/flutter/lib/engine/analysis.dart rename to src/ui/flutter/lib/engine/analyze.dart index 9de1590b..c14aa6dc 100644 --- a/src/ui/flutter/lib/engine/analysis.dart +++ b/src/ui/flutter/lib/engine/analyze.dart @@ -17,41 +17,37 @@ along with this program. If not, see . */ -class AnalysisItem { - // - String move, stepName; +class AnalyzeItem { + String move, moveName; int score; - double winrate; + double winRate; - AnalysisItem({this.move, this.score, this.winrate}); + AnalyzeItem({this.move, this.score, this.winRate}); @override String toString() { - return '{move: ${stepName ?? move}, score: $score, winrate: $winrate}'; + return '{move: ${moveName ?? move}, score: $score, winRate: $winRate}'; } } -class AnalysisFetcher { - // - static List fetch(String response, {limit = 5}) { - // +class AnalyzeFetcher { + static List fetch(String response, {limit = 5}) { final segments = response.split('|'); - List result = []; + List result = []; - final regx = RegExp(r'move:(.{4}).+score:(\-?\d+).+winrate:(\d+.?\d*)'); + final regExp = RegExp(r'move:(.{4}).+score:(\-?\d+).+winRate:(\d+.?\d*)'); for (var segment in segments) { - // - final match = regx.firstMatch(segment); + final match = regExp.firstMatch(segment); if (match == null) break; final move = match.group(1); final score = int.parse(match.group(2)); - final winrate = double.parse(match.group(3)); + final winRate = double.parse(match.group(3)); - result.add(AnalysisItem(move: move, score: score, winrate: winrate)); + result.add(AnalyzeItem(move: move, score: score, winRate: winRate)); if (result.length == limit) break; } diff --git a/src/ui/flutter/lib/engine/engine.dart b/src/ui/flutter/lib/engine/engine.dart index 42dff9e7..bad829a3 100644 --- a/src/ui/flutter/lib/engine/engine.dart +++ b/src/ui/flutter/lib/engine/engine.dart @@ -17,7 +17,7 @@ along with this program. If not, see . */ -import '../mill/position.dart'; +import 'package:sanmill/mill/position.dart'; enum EngineType { Cloud, Native } @@ -28,10 +28,7 @@ class EngineResponse { } abstract class AiEngine { - // Future startup() async {} - Future shutdown() async {} - Future search(Position position, {bool byUser = true}); } diff --git a/src/ui/flutter/lib/engine/native_engine.dart b/src/ui/flutter/lib/engine/native_engine.dart index da3d0419..54b72b69 100644 --- a/src/ui/flutter/lib/engine/native_engine.dart +++ b/src/ui/flutter/lib/engine/native_engine.dart @@ -18,30 +18,25 @@ */ import 'package:flutter/services.dart'; +import 'package:sanmill/mill/mill.dart'; +import 'package:sanmill/mill/position.dart'; -import '../mill/mill.dart'; -import '../mill/position.dart'; import 'engine.dart'; class NativeEngine extends AiEngine { - // static const platform = const MethodChannel('com.calcitem.sanmill/engine'); Future startup() async { - // try { await platform.invokeMethod('startup'); } catch (e) { print('Native startup Error: $e'); } - //await setBookFile(); - await waitResponse(['uciok'], sleep: 1, times: 30); } Future send(String command) async { - // try { print("send: $command"); await platform.invokeMethod('send', command); @@ -51,7 +46,6 @@ class NativeEngine extends AiEngine { } Future read() async { - // try { return await platform.invokeMethod('read'); } catch (e) { @@ -62,7 +56,6 @@ class NativeEngine extends AiEngine { } Future shutdown() async { - // try { await platform.invokeMethod('shutdown'); } catch (e) { @@ -71,7 +64,6 @@ class NativeEngine extends AiEngine { } Future isReady() async { - // try { return await platform.invokeMethod('isReady'); } catch (e) { @@ -82,7 +74,6 @@ class NativeEngine extends AiEngine { } Future isThinking() async { - // try { return await platform.invokeMethod('isThinking'); } catch (e) { @@ -92,32 +83,11 @@ class NativeEngine extends AiEngine { return null; } -/* - Future setBookFile() async { - // - final docDir = await getApplicationDocumentsDirectory(); - final bookFile = File('${docDir.path}/book.dat'); - - try { - if (!await bookFile.exists()) { - await bookFile.create(recursive: true); - final bytes = await rootBundle.load("assets/book.dat"); - await bookFile.writeAsBytes(bytes.buffer.asUint8List()); - } - } catch (e) { - print(e); - } - - await send("setoption bookfiles ${bookFile.path}"); - } - */ - @override Future search(Position position, {bool byUser = true}) async { - // if (await isThinking()) await stopSearching(); - send(buildPositionCommand(position)); + send(getPositionFen(position)); send('go'); final response = await waitResponse(['bestmove', 'nobestmove']); @@ -125,13 +95,12 @@ class NativeEngine extends AiEngine { print("response: $response"); if (response.startsWith('bestmove')) { - // - var step = response.substring('bestmove'.length + 1); + var best = response.substring('bestmove'.length + 1); - final pos = step.indexOf(' '); - if (pos > -1) step = step.substring(0, pos); + final pos = best.indexOf(' '); + if (pos > -1) best = best.substring(0, pos); - return EngineResponse('move', value: Move.fromEngineMove(step)); + return EngineResponse('move', value: Move.set(best)); } if (response.startsWith('nobestmove')) { @@ -143,7 +112,6 @@ class NativeEngine extends AiEngine { Future waitResponse(List prefixes, {sleep = 100, times = 100}) async { - // if (times <= 0) return ''; final response = await read(); @@ -164,7 +132,7 @@ class NativeEngine extends AiEngine { await send('stop'); } - String buildPositionCommand(Position position) { + String getPositionFen(Position position) { /* final startPosition = position.lastCapturedPosition; final moves = position.movesSinceLastCaptured(); diff --git a/src/ui/flutter/lib/main.dart b/src/ui/flutter/lib/main.dart index f9cb5ad4..1d7fadce 100644 --- a/src/ui/flutter/lib/main.dart +++ b/src/ui/flutter/lib/main.dart @@ -22,9 +22,9 @@ import 'dart:io'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; -import './routes/main_menu.dart'; import 'services/audios.dart'; import 'services/player.dart'; +import 'widgets/main_menu.dart'; void main() { // diff --git a/src/ui/flutter/lib/game/battle.dart b/src/ui/flutter/lib/mill/game.dart similarity index 67% rename from src/ui/flutter/lib/game/battle.dart rename to src/ui/flutter/lib/mill/game.dart index 6f97ff31..2caf220a 100644 --- a/src/ui/flutter/lib/game/battle.dart +++ b/src/ui/flutter/lib/mill/game.dart @@ -17,14 +17,13 @@ along with this program. If not, see . */ -import 'package:sanmill/common/types.dart'; +import 'package:sanmill/mill/types.dart'; -import '../mill/mill.dart'; -import '../mill/position.dart'; +import 'mill.dart'; +import 'position.dart'; -class Battle { - // - static Battle _instance; +class Game { + static Game _instance; Position _position; int _focusIndex, _blurIndex; @@ -32,21 +31,16 @@ class Battle { String sideToMove = Color.black; // 是否黑白反转 - bool isInverted; + bool isColorInverted; - Map isAiPlayer = {Color.black: false, Color.white: true}; - Map isAiSearching = {Color.black: false, Color.white: false}; - - Battle() { - //cmdlist = new List; - } + Map isAi = {Color.black: false, Color.white: true}; + Map isSearching = {Color.black: false, Color.white: false}; bool aiIsSearching() { - return isAiSearching[Color.black] == true || - isAiSearching[Color.white] == true; + return isSearching[Color.black] == true || isSearching[Color.white] == true; } - void gameStart() { + void start() { position.start(); } @@ -60,7 +54,7 @@ class Battle { static bool hasSound = true; // 是否必败时认输 - bool resignIfMostLose_ = false; + bool resignIfMostLose = false; // 是否自动交换先后手 bool isAutoChangeFirstMove = false; @@ -74,34 +68,34 @@ class Battle { // 提示语 String tips; - List cmdlist = [""]; + List moveHistory = [""]; String getTips() => tips; - bool isAIsTurn() { - return isAiPlayer[sideToMove]; + bool isAiToMove() { + return isAi[sideToMove]; } static get shared { - _instance ??= Battle(); + _instance ??= Game(); return _instance; } init() { _position = Position(); - _focusIndex = _blurIndex = Move.invalidValue; + _focusIndex = _blurIndex = Move.invalidMove; } newGame() { - Battle.shared.position.init(); - _focusIndex = _blurIndex = Move.invalidValue; - cmdlist = [""]; + Game.shared.position.init(); + _focusIndex = _blurIndex = Move.invalidMove; + moveHistory = [""]; sideToMove = Color.black; } select(int pos) { _focusIndex = pos; - _blurIndex = Move.invalidValue; + _blurIndex = Move.invalidMove; //Audios.playTone('click.mp3'); } @@ -112,30 +106,23 @@ class Battle { _blurIndex = from; _focusIndex = to; - /* - if (ChessRules.checked(position)) { - //Audios.playTone('check.mp3'); - } else { - //Audios.playTone(captured != Piece.Empty ? 'capture.mp3' : 'move.mp3'); - } - */ - return true; } - bool regret({steps = 2}) { + bool regret({moves = 2}) { // // 轮到自己走棋的时候,才能悔棋 + // TODO if (_position.side != Color.white) { //Audios.playTone('invalid.mp3'); return false; } - var regreted = false; + var regretted = false; /// 悔棋一回合(两步),才能撤回自己上一次的动棋 - for (var i = 0; i < steps; i++) { + for (var i = 0; i < moves; i++) { // if (!_position.regret()) break; @@ -148,13 +135,13 @@ class Battle { // } else { // - _blurIndex = _focusIndex = Move.invalidValue; + _blurIndex = _focusIndex = Move.invalidMove; } - regreted = true; + regretted = true; } - if (regreted) { + if (regretted) { //Audios.playTone('regret.mp3'); return true; } @@ -164,7 +151,7 @@ class Battle { } clear() { - _blurIndex = _focusIndex = Move.invalidValue; + _blurIndex = _focusIndex = Move.invalidMove; } GameResult scanBattleResult() { @@ -196,12 +183,12 @@ class Battle { // 如果未开局则开局 if (position.phase == Phase.ready) { - gameStart(); + start(); } print("Computer: $cmd"); - cmdlist.add(cmd); + moveHistory.add(cmd); if (!position.command(cmd)) { return false; @@ -209,30 +196,6 @@ class Battle { sideToMove = position.sideToMove(); - String winner = position.winner; - - if (winner != Color.nobody) { - //resumeAiThreads(position.sideToMove()); - // TODO - } else { - // pauseThreads(); - - /* - if (gameOptions.getAutoRestart()) { - saveScore(); - - gameReset(); - gameStart(); - - if (isAiPlayer[BLACK]) { - setEngine(BLACK, true); - } - if (isAiPlayer[WHITE]) { - setEngine(WHITE, true); - } - } - */ - } total = position.score[Color.black] + position.score[Color.white] + position.score[Color.draw]; @@ -247,7 +210,7 @@ class Battle { drawRate = position.score[Color.draw] * 100 / total; } - String outStr = "Score: " + + String stat = "Score: " + position.score[Color.black].toString() + " : " + position.score[Color.white].toString() + @@ -264,7 +227,7 @@ class Battle { "%" + "\n"; - print(outStr); + print(stat); return true; } } diff --git a/src/ui/flutter/lib/mill/mill.dart b/src/ui/flutter/lib/mill/mill.dart index 5686f1f9..9dda9c32 100644 --- a/src/ui/flutter/lib/mill/mill.dart +++ b/src/ui/flutter/lib/mill/mill.dart @@ -17,7 +17,7 @@ along with this program. If not, see . */ -import 'package:sanmill/common/types.dart'; +import 'types.dart'; Map squareToIndex = { 8: 17, @@ -56,7 +56,6 @@ int makeSquare(int file, int rank) { enum GameResult { pending, win, lose, draw } class Color { - // static const none = '*'; static const black = '@'; static const white = 'O'; @@ -85,24 +84,19 @@ class Color { } class Piece { - // - static const noPiece = '*'; - // - static const blackStone = '@'; - static const whiteStone = 'O'; - static const ban = 'X'; + static const noPiece = Color.none; + static const blackStone = Color.black; + static const whiteStone = Color.white; + static const ban = Color.ban; - static bool isBlack(String c) => '@'.contains(c); - - static bool isWhite(String c) => 'O'.contains(c); - - static bool isBan(String c) => 'X'.contains(c); - - static bool isEmpty(String c) => '*'.contains(c); + static bool isEmpty(String c) => noPiece.contains(c); + static bool isBlack(String c) => blackStone.contains(c); + static bool isWhite(String c) => whiteStone.contains(c); + static bool isBan(String c) => ban.contains(c); } class Move { - static const invalidValue = -1; + static const invalidMove = -1; // Square int from = 0; @@ -118,7 +112,7 @@ class Move { int fromIndex = 0; int toIndex = 0; - String captured; + String removed; // 'move' is the UCI engine's move-string String move; @@ -129,13 +123,13 @@ class Move { String counterMarks; parse() { - if (!validateEngineMove(move)) { + if (!legal(move)) { throw "Error: Invalid Move: $move"; } if (move[0] == '-' && move.length == "-(1,2)".length) { type = MoveType.remove; - from = fromFile = fromRank = fromIndex = invalidValue; + from = fromFile = fromRank = fromIndex = invalidMove; toFile = int.parse(move[2]); toRank = int.parse(move[4]); //captured = Piece.noPiece; @@ -147,13 +141,13 @@ class Move { fromIndex = squareToIndex[from]; toFile = int.parse(move[8]); toRank = int.parse(move[10]); - captured = Piece.noPiece; + removed = Piece.noPiece; } else if (move.length == "(1,2)".length) { type = MoveType.place; - from = fromFile = fromRank = fromIndex = invalidValue; + from = fromFile = fromRank = fromIndex = invalidMove; toFile = int.parse(move[1]); toRank = int.parse(move[3]); - captured = Piece.noPiece; + removed = Piece.noPiece; } else if (move == "draw") { // TODO print("Computer request draw"); @@ -169,44 +163,24 @@ class Move { parse(); } - /* - Move(this.from, this.to, - {this.captured = Piece.noPiece, this.counterMarks = '0 0'}) { - // - fx = from % 9; - fy = from ~/ 9; - - tx = to % 9; - ty = to ~/ 9; - - if (fx < 0 || fx > 8 || fy < 0 || fy > 9) { - throw "Error: Invalid Step (from:$from, to:$to)"; - } - - move = String.fromCharCode('a'.codeUnitAt(0) + fx) + (9 - fy).toString(); - move += String.fromCharCode('a'.codeUnitAt(0) + tx) + (9 - ty).toString(); - } - */ - /// 引擎返回的招法用是如此表示的,例如: /// 落子:(1,2) /// 吃子:-(1,2) /// 走子:(3,1)->(2,1) - Move.fromEngineMove(String move) { - // + Move.set(String move) { this.move = move; parse(); } - static bool validateEngineMove(String move) { + static bool legal(String move) { if (move == "draw") { return true; // TODO } if (move == null || move.length > "(3,1)->(2,1)".length) return false; - String sets = "0123456789(,)->"; + String range = "0123456789(,)->"; if (!(move[0] == '(' || move[0] == '-')) { return false; @@ -217,7 +191,13 @@ class Move { } for (int i = 0; i < move.length; i++) { - if (!sets.contains(move[i])) return false; + if (!range.contains(move[i])) return false; + } + + if (move.length == "(3,1)->(2,1)".length) { + if (move.substring(0, 4) == move.substring(7, 11)) { + return false; + } } return true; diff --git a/src/ui/flutter/lib/mill/position.dart b/src/ui/flutter/lib/mill/position.dart index 8b13388a..aa5585bd 100644 --- a/src/ui/flutter/lib/mill/position.dart +++ b/src/ui/flutter/lib/mill/position.dart @@ -18,11 +18,11 @@ */ import 'package:flutter/cupertino.dart'; +import 'package:sanmill/mill/mill.dart'; +import 'package:sanmill/mill/recorder.dart'; +import 'package:sanmill/mill/rule.dart'; -import '../common/types.dart'; -import '../mill/mill.dart'; -import '../mill/recorder.dart'; -import '../mill/rule.dart'; +import 'types.dart'; class StateInfo { /* @@ -44,10 +44,10 @@ class Position { GameResult result = GameResult.pending; - List board = List(40); - List _grid = List(49); // 7 * 7 + List board = List(sqNumber); + List _grid = List(7 * 7); - MillRecorder _recorder; + GameRecorder _recorder; Map pieceCountInHand = {Color.black: 12, Color.white: 12}; Map pieceCountOnBoard = {Color.black: 0, Color.white: 0}; @@ -64,6 +64,7 @@ class Position { String us = Color.black; String them = Color.white; String winner = Color.nobody; + GameOverReason gameOverReason = GameOverReason.noReason; Phase phase = Phase.none; @@ -145,57 +146,9 @@ class Position { return pieceOn(fromSq(move)); } - bool selectPieceFR(int file, int rank) { - return selectPieceSQ(makeSquare(file, rank)); - } - - 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 (selectPiece(fromSq)) { - return putPiece(toSq); + bool movePiece(int from, int to) { + if (selectPiece(from)) { + return putPiece(to); } return false; @@ -219,7 +172,7 @@ class Position { // TODO - _recorder = MillRecorder(lastCapturedPosition: fen()); + _recorder = GameRecorder(lastPositionWithRemove: fen()); } Position() { @@ -227,41 +180,6 @@ class Position { init(); } - 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() { @@ -354,19 +272,19 @@ class Position { /// Position::legal() tests whether a pseudo-legal move is legal - bool legal(int move) { - assert(isOk(move)); + bool legal(Move move) { + if (!isOk(move.from) || !isOk(move.to)) return false; String us = _sideToMove; - int fromSQ = fromSq(move); - int toSQ = toSq(move); - if (fromSQ == toSQ) { + if (move.from == move.to) { + print("Move $move.move from == to"); return false; // TODO: Same with is_ok(m) } - if (phase == Phase.moving && typeOf(move) != MoveType.remove) { - if (movedPiece(move) != us) { + if (move.type == MoveType.remove) { + if (movedPiece(move.to) != us) { + print("Move $move.to to != us"); return false; } } @@ -376,20 +294,10 @@ class Position { 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); - } - void doMove(Move m) { - // - //if (!validateMove(m)) return null; - - //final move = Move(m); + if (!legal(m)) { + return null; + } bool ret = false; @@ -421,22 +329,11 @@ class Position { this.move = m; - //StepName.translate(this, move); - _recorder.stepIn(move, this); - - // 交换走棋方 - //_sideToMove = Color.opponent(_sideToMove); - } - - void doNullMove() { - changeSideToMove(); - } - - void undoNullMove() { - changeSideToMove(); + _recorder.moveIn(move, this); } bool posIsOk() { + // TODO return true; } @@ -445,9 +342,9 @@ class Position { int piecesOnBoardCount() { pieceCountOnBoard[Color.black] = pieceCountOnBoard[Color.white] = 0; - for (int f = 1; f < 3 + 2; f++) { - for (int r = 0; r < 8; r++) { - int s = f * 8 + r; + for (int f = 1; f < fileExNumber; f++) { + for (int r = 0; r < rankNumber; r++) { + int s = f * rankNumber + r; if (board[s] == Piece.blackStone) { pieceCountOnBoard[Color.black]++; } else if (board[s] == Piece.whiteStone) { @@ -473,6 +370,16 @@ class Position { return pieceCountOnBoard[Color.black] + pieceCountOnBoard[Color.white]; } + void clearBoard() { + for (int i = 0; i < _grid.length; i++) { + _grid[i] = Piece.noPiece; + } + + for (int i = 0; i < board.length; i++) { + board[i] = Piece.noPiece; + } + } + int setPosition(Rule newRule) { result = GameResult.pending; @@ -490,13 +397,7 @@ class Position { cmdline = ""; - for (int i = 0; i < _grid.length; i++) { - _grid[i] = Piece.noPiece; - } - - for (int i = 0; i < board.length; i++) { - board[i] = Piece.noPiece; - } + clearBoard(); if (piecesOnBoardCount() == -1) { return -1; @@ -509,6 +410,7 @@ class Position { createMoveTable(); createMillTable(); currentSquare = 0; + return -1; } @@ -523,13 +425,7 @@ class Position { winner = Color.nobody; 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; - } + clearBoard(); pieceCountOnBoard[Color.black] = pieceCountOnBoard[Color.white] = 0; pieceCountInHand[Color.black] = @@ -761,13 +657,13 @@ class Position { return true; } - bool selectPiece(int s) { + bool selectPiece(int sq) { if (phase != Phase.moving) return false; if (action != Act.select && action != Act.place) return false; - if (board[s] == sideToMove()) { - currentSquare = s; + if (board[sq] == sideToMove()) { + currentSquare = sq; action = Act.place; return true; @@ -793,18 +689,19 @@ class Position { bool command(String cmd) { // TODO /* - if (sscanf(cmd, "r%1u s%3d t%2u", &ruleIndex, &step, &t) == 3) { - if (ruleIndex <= 0 || ruleIndex > N_RULES) { - return false; - } + if (sscanf(cmd, "r%1u s%3d t%2u", &ruleIndex, &step, &t) == 3) { + if (ruleIndex <= 0 || ruleIndex > N_RULES) { + return false; + } - return set_position(&RULES[ruleIndex - 1]) >= 0 ? true : false; - } + return set_position(&RULES[ruleIndex - 1]) >= 0 ? true : false; + } */ print("position: command = $cmd"); - if (cmd.length > 6 && cmd.substring(0, 5) == "Player") { - if (cmd[6] == '1') { + if (cmd.length > "Player".length && + cmd.substring(0, "Player".length - 1) == "Player") { + if (cmd["Player".length] == '1') { return resign(Color.black); } else { return resign(Color.white); @@ -1449,7 +1346,7 @@ class Position { int inHowManyMills(int s, String c, {int squareSelected = 0}) { int n = 0; - String locbak = Piece.noPiece; + String ptBak = Piece.noPiece; assert(0 <= squareSelected && squareSelected < sqNumber); @@ -1458,20 +1355,19 @@ class Position { } if (squareSelected != 0) { - locbak = board[squareSelected]; + ptBak = board[squareSelected]; board[squareSelected] = _grid[squareToIndex[squareSelected]] = Piece.noPiece; } for (int l = 0; l < lineDirectionNumber; l++) { - // TODO: right? if (c == board[millTable[s][l][0]] && c == board[millTable[s][l][1]]) { n++; } } if (squareSelected != 0) { - board[squareSelected] = _grid[squareToIndex[squareSelected]] = locbak; + board[squareSelected] = _grid[squareToIndex[squareSelected]] = ptBak; } return n; @@ -1490,7 +1386,6 @@ class Position { idx[2] = millTable[s][i][1]; // no mill - // TODO: right? if (!(m == board[idx[1]] && m == board[idx[2]])) { continue; } @@ -1571,45 +1466,37 @@ class Position { /////////////////////////////////////////////////////////////////////////////// -// 验证移动棋子的着法是否合法 - bool validateMove(int from, int to) { - // 移动的棋子的选手,应该是当前方 - //if (Color.of(_board[from]) != _sideToMove) return false; - return true; - //(StepValidate.validate(this, Move(from, to))); - } - bool regret() { // TODO final lastMove = _recorder.removeLast(); if (lastMove == null) return false; _grid[lastMove.from] = _grid[lastMove.to]; - _grid[lastMove.to] = lastMove.captured; + _grid[lastMove.to] = lastMove.removed; board[lastMove.from] = board[lastMove.to]; - board[lastMove.to] = lastMove.captured; + board[lastMove.to] = lastMove.removed; changeSideToMove(); - final counterMarks = MillRecorder.fromCounterMarks(lastMove.counterMarks); + final counterMarks = GameRecorder.fromCounterMarks(lastMove.counterMarks); _recorder.halfMove = counterMarks.halfMove; _recorder.fullMove = counterMarks.fullMove; - if (lastMove.captured != Piece.noPiece) { + if (lastMove.removed != Piece.noPiece) { // // 查找上一个吃子局面(或开局),NativeEngine 需要 final tempPosition = Position.clone(this); - final moves = _recorder.reverseMovesToPrevCapture(); + final moves = _recorder.reverseMovesToPrevRemove(); moves.forEach((move) { // tempPosition._grid[move.from] = tempPosition._grid[move.to]; - tempPosition._grid[move.to] = move.captured; + tempPosition._grid[move.to] = move.removed; tempPosition._sideToMove = Color.opponent(tempPosition._sideToMove); }); - _recorder.lastCapturedPosition = tempPosition.fen(); + _recorder.lastPositionWithRemove = tempPosition.fen(); } result = GameResult.pending; @@ -1617,20 +1504,20 @@ class Position { return true; } - String movesSinceLastCaptured() { + String movesSinceLastRemove() { // - var steps = '', posAfterLastCaptured = 0; + var moves = '', posAfterLastRemove = 0; - for (var i = _recorder.stepsCount - 1; i >= 0; i--) { - if (_recorder.stepAt(i).captured != Piece.noPiece) break; - posAfterLastCaptured = i; + for (var i = _recorder.movesCount - 1; i >= 0; i--) { + if (_recorder.stepAt(i).removed != Piece.noPiece) break; + posAfterLastRemove = i; } - for (var i = posAfterLastCaptured; i < _recorder.stepsCount; i++) { - steps += ' ${_recorder.stepAt(i).move}'; + for (var i = posAfterLastRemove; i < _recorder.movesCount; i++) { + moves += ' ${_recorder.stepAt(i).move}'; } - return steps.length > 0 ? steps.substring(1) : ''; + return moves.length > 0 ? moves.substring(1) : ''; } get manualText => _recorder.buildManualText(); @@ -1649,5 +1536,5 @@ class Position { get lastMove => _recorder.last; - get lastCapturedPosition => _recorder.lastCapturedPosition; + get lastPositionWithRemove => _recorder.lastPositionWithRemove; } diff --git a/src/ui/flutter/lib/mill/recorder.dart b/src/ui/flutter/lib/mill/recorder.dart index 0b6d9358..a65427d2 100644 --- a/src/ui/flutter/lib/mill/recorder.dart +++ b/src/ui/flutter/lib/mill/recorder.dart @@ -20,16 +20,16 @@ import 'mill.dart'; import 'position.dart'; -class MillRecorder { +class GameRecorder { // // 无吃子步数、总回合数 int halfMove, fullMove; - String lastCapturedPosition; + String lastPositionWithRemove; final _history = []; - MillRecorder( - {this.halfMove = 0, this.fullMove = 0, this.lastCapturedPosition}); - MillRecorder.fromCounterMarks(String marks) { + GameRecorder( + {this.halfMove = 0, this.fullMove = 0, this.lastPositionWithRemove}); + GameRecorder.fromCounterMarks(String marks) { // var segments = marks.split(' '); if (segments.length != 2) { @@ -43,9 +43,9 @@ class MillRecorder { throw 'Error: Invalid Counter Marks: $marks'; } } - void stepIn(Move move, Position position) { + void moveIn(Move move, Position position) { // - if (move.captured != Piece.noPiece) { + if (move.removed != Piece.noPiece) { halfMove = 0; } else { halfMove++; @@ -59,8 +59,8 @@ class MillRecorder { _history.add(move); - if (move.captured != Piece.noPiece) { - lastCapturedPosition = position.fen(); + if (move.removed != Piece.noPiece) { + lastPositionWithRemove = position.fen(); } } @@ -71,12 +71,12 @@ class MillRecorder { get last => _history.isEmpty ? null : _history.last; - List reverseMovesToPrevCapture() { + List reverseMovesToPrevRemove() { // List moves = []; for (var i = _history.length - 1; i >= 0; i--) { - if (_history[i].captured != Piece.noPiece) break; + if (_history[i].removed != Piece.noPiece) break; moves.add(_history[i]); } @@ -101,7 +101,7 @@ class MillRecorder { Move stepAt(int index) => _history[index]; - get stepsCount => _history.length; + get movesCount => _history.length; @override String toString() { diff --git a/src/ui/flutter/lib/common/types.dart b/src/ui/flutter/lib/mill/types.dart similarity index 84% rename from src/ui/flutter/lib/common/types.dart rename to src/ui/flutter/lib/mill/types.dart index a6b7aedc..7f0abb1a 100644 --- a/src/ui/flutter/lib/common/types.dart +++ b/src/ui/flutter/lib/mill/types.dart @@ -17,7 +17,7 @@ along with this program. If not, see . */ -import 'package:sanmill/common/misc.dart'; +import 'package:sanmill/common/algorithm.dart'; enum MoveType { place, move, remove } @@ -91,13 +91,20 @@ const lineDirectionNumber = 3; enum File { A, B, C } const fileNumber = 3; +const fileExNumber = fileNumber + 2; enum Rank { rank_1, rank_2, rank_3, rank_4, rank_5, rank_6, rank_7, rank_8 } const rankNumber = 8; bool isOk(int sq) { - return sq == 0 || (sq >= 8 && sq <= 31); // TODO: SQ_NONE? + bool ret = (sq == 0 || (sq >= 8 && sq <= 31)); + + if (ret == false) { + print("$sq is not OK"); + } + + return ret; // TODO: SQ_NONE? } int fileOf(int sq) { @@ -118,20 +125,6 @@ int toSq(int move) { return (move & 0x00FF); } -MoveType typeOf(int move) { - if (move < 0) { - return MoveType.remove; - } else if (move & 0x1f00 > 0) { - return MoveType.move; - } - - return MoveType.place; // m & 0x00ff -} - -int makeMove(int fromSq, int toSq) { - return (fromSq << 8) + toSq; -} - -int reverseMove(int move) { - return makeMove(toSq(move), fromSq(move)); +int makeMove(int from, int to) { + return (from << 8) + to; } diff --git a/src/ui/flutter/lib/board/board_painter.dart b/src/ui/flutter/lib/painting/board_painter.dart similarity index 92% rename from src/ui/flutter/lib/board/board_painter.dart rename to src/ui/flutter/lib/painting/board_painter.dart index 9cc8821c..2a6ef351 100644 --- a/src/ui/flutter/lib/board/board_painter.dart +++ b/src/ui/flutter/lib/painting/board_painter.dart @@ -18,25 +18,23 @@ */ import 'package:flutter/material.dart'; +import 'package:sanmill/style/colors.dart'; +import 'package:sanmill/widgets/board.dart'; -import '../board/painter_base.dart'; -import '../common/properties.dart'; -import 'board_widget.dart'; +import 'painter_base.dart'; -class BoardPainter extends PainterBase { - // +class BoardPainter extends PiecesBasePainter { BoardPainter({@required double width}) : super(width: width); @override void paint(Canvas canvas, Size size) { - // doPaint( canvas, thePaint, gridWidth, squareWidth, - offsetX: BoardWidget.padding + squareWidth / 2, - offsetY: BoardWidget.padding + BoardWidget.digitsHeight + squareWidth / 2, + offsetX: Board.padding + squareWidth / 2, + offsetY: Board.padding + Board.digitsHeight + squareWidth / 2, ); } @@ -53,8 +51,7 @@ class BoardPainter extends PainterBase { double offsetX, double offsetY, }) { - // - paint.color = Properties.boardLineColor; + paint.color = UIColors.boardLineColor; paint.style = PaintingStyle.stroke; const double borderLineWidth = 2.0; diff --git a/src/ui/flutter/lib/board/painter_base.dart b/src/ui/flutter/lib/painting/painter_base.dart similarity index 79% rename from src/ui/flutter/lib/board/painter_base.dart rename to src/ui/flutter/lib/painting/painter_base.dart index c7fc73c8..58856ff9 100644 --- a/src/ui/flutter/lib/board/painter_base.dart +++ b/src/ui/flutter/lib/painting/painter_base.dart @@ -18,18 +18,16 @@ */ import 'package:flutter/material.dart'; +import 'package:sanmill/widgets/board.dart'; -import 'board_widget.dart'; - -abstract class PainterBase extends CustomPainter { - // +abstract class PiecesBasePainter extends CustomPainter { final double width; final thePaint = Paint(); final gridWidth; final squareWidth; - PainterBase({@required this.width}) - : gridWidth = (width - BoardWidget.padding * 2), - squareWidth = (width - BoardWidget.padding * 2) / 7; + PiecesBasePainter({@required this.width}) + : gridWidth = (width - Board.padding * 2), + squareWidth = (width - Board.padding * 2) / 7; } diff --git a/src/ui/flutter/lib/board/pieces_painter.dart b/src/ui/flutter/lib/painting/pieces_painter.dart similarity index 70% rename from src/ui/flutter/lib/board/pieces_painter.dart rename to src/ui/flutter/lib/painting/pieces_painter.dart index b722cc44..6e33995d 100644 --- a/src/ui/flutter/lib/board/pieces_painter.dart +++ b/src/ui/flutter/lib/painting/pieces_painter.dart @@ -18,21 +18,20 @@ */ import 'package:flutter/material.dart'; +import 'package:sanmill/mill/mill.dart'; +import 'package:sanmill/mill/position.dart'; +import 'package:sanmill/style/colors.dart'; +import 'package:sanmill/widgets/board.dart'; -import '../board/painter_base.dart'; -import '../common/properties.dart'; -import '../mill/mill.dart'; -import '../mill/position.dart'; -import 'board_widget.dart'; +import 'painter_base.dart'; -class PiecePaintStub { +class PiecePaintPair { final String piece; final Offset pos; - PiecePaintStub({this.piece, this.pos}); + PiecePaintPair({this.piece, this.pos}); } -class PiecesPainter extends PainterBase { - // +class PiecesPainter extends PiecesBasePainter { final Position position; final int focusIndex, blurIndex; @@ -41,8 +40,8 @@ class PiecesPainter extends PainterBase { PiecesPainter({ @required double width, @required this.position, - this.focusIndex = Move.invalidValue, - this.blurIndex = Move.invalidValue, + this.focusIndex = Move.invalidMove, + this.blurIndex = Move.invalidMove, }) : super(width: width) { // pieceWidth = squareWidth * 0.9; // 棋子大小 @@ -50,7 +49,6 @@ class PiecesPainter extends PainterBase { @override void paint(Canvas canvas, Size size) { - // doPaint( canvas, thePaint, @@ -59,8 +57,8 @@ class PiecesPainter extends PainterBase { squareWidth: squareWidth, pieceWidth: pieceWidth, // 棋子放在线上中央 - offsetX: BoardWidget.padding + squareWidth / 2, - offsetY: BoardWidget.padding + BoardWidget.digitsHeight + squareWidth / 2, + offsetX: Board.padding + squareWidth / 2, + offsetY: Board.padding + Board.digitsHeight + squareWidth / 2, focusIndex: focusIndex, blurIndex: blurIndex, ); @@ -81,19 +79,18 @@ class PiecesPainter extends PainterBase { double pieceWidth, double offsetX, double offsetY, - int focusIndex = Move.invalidValue, - int blurIndex = Move.invalidValue, + int focusIndex = Move.invalidMove, + int blurIndex = Move.invalidMove, }) { // final left = offsetX; final top = offsetY; final shadowPath = Path(); - final piecesToDraw = []; + final piecesToDraw = []; // 在棋盘上画棋子 for (var row = 0; row < 7; row++) { - // for (var col = 0; col < 7; col++) { // final piece = position.pieceOnGrid(row * 7 + col); // 初始状态无棋子 @@ -102,7 +99,7 @@ class PiecesPainter extends PainterBase { var pos = Offset(left + squareWidth * col, top + squareWidth * row); - piecesToDraw.add(PiecePaintStub(piece: piece, pos: pos)); + piecesToDraw.add(PiecePaintPair(piece: piece, pos: pos)); shadowPath.addOval( Rect.fromCenter(center: pos, width: pieceWidth, height: pieceWidth), @@ -130,22 +127,22 @@ class PiecesPainter extends PainterBase { // 绘制棋子边界 switch (pps.piece) { case Piece.blackStone: - paint.color = Properties.blackPieceBorderColor; + paint.color = UIColors.blackPieceBorderColor; canvas.drawCircle(pps.pos, pieceRadius, paint); // 临时调试用 - paint.color = Properties.blackPieceColor; + paint.color = UIColors.blackPieceColor; canvas.drawCircle(pps.pos, pieceInnerRadius, paint); break; case Piece.whiteStone: - paint.color = Properties.whitePieceBorderColor; + paint.color = UIColors.whitePieceBorderColor; canvas.drawCircle(pps.pos, pieceRadius, paint); // 临时调试用 - paint.color = Properties.whitePieceColor; + paint.color = UIColors.whitePieceColor; canvas.drawCircle(pps.pos, pieceInnerRadius, paint); break; case Piece.ban: print("pps.piece is Ban"); - paint.color = Properties.banBorderColor; + paint.color = UIColors.banBorderColor; // TODO - paint.color = Properties.banColor; + paint.color = UIColors.banColor; canvas.drawLine(new Offset(0, 0), new Offset(pieceInnerRadius, pieceInnerRadius), paint); canvas.drawLine(new Offset(pieceInnerRadius, 0), @@ -155,33 +152,15 @@ class PiecesPainter extends PainterBase { assert(false); break; } - - /* - final textSpan = TextSpan(text: Piece.Names[pps.piece], style: textStyle); - - final textPainter = TextPainter( - text: textSpan, - textDirection: TextDirection.ltr, - )..layout(); - - - final metric = textPainter.computeLineMetrics()[0]; - final textSize = textPainter.size; - - // 从顶上算,文字的 Baseline 在 2/3 高度线上 - final textOffset = pps.pos - Offset(textSize.width / 2, metric.baseline - textSize.height / 3); - - textPainter.paint(canvas, textOffset); - */ }); // draw focus and blur position - if (focusIndex != Move.invalidValue) { + if (focusIndex != Move.invalidMove) { // final int row = focusIndex ~/ 7, column = focusIndex % 7; - paint.color = Properties.focusPositionColor; + paint.color = UIColors.focusPositionColor; paint.style = PaintingStyle.stroke; paint.strokeWidth = 2; @@ -192,11 +171,10 @@ class PiecesPainter extends PainterBase { ); } - if (blurIndex != Move.invalidValue) { - // + if (blurIndex != Move.invalidMove) { final row = blurIndex ~/ 7, column = blurIndex % 7; - paint.color = Properties.blurPositionColor; + paint.color = UIColors.blurPositionColor; paint.style = PaintingStyle.fill; canvas.drawCircle( diff --git a/src/ui/flutter/lib/services/audios.dart b/src/ui/flutter/lib/services/audios.dart index e810dd64..eaf237f7 100644 --- a/src/ui/flutter/lib/services/audios.dart +++ b/src/ui/flutter/lib/services/audios.dart @@ -29,7 +29,6 @@ class Audios { // try { if (_bgmPlayer == null) { - // _fixedBgmPlayer = AudioPlayer(); _bgmPlayer = AudioCache(prefix: 'audios/', fixedPlayer: _fixedBgmPlayer); @@ -43,7 +42,6 @@ class Audios { } static playTone(String fileName) async { - // try { if (_tonePlayer == null) { // diff --git a/src/ui/flutter/lib/services/player.dart b/src/ui/flutter/lib/services/player.dart index 1b402a58..e6df3e0f 100644 --- a/src/ui/flutter/lib/services/player.dart +++ b/src/ui/flutter/lib/services/player.dart @@ -32,7 +32,6 @@ class Player extends RankItem { static get shared => _instance; static Future loadProfile() async { - // if (_instance == null) { _instance = Player(); await _instance._load(); @@ -42,7 +41,6 @@ class Player extends RankItem { } _load() async { - // final profile = await Profile.shared(); _uuid = profile['player-uuid']; @@ -56,14 +54,14 @@ class Player extends RankItem { name = values['name'] ?? '无名英雄'; winCloudEngine = values['win_cloud_engine'] ?? 0; - winPhoneAi = values['win_phone_ai'] ?? 0; + winAi = values['win_ai'] ?? 0; } } Player() : super.empty(); - Future increaseWinPhoneAi() async { - winPhoneAi++; + Future increaseWinAi() async { + winAi++; await saveAndUpload(); } diff --git a/src/ui/flutter/lib/services/ranks.dart b/src/ui/flutter/lib/services/ranks.dart index f4169638..c494fa3b 100644 --- a/src/ui/flutter/lib/services/ranks.dart +++ b/src/ui/flutter/lib/services/ranks.dart @@ -23,33 +23,33 @@ import 'dart:io'; class RankItem { // String name; - int winCloudEngine, winPhoneAi; + int winCloudEngine, winAi; RankItem(Map values) { name = values['name'] ?? '无名英雄'; winCloudEngine = values['win_cloud_engine'] ?? 0; - winPhoneAi = values['win_phone_ai'] ?? 0; + winAi = values['win_ai'] ?? 0; } RankItem.empty() { name = '无名英雄'; winCloudEngine = 0; - winPhoneAi = 0; + winAi = 0; } RankItem.mock() { name = '我是英雄'; winCloudEngine = 3; - winPhoneAi = 12; + winAi = 12; } Map toMap() => { 'name': name, 'win_cloud_engine': winCloudEngine, - 'win_phone_ai': winPhoneAi, + 'win_ai': winAi, }; - get score => winCloudEngine * 30 + winPhoneAi * 5; + get score => winCloudEngine * 30 + winAi * 5; } class Ranks { @@ -113,7 +113,7 @@ class Ranks { 'uuid': uuid, 'name': rank.name, 'win_cloud_engine': '${rank.winCloudEngine}', - 'win_phone_ai': '${rank.winPhoneAi}', + 'win_ai': '${rank.winAi}', }); final httpClient = HttpClient(); diff --git a/src/ui/flutter/lib/common/properties.dart b/src/ui/flutter/lib/style/colors.dart similarity index 99% rename from src/ui/flutter/lib/common/properties.dart rename to src/ui/flutter/lib/style/colors.dart index bb957e77..da4af433 100644 --- a/src/ui/flutter/lib/common/properties.dart +++ b/src/ui/flutter/lib/style/colors.dart @@ -19,7 +19,7 @@ import 'package:flutter/material.dart'; -class Properties { +class UIColors { // static const logoColor = Color(0xFF6D000D); diff --git a/src/ui/flutter/lib/common/toast.dart b/src/ui/flutter/lib/style/toast.dart similarity index 100% rename from src/ui/flutter/lib/common/toast.dart rename to src/ui/flutter/lib/style/toast.dart diff --git a/src/ui/flutter/lib/board/board_widget.dart b/src/ui/flutter/lib/widgets/board.dart similarity index 83% rename from src/ui/flutter/lib/board/board_widget.dart rename to src/ui/flutter/lib/widgets/board.dart index bea1a07c..7ac20546 100644 --- a/src/ui/flutter/lib/board/board_widget.dart +++ b/src/ui/flutter/lib/widgets/board.dart @@ -18,14 +18,14 @@ */ import 'package:flutter/material.dart'; +import 'package:sanmill/mill/game.dart'; +import 'package:sanmill/painting/board_painter.dart'; +import 'package:sanmill/painting/pieces_painter.dart'; +import 'package:sanmill/style/colors.dart'; -import '../common/properties.dart'; -import '../game/battle.dart'; -import 'board_painter.dart'; -import 'pieces_painter.dart'; import 'words_on_board.dart'; -class BoardWidget extends StatelessWidget { +class Board extends StatelessWidget { // static const padding = 5.0; static const digitsHeight = 0.0; @@ -36,8 +36,7 @@ class BoardWidget extends StatelessWidget { final double height; final Function(BuildContext, int) onBoardTap; - BoardWidget({@required this.width, @required this.onBoardTap}) - : height = width; + Board({@required this.width, @required this.onBoardTap}) : height = width; @override Widget build(BuildContext context) { @@ -47,15 +46,15 @@ class BoardWidget extends StatelessWidget { height: height, decoration: BoxDecoration( borderRadius: BorderRadius.circular(boardBorderRadius), - color: Properties.boardBackgroundColor, + color: UIColors.boardBackgroundColor, ), child: CustomPaint( painter: BoardPainter(width: width), foregroundPainter: PiecesPainter( width: width, - position: Battle.shared.position, - focusIndex: Battle.shared.focusIndex, - blurIndex: Battle.shared.blurIndex, + position: Game.shared.position, + focusIndex: Game.shared.focusIndex, + blurIndex: Game.shared.blurIndex, ), child: Container( margin: EdgeInsets.symmetric( diff --git a/src/ui/flutter/lib/routes/edit_page.dart b/src/ui/flutter/lib/widgets/edit_page.dart similarity index 92% rename from src/ui/flutter/lib/routes/edit_page.dart rename to src/ui/flutter/lib/widgets/edit_page.dart index dd836054..4ec45a06 100644 --- a/src/ui/flutter/lib/routes/edit_page.dart +++ b/src/ui/flutter/lib/widgets/edit_page.dart @@ -18,8 +18,7 @@ */ import 'package:flutter/material.dart'; - -import '../common/properties.dart'; +import 'package:sanmill/style/colors.dart'; class EditPage extends StatefulWidget { // @@ -58,7 +57,7 @@ class _EditPageState extends State { // final inputBorder = OutlineInputBorder( borderRadius: BorderRadius.circular(25), - borderSide: BorderSide(color: Properties.secondaryColor), + borderSide: BorderSide(color: UIColors.secondaryColor), ); return Scaffold( @@ -72,7 +71,7 @@ class _EditPageState extends State { ) ], ), - backgroundColor: Properties.lightBackgroundColor, + backgroundColor: UIColors.lightBackgroundColor, body: Container( margin: EdgeInsets.all(16), child: Column( @@ -86,7 +85,7 @@ class _EditPageState extends State { focusedBorder: inputBorder, ), style: TextStyle( - color: Properties.primaryColor, fontSize: 16, fontFamily: ''), + color: UIColors.primaryColor, fontSize: 16, fontFamily: ''), onSubmitted: (input) => onSubmit(input), focusNode: _commentFocus, ), diff --git a/src/ui/flutter/lib/routes/battle_page.dart b/src/ui/flutter/lib/widgets/game_page.dart similarity index 61% rename from src/ui/flutter/lib/routes/battle_page.dart rename to src/ui/flutter/lib/widgets/game_page.dart index 20fb1613..fdfff7cf 100644 --- a/src/ui/flutter/lib/routes/battle_page.dart +++ b/src/ui/flutter/lib/widgets/game_page.dart @@ -18,53 +18,49 @@ */ import 'package:flutter/material.dart'; +import 'package:sanmill/engine/analyze.dart'; +import 'package:sanmill/engine/engine.dart'; +import 'package:sanmill/engine/native_engine.dart'; +import 'package:sanmill/main.dart'; +import 'package:sanmill/mill/game.dart'; +import 'package:sanmill/mill/mill.dart'; +import 'package:sanmill/mill/types.dart'; +import 'package:sanmill/services/player.dart'; +import 'package:sanmill/style/colors.dart'; +import 'package:sanmill/style/toast.dart'; -import '../board/board_widget.dart'; -import '../common/properties.dart'; -import '../common/toast.dart'; -import '../common/types.dart'; -import '../engine/analysis.dart'; -import '../engine/engine.dart'; -import '../engine/native_engine.dart'; -import '../game/battle.dart'; -import '../main.dart'; -import '../mill/mill.dart'; -import '../services/player.dart'; +import 'board.dart'; import 'settings_page.dart'; -class BattlePage extends StatefulWidget { +class GamePage extends StatefulWidget { // static double boardMargin = 10.0, screenPaddingH = 10.0; final EngineType engineType; final AiEngine engine; - BattlePage(this.engineType) : engine = NativeEngine(); + GamePage(this.engineType) : engine = NativeEngine(); @override - _BattlePageState createState() => _BattlePageState(); + _GamePageState createState() => _GamePageState(); } -class _BattlePageState extends State { +class _GamePageState extends State { // String _status = ''; - bool _analysising = false; - - //static int flag = 0; + bool _searching = false; @override void initState() { - // super.initState(); - Battle.shared.init(); - + Game.shared.init(); widget.engine.startup(); } changeStatus(String status) => setState(() => _status = status); onBoardTap(BuildContext context, int index) { - final position = Battle.shared.position; + final position = Game.shared.position; int sq = indexToSquare[index]; @@ -75,13 +71,13 @@ class _BattlePageState extends State { } // AI 走棋或正在搜索时,点击无效 - if (Battle.shared.isAIsTurn() || Battle.shared.aiIsSearching()) { + if (Game.shared.isAiToMove() || Game.shared.aiIsSearching()) { return false; } // 如果未开局则开局 if (position.phase == Phase.ready) { - Battle.shared.gameStart(); + Game.shared.start(); } // 判断执行选子、落子或去子 @@ -92,11 +88,11 @@ class _BattlePageState extends State { if (position.putPiece(sq)) { if (position.action == Act.remove) { // 播放成三音效 - //playSound(GAME_SOUND_MILL, position.side_to_move()); + //Audios.playTone('mill.mp3'); changeStatus('请吃子'); } else { // 播放移动棋子音效 - //playSound(GAME_SOUND_DROG, position.side_to_move()); + //Audios.playTone('put.mp3'); changeStatus('已落子'); } result = true; @@ -112,19 +108,16 @@ class _BattlePageState extends State { continue select; select: case Act.select: - //piece = qgraphicsitem_cast(item); - //if (!piece) - //break; if (position.selectPiece(sq)) { // 播放选子音效 - //playSound(GAME_SOUND_SELECT, position.side_to_move()); - Battle.shared.select(index); + //Audios.playTone('select.mp3'); + Game.shared.select(index); result = true; print("selectPiece: [$sq]"); changeStatus('请落子'); } else { // 播放禁止音效 - //playSound(GAME_SOUND_BANNED, position.side_to_move()); + //Audios.playTone('banned.mp3'); print("selectPiece: skip [$sq]"); changeStatus('选择的子不对'); } @@ -133,13 +126,13 @@ class _BattlePageState extends State { case Act.remove: if (position.removePiece(sq)) { // 播放音效 - //playSound(GAME_SOUND_REMOVE, position.side_to_move()); + //Audios.playTone('remove.mp3'); result = true; print("removePiece: [$sq]"); changeStatus('已吃子'); } else { // 播放禁止音效 - //playSound(GAME_SOUND_BANNED, position.side_to_move()); + //Audios.playTone('banned.mp3'); print("removePiece: skip [$sq]"); changeStatus('不能吃这个子'); } @@ -151,135 +144,46 @@ class _BattlePageState extends State { } if (result) { - Battle.shared.cmdlist.add(position.cmdline); + Game.shared.moveHistory.add(position.cmdline); // 发信号更新状态栏 setState(() {}); - //message = QString::fromStdString(getTips()); - //emit statusBarChanged(message); - - // 将新增的棋谱行插入到ListModel - /* - currentRow = manualListModel.rowCount() - 1; - int k = 0; - - // 输出命令行 - for (const auto & i : *(cmd_list())) { - // 跳过已添加的,因标准list容器没有下标 - if (k++ <= currentRow) - continue; - manualListModel.insertRow(++currentRow); - manualListModel.setData(manualListModel.index(currentRow), i.c_str()); - } - */ - - // 播放胜利或失败音效 - /* - String winner = position.winner; - if (winner != Color.nobody && - (manualListModel.data(manualListModel.index(currentRow - 1))) - .toString() - .contains("Time over.")) playSound(GAME_SOUND_WIN, winner); - */ // AI设置 // 如果还未决出胜负 if (position.winner == Color.nobody) { - // Color.black is TODO - //resumeAiThreads(position.sideToMove()); engineToGo(); } } - Battle.shared.sideToMove = position.sideToMove(); + Game.shared.sideToMove = position.sideToMove(); setState(() {}); return result; - - // TODO: - - // 仅 Position 中的 side 指示一方能动棋 - //if (position.side != Color.black) return; - - final tapedPiece = position.pieceOnGrid(index); - print("Tap piece $tapedPiece at <$index>"); - - switch (position.phase) { - case Phase.placing: - engineToGo(); - break; - case Phase.moving: - // 之前已经有棋子被选中了 - if (Battle.shared.focusIndex != Move.invalidValue && - Color.of(position.pieceOnGrid(Battle.shared.focusIndex)) == - Color.black) { - // - // 当前点击的棋子和之前已经选择的是同一个位置 - if (Battle.shared.focusIndex == index) return; - - // 之前已经选择的棋子和现在点击的棋子是同一边的,说明是选择另外一个棋子 - final focusPiece = position.pieceOnGrid(Battle.shared.focusIndex); - - if (Color.isSameColor(focusPiece, tapedPiece)) { - // - Battle.shared.select(index); - // - } else if (Battle.shared.move(Battle.shared.focusIndex, index)) { - // 现在点击的棋子和上一次选择棋子不同边,要么是吃子,要么是移动棋子到空白处 - final result = Battle.shared.scanBattleResult(); - - switch (result) { - case GameResult.pending: - engineToGo(); - break; - case GameResult.win: - gotWin(); - break; - case GameResult.lose: - gotLose(); - break; - case GameResult.draw: - gotDraw(); - break; - } - } - // - } else { - // 之前未选择棋子,现在点击就是选择棋子 - if (tapedPiece != Piece.noPiece) Battle.shared.select(index); - } - - break; - default: - break; - } - - setState(() {}); } engineToGo() async { // TODO - while (Battle.shared.position.sideToMove() == Color.white) { - changeStatus('电脑思考中...'); + while (Game.shared.position.sideToMove() == Color.white) { + changeStatus('对方思考中...'); - final response = await widget.engine.search(Battle.shared.position); + final response = await widget.engine.search(Game.shared.position); if (response.type == 'move') { - // Move mv = response.value; final Move move = new Move(mv.move); //Battle.shared.move = move; - Battle.shared.command(move.move); + Game.shared.command(move.move); - final winner = Battle.shared.position.winner; + final winner = Game.shared.position.winner; switch (winner) { case Color.nobody: - if (Battle.shared.position.phase == Phase.placing) { + if (Game.shared.position.phase == Phase.placing) { changeStatus('请摆子'); - } else if (Battle.shared.position.phase == Phase.moving) { + } else if (Game.shared.position.phase == Phase.moving) { changeStatus('请走子'); } break; @@ -296,28 +200,22 @@ class _BattlePageState extends State { gotDraw(); break; } - // } else { - // changeStatus('Error: ${response.type}'); } } } newGame() { - // confirm() { Navigator.of(context).pop(); - Battle.shared.newGame(); - //setState(() {}); + Game.shared.newGame(); changeStatus('新游戏'); - if (Battle.shared.isAIsTurn()) { + if (Game.shared.isAiToMove()) { print("New Game: AI's turn."); engineToGo(); } - - //setState(() {}); } cancel() => Navigator.of(context).pop(); @@ -326,7 +224,7 @@ class _BattlePageState extends State { context: context, builder: (BuildContext context) { return AlertDialog( - title: Text('新局?', style: TextStyle(color: Properties.primaryColor)), + title: Text('新局?', style: TextStyle(color: UIColors.primaryColor)), content: SingleChildScrollView(child: Text('开始新局?')), actions: [ FlatButton(child: Text('确定'), onPressed: confirm), @@ -337,33 +235,32 @@ class _BattlePageState extends State { ); } - analysisPosition() async { + analyzePosition() async { // Toast.toast(context, msg: '正在分析局面...', position: ToastPostion.bottom); - setState(() => _analysising = true); + setState(() => _searching = true); try {} catch (e) { Toast.toast(context, msg: '错误: $e', position: ToastPostion.bottom); } finally { - setState(() => _analysising = false); + setState(() => _searching = false); } } - showAnalysisItems( + showAnalyzeItems( BuildContext context, { String title, - List items, - Function(AnalysisItem item) callback, + List items, + Function(AnalyzeItem item) callback, }) { - // final List children = []; for (var item in items) { children.add( ListTile( - title: Text(item.stepName, style: TextStyle(fontSize: 18)), - subtitle: Text('胜率:${item.winrate}%'), + title: Text(item.moveName, style: TextStyle(fontSize: 18)), + subtitle: Text('胜率:${item.winRate}%'), trailing: Text('分数:${item.score}'), onTap: () => callback(item), ), @@ -384,7 +281,7 @@ class _BattlePageState extends State { void gotWin() { // - Battle.shared.position.result = GameResult.win; + Game.shared.position.result = GameResult.win; //Audios.playTone('win.mp3'); showDialog( @@ -392,7 +289,7 @@ class _BattlePageState extends State { barrierDismissible: false, builder: (BuildContext context) { return AlertDialog( - title: Text('赢了', style: TextStyle(color: Properties.primaryColor)), + title: Text('赢了', style: TextStyle(color: UIColors.primaryColor)), content: Text('恭喜您取得了伟大的胜利!'), actions: [ FlatButton(child: Text('再来一盘'), onPressed: newGame), @@ -407,12 +304,12 @@ class _BattlePageState extends State { if (widget.engineType == EngineType.Cloud) Player.shared.increaseWinCloudEngine(); else - Player.shared.increaseWinPhoneAi(); + Player.shared.increaseWinAi(); } void gotLose() { // - Battle.shared.position.result = GameResult.lose; + Game.shared.position.result = GameResult.lose; //Audios.playTone('lose.mp3'); showDialog( @@ -420,7 +317,7 @@ class _BattlePageState extends State { barrierDismissible: false, builder: (BuildContext context) { return AlertDialog( - title: Text('输了', style: TextStyle(color: Properties.primaryColor)), + title: Text('输了', style: TextStyle(color: UIColors.primaryColor)), content: Text('勇士!坚定战斗,虽败犹荣!'), actions: [ FlatButton(child: Text('再来一盘'), onPressed: newGame), @@ -435,14 +332,14 @@ class _BattlePageState extends State { void gotDraw() { // - Battle.shared.position.result = GameResult.draw; + Game.shared.position.result = GameResult.draw; showDialog( context: context, barrierDismissible: false, builder: (BuildContext context) { return AlertDialog( - title: Text('和���', style: TextStyle(color: Properties.primaryColor)), + title: Text('和棋', style: TextStyle(color: UIColors.primaryColor)), content: Text('您用自己的力量捍卫了和平!'), actions: [ FlatButton(child: Text('再来一盘'), onPressed: newGame), @@ -463,17 +360,17 @@ class _BattlePageState extends State { if (height / width < 16.0 / 9.0) { width = height * 9 / 16; - BattlePage.screenPaddingH = - (windowSize.width - width) / 2 - BattlePage.boardMargin; + GamePage.screenPaddingH = + (windowSize.width - width) / 2 - GamePage.boardMargin; } } Widget createPageHeader() { // final titleStyle = - TextStyle(fontSize: 28, color: Properties.darkTextPrimaryColor); + TextStyle(fontSize: 28, color: UIColors.darkTextPrimaryColor); final subTitleStyle = - TextStyle(fontSize: 16, color: Properties.darkTextSecondaryColor); + TextStyle(fontSize: 16, color: UIColors.darkTextSecondaryColor); return Container( margin: EdgeInsets.only(top: SanmillApp.StatusBarHeight), @@ -483,7 +380,7 @@ class _BattlePageState extends State { children: [ IconButton( icon: Icon(Icons.arrow_back, - color: Properties.darkTextPrimaryColor), + color: UIColors.darkTextPrimaryColor), onPressed: () => Navigator.of(context).pop(), ), Expanded(child: SizedBox()), @@ -493,8 +390,8 @@ class _BattlePageState extends State { style: titleStyle), Expanded(child: SizedBox()), IconButton( - icon: Icon(Icons.settings, - color: Properties.darkTextPrimaryColor), + icon: + Icon(Icons.settings, color: UIColors.darkTextPrimaryColor), onPressed: () => Navigator.of(context).push( MaterialPageRoute(builder: (context) => SettingsPage()), ), @@ -506,7 +403,7 @@ class _BattlePageState extends State { width: 180, margin: EdgeInsets.only(bottom: 10), decoration: BoxDecoration( - color: Properties.boardBackgroundColor, + color: UIColors.boardBackgroundColor, borderRadius: BorderRadius.circular(2), ), ), @@ -523,12 +420,11 @@ class _BattlePageState extends State { // return Container( margin: EdgeInsets.symmetric( - horizontal: BattlePage.screenPaddingH, - vertical: BattlePage.boardMargin, + horizontal: GamePage.screenPaddingH, + vertical: GamePage.boardMargin, ), - child: BoardWidget( - width: - MediaQuery.of(context).size.width - BattlePage.screenPaddingH * 2, + child: Board( + width: MediaQuery.of(context).size.width - GamePage.screenPaddingH * 2, onBoardTap: onBoardTap, ), ); @@ -536,14 +432,14 @@ class _BattlePageState extends State { Widget createOperatorBar() { // - final buttonStyle = TextStyle(color: Properties.primaryColor, fontSize: 20); + final buttonStyle = TextStyle(color: UIColors.primaryColor, fontSize: 20); return Container( decoration: BoxDecoration( borderRadius: BorderRadius.circular(5), - color: Properties.boardBackgroundColor, + color: UIColors.boardBackgroundColor, ), - margin: EdgeInsets.symmetric(horizontal: BattlePage.screenPaddingH), + margin: EdgeInsets.symmetric(horizontal: GamePage.screenPaddingH), padding: EdgeInsets.symmetric(vertical: 2), child: Row(children: [ Expanded(child: SizedBox()), @@ -552,14 +448,14 @@ class _BattlePageState extends State { FlatButton( child: Text('悔棋', style: buttonStyle), onPressed: () { - Battle.shared.regret(steps: 2); + Game.shared.regret(steps: 2); setState(() {}); }, ), Expanded(child: SizedBox()), FlatButton( child: Text('分析', style: buttonStyle), - onPressed: _analysising ? null : analysisPosition, + onPressed: _searching ? null : analyzePosition, ), Expanded(child: SizedBox()), ]), @@ -570,12 +466,12 @@ class _BattlePageState extends State { // final size = MediaQuery.of(context).size; - final manualText = Battle.shared.position.manualText; + final manualText = Game.shared.position.manualText; if (size.height / size.width > 16 / 9) { return buildManualPanel(manualText); } else { - return buildExpandableManaulPanel(manualText); + return buildExpandableRecordPanel(manualText); } } @@ -583,7 +479,7 @@ class _BattlePageState extends State { // final manualStyle = TextStyle( fontSize: 18, - color: Properties.darkTextSecondaryColor, + color: UIColors.darkTextSecondaryColor, height: 1.5, ); @@ -595,20 +491,19 @@ class _BattlePageState extends State { ); } - Widget buildExpandableManaulPanel(String text) { + Widget buildExpandableRecordPanel(String text) { // final manualStyle = TextStyle(fontSize: 18, height: 1.5); return Expanded( child: IconButton( - icon: Icon(Icons.expand_less, color: Properties.darkTextPrimaryColor), + icon: Icon(Icons.expand_less, color: UIColors.darkTextPrimaryColor), onPressed: () => showDialog( context: context, barrierDismissible: false, builder: (BuildContext context) { return AlertDialog( - title: - Text('棋谱', style: TextStyle(color: Properties.primaryColor)), + title: Text('棋谱', style: TextStyle(color: UIColors.primaryColor)), content: SingleChildScrollView(child: Text(text, style: manualStyle)), actions: [ @@ -635,7 +530,7 @@ class _BattlePageState extends State { final footer = buildFooter(); return Scaffold( - backgroundColor: Properties.darkBackgroundColor, + backgroundColor: UIColors.darkBackgroundColor, body: Column(children: [header, board, operatorBar, footer]), ); } diff --git a/src/ui/flutter/lib/routes/main_menu.dart b/src/ui/flutter/lib/widgets/main_menu.dart similarity index 91% rename from src/ui/flutter/lib/routes/main_menu.dart rename to src/ui/flutter/lib/widgets/main_menu.dart index 63ed5311..db1485cf 100644 --- a/src/ui/flutter/lib/routes/main_menu.dart +++ b/src/ui/flutter/lib/widgets/main_menu.dart @@ -18,11 +18,11 @@ */ import 'package:flutter/material.dart'; +import 'package:sanmill/engine/engine.dart'; +import 'package:sanmill/main.dart'; +import 'package:sanmill/style/colors.dart'; -import '../common/properties.dart'; -import '../engine/engine.dart'; -import '../main.dart'; -import 'battle_page.dart'; +import 'game_page.dart'; import 'settings_page.dart'; class MainMenu extends StatefulWidget { @@ -31,13 +31,11 @@ class MainMenu extends StatefulWidget { } class _MainMenuState extends State with TickerProviderStateMixin { - // AnimationController inController, shadowController; Animation inAnimation, shadowAnimation; @override void initState() { - // super.initState(); inController = AnimationController( @@ -78,7 +76,6 @@ class _MainMenuState extends State with TickerProviderStateMixin { } navigateTo(Widget page) async { - // await Navigator.of(context) .push(MaterialPageRoute(builder: (context) => page)); @@ -108,7 +105,7 @@ class _MainMenuState extends State with TickerProviderStateMixin { ); final menuItemStyle = TextStyle( fontSize: 28, - color: Properties.primaryColor, + color: UIColors.primaryColor, shadows: [menuItemShadow], ); @@ -123,7 +120,7 @@ class _MainMenuState extends State with TickerProviderStateMixin { Expanded(child: SizedBox()), FlatButton( child: Text('人机对战', style: menuItemStyle), - onPressed: () => navigateTo(BattlePage(EngineType.Native)), + onPressed: () => navigateTo(GamePage(EngineType.Native)), ), Expanded(child: SizedBox()), Text('Calcitem', @@ -134,7 +131,7 @@ class _MainMenuState extends State with TickerProviderStateMixin { ); return Scaffold( - backgroundColor: Properties.lightBackgroundColor, + backgroundColor: UIColors.lightBackgroundColor, body: Stack( children: [ menuItems, @@ -142,7 +139,7 @@ class _MainMenuState extends State with TickerProviderStateMixin { top: SanmillApp.StatusBarHeight, left: 10, child: IconButton( - icon: Icon(Icons.settings, color: Properties.primaryColor), + icon: Icon(Icons.settings, color: UIColors.primaryColor), onPressed: () => Navigator.of(context).push( MaterialPageRoute(builder: (context) => SettingsPage()), ), diff --git a/src/ui/flutter/lib/routes/settings_page.dart b/src/ui/flutter/lib/widgets/settings_page.dart similarity index 82% rename from src/ui/flutter/lib/routes/settings_page.dart rename to src/ui/flutter/lib/widgets/settings_page.dart index 19e576e9..b498795a 100644 --- a/src/ui/flutter/lib/routes/settings_page.dart +++ b/src/ui/flutter/lib/widgets/settings_page.dart @@ -20,12 +20,12 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:package_info/package_info.dart'; +import 'package:sanmill/common/config.dart'; +import 'package:sanmill/services/audios.dart'; +import 'package:sanmill/services/player.dart'; +import 'package:sanmill/style/colors.dart'; +import 'package:sanmill/style/toast.dart'; -import '../common/config.dart'; -import '../common/properties.dart'; -import '../common/toast.dart'; -import '../services/audios.dart'; -import '../services/player.dart'; import 'edit_page.dart'; class SettingsPage extends StatefulWidget { @@ -34,8 +34,7 @@ class SettingsPage extends StatefulWidget { } class _SettingsPageState extends State { - // - String _version = 'Ver 1.00'; + String _version = ""; @override void initState() { @@ -53,12 +52,12 @@ class _SettingsPageState extends State { changeDifficult() { // - callback(int stepTime) async { + callback(int thinkingTime) async { // Navigator.of(context).pop(); setState(() { - Config.stepTime = stepTime; + Config.thinkingTime = thinkingTime; }); Config.save(); @@ -71,25 +70,25 @@ class _SettingsPageState extends State { children: [ SizedBox(height: 10), RadioListTile( - activeColor: Properties.primaryColor, + activeColor: UIColors.primaryColor, title: Text('初级'), - groupValue: Config.stepTime, + groupValue: Config.thinkingTime, value: 5000, onChanged: callback, ), Divider(), RadioListTile( - activeColor: Properties.primaryColor, + activeColor: UIColors.primaryColor, title: Text('中级'), - groupValue: Config.stepTime, + groupValue: Config.thinkingTime, value: 15000, onChanged: callback, ), Divider(), RadioListTile( - activeColor: Properties.primaryColor, + activeColor: UIColors.primaryColor, title: Text('高级'), - groupValue: Config.stepTime, + groupValue: Config.thinkingTime, value: 30000, onChanged: callback, ), @@ -150,8 +149,7 @@ class _SettingsPageState extends State { context: context, barrierDismissible: false, builder: (context) => AlertDialog( - title: - Text('关于「直棋 」', style: TextStyle(color: Properties.primaryColor)), + title: Text('关于「直棋 」', style: TextStyle(color: UIColors.primaryColor)), content: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, @@ -187,11 +185,11 @@ class _SettingsPageState extends State { Widget build(BuildContext context) { // final TextStyle headerStyle = - TextStyle(color: Properties.secondaryColor, fontSize: 20.0); - final TextStyle itemStyle = TextStyle(color: Properties.primaryColor); + TextStyle(color: UIColors.secondaryColor, fontSize: 20.0); + final TextStyle itemStyle = TextStyle(color: UIColors.primaryColor); return Scaffold( - backgroundColor: Properties.lightBackgroundColor, + backgroundColor: UIColors.lightBackgroundColor, appBar: AppBar(title: Text('设置')), body: SingleChildScrollView( padding: const EdgeInsets.all(16), @@ -202,7 +200,7 @@ class _SettingsPageState extends State { Text("人机难度", style: headerStyle), const SizedBox(height: 10.0), Card( - color: Properties.boardBackgroundColor, + color: UIColors.boardBackgroundColor, elevation: 0.5, margin: const EdgeInsets.symmetric(vertical: 4.0, horizontal: 0), child: Column( @@ -211,11 +209,13 @@ class _SettingsPageState extends State { title: Text("游戏难度", style: itemStyle), trailing: Row(mainAxisSize: MainAxisSize.min, children: [ - Text(Config.stepTime <= 5000 + Text(Config.thinkingTime <= 5000 ? '初级' - : Config.stepTime <= 15000 ? '中级' : '高级'), + : Config.thinkingTime <= 15000 + ? '中级' + : '高级'), Icon(Icons.keyboard_arrow_right, - color: Properties.secondaryColor), + color: UIColors.secondaryColor), ]), onTap: changeDifficult, ), @@ -225,19 +225,19 @@ class _SettingsPageState extends State { const SizedBox(height: 16), Text("声音", style: headerStyle), Card( - color: Properties.boardBackgroundColor, + color: UIColors.boardBackgroundColor, margin: const EdgeInsets.symmetric(vertical: 10), child: Column( children: [ SwitchListTile( - activeColor: Properties.primaryColor, + activeColor: UIColors.primaryColor, value: Config.bgmEnabled, title: Text("背景音乐", style: itemStyle), onChanged: switchMusic, ), _buildDivider(), SwitchListTile( - activeColor: Properties.primaryColor, + activeColor: UIColors.primaryColor, value: Config.toneEnabled, title: Text("提示音效", style: itemStyle), onChanged: switchTone, @@ -248,7 +248,7 @@ class _SettingsPageState extends State { const SizedBox(height: 16), Text("排行榜", style: headerStyle), Card( - color: Properties.boardBackgroundColor, + color: UIColors.boardBackgroundColor, margin: const EdgeInsets.symmetric(vertical: 10), child: Column( children: [ @@ -258,7 +258,7 @@ class _SettingsPageState extends State { Row(mainAxisSize: MainAxisSize.min, children: [ Text(Player.shared.name), Icon(Icons.keyboard_arrow_right, - color: Properties.secondaryColor), + color: UIColors.secondaryColor), ]), onTap: changeName, ), @@ -268,7 +268,7 @@ class _SettingsPageState extends State { const SizedBox(height: 16), Text("关于", style: headerStyle), Card( - color: Properties.boardBackgroundColor, + color: UIColors.boardBackgroundColor, margin: const EdgeInsets.symmetric(vertical: 10), child: Column( children: [ @@ -278,7 +278,7 @@ class _SettingsPageState extends State { Row(mainAxisSize: MainAxisSize.min, children: [ Text(_version ?? ''), Icon(Icons.keyboard_arrow_right, - color: Properties.secondaryColor), + color: UIColors.secondaryColor), ]), onTap: showAbout, ), @@ -297,7 +297,7 @@ class _SettingsPageState extends State { margin: const EdgeInsets.symmetric(horizontal: 16), width: double.infinity, height: 1.0, - color: Properties.lightLineColor, + color: UIColors.lightLineColor, ); } } diff --git a/src/ui/flutter/lib/board/words_on_board.dart b/src/ui/flutter/lib/widgets/words_on_board.dart similarity index 93% rename from src/ui/flutter/lib/board/words_on_board.dart rename to src/ui/flutter/lib/widgets/words_on_board.dart index 0dbee8ea..ffe2fe69 100644 --- a/src/ui/flutter/lib/board/words_on_board.dart +++ b/src/ui/flutter/lib/widgets/words_on_board.dart @@ -18,8 +18,7 @@ */ import 'package:flutter/material.dart'; - -import '../common/properties.dart'; +import 'package:sanmill/style/colors.dart'; class WordsOnBoard extends StatelessWidget { // @@ -45,7 +44,7 @@ class WordsOnBoard extends StatelessWidget { Row(children: rChildren), ], ), - style: TextStyle(color: Properties.boardTipsColor), + style: TextStyle(color: UIColors.boardTipsColor), ); } }