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'; enum ChessPieceClass { none, pawn, bishop, knight, rook, queen, king, } class ChessPieceAssetKey { final ChessPieceClass pieceClass; final ChessColor color; ChessPieceAssetKey({required this.pieceClass, required this.color}); @override bool operator ==(Object other) { return (other is ChessPieceAssetKey && (pieceClass == other.pieceClass) && (color == other.color)); } @override int get hashCode { return hash2(pieceClass, color); } } enum ChessColor { black, white; static ChessColor fromApiColor(ApiColor color) { if (color == ApiColor.black) { return black; } else { return white; } } ChessColor getOpposite() { if (name == 'black') { return white; } else { return black; } } } 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, ): '-', }; class ChessCoordinate { final int column; final int row; ChessCoordinate(this.column, this.row); factory ChessCoordinate.fromString(String coordString) { var column = int.parse(coordString[0]); var row = int.parse(coordString[1]); return ChessCoordinate(column, row); } factory ChessCoordinate.fromApiCoordinate(ApiCoordinate apiCoordinate) { return ChessCoordinate(apiCoordinate.col, apiCoordinate.row); } ApiCoordinate toApiCoordinate() { return ApiCoordinate(col: column, row: row); } ChessCoordinate.copyFrom(ChessCoordinate original) : column = original.column, row = original.row; 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; } @override String toString() { String rowStr = row.toString(); String colStr = column.toString(); return '$colStr$rowStr'; } 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'; } @override operator ==(other) { return other is ChessCoordinate && other.column == column && other.row == row; } @override int get hashCode { return hash2(column, row); } } class ChessPiece extends StatelessWidget { final ChessColor color; final ChessPieceClass pieceClass; final String shortName; final Widget? pieceImage; const ChessPiece._( this.pieceClass, this.color, this.pieceImage, this.shortName); 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 = "-"; @override Widget build(BuildContext context) { return SizedBox( child: pieceImage, ); } } 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); } ApiMove toApiMove() { var toSquare = to.toApiCoordinate(); var fromSquare = from.toApiCoordinate(); return ApiMove( startSquare: fromSquare, endSquare: toSquare, promotionToPiece: null); } @override operator ==(other) { return other is ChessMove && other.from == from && other.to == to; } @override int get hashCode { return hash2(from, to); } } class PieceDragged { ChessCoordinate fromSquare; ChessCoordinate toSquare; ChessPiece? movedPiece; PieceDragged(this.fromSquare, this.toSquare, this.movedPiece); }