diff --git a/lib/chess/chess_square.dart b/lib/chess/chess_square.dart index 425a572..3e1d3ff 100644 --- a/lib/chess/chess_square.dart +++ b/lib/chess/chess_square.dart @@ -1,13 +1,10 @@ import 'package:flutter/material.dart'; -import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:mchess/chess_bloc/chess_bloc.dart'; -import '../connection/ws_connection.dart'; +import '../chess_bloc/chess_events.dart'; import '../utils/chess_utils.dart'; -int messageIndex = 0; - class ChessSquare extends StatelessWidget { final ChessCoordinate coordinate; final ChessPiece? containedPiece; @@ -60,58 +57,44 @@ class ChessSquare extends StatelessWidget { draggableFdbSize = 0.15 * windowHeight; } - return DragTarget( + return DragTarget( + onWillAccept: (move) { + if (move?.fromSquare == coordinate) { + return false; + } + return true; + }, + onAccept: (move) { + if (coordinate != move.fromSquare) { + ChessBloc.getInstance().add(OwnPieceMoved( + startSquare: move.fromSquare, endSquare: coordinate)); + } + }, builder: (context, candidateData, rejectedData) { return Container( color: color, width: ChessSquare.pieceWidth, height: ChessSquare.pieceWidth, - child: BlocBuilder( - builder: (context, state) { - int allowDrags = 0; - if (ChessBloc.myColor == null) { - allowDrags = 0; - } else { - if (containedPiece == null) { - allowDrags = 0; - } else if (containedPiece!.color == ChessBloc.myColor) { - if (ChessBloc.myColor == state.newTurnColor) { - allowDrags = 1; - } else { - allowDrags = 0; - } - } - } - - return Draggable( - /* We create the move with the startSquare == endSquare. The receiving widget will give the correct value to end square. */ - data: ChessMove(coordinate, coordinate, containedPiece), - maxSimultaneousDrags: allowDrags, - feedback: FractionalTranslation( - translation: const Offset(-0.5, -0.75), - child: SizedBox( - height: draggableFdbSize, - width: draggableFdbSize, - child: containedPiece), - ), - childWhenDragging: Container(), - dragAnchorStrategy: pointerDragAnchorStrategy, - child: containedPiece ?? Container(), - onDragCompleted: () {}, - onDragStarted: () {}, - ); - }, + child: Draggable( + /* We create the move with the startSquare == endSquare. The receiving widget will give the correct value to end square. */ + data: PieceMovedFrom(coordinate, containedPiece), + maxSimultaneousDrags: + ChessBloc.turnColor == ChessBloc.myColor ? 1 : 0, + feedback: FractionalTranslation( + translation: const Offset(-0.5, -0.75), + child: SizedBox( + height: draggableFdbSize, + width: draggableFdbSize, + child: containedPiece), + ), + childWhenDragging: Container(), + dragAnchorStrategy: pointerDragAnchorStrategy, + child: containedPiece ?? Container(), + onDragCompleted: () {}, + onDragStarted: () {}, ), ); }, - onAccept: (move) { - move.endSquare = coordinate; - - if (move.endSquare != move.startSquare) { - ServerConnection.getInstance().send( - 'mv ${move.startSquare.toString()} ${move.endSquare.toString()}'); - } - }, ); } } diff --git a/lib/chess_bloc/chess_bloc.dart b/lib/chess_bloc/chess_bloc.dart index 0fd891f..6285f7f 100644 --- a/lib/chess_bloc/chess_bloc.dart +++ b/lib/chess_bloc/chess_bloc.dart @@ -1,10 +1,13 @@ import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:mchess/chess_bloc/chess_events.dart'; +import 'package:mchess/chess_bloc/chess_position.dart'; +import 'package:mchess/connection/ws_connection.dart'; import 'package:mchess/utils/chess_utils.dart'; import 'dart:developer'; class ChessBloc extends Bloc { static final ChessBloc _instance = ChessBloc._internal(); + static ChessColor turnColor = ChessColor.white; static ChessColor? myColor; static ChessColor? getSidesColor() { @@ -14,7 +17,8 @@ class ChessBloc extends Bloc { ChessBloc._internal() : super(ChessBoardState.init()) { on(initBoard); on(flipBoard); - on(moveHandler); + on(opponentMoveHandler); + on(ownMoveHandler); } factory ChessBloc.getInstance() { @@ -35,25 +39,32 @@ class ChessBloc extends Bloc { emit(ChessBoardState(event.myColor, state.newTurnColor, state.position)); } - void moveHandler(PieceMoved event, Emitter emit) { - Map newPosition = state.position; + void opponentMoveHandler( + OpponentPieceMoved event, Emitter emit) { + ChessPosition.getInstance().recordMove(event.startSquare, event.endSquare); + var newPosition = ChessPosition.getInstance().currentPosition; - newPosition[event.endSquare] = state.position[event.startSquare]!; - newPosition[event.startSquare] = const ChessPiece.none(); - - var newTurnColor = state.newTurnColor == ChessColor.white + turnColor = state.newTurnColor == ChessColor.white ? ChessColor.black : ChessColor.white; log('emitting new state with position $newPosition'); + emit( ChessBoardState( state.bottomColor, - newTurnColor, + turnColor, newPosition, ), ); } + + void ownMoveHandler(OwnPieceMoved event, Emitter emit) { + ChessPosition.getInstance().recordMove(event.startSquare, event.endSquare); + + ServerConnection.getInstance().send( + 'mv ${event.startSquare.toString()} ${event.endSquare.toString()}'); + } } class ChessBoardState { @@ -74,50 +85,10 @@ class ChessBoardState { factory ChessBoardState.init() { ChessColor bottomColor = ChessColor.white; ChessColor turnColor = ChessColor.white; - Map position = {}; + Map position = + ChessPosition.getInstance().currentPosition; - for (int i = 1; i <= 8; i++) { - position[ChessCoordinate(i, 7)] = - ChessPiece(ChessPieceName.blackPawn, ChessColor.black); - position[ChessCoordinate(i, 2)] = - ChessPiece(ChessPieceName.whitePawn, ChessColor.white); - } - - position[ChessCoordinate(1, 8)] = - ChessPiece(ChessPieceName.blackRook, ChessColor.black); - position[ChessCoordinate(2, 8)] = - ChessPiece(ChessPieceName.blackKnight, ChessColor.black); - position[ChessCoordinate(3, 8)] = - ChessPiece(ChessPieceName.blackBishop, ChessColor.black); - position[ChessCoordinate(4, 8)] = - ChessPiece(ChessPieceName.blackQueen, ChessColor.black); - position[ChessCoordinate(5, 8)] = - ChessPiece(ChessPieceName.blackKing, ChessColor.black); - position[ChessCoordinate(6, 8)] = - ChessPiece(ChessPieceName.blackBishop, ChessColor.black); - position[ChessCoordinate(7, 8)] = - ChessPiece(ChessPieceName.blackKnight, ChessColor.black); - position[ChessCoordinate(8, 8)] = - ChessPiece(ChessPieceName.blackRook, ChessColor.black); - - position[ChessCoordinate(1, 1)] = - ChessPiece(ChessPieceName.whiteRook, ChessColor.white); - position[ChessCoordinate(2, 1)] = - ChessPiece(ChessPieceName.whiteKnight, ChessColor.white); - position[ChessCoordinate(3, 1)] = - ChessPiece(ChessPieceName.whiteBishop, ChessColor.white); - position[ChessCoordinate(4, 1)] = - ChessPiece(ChessPieceName.whiteQueen, ChessColor.white); - position[ChessCoordinate(5, 1)] = - ChessPiece(ChessPieceName.whiteKing, ChessColor.white); - position[ChessCoordinate(6, 1)] = - ChessPiece(ChessPieceName.whiteBishop, ChessColor.white); - position[ChessCoordinate(7, 1)] = - ChessPiece(ChessPieceName.whiteKnight, ChessColor.white); - position[ChessCoordinate(8, 1)] = - ChessPiece(ChessPieceName.whiteRook, ChessColor.white); - - return ChessBoardState._(bottomColor, turnColor, position); + return ChessBoardState(bottomColor, turnColor, position); } void logPosition(Map pos) { diff --git a/lib/chess_bloc/chess_events.dart b/lib/chess_bloc/chess_events.dart index 01298e3..a7becb1 100644 --- a/lib/chess_bloc/chess_events.dart +++ b/lib/chess_bloc/chess_events.dart @@ -2,11 +2,18 @@ import 'package:mchess/utils/chess_utils.dart'; abstract class ChessEvent {} -class PieceMoved extends ChessEvent { +class OpponentPieceMoved extends ChessEvent { final ChessCoordinate startSquare; final ChessCoordinate endSquare; - PieceMoved({required this.startSquare, required this.endSquare}); + OpponentPieceMoved({required this.startSquare, required this.endSquare}); +} + +class OwnPieceMoved extends ChessEvent { + final ChessCoordinate startSquare; + final ChessCoordinate endSquare; + + OwnPieceMoved({required this.startSquare, required this.endSquare}); } class InitBoard extends ChessEvent { diff --git a/lib/chess_bloc/chess_position.dart b/lib/chess_bloc/chess_position.dart new file mode 100644 index 0000000..464061f --- /dev/null +++ b/lib/chess_bloc/chess_position.dart @@ -0,0 +1,89 @@ +import 'dart:developer'; + +import 'package:mchess/utils/chess_utils.dart'; + +typedef ChessPositionType = Map; + +class ChessPosition { + static final ChessPosition _instance = ChessPosition._internal(); + late ChessPositionType position; + + static ChessPosition getInstance() { + return _instance; + } + + ChessPosition({required this.position}); + + factory ChessPosition._internal() { + ChessPositionType pos = {}; + + for (int i = 1; i <= 8; i++) { + pos[ChessCoordinate(i, 7)] = + ChessPiece(ChessPieceName.blackPawn, ChessColor.black); + pos[ChessCoordinate(i, 2)] = + ChessPiece(ChessPieceName.whitePawn, ChessColor.white); + } + + pos[ChessCoordinate(1, 8)] = + ChessPiece(ChessPieceName.blackRook, ChessColor.black); + pos[ChessCoordinate(2, 8)] = + ChessPiece(ChessPieceName.blackKnight, ChessColor.black); + pos[ChessCoordinate(3, 8)] = + ChessPiece(ChessPieceName.blackBishop, ChessColor.black); + pos[ChessCoordinate(4, 8)] = + ChessPiece(ChessPieceName.blackQueen, ChessColor.black); + pos[ChessCoordinate(5, 8)] = + ChessPiece(ChessPieceName.blackKing, ChessColor.black); + pos[ChessCoordinate(6, 8)] = + ChessPiece(ChessPieceName.blackBishop, ChessColor.black); + pos[ChessCoordinate(7, 8)] = + ChessPiece(ChessPieceName.blackKnight, ChessColor.black); + pos[ChessCoordinate(8, 8)] = + ChessPiece(ChessPieceName.blackRook, ChessColor.black); + + pos[ChessCoordinate(1, 1)] = + ChessPiece(ChessPieceName.whiteRook, ChessColor.white); + pos[ChessCoordinate(2, 1)] = + ChessPiece(ChessPieceName.whiteKnight, ChessColor.white); + pos[ChessCoordinate(3, 1)] = + ChessPiece(ChessPieceName.whiteBishop, ChessColor.white); + pos[ChessCoordinate(4, 1)] = + ChessPiece(ChessPieceName.whiteQueen, ChessColor.white); + pos[ChessCoordinate(5, 1)] = + ChessPiece(ChessPieceName.whiteKing, ChessColor.white); + pos[ChessCoordinate(6, 1)] = + ChessPiece(ChessPieceName.whiteBishop, ChessColor.white); + pos[ChessCoordinate(7, 1)] = + ChessPiece(ChessPieceName.whiteKnight, ChessColor.white); + pos[ChessCoordinate(8, 1)] = + ChessPiece(ChessPieceName.whiteRook, ChessColor.white); + + return ChessPosition(position: pos); + } + + ChessPositionType get currentPosition => position; + + void recordMove(ChessCoordinate from, ChessCoordinate to) { + position[to] = position[from] ?? const ChessPiece.none(); + position[from] = const ChessPiece.none(); + logPosition(position); + } + + void logPosition(ChessPositionType p) { + String logString = ''; + + for (int row = 8; row > 0; row--) { + for (int col = 1; col <= 8; col++) { + var coord = ChessCoordinate(col, row); + if (p.containsKey(coord)) { + logString = '$logString ${p[coord]?.shortName}'; + } else { + logString = '$logString .'; + } + } + logString = '$logString\n'; + } + + log(logString); + } +} diff --git a/lib/connection/ws_connection.dart b/lib/connection/ws_connection.dart index 86a2e1b..d967520 100644 --- a/lib/connection/ws_connection.dart +++ b/lib/connection/ws_connection.dart @@ -67,8 +67,8 @@ class ServerConnection { log('Move received : ${splitString[1]}:${splitString[2]}'); - ChessBloc.getInstance() - .add(PieceMoved(startSquare: startSquare, endSquare: endSquare)); + ChessBloc.getInstance().add( + OpponentPieceMoved(startSquare: startSquare, endSquare: endSquare)); } }); } diff --git a/lib/utils/chess_utils.dart b/lib/utils/chess_utils.dart index a5322eb..df72cbd 100644 --- a/lib/utils/chess_utils.dart +++ b/lib/utils/chess_utils.dart @@ -36,6 +36,22 @@ Map chessPiecesAssets = { ChessPieceName.none: 'assets/empty.svg', }; +Map chessPiecesShortName = { + ChessPieceName.whitePawn: 'P', + ChessPieceName.whiteBishop: 'B', + ChessPieceName.whiteKnight: 'N', + ChessPieceName.whiteRook: 'R', + ChessPieceName.whiteQueen: 'Q', + ChessPieceName.whiteKing: 'K', + ChessPieceName.blackPawn: 'p', + ChessPieceName.blackBishop: 'b', + ChessPieceName.blackKnight: 'n', + ChessPieceName.blackRook: 'r', + ChessPieceName.blackQueen: 'q', + ChessPieceName.blackKing: 'k', + ChessPieceName.none: 'X', +}; + class ChessCoordinate { final int column; final int row; @@ -91,22 +107,26 @@ class ChessCoordinate { class ChessPiece extends StatelessWidget { final ChessColor color; final ChessPieceName pieceName; + final String shortName; final Widget? pieceImage; - const ChessPiece._(this.pieceName, this.color, this.pieceImage); + const ChessPiece._( + this.pieceName, this.color, this.pieceImage, this.shortName); factory ChessPiece(ChessPieceName name, ChessColor color) { Widget? pieceImage; String pieceAssetUrl = chessPiecesAssets[name]!; + String shortName = chessPiecesShortName[name]!; pieceImage = SvgPicture.asset(pieceAssetUrl); - return ChessPiece._(name, color, pieceImage); + return ChessPiece._(name, color, pieceImage, shortName); } const ChessPiece.none({super.key}) : pieceName = ChessPieceName.none, color = ChessColor.white, - pieceImage = null; + pieceImage = null, + shortName = "-"; @override Widget build(BuildContext context) { @@ -116,11 +136,9 @@ class ChessPiece extends StatelessWidget { } } -class ChessMove { - ChessCoordinate startSquare; - ChessCoordinate endSquare; +class PieceMovedFrom { + ChessCoordinate fromSquare; ChessPiece? movedPiece; - ChessPiece? pieceOnEndSquare; - ChessMove(this.startSquare, this.endSquare, this.movedPiece); + PieceMovedFrom(this.fromSquare, this.movedPiece); }