| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518 | 
							- import 'dart:async';
 
- import 'package:cchess/cchess.dart';
 
- import 'package:shirne_dialog/shirne_dialog.dart';
 
- import 'package:flutter/material.dart';
 
- import 'action_dialog.dart';
 
- import 'board.dart';
 
- import 'piece.dart';
 
- import 'chess_pieces.dart';
 
- import 'mark_component.dart';
 
- import 'point_component.dart';
 
- import '../global.dart';
 
- import '../models/game_event.dart';
 
- import '../models/sound.dart';
 
- import '../models/game_manager.dart';
 
- import '../driver/player_driver.dart';
 
- import '../pages/home_page.dart';
 
- class Chess extends StatefulWidget {
 
-   final String skin;
 
-   const Chess({Key? key, this.skin = 'woods'}) : super(key: key);
 
-   @override
 
-   State<Chess> createState() => ChessState();
 
- }
 
- class ChessState extends State<Chess> {
 
-   
 
-   ChessItem? activeItem;
 
-   double skewStepper = 0;
 
-   
 
-   ChessItem? dieFlash;
 
-   
 
-   String lastPosition = 'a0';
 
-   
 
-   List<String> movePoints = [];
 
-   bool isInit = false;
 
-   late GameManager gamer;
 
-   bool isLoading = true;
 
-   
 
-   List<ChessItem> items = [];
 
-   @override
 
-   void initState() {
 
-     super.initState();
 
-     initGamer();
 
-   }
 
-   void initGamer() {
 
-     if (isInit) return;
 
-     isInit = true;
 
-     HomePageState? gameWrapper =
 
-         context.findAncestorStateOfType<HomePageState>();
 
-     if (gameWrapper == null) return;
 
-     gamer = gameWrapper.gamer;
 
-     gamer.on<GameLoadEvent>(reloadGame);
 
-     gamer.on<GameResultEvent>(onResult);
 
-     gamer.on<GameMoveEvent>(onMove);
 
-     gamer.on<GameFlipEvent>(onFlip);
 
-     reloadGame(GameLoadEvent(0));
 
-   }
 
-   @override
 
-   void dispose() {
 
-     gamer.off<GameLoadEvent>(reloadGame);
 
-     gamer.off<GameResultEvent>(onResult);
 
-     gamer.off<GameMoveEvent>(onMove);
 
-     super.dispose();
 
-   }
 
-   void onFlip(GameEvent event) {
 
-     setState(() {});
 
-   }
 
-   void onResult(GameEvent event) {
 
-     if (event.data == null || event.data!.isEmpty) {
 
-       return;
 
-     }
 
-     List<String> parts = event.data.split(' ');
 
-     String? resultText =
 
-         (parts.length > 1 && parts[1].isNotEmpty) ? parts[1] : null;
 
-     switch (parts[0]) {
 
-       case 'checkMate':
 
-         
 
-         showAction(ActionType.checkMate);
 
-         break;
 
-       case 'eat':
 
-         showAction(ActionType.eat);
 
-         break;
 
-       case ChessManual.resultFstLoose:
 
-         alertResult(resultText ?? context.l10n.redLoose);
 
-         break;
 
-       case ChessManual.resultFstWin:
 
-         alertResult(resultText ?? context.l10n.redWin);
 
-         break;
 
-       case ChessManual.resultFstDraw:
 
-         alertResult(resultText ?? context.l10n.redDraw);
 
-         break;
 
-       default:
 
-         break;
 
-     }
 
-   }
 
-   void reloadGame(GameEvent event) {
 
-     if (event.data < -1) {
 
-       return;
 
-     }
 
-     if (event.data < 0) {
 
-       if (!isLoading) {
 
-         setState(() {
 
-           isLoading = true;
 
-         });
 
-       }
 
-       return;
 
-     }
 
-     setState(() {
 
-       items = gamer.manual.getChessItems();
 
-       isLoading = false;
 
-       lastPosition = '';
 
-       activeItem = null;
 
-     });
 
-     String position = gamer.lastMove;
 
-     if (position.isNotEmpty) {
 
-       logger.info('last move $position');
 
-       Future.delayed(const Duration(milliseconds: 32)).then((value) {
 
-         setState(() {
 
-           lastPosition = position.substring(0, 2);
 
-           ChessPos activePos = ChessPos.fromCode(position.substring(2, 4));
 
-           activeItem = items.firstWhere(
 
-             (item) =>
 
-                 !item.isBlank &&
 
-                 item.position == ChessPos.fromCode(lastPosition),
 
-             orElse: () => ChessItem('0'),
 
-           );
 
-           activeItem!.position = activePos;
 
-         });
 
-       });
 
-     }
 
-   }
 
-   void addStep(ChessPos chess, ChessPos next) {
 
-     gamer.addStep(chess, next);
 
-   }
 
-   Future<void> fetchMovePoints() async {
 
-     setState(() {
 
-       movePoints = gamer.rule.movePoints(activeItem!.position);
 
-       
 
-     });
 
-   }
 
-   
 
-   void onMove(GameEvent event) {
 
-     String move = event.data!;
 
-     logger.info('onmove $move');
 
-     if (move.isEmpty) return;
 
-     if (move == PlayerDriver.rstGiveUp) return;
 
-     if (move.contains(PlayerDriver.rstRqstDraw)) {
 
-       toast(
 
-         context.l10n.requestDraw,
 
-         SnackBarAction(
 
-           label: context.l10n.agreeToDraw,
 
-           onPressed: () {
 
-             gamer.player.completeMove(PlayerDriver.rstDraw);
 
-           },
 
-         ),
 
-         5,
 
-       );
 
-       move = move.replaceAll(PlayerDriver.rstRqstDraw, '').trim();
 
-       if (move.isEmpty) {
 
-         return;
 
-       }
 
-     }
 
-     if (move == PlayerDriver.rstRqstRetract) {
 
-       confirm(
 
-         context.l10n.requestRetract,
 
-         context.l10n.agreeRetract,
 
-         context.l10n.disagreeRetract,
 
-       ).then((bool? isAgree) {
 
-         gamer.player
 
-             .completeMove(isAgree == true ? PlayerDriver.rstRetract : '');
 
-       });
 
-       return;
 
-     }
 
-     ChessPos fromPos = ChessPos.fromCode(move.substring(0, 2));
 
-     ChessPos toPosition = ChessPos.fromCode(move.substring(2, 4));
 
-     activeItem = items.firstWhere(
 
-       (item) => !item.isBlank && item.position == fromPos,
 
-       orElse: () => ChessItem('0'),
 
-     );
 
-     ChessItem newActive = items.firstWhere(
 
-       (item) => !item.isBlank && item.position == toPosition,
 
-       orElse: () => ChessItem('0'),
 
-     );
 
-     setState(() {
 
-       if (activeItem != null && !activeItem!.isBlank) {
 
-         logger.info('$activeItem => $move');
 
-         activeItem!.position = ChessPos.fromCode(move.substring(2, 4));
 
-         lastPosition = fromPos.toCode();
 
-         if (!newActive.isBlank) {
 
-           logger.info('eat $newActive');
 
-           
 
-           
 
-           dieFlash = ChessItem(newActive.code, position: toPosition);
 
-           newActive.isDie = true;
 
-           Future.delayed(const Duration(milliseconds: 250), () {
 
-             setState(() {
 
-               dieFlash = null;
 
-             });
 
-           });
 
-         }
 
-       } else {
 
-         logger.info('Remote move error $move');
 
-       }
 
-     });
 
-   }
 
-   void animateMove(ChessPos nextPosition) {
 
-     logger.info('$activeItem => $nextPosition');
 
-     setState(() {
 
-       activeItem!.position = nextPosition.copy();
 
-     });
 
-   }
 
-   void clearActive() {
 
-     setState(() {
 
-       activeItem = null;
 
-       lastPosition = '';
 
-     });
 
-   }
 
-   
 
-   Future<bool> checkCanMove(
 
-     String activePos,
 
-     ChessPos toPosition, [
 
-     ChessItem? toItem,
 
-   ]) async {
 
-     if (!movePoints.contains(toPosition.toCode())) {
 
-       if (toItem != null) {
 
-         toast('can\'t eat ${toItem.code} at $toPosition');
 
-       } else {
 
-         toast('can\'t move to $toPosition');
 
-       }
 
-       return false;
 
-     }
 
-     String move = activePos + toPosition.toCode();
 
-     ChessRule rule = ChessRule(gamer.fen.copy());
 
-     rule.fen.move(move);
 
-     if (rule.isKingMeet(gamer.curHand)) {
 
-       toast(context.l10n.cantSendCheck);
 
-       return false;
 
-     }
 
-     
 
-     if (rule.isCheck(gamer.curHand)) {
 
-       if (gamer.isCheckMate) {
 
-         toast(context.l10n.plsParryCheck);
 
-       } else {
 
-         toast(context.l10n.cantSendCheck);
 
-       }
 
-       return false;
 
-     }
 
-     return true;
 
-   }
 
-   
 
-   bool onPointer(ChessPos toPosition) {
 
-     ChessItem newActive = items.firstWhere(
 
-       (item) => !item.isBlank && item.position == toPosition,
 
-       orElse: () => ChessItem('0'),
 
-     );
 
-     int ticker = DateTime.now().millisecondsSinceEpoch;
 
-     if (newActive.isBlank) {
 
-       if (activeItem != null && activeItem!.team == gamer.curHand) {
 
-         String activePos = activeItem!.position.toCode();
 
-         animateMove(toPosition);
 
-         checkCanMove(activePos, toPosition).then((canMove) {
 
-           int delay = 250 - (DateTime.now().millisecondsSinceEpoch - ticker);
 
-           if (delay < 0) {
 
-             delay = 0;
 
-           }
 
-           if (canMove) {
 
-             
 
-             setState(() {
 
-               
 
-               movePoints = [];
 
-               lastPosition = activePos;
 
-             });
 
-             addStep(ChessPos.fromCode(activePos), toPosition);
 
-           } else {
 
-             Future.delayed(Duration(milliseconds: delay), () {
 
-               setState(() {
 
-                 activeItem!.position = ChessPos.fromCode(activePos);
 
-               });
 
-             });
 
-           }
 
-         });
 
-         return true;
 
-       }
 
-       return false;
 
-     }
 
-     
 
-     if (activeItem != null && activeItem!.position == toPosition) {
 
-       Sound.play(Sound.click);
 
-       setState(() {
 
-         activeItem = null;
 
-         lastPosition = '';
 
-         movePoints = [];
 
-       });
 
-     } else if (newActive.team == gamer.curHand) {
 
-       Sound.play(Sound.click);
 
-       
 
-       setState(() {
 
-         activeItem = newActive;
 
-         lastPosition = '';
 
-         movePoints = [];
 
-       });
 
-       fetchMovePoints();
 
-       return true;
 
-     } else {
 
-       
 
-       if (activeItem != null && activeItem!.team == gamer.curHand) {
 
-         String activePos = activeItem!.position.toCode();
 
-         animateMove(toPosition);
 
-         checkCanMove(activePos, toPosition, newActive).then((canMove) {
 
-           int delay = 250 - (DateTime.now().millisecondsSinceEpoch - ticker);
 
-           if (delay < 0) {
 
-             delay = 0;
 
-           }
 
-           if (canMove) {
 
-             addStep(ChessPos.fromCode(activePos), toPosition);
 
-             
 
-             setState(() {
 
-               
 
-               movePoints = [];
 
-               lastPosition = activePos;
 
-               
 
-               dieFlash = ChessItem(newActive.code, position: toPosition);
 
-               newActive.isDie = true;
 
-             });
 
-             Future.delayed(Duration(milliseconds: delay), () {
 
-               setState(() {
 
-                 dieFlash = null;
 
-               });
 
-             });
 
-           } else {
 
-             Future.delayed(Duration(milliseconds: delay), () {
 
-               setState(() {
 
-                 activeItem!.position = ChessPos.fromCode(activePos);
 
-               });
 
-             });
 
-           }
 
-         });
 
-         return true;
 
-       }
 
-     }
 
-     return false;
 
-   }
 
-   ChessPos pointTrans(Offset tapPoint) {
 
-     int x = (tapPoint.dx - gamer.skin.offset.dx * gamer.scale) ~/
 
-         (gamer.skin.size * gamer.scale);
 
-     int y = 9 -
 
-         (tapPoint.dy - gamer.skin.offset.dy * gamer.scale) ~/
 
-             (gamer.skin.size * gamer.scale);
 
-     return ChessPos(gamer.isFlip ? 8 - x : x, gamer.isFlip ? 9 - y : y);
 
-   }
 
-   void toast(String message, [SnackBarAction? action, int duration = 3]) {
 
-     MyDialog.snack(
 
-       message,
 
-       action: action,
 
-       duration: Duration(seconds: duration),
 
-     );
 
-   }
 
-   void alertResult(message) {
 
-     confirm(message, context.l10n.oneMoreGame, context.l10n.letMeSee)
 
-         .then((isConfirm) {
 
-       if (isConfirm ?? false) {
 
-         gamer.newGame();
 
-       }
 
-     });
 
-   }
 
-   Future<bool?> confirm(String message, String agreeText, String cancelText) {
 
-     return MyDialog.confirm(
 
-       message,
 
-       buttonText: agreeText,
 
-       cancelText: cancelText,
 
-     );
 
-   }
 
-   Future<bool?> alert(String message) async {
 
-     return MyDialog.alert(message);
 
-   }
 
-   
 
-   void showAction(ActionType type) {
 
-     final overlay = Overlay.of(context);
 
-     late OverlayEntry entry;
 
-     entry = OverlayEntry(
 
-       builder: (context) => Center(
 
-         child: ActionDialog(
 
-           type,
 
-           delay: 2,
 
-           onHide: () {
 
-             entry.remove();
 
-           },
 
-         ),
 
-       ),
 
-     );
 
-     overlay.insert(entry);
 
-   }
 
-   @override
 
-   Widget build(BuildContext context) {
 
-     initGamer();
 
-     if (isLoading) {
 
-       return const Center(
 
-         child: CircularProgressIndicator(),
 
-       );
 
-     }
 
-     List<Widget> widgets = [const Board()];
 
-     List<Widget> layer0 = [];
 
-     if (dieFlash != null) {
 
-       layer0.add(
 
-         Align(
 
-           alignment: gamer.skin.getAlign(dieFlash!.position),
 
-           child: Piece(item: dieFlash!, isActive: false, isAblePoint: false),
 
-         ),
 
-       );
 
-     }
 
-     if (lastPosition.isNotEmpty) {
 
-       ChessItem emptyItem =
 
-           ChessItem('0', position: ChessPos.fromCode(lastPosition));
 
-       layer0.add(
 
-         Align(
 
-           alignment: gamer.skin.getAlign(emptyItem.position),
 
-           child: MarkComponent(
 
-             size: gamer.skin.size * gamer.scale,
 
-           ),
 
-         ),
 
-       );
 
-     }
 
-     widgets.add(
 
-       Stack(
 
-         alignment: Alignment.center,
 
-         fit: StackFit.expand,
 
-         children: layer0,
 
-       ),
 
-     );
 
-     widgets.add(
 
-       ChessPieces(
 
-         items: items,
 
-         activeItem: activeItem,
 
-       ),
 
-     );
 
-     List<Widget> layer2 = [];
 
-     for (var element in movePoints) {
 
-       ChessItem emptyItem =
 
-           ChessItem('0', position: ChessPos.fromCode(element));
 
-       layer2.add(
 
-         Align(
 
-           alignment: gamer.skin.getAlign(emptyItem.position),
 
-           child: PointComponent(size: gamer.skin.size * gamer.scale),
 
-         ),
 
-       );
 
-     }
 
-     widgets.add(
 
-       Stack(
 
-         alignment: Alignment.center,
 
-         fit: StackFit.expand,
 
-         children: layer2,
 
-       ),
 
-     );
 
-     return GestureDetector(
 
-       onTapUp: (detail) {
 
-         if (gamer.isLock) return;
 
-         setState(() {
 
-           onPointer(pointTrans(detail.localPosition));
 
-         });
 
-       },
 
-       child: SizedBox(
 
-         width: gamer.skin.width,
 
-         height: gamer.skin.height,
 
-         child: Stack(
 
-           alignment: Alignment.center,
 
-           fit: StackFit.expand,
 
-           children: widgets,
 
-         ),
 
-       ),
 
-     );
 
-   }
 
- }
 
 
  |