import 'package:flutter/material.dart'; import 'package:flutter_svg/svg.dart'; import 'package:mchess/api/move.dart'; import 'package:mchess/api/websocket_message.dart'; import 'package:quiver/core.dart'; Map chessPiecesAssets = { ChessPieceAssetKey( pieceClass: ChessPieceClass.pawn, color: ChessColor.white, ): 'assets/pieces/white/pawn.svg', ChessPieceAssetKey( pieceClass: ChessPieceClass.bishop, color: ChessColor.white, ): 'assets/pieces/white/bishop.svg', ChessPieceAssetKey( pieceClass: ChessPieceClass.knight, color: ChessColor.white, ): 'assets/pieces/white/knight.svg', ChessPieceAssetKey( pieceClass: ChessPieceClass.rook, color: ChessColor.white, ): 'assets/pieces/white/rook.svg', ChessPieceAssetKey( pieceClass: ChessPieceClass.queen, color: ChessColor.white, ): 'assets/pieces/white/queen.svg', ChessPieceAssetKey( pieceClass: ChessPieceClass.king, color: ChessColor.white, ): 'assets/pieces/white/king.svg', ChessPieceAssetKey( pieceClass: ChessPieceClass.pawn, color: ChessColor.black, ): 'assets/pieces/black/pawn.svg', ChessPieceAssetKey( pieceClass: ChessPieceClass.bishop, color: ChessColor.black, ): 'assets/pieces/black/bishop.svg', ChessPieceAssetKey( pieceClass: ChessPieceClass.knight, color: ChessColor.black, ): 'assets/pieces/black/knight.svg', ChessPieceAssetKey( pieceClass: ChessPieceClass.rook, color: ChessColor.black, ): 'assets/pieces/black/rook.svg', ChessPieceAssetKey( pieceClass: ChessPieceClass.queen, color: ChessColor.black, ): 'assets/pieces/black/queen.svg', ChessPieceAssetKey( pieceClass: ChessPieceClass.king, color: ChessColor.black, ): 'assets/pieces/black/king.svg', ChessPieceAssetKey( pieceClass: ChessPieceClass.none, color: ChessColor.black, ): 'assets/empty.svg', }; Map chessPiecesShortName = { ChessPieceAssetKey( pieceClass: ChessPieceClass.pawn, color: ChessColor.white, ): 'P', ChessPieceAssetKey( pieceClass: ChessPieceClass.bishop, color: ChessColor.white, ): 'B', ChessPieceAssetKey( pieceClass: ChessPieceClass.knight, color: ChessColor.white, ): 'N', ChessPieceAssetKey( pieceClass: ChessPieceClass.rook, color: ChessColor.white, ): 'R', ChessPieceAssetKey( pieceClass: ChessPieceClass.queen, color: ChessColor.white, ): 'Q', ChessPieceAssetKey( pieceClass: ChessPieceClass.king, color: ChessColor.white, ): 'K', ChessPieceAssetKey( pieceClass: ChessPieceClass.pawn, color: ChessColor.black, ): 'p', ChessPieceAssetKey( pieceClass: ChessPieceClass.bishop, color: ChessColor.black, ): 'b', ChessPieceAssetKey( pieceClass: ChessPieceClass.knight, color: ChessColor.black, ): 'n', ChessPieceAssetKey( pieceClass: ChessPieceClass.rook, color: ChessColor.black, ): 'r', ChessPieceAssetKey( pieceClass: ChessPieceClass.queen, color: ChessColor.black, ): 'q', ChessPieceAssetKey( pieceClass: ChessPieceClass.king, color: ChessColor.black, ): 'k', ChessPieceAssetKey( pieceClass: ChessPieceClass.none, color: ChessColor.black, ): '-', }; Map pieceCharacter = { ChessPieceAssetKey(pieceClass: ChessPieceClass.pawn, color: ChessColor.white): "♙", ChessPieceAssetKey(pieceClass: ChessPieceClass.rook, color: ChessColor.white): "♖", ChessPieceAssetKey( pieceClass: ChessPieceClass.knight, color: ChessColor.white): "♘", ChessPieceAssetKey( pieceClass: ChessPieceClass.bishop, color: ChessColor.white): "♗", ChessPieceAssetKey(pieceClass: ChessPieceClass.king, color: ChessColor.white): "♔", ChessPieceAssetKey( pieceClass: ChessPieceClass.queen, color: ChessColor.white): "♕", ChessPieceAssetKey(pieceClass: ChessPieceClass.pawn, color: ChessColor.black): "♟︎", ChessPieceAssetKey(pieceClass: ChessPieceClass.rook, color: ChessColor.black): "♜", ChessPieceAssetKey( pieceClass: ChessPieceClass.knight, color: ChessColor.black): "♞", ChessPieceAssetKey( pieceClass: ChessPieceClass.bishop, color: ChessColor.black): "♝", ChessPieceAssetKey(pieceClass: ChessPieceClass.king, color: ChessColor.black): "♚", ChessPieceAssetKey( pieceClass: ChessPieceClass.queen, color: ChessColor.black): "♛", }; Map pieceFromShortname = { 'P': ChessPiece(ChessPieceClass.pawn, ChessColor.white), 'R': ChessPiece(ChessPieceClass.rook, ChessColor.white), 'N': ChessPiece(ChessPieceClass.knight, ChessColor.white), 'B': ChessPiece(ChessPieceClass.bishop, ChessColor.white), 'K': ChessPiece(ChessPieceClass.king, ChessColor.white), 'Q': ChessPiece(ChessPieceClass.queen, ChessColor.white), 'p': ChessPiece(ChessPieceClass.pawn, ChessColor.black), 'r': ChessPiece(ChessPieceClass.rook, ChessColor.black), 'n': ChessPiece(ChessPieceClass.knight, ChessColor.black), 'b': ChessPiece(ChessPieceClass.bishop, ChessColor.black), 'k': ChessPiece(ChessPieceClass.king, ChessColor.black), 'q': ChessPiece(ChessPieceClass.queen, ChessColor.black), }; enum ChessColor { black, white; ChessColor getOpposite() { if (name == 'black') { return white; } else { return black; } } static ChessColor fromApiColor(ApiColor color) { if (color == ApiColor.black) { return black; } else { return white; } } } class ChessCoordinate { final int column; final int row; ChessCoordinate(this.column, this.row); ChessCoordinate.copyFrom(ChessCoordinate original) : column = original.column, row = original.row; factory ChessCoordinate.fromApiCoordinate(ApiCoordinate apiCoordinate) { return ChessCoordinate(apiCoordinate.col, apiCoordinate.row); } factory ChessCoordinate.fromString(String coordString) { var column = int.parse(coordString[0]); var row = int.parse(coordString[1]); return ChessCoordinate(column, row); } factory ChessCoordinate.none() { return ChessCoordinate(0, 0); } @override int get hashCode { return hash2(column, row); } @override operator ==(other) { return other is ChessCoordinate && other.column == column && other.row == row; } String toAlphabetical() { Map columnMap = { 1: "a", 2: "b", 3: "c", 4: "d", 5: "e", 6: "f", 7: "g", 8: "h" }; String rowStr = row.toString(); String colStr = columnMap[column]!; return '$colStr$rowStr'; } ApiCoordinate toApiCoordinate() { return ApiCoordinate(col: column, row: row); } @override String toString() { String rowStr = row.toString(); String colStr = column.toString(); return '$colStr$rowStr'; } static String columnIntToColumnString(int col) { String colStr; colStr = String.fromCharCode(col + 96); return colStr; } static int columnStringToColumnInt(String col) { int colInt; colInt = col.codeUnitAt(0) - 96; return colInt; } } class ChessMove { ChessCoordinate from; ChessCoordinate to; ChessMove({required this.from, required this.to}); factory ChessMove.fromApiMove(ApiMove apiMove) { final start = ChessCoordinate.fromApiCoordinate(apiMove.startSquare); final end = ChessCoordinate.fromApiCoordinate(apiMove.endSquare); return ChessMove(from: start, to: end); } factory ChessMove.none() { return ChessMove(from: ChessCoordinate(0, 0), to: ChessCoordinate(0, 0)); } @override int get hashCode { return hash2(from, to); } @override operator ==(other) { return other is ChessMove && other.from == from && other.to == to; } ApiMove toApiMove() { var toSquare = to.toApiCoordinate(); var fromSquare = from.toApiCoordinate(); return ApiMove( startSquare: fromSquare, endSquare: toSquare, promotionToPiece: null); } } class ChessPiece extends StatelessWidget { final ChessColor color; final ChessPieceClass pieceClass; final String shortName; final Widget? pieceImage; factory ChessPiece(ChessPieceClass pieceClass, ChessColor color) { Widget? pieceImage; String pieceAssetUrl = chessPiecesAssets[ ChessPieceAssetKey(pieceClass: pieceClass, color: color)]!; String shortName = chessPiecesShortName[ ChessPieceAssetKey(pieceClass: pieceClass, color: color)]!; pieceImage = SvgPicture.asset(pieceAssetUrl); return ChessPiece._(pieceClass, color, pieceImage, shortName); } const ChessPiece.none({super.key}) : pieceClass = ChessPieceClass.none, color = ChessColor.white, pieceImage = null, shortName = "-"; const ChessPiece._( this.pieceClass, this.color, this.pieceImage, this.shortName); @override Widget build(BuildContext context) { return SizedBox( child: pieceImage, ); } } class ChessPieceAssetKey { final ChessPieceClass pieceClass; final ChessColor color; ChessPieceAssetKey({required this.pieceClass, required this.color}); @override int get hashCode { return hash2(pieceClass, color); } @override bool operator ==(Object other) { return (other is ChessPieceAssetKey && (pieceClass == other.pieceClass) && (color == other.color)); } } enum ChessPieceClass { none, pawn, bishop, knight, rook, queen, king, } class PieceDragged { ChessCoordinate fromSquare; ChessCoordinate toSquare; ChessPiece? movedPiece; PieceDragged(this.fromSquare, this.toSquare, this.movedPiece); } bool isPromotionMove( ChessPieceClass pieceMoved, ChessColor myColor, ChessCoordinate toSquare) { bool isPromotion = false; if (pieceMoved != ChessPieceClass.pawn) { return isPromotion; } switch (myColor) { case ChessColor.black: if (toSquare.row == 1) { isPromotion = true; } break; case ChessColor.white: if (toSquare.row == 8) { isPromotion = true; } break; } return isPromotion; }