mchess-client/lib/chess/chess_board.dart
Marco 212a54612c Implement moves by tapping the squares
This adds an option to dragging-and-dropping which is slightly hard on
smaller screens.

Fix promotions when tapping and fix handling of subsequently tapping two pieces of your color

Cancel tap if a drag is started (tapped square will not stay red in case a drag is started)

Change url strategy back to the hashtag thing

Change version

Fix bug that would not allow a piece move if you tried to take an opponents piece.

Fix the coloring of the last move after an invalid move was played.

Upgrading deps
2024-01-17 20:58:13 +01:00

122 lines
3.7 KiB
Dart

import 'dart:developer';
import 'dart:math' as math;
import 'package:flutter/material.dart';
import 'package:mchess/chess_bloc/chess_bloc.dart';
import 'chess_square.dart';
import '../utils/chess_utils.dart';
class ChessBoard extends StatelessWidget {
final ChessBoardState bState;
final List<ChessSquare> squares;
const ChessBoard._({required this.bState, required this.squares});
factory ChessBoard(
{required ChessBoardState boardState, ChessCoordinate? tappedSquare}) {
List<ChessSquare> squares = List.empty(growable: true);
for (int i = 0; i < 64; i++) {
var column = (i % 8) + 1;
var row = (i ~/ 8) + 1;
final piece = boardState.position[ChessCoordinate(column, row)];
bool squareWasPartOfLastMove = false;
if ((boardState.lastMove.to == ChessCoordinate(column, row) ||
boardState.lastMove.from == ChessCoordinate(column, row)) &&
boardState.colorLastMove) {
squareWasPartOfLastMove = true;
}
squares.add(
ChessSquare(
ChessCoordinate(column, row),
piece,
squareWasPartOfLastMove,
tappedSquare == ChessCoordinate(column, row)),
);
}
return ChessBoard._(bState: boardState, squares: squares);
}
@override
Widget build(BuildContext context) {
log("ChessBoard's build()");
return LayoutBuilder(builder: (context, constraints) {
/*We calculate the margins manually, because otherwise we would have
lines that are 1 pixel wide between the squares (which is ugly)*/
int smallerSize =
math.min(constraints.maxWidth.toInt(), constraints.maxHeight.toInt());
int desiredSize = smallerSize - smallerSize % 8;
int verticalMargin = constraints.maxHeight.toInt() - desiredSize;
int verticalMarginTop = verticalMargin ~/ 2;
int verticalMarginBottom = verticalMargin - verticalMarginTop;
int horizontalMargin = constraints.maxWidth.toInt() - desiredSize;
int horizontalMarginLeft = horizontalMargin ~/ 2;
int horizontalMarginRight = horizontalMargin - horizontalMarginLeft;
return Container(
margin: EdgeInsets.only(
left: horizontalMarginLeft.toDouble(),
right: horizontalMarginRight.toDouble(),
top: verticalMarginTop.toDouble(),
bottom: verticalMarginBottom.toDouble(),
),
child: FittedBox(
fit: BoxFit.contain,
child: Container(
decoration: const BoxDecoration(boxShadow: [
BoxShadow(color: Colors.black, offset: Offset(10, 10))
]),
child: _buildBoard(bState.bottomColor == ChessColor.black),
),
),
);
});
}
Row _buildChessRow(int rowNo, bool flipped) {
if (!flipped) {
return Row(
children: [
for (int i = 8 * rowNo - 8; i < 8 * rowNo; i++) squares.elementAt(i)
],
);
} else {
return Row(
children: [
for (int i = 8 * rowNo - 1; i >= 8 * rowNo - 8; i--)
squares.elementAt(i)
],
);
}
}
Column _buildBoard(bool flipped) {
List<Row> chessBoard = <Row>[];
if (!flipped) {
for (int row = 8; row > 0; row--) {
chessBoard.add(_buildChessRow(row, flipped));
}
} else {
for (int row = 1; row <= 8; row++) {
chessBoard.add(_buildChessRow(row, flipped));
}
}
return Column(children: [...chessBoard]);
}
ChessSquare getSquareAtCoordinate(ChessCoordinate coord) {
/* Calculate index in squares[] from column and row */
int index = (coord.row - 1) * 8 + (coord.column - 1);
log("getSquareAtCoordinates: index calculated to $index");
return squares.elementAt(index);
}
}