221 lines
7.0 KiB
Dart
221 lines
7.0 KiB
Dart
import 'dart:convert';
|
|
|
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
|
import 'package:mchess/api/websocket_message.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<ChessEvent, ChessBoardState> {
|
|
static final ChessBloc _instance = ChessBloc._internal();
|
|
static ChessColor turnColor = ChessColor.white;
|
|
static ChessColor? myColor = ChessColor.white;
|
|
|
|
static ChessColor? getSidesColor() {
|
|
return myColor;
|
|
}
|
|
|
|
ChessBloc._internal() : super(ChessBoardState.init()) {
|
|
on<InitBoard>(initBoard);
|
|
on<ColorDetermined>(flipBoard);
|
|
on<ReceivedMove>(moveHandler);
|
|
on<ReceivedPromotion>(promotionHandler);
|
|
on<OwnPieceMoved>(ownMoveHandler);
|
|
on<OwnPromotionPlayed>(ownPromotionHandler);
|
|
on<InvalidMovePlayed>(invalidMoveHandler);
|
|
}
|
|
|
|
factory ChessBloc.getInstance() {
|
|
return ChessBloc();
|
|
}
|
|
|
|
factory ChessBloc() {
|
|
return _instance;
|
|
}
|
|
|
|
void initBoard(InitBoard event, Emitter<ChessBoardState> emit) {
|
|
ChessPosition.getInstance().resetToStartingPosition();
|
|
emit(ChessBoardState(ChessColor.white, ChessColor.white,
|
|
ChessPosition.getInstance().currentPosition));
|
|
}
|
|
|
|
void flipBoard(ColorDetermined event, Emitter<ChessBoardState> emit) {
|
|
log("My Color is $myColor");
|
|
myColor = event.myColor;
|
|
emit(ChessBoardState(event.myColor, state.newTurnColor, state.position));
|
|
}
|
|
|
|
void moveHandler(ReceivedMove event, Emitter<ChessBoardState> emit) {
|
|
log('opponentMoveHandler()');
|
|
|
|
var move = ChessMove(from: event.startSquare, to: event.endSquare);
|
|
bool wasEnPassant = move.wasEnPassant();
|
|
bool wasCastling = move.wasCastling();
|
|
|
|
var oldPosition = ChessPosition.getInstance().copyOfCurrentPosition;
|
|
ChessPosition.getInstance().recordMove(event.startSquare, event.endSquare);
|
|
var newPosition = ChessPosition.getInstance().currentPosition;
|
|
|
|
if (wasEnPassant) {
|
|
if (turnColor == ChessColor.white) {
|
|
newPosition[ChessCoordinate(
|
|
event.endSquare.column, event.endSquare.row - 1)] =
|
|
const ChessPiece.none();
|
|
} else {
|
|
newPosition[ChessCoordinate(
|
|
event.endSquare.column, event.endSquare.row + 1)] =
|
|
const ChessPiece.none();
|
|
}
|
|
} else if (wasCastling) {
|
|
ChessPiece rookToMove;
|
|
ChessPiece kingToMove;
|
|
if (move.to.column == 7) {
|
|
rookToMove = oldPosition[ChessCoordinate(8, move.to.row)]!;
|
|
newPosition[ChessCoordinate(6, move.to.row)] = rookToMove;
|
|
newPosition[ChessCoordinate(8, move.to.row)] = const ChessPiece.none();
|
|
|
|
kingToMove = oldPosition[ChessCoordinate(5, move.to.row)]!;
|
|
newPosition[ChessCoordinate(7, move.to.row)] = kingToMove;
|
|
newPosition[ChessCoordinate(5, move.to.row)] = const ChessPiece.none();
|
|
}
|
|
if (move.to.column == 3) {
|
|
rookToMove = oldPosition[ChessCoordinate(1, move.to.row)]!;
|
|
newPosition[ChessCoordinate(4, move.to.row)] = rookToMove;
|
|
newPosition[ChessCoordinate(1, move.to.row)] = const ChessPiece.none();
|
|
|
|
kingToMove = oldPosition[ChessCoordinate(5, move.to.row)]!;
|
|
newPosition[ChessCoordinate(3, move.to.row)] = kingToMove;
|
|
newPosition[ChessCoordinate(5, move.to.row)] = const ChessPiece.none();
|
|
}
|
|
}
|
|
|
|
turnColor = state.newTurnColor == ChessColor.white
|
|
? ChessColor.black
|
|
: ChessColor.white;
|
|
|
|
emit(
|
|
ChessBoardState(
|
|
state.bottomColor,
|
|
turnColor,
|
|
newPosition,
|
|
),
|
|
);
|
|
}
|
|
|
|
void promotionHandler(
|
|
ReceivedPromotion event,
|
|
Emitter<ChessBoardState> emit,
|
|
) {
|
|
var pieceAtStartSquare = ChessPosition.getInstance().getPieceAt(
|
|
ChessCoordinate(event.startSquare.column, event.startSquare.row));
|
|
if (pieceAtStartSquare == null) {
|
|
log('received a promotion but piece on start square was empty');
|
|
return;
|
|
}
|
|
|
|
ChessPieceClass pieceClass = ChessPieceClass.none;
|
|
for (var piece in chessPiecesShortName.entries) {
|
|
if (piece.value.toLowerCase() == event.piece) {
|
|
pieceClass = piece.key.pieceClass;
|
|
break;
|
|
}
|
|
}
|
|
var newPosition = ChessPosition.getInstance().currentPosition;
|
|
newPosition[
|
|
ChessCoordinate(event.startSquare.column, event.startSquare.row)] =
|
|
const ChessPiece.none();
|
|
newPosition[ChessCoordinate(event.endSquare.column, event.endSquare.row)] =
|
|
ChessPiece(pieceClass, pieceAtStartSquare.color);
|
|
|
|
emit(ChessBoardState(
|
|
state.bottomColor,
|
|
turnColor,
|
|
newPosition,
|
|
));
|
|
}
|
|
|
|
void ownMoveHandler(OwnPieceMoved event, Emitter<ChessBoardState> emit) {
|
|
log('ownMoveHandler()');
|
|
var apiMove =
|
|
ChessMove(from: event.startSquare, to: event.endSquare).toApiMove();
|
|
var apiMessage = ApiWebsocketMessage(
|
|
type: MessageType.move, move: apiMove, color: null, reason: null);
|
|
|
|
ServerConnection.getInstance().send(jsonEncode(apiMessage));
|
|
|
|
//Temporary chess position until server responds with acknowledgement
|
|
var move = ChessMove.fromApiMove(apiMove);
|
|
var tempPosition = ChessPosition.getInstance().copyOfCurrentPosition;
|
|
tempPosition[move.to] = tempPosition[move.from] ?? const ChessPiece.none();
|
|
tempPosition[move.from] = const ChessPiece.none();
|
|
|
|
emit(
|
|
ChessBoardState(
|
|
state.bottomColor,
|
|
turnColor,
|
|
tempPosition,
|
|
),
|
|
);
|
|
}
|
|
|
|
void ownPromotionHandler(
|
|
OwnPromotionPlayed event, Emitter<ChessBoardState> emit) {
|
|
var apiMove = event.move.toApiMove();
|
|
var shorNameForPiece = chessPiecesShortName[
|
|
ChessPieceAssetKey(pieceClass: event.pieceClass, color: myColor!)]!
|
|
.toLowerCase();
|
|
apiMove.promotionToPiece = shorNameForPiece;
|
|
var message = ApiWebsocketMessage(
|
|
type: MessageType.move,
|
|
move: apiMove,
|
|
color: null,
|
|
reason: null,
|
|
);
|
|
log(jsonEncode(message));
|
|
ServerConnection.getInstance().send(jsonEncode(message));
|
|
}
|
|
|
|
void invalidMoveHandler(
|
|
InvalidMovePlayed event, Emitter<ChessBoardState> emit) {
|
|
emit(
|
|
ChessBoardState(
|
|
state.bottomColor,
|
|
turnColor,
|
|
ChessPosition.getInstance().currentPosition,
|
|
),
|
|
);
|
|
}
|
|
}
|
|
|
|
class ChessBoardState {
|
|
late ChessColor bottomColor;
|
|
final ChessColor newTurnColor;
|
|
final Map<ChessCoordinate, ChessPiece> position;
|
|
|
|
ChessBoardState._(this.bottomColor, this.newTurnColor, this.position);
|
|
|
|
factory ChessBoardState(
|
|
ChessColor bottomColor,
|
|
ChessColor turnColor,
|
|
Map<ChessCoordinate, ChessPiece> position,
|
|
) {
|
|
return ChessBoardState._(bottomColor, turnColor, position);
|
|
}
|
|
|
|
factory ChessBoardState.init() {
|
|
ChessColor bottomColor = ChessColor.white;
|
|
ChessColor turnColor = ChessColor.white;
|
|
|
|
ChessPosition.getInstance().resetToStartingPosition();
|
|
|
|
return ChessBoardState(
|
|
bottomColor, turnColor, ChessPosition.getInstance().currentPosition);
|
|
}
|
|
|
|
void logPosition(Map<ChessCoordinate, ChessPiece> pos) {
|
|
// for (int i = 0; i < 7; i++)
|
|
}
|
|
}
|