diff --git a/androidApp/src/main/java/com/nwagu/chessboy/screens/history/HistoryView.kt b/androidApp/src/main/java/com/nwagu/chessboy/screens/history/HistoryView.kt index 258684d..d60f7fb 100644 --- a/androidApp/src/main/java/com/nwagu/chessboy/screens/history/HistoryView.kt +++ b/androidApp/src/main/java/com/nwagu/chessboy/screens/history/HistoryView.kt @@ -50,7 +50,7 @@ fun HistoryView( .verticalScroll(rememberScrollState()) ) { - for (gamePgn in gamesHistory.asReversed()) { + for (gamePgn in gamesHistory) { PreviousGameView(modifier = Modifier.fillMaxWidth(), gamePgn) { context.gameAnalysisViewModel.pgn = gamePgn navHostController.navigate(Screen.GameAnalysis.route) diff --git a/androidApp/src/main/java/com/nwagu/chessboy/screens/play/PlayView.kt b/androidApp/src/main/java/com/nwagu/chessboy/screens/play/PlayView.kt index b1010e4..0b32e26 100644 --- a/androidApp/src/main/java/com/nwagu/chessboy/screens/play/PlayView.kt +++ b/androidApp/src/main/java/com/nwagu/chessboy/screens/play/PlayView.kt @@ -174,7 +174,7 @@ fun PlayViewPortrait( verticalArrangement = Arrangement.Center ) { PlayerDisplay(modifier = Modifier, viewModel, viewModel.game.colorOnUserSideOfBoard.opposite()) - ChessBoardView(modifier = Modifier.fillMaxWidth(), navHostController, viewModel) + ChessBoardView(modifier = Modifier.fillMaxWidth(), viewModel) PlayerDisplay(modifier = Modifier, viewModel, viewModel.game.colorOnUserSideOfBoard) Row(modifier = Modifier .fillMaxWidth() @@ -227,7 +227,6 @@ fun PlayViewLandscape( ) { ChessBoardView( modifier = Modifier.width((screenConfig.screenWidthDp - 64).dp), - navHostController, viewModel ) } diff --git a/androidApp/src/main/java/com/nwagu/chessboy/widgets/ChessBoard.kt b/androidApp/src/main/java/com/nwagu/chessboy/widgets/ChessBoard.kt index 97afb8b..cd5fdf3 100644 --- a/androidApp/src/main/java/com/nwagu/chessboy/widgets/ChessBoard.kt +++ b/androidApp/src/main/java/com/nwagu/chessboy/widgets/ChessBoard.kt @@ -41,7 +41,6 @@ import kotlinx.serialization.json.* @Composable fun ChessBoardView( modifier: Modifier = Modifier, - navHostController: NavHostController, viewModel: PlayViewModel ) { diff --git a/androidApp/src/main/java/com/nwagu/chessboy/widgets/CustomWidgets.kt b/androidApp/src/main/java/com/nwagu/chessboy/widgets/CustomWidgets.kt index 2a501b9..f13611e 100644 --- a/androidApp/src/main/java/com/nwagu/chessboy/widgets/CustomWidgets.kt +++ b/androidApp/src/main/java/com/nwagu/chessboy/widgets/CustomWidgets.kt @@ -126,9 +126,6 @@ fun PreviousGameView( val whitePlayer = getHeaderValueFromPgn(PGN_HEADER_WHITE_PLAYER, pgn) val blackPlayer = getHeaderValueFromPgn(PGN_HEADER_BLACK_PLAYER, pgn) - val board = Board() - board.importMovesFromPGN(pgn) - Card( modifier = modifier.padding(8.dp), onClick = { diff --git a/chess/src/commonMain/kotlin/com/nwagu/chess/gamelogic/CheckLogic.kt b/chess/src/commonMain/kotlin/com/nwagu/chess/gamelogic/CheckLogic.kt index 78c3de6..73dd058 100644 --- a/chess/src/commonMain/kotlin/com/nwagu/chess/gamelogic/CheckLogic.kt +++ b/chess/src/commonMain/kotlin/com/nwagu/chess/gamelogic/CheckLogic.kt @@ -5,7 +5,7 @@ import com.nwagu.chess.gamelogic.moves.* fun Board.validateMoveDoesNotLeaveKingExposed(move: Move): Boolean { move(move, false) - val kingNotExposed = !isOnCheck(getSquareOccupant(move.destination).chessPieceColor) + val kingNotExposed = !isOnCheck(getSquareOccupantAsChessPiece(move.destination).chessPieceColor) undoMove() return kingNotExposed } diff --git a/chess/src/commonMain/kotlin/com/nwagu/chess/gamelogic/Move.kt b/chess/src/commonMain/kotlin/com/nwagu/chess/gamelogic/Move.kt index 8cc7fbe..fd91d08 100644 --- a/chess/src/commonMain/kotlin/com/nwagu/chess/gamelogic/Move.kt +++ b/chess/src/commonMain/kotlin/com/nwagu/chess/gamelogic/Move.kt @@ -7,7 +7,7 @@ import com.nwagu.chess.gamelogic.moves.* fun Board.move(move: Move, attachSan: Boolean = true): Boolean { val movingPiece = try { - getSquareOccupant(move.source) + getSquareOccupantAsChessPiece(move.source) } catch (e: Exception) { return false } @@ -15,11 +15,9 @@ fun Board.move(move: Move, attachSan: Boolean = true): Boolean { when(move) { is RegularMove -> { movingPiece.numberOfMovesMade++ - squaresMap[move.destination].let { captive -> - if (captive is ChessPiece) { - move.isCapture = true - captives.add(captive) - } + getSquareOccupantAsChessPieceOrNull(move.destination)?.let { captive -> + move.isCapture = true + captives.add(captive) } setSquareOccupant(move.source, EmptySquare) setSquareOccupant(move.destination, movingPiece) @@ -32,11 +30,9 @@ fun Board.move(move: Move, attachSan: Boolean = true): Boolean { startingRow = movingPiece.startingRow, startingColumn = movingPiece.startingColumn ) - squaresMap[move.destination].let { captive -> - if (captive is ChessPiece) { - move.isCapture = true - captives.add(captive) - } + getSquareOccupantAsChessPieceOrNull(move.destination)?.let { captive -> + move.isCapture = true + captives.add(captive) } setSquareOccupant(move.source, EmptySquare) setSquareOccupant(move.destination, promotionPiece) @@ -45,7 +41,7 @@ fun Board.move(move: Move, attachSan: Boolean = true): Boolean { val captivePosition = square(row(move.source), column(move.destination)) move.isCapture = true movingPiece.numberOfMovesMade++ - captives.add(getSquareOccupant(captivePosition)) + captives.add(getSquareOccupantAsChessPiece(captivePosition)) setSquareOccupant(move.source, EmptySquare) setSquareOccupant(move.destination, movingPiece) setSquareOccupant(captivePosition, EmptySquare) @@ -55,7 +51,7 @@ fun Board.move(move: Move, attachSan: Boolean = true): Boolean { val rookSource = getCastlePartnerSourceForKingMove(move.source, move.destination) val rookDestination = getCastlePartnerDestinationForKingMove(move.source, move.destination) - val rook = getSquareOccupant(rookSource) + val rook = getSquareOccupantAsChessPiece(rookSource) movingPiece.numberOfMovesMade++ rook.numberOfMovesMade++ @@ -87,7 +83,7 @@ fun Board.undoMove(): Move? { val move = movesHistory.removeLastOrNull() ?: return null val movingPiece = try { - getSquareOccupant(move.destination) + getSquareOccupantAsChessPiece(move.destination) } catch (e: Exception) { return null } @@ -128,7 +124,7 @@ fun Board.undoMove(): Move? { val rookSource = getCastlePartnerSourceForKingMove(move.source, move.destination) val rookDestination = getCastlePartnerDestinationForKingMove(move.source, move.destination) - val rook = getSquareOccupant(rookDestination) + val rook = getSquareOccupantAsChessPiece(rookDestination) movingPiece.numberOfMovesMade-- rook.numberOfMovesMade-- diff --git a/chess/src/commonMain/kotlin/com/nwagu/chess/gamelogic/SquareValidators.kt b/chess/src/commonMain/kotlin/com/nwagu/chess/gamelogic/SquareValidators.kt index 294b929..81279fe 100644 --- a/chess/src/commonMain/kotlin/com/nwagu/chess/gamelogic/SquareValidators.kt +++ b/chess/src/commonMain/kotlin/com/nwagu/chess/gamelogic/SquareValidators.kt @@ -4,22 +4,22 @@ import com.nwagu.chess.model.* fun Board.squareEmpty(square: Square) = squaresMap[square] is EmptySquare -fun Board.squareContainsOccupantColored(square: Square, color: ChessPieceColor): Boolean { - return getSquareOccupantOrNull(square)?.chessPieceColor == color +fun Board.squareContainsChessPieceColored(square: Square, color: ChessPieceColor): Boolean { + return getSquareOccupantAsChessPieceOrNull(square)?.chessPieceColor == color } fun Board.squareOccupantHasNotMoved(square: Square): Boolean { if (squareEmpty(square)) return false - return getSquareOccupant(square).numberOfMovesMade == 0 + return getSquareOccupantAsChessPiece(square).numberOfMovesMade == 0 } fun Board.destinationIsEmptyOrHasEnemy(destination: Square, color: ChessPieceColor): Boolean { return if (squareEmpty(destination)) true else - getSquareOccupant(destination).chessPieceColor != color + getSquareOccupantAsChessPiece(destination).chessPieceColor != color } fun Board.destinationContainsAnEnemy(destination: Square, color: ChessPieceColor): Boolean { diff --git a/chess/src/commonMain/kotlin/com/nwagu/chess/gamelogic/Turn.kt b/chess/src/commonMain/kotlin/com/nwagu/chess/gamelogic/Turn.kt index d68aef4..ee46ce9 100644 --- a/chess/src/commonMain/kotlin/com/nwagu/chess/gamelogic/Turn.kt +++ b/chess/src/commonMain/kotlin/com/nwagu/chess/gamelogic/Turn.kt @@ -8,7 +8,7 @@ val Board.turn: ChessPieceColor get() { try { val lastMove = movesHistory.lastOrNull() ?: return ChessPieceColor.WHITE - return getSquareOccupant(lastMove.destination).chessPieceColor.opposite() + return getSquareOccupantAsChessPiece(lastMove.destination).chessPieceColor.opposite() } catch (e: Exception) { e.printStackTrace() TODO() diff --git a/chess/src/commonMain/kotlin/com/nwagu/chess/gamelogic/moves/AllMoves.kt b/chess/src/commonMain/kotlin/com/nwagu/chess/gamelogic/moves/AllMoves.kt index 3c5fbf7..4cd9479 100644 --- a/chess/src/commonMain/kotlin/com/nwagu/chess/gamelogic/moves/AllMoves.kt +++ b/chess/src/commonMain/kotlin/com/nwagu/chess/gamelogic/moves/AllMoves.kt @@ -24,7 +24,7 @@ fun Board.getPossibleMovesFrom(source: Square): List { if (squareEmpty(source)) return emptyList() - val possibleMoves = when (getSquareOccupant(source).chessPieceType) { + val possibleMoves = when (getSquareOccupantAsChessPiece(source).chessPieceType) { ChessPieceType.QUEEN -> { getQueenMovesFrom(source) } diff --git a/chess/src/commonMain/kotlin/com/nwagu/chess/gamelogic/moves/BishopMoves.kt b/chess/src/commonMain/kotlin/com/nwagu/chess/gamelogic/moves/BishopMoves.kt index aa39e0a..94a5bf5 100644 --- a/chess/src/commonMain/kotlin/com/nwagu/chess/gamelogic/moves/BishopMoves.kt +++ b/chess/src/commonMain/kotlin/com/nwagu/chess/gamelogic/moves/BishopMoves.kt @@ -6,12 +6,12 @@ import com.nwagu.chess.model.* fun Board.getBishopMovesFrom(source: Square): List { - if (getSquareOccupant(source).chessPieceType != ChessPieceType.BISHOP) + if (getSquareOccupantAsChessPiece(source).chessPieceType != ChessPieceType.BISHOP) throw IllegalStateException("Type must be BISHOP!") return this.squaresMap.keys.filter { destination -> canBishopMoveFrom(source, destination) && - destinationIsEmptyOrHasEnemy(destination, getSquareOccupant(source).chessPieceColor) + destinationIsEmptyOrHasEnemy(destination, getSquareOccupantAsChessPiece(source).chessPieceColor) }.map { destination -> RegularMove(source, destination) } diff --git a/chess/src/commonMain/kotlin/com/nwagu/chess/gamelogic/moves/CastlingAvailability.kt b/chess/src/commonMain/kotlin/com/nwagu/chess/gamelogic/moves/CastlingAvailability.kt index ba9f475..acdd127 100644 --- a/chess/src/commonMain/kotlin/com/nwagu/chess/gamelogic/moves/CastlingAvailability.kt +++ b/chess/src/commonMain/kotlin/com/nwagu/chess/gamelogic/moves/CastlingAvailability.kt @@ -9,7 +9,7 @@ import com.nwagu.chess.model.Board val Board.isWhiteQueenSideCastlingAvailable: Boolean get() { - return (getSquareOccupant(whiteKingPosition).numberOfMovesMade == 0) && + return (getSquareOccupantAsChessPiece(whiteKingPosition).numberOfMovesMade == 0) && run { val queenSideCastlingRookSquare = square(row(whiteKingPosition), column(whiteKingPosition) - 4) squareOccupantHasNotMoved(queenSideCastlingRookSquare) @@ -18,7 +18,7 @@ val Board.isWhiteQueenSideCastlingAvailable: Boolean val Board.isWhiteKingSideCastlingAvailable: Boolean get() { - return (getSquareOccupant(whiteKingPosition).numberOfMovesMade == 0) && + return (getSquareOccupantAsChessPiece(whiteKingPosition).numberOfMovesMade == 0) && run { val kingSideCastlingRookSquare = square(row(whiteKingPosition), column(whiteKingPosition) + 3) squareOccupantHasNotMoved(kingSideCastlingRookSquare) @@ -27,7 +27,7 @@ val Board.isWhiteKingSideCastlingAvailable: Boolean val Board.isBlackQueenSideCastlingAvailable: Boolean get() { - return (getSquareOccupant(blackKingPosition).numberOfMovesMade == 0) && + return (getSquareOccupantAsChessPiece(blackKingPosition).numberOfMovesMade == 0) && run { val queenSideCastlingRookSquare = square(row(blackKingPosition), column(blackKingPosition) - 4) squareOccupantHasNotMoved(queenSideCastlingRookSquare) @@ -36,7 +36,7 @@ val Board.isBlackQueenSideCastlingAvailable: Boolean val Board.isBlackKingSideCastlingAvailable: Boolean get() { - return (getSquareOccupant(blackKingPosition).numberOfMovesMade == 0) && + return (getSquareOccupantAsChessPiece(blackKingPosition).numberOfMovesMade == 0) && run { val kingSideCastlingRookSquare = square(row(blackKingPosition), column(blackKingPosition) + 3) squareOccupantHasNotMoved(kingSideCastlingRookSquare) diff --git a/chess/src/commonMain/kotlin/com/nwagu/chess/gamelogic/moves/KingMoves.kt b/chess/src/commonMain/kotlin/com/nwagu/chess/gamelogic/moves/KingMoves.kt index 1674b3a..14324d0 100644 --- a/chess/src/commonMain/kotlin/com/nwagu/chess/gamelogic/moves/KingMoves.kt +++ b/chess/src/commonMain/kotlin/com/nwagu/chess/gamelogic/moves/KingMoves.kt @@ -6,12 +6,12 @@ import kotlin.math.abs fun Board.getKingMovesFrom(source: Square): List { - if (getSquareOccupant(source).chessPieceType != ChessPieceType.KING) + if (getSquareOccupantAsChessPiece(source).chessPieceType != ChessPieceType.KING) throw IllegalStateException("Type must be KING!") return this.squaresMap.keys.filter { destination -> canKingMoveFrom(source, destination) && - destinationIsEmptyOrHasEnemy(destination, getSquareOccupant(source).chessPieceColor) + destinationIsEmptyOrHasEnemy(destination, getSquareOccupantAsChessPiece(source).chessPieceColor) }.map { destination -> if (abs(column(source) - column(destination)) == 2) Castling(source, destination) diff --git a/chess/src/commonMain/kotlin/com/nwagu/chess/gamelogic/moves/KnightMoves.kt b/chess/src/commonMain/kotlin/com/nwagu/chess/gamelogic/moves/KnightMoves.kt index c3325dd..6cc8cc9 100644 --- a/chess/src/commonMain/kotlin/com/nwagu/chess/gamelogic/moves/KnightMoves.kt +++ b/chess/src/commonMain/kotlin/com/nwagu/chess/gamelogic/moves/KnightMoves.kt @@ -6,12 +6,12 @@ import kotlin.math.abs fun Board.getKnightMovesFrom(source: Square): List { - if (getSquareOccupant(source).chessPieceType != ChessPieceType.KNIGHT) + if (getSquareOccupantAsChessPiece(source).chessPieceType != ChessPieceType.KNIGHT) throw IllegalStateException("Type must be KNIGHT!") return this.squaresMap.keys.filter { destination -> canKnightMoveFrom(source, destination) && - destinationIsEmptyOrHasEnemy(destination, getSquareOccupant(source).chessPieceColor) + destinationIsEmptyOrHasEnemy(destination, getSquareOccupantAsChessPiece(source).chessPieceColor) }.map { destination -> RegularMove(source, destination) } diff --git a/chess/src/commonMain/kotlin/com/nwagu/chess/gamelogic/moves/PawnMoves.kt b/chess/src/commonMain/kotlin/com/nwagu/chess/gamelogic/moves/PawnMoves.kt index a1d00d7..8e8a735 100644 --- a/chess/src/commonMain/kotlin/com/nwagu/chess/gamelogic/moves/PawnMoves.kt +++ b/chess/src/commonMain/kotlin/com/nwagu/chess/gamelogic/moves/PawnMoves.kt @@ -8,14 +8,14 @@ fun Board.getPawnMovesFrom(source: Square): List { try { - if (getSquareOccupant(source).chessPieceType != ChessPieceType.PAWN) + if (getSquareOccupantAsChessPiece(source).chessPieceType != ChessPieceType.PAWN) throw IllegalStateException("Type must be PAWN!") return this.squaresMap.keys.filter { destination -> canPawnMoveFrom(source, destination) && destinationIsEmptyOrHasEnemy( destination, - getSquareOccupant(source).chessPieceColor + getSquareOccupantAsChessPiece(source).chessPieceColor ) }.map { destination -> if (column(destination) != column(source) && squareEmpty(destination)) diff --git a/chess/src/commonMain/kotlin/com/nwagu/chess/gamelogic/moves/QueenMoves.kt b/chess/src/commonMain/kotlin/com/nwagu/chess/gamelogic/moves/QueenMoves.kt index 1470aaf..472b66a 100644 --- a/chess/src/commonMain/kotlin/com/nwagu/chess/gamelogic/moves/QueenMoves.kt +++ b/chess/src/commonMain/kotlin/com/nwagu/chess/gamelogic/moves/QueenMoves.kt @@ -5,12 +5,12 @@ import com.nwagu.chess.model.* fun Board.getQueenMovesFrom(source: Square): List { - if (getSquareOccupant(source).chessPieceType != ChessPieceType.QUEEN) + if (getSquareOccupantAsChessPiece(source).chessPieceType != ChessPieceType.QUEEN) throw IllegalStateException("Type must be QUEEN!") return this.squaresMap.keys.filter { destination -> canQueenMoveFrom(source, destination) && - destinationIsEmptyOrHasEnemy(destination, getSquareOccupant(source).chessPieceColor) + destinationIsEmptyOrHasEnemy(destination, getSquareOccupantAsChessPiece(source).chessPieceColor) }.map { destination -> RegularMove(source, destination) } diff --git a/chess/src/commonMain/kotlin/com/nwagu/chess/gamelogic/moves/RookMoves.kt b/chess/src/commonMain/kotlin/com/nwagu/chess/gamelogic/moves/RookMoves.kt index e68f728..742acbe 100644 --- a/chess/src/commonMain/kotlin/com/nwagu/chess/gamelogic/moves/RookMoves.kt +++ b/chess/src/commonMain/kotlin/com/nwagu/chess/gamelogic/moves/RookMoves.kt @@ -5,12 +5,12 @@ import com.nwagu.chess.model.* fun Board.getRookMovesFrom(source: Square): List { - if (getSquareOccupant(source).chessPieceType != ChessPieceType.ROOK) + if (getSquareOccupantAsChessPiece(source).chessPieceType != ChessPieceType.ROOK) throw IllegalStateException("Type must be ROOK!") return this.squaresMap.keys.filter { destination -> canRookMoveFrom(source, destination) && - destinationIsEmptyOrHasEnemy(destination, getSquareOccupant(source).chessPieceColor) + destinationIsEmptyOrHasEnemy(destination, getSquareOccupantAsChessPiece(source).chessPieceColor) }.map { destination -> RegularMove(source, destination) } diff --git a/chess/src/commonMain/kotlin/com/nwagu/chess/model/Board.kt b/chess/src/commonMain/kotlin/com/nwagu/chess/model/Board.kt index 13a9b2d..782e10f 100644 --- a/chess/src/commonMain/kotlin/com/nwagu/chess/model/Board.kt +++ b/chess/src/commonMain/kotlin/com/nwagu/chess/model/Board.kt @@ -15,10 +15,10 @@ class Board( var whiteKingPosition: Int = 0 init { - reset() + clear() } - fun reset() { + fun clear() { movesHistory.clear() captives.clear() repeat(numberOfColumns * numberOfRows) { index -> @@ -26,11 +26,17 @@ class Board( } } - fun getSquareOccupant(square: Square): ChessPiece { + /* + * Throws an exception if square is empty + * */ + fun getSquareOccupantAsChessPiece(square: Square): ChessPiece { return squaresMap[square] as ChessPiece } - fun getSquareOccupantOrNull(square: Square): ChessPiece? { + /* + * Returns null if square is empty + * */ + fun getSquareOccupantAsChessPieceOrNull(square: Square): ChessPiece? { return if (squareEmpty(square)) null else squaresMap[square] as ChessPiece } diff --git a/chess/src/commonMain/kotlin/com/nwagu/chess/model/ChessPiece.kt b/chess/src/commonMain/kotlin/com/nwagu/chess/model/ChessPiece.kt index 6ce2c55..9708f89 100644 --- a/chess/src/commonMain/kotlin/com/nwagu/chess/model/ChessPiece.kt +++ b/chess/src/commonMain/kotlin/com/nwagu/chess/model/ChessPiece.kt @@ -10,4 +10,7 @@ data class ChessPiece( var numberOfMovesMade: Int, val startingRow: Int, val startingColumn: Int -): SquareOccupant() \ No newline at end of file +): SquareOccupant() + +val ChessPiece.id: String + get() = "${chessPieceType.fenSymbol}_${startingRow}_${startingColumn}" \ No newline at end of file diff --git a/chess/src/commonMain/kotlin/com/nwagu/chess/model/Game.kt b/chess/src/commonMain/kotlin/com/nwagu/chess/model/Game.kt index c07d92d..ca88dfa 100644 --- a/chess/src/commonMain/kotlin/com/nwagu/chess/model/Game.kt +++ b/chess/src/commonMain/kotlin/com/nwagu/chess/model/Game.kt @@ -4,10 +4,16 @@ import com.benasher44.uuid.uuid4 import com.nwagu.chess.representation.loadStandardStartingPosition class Game( - val id: String = uuid4().toString(), + val id: String, val whitePlayer: Player, val blackPlayer: Player ) { + // Using a second constructor (instead of default arguments) + // in order to support initialization in swift + constructor( + whitePlayer: Player, + blackPlayer: Player + ): this(uuid4().toString(), whitePlayer, blackPlayer) var title = "${whitePlayer.name} (W) vs ${blackPlayer.name} (B)" diff --git a/chess/src/commonMain/kotlin/com/nwagu/chess/representation/FEN.kt b/chess/src/commonMain/kotlin/com/nwagu/chess/representation/FEN.kt index 666fe14..3d05293 100644 --- a/chess/src/commonMain/kotlin/com/nwagu/chess/representation/FEN.kt +++ b/chess/src/commonMain/kotlin/com/nwagu/chess/representation/FEN.kt @@ -27,7 +27,7 @@ fun Board.loadStandardStartingPosition() { * */ fun Board.loadPositionFromFen(fen: String) { - reset() + clear() val pieceArrangement = fen.takeWhile { it != ' ' } @@ -80,7 +80,7 @@ fun Board.getFen(): String { return@repeat } - val piece = getSquareOccupant(square) + val piece = getSquareOccupantAsChessPiece(square) if (emptySquaresCount > 0) { fen.append(emptySquaresCount) diff --git a/chess/src/commonMain/kotlin/com/nwagu/chess/representation/PGN.kt b/chess/src/commonMain/kotlin/com/nwagu/chess/representation/PGN.kt index 1958764..ea27acc 100644 --- a/chess/src/commonMain/kotlin/com/nwagu/chess/representation/PGN.kt +++ b/chess/src/commonMain/kotlin/com/nwagu/chess/representation/PGN.kt @@ -65,7 +65,7 @@ fun getHeaderValueFromPgn(name: String, pgn: String): String? { fun Board.importMovesFromPGN(pgn: String) { - reset() + clear() loadStandardStartingPosition() val lines = pgn.split("\n") diff --git a/chess/src/commonMain/kotlin/com/nwagu/chess/representation/UCI.kt b/chess/src/commonMain/kotlin/com/nwagu/chess/representation/UCI.kt index 909108a..dd2be98 100644 --- a/chess/src/commonMain/kotlin/com/nwagu/chess/representation/UCI.kt +++ b/chess/src/commonMain/kotlin/com/nwagu/chess/representation/UCI.kt @@ -15,11 +15,11 @@ fun Board.parseUciEngineMove(move: String): Move? { if (move.length == 4) { - if (getSquareOccupant(source).chessPieceType == ChessPieceType.PAWN && !areSquaresOnSameColumn(source, destination) && squareEmpty(destination)) { + if (getSquareOccupantAsChessPiece(source).chessPieceType == ChessPieceType.PAWN && !areSquaresOnSameColumn(source, destination) && squareEmpty(destination)) { return EnPassant(source, destination) } else { - if (getSquareOccupant(source).chessPieceType == ChessPieceType.KING && + if (getSquareOccupantAsChessPiece(source).chessPieceType == ChessPieceType.KING && areSquaresOnSameRow(source, destination) && squaresBetweenSquaresOnRow( source, diff --git a/iosApp/iosApp.xcodeproj/project.pbxproj b/iosApp/iosApp.xcodeproj/project.pbxproj index b82e726..7160406 100644 --- a/iosApp/iosApp.xcodeproj/project.pbxproj +++ b/iosApp/iosApp.xcodeproj/project.pbxproj @@ -281,7 +281,7 @@ attributes = { LastSwiftUpdateCheck = 1130; LastUpgradeCheck = 1130; - ORGANIZATIONNAME = orgName; + ORGANIZATIONNAME = "Chukwuemeka Nwagu"; TargetAttributes = { 7555FF7A242A565900829871 = { CreatedOnToolsVersion = 11.3.1; diff --git a/iosApp/iosApp.xcworkspace/xcuserdata/cnwagu.xcuserdatad/UserInterfaceState.xcuserstate b/iosApp/iosApp.xcworkspace/xcuserdata/cnwagu.xcuserdatad/UserInterfaceState.xcuserstate index 8a95d3c..6aaab89 100644 Binary files a/iosApp/iosApp.xcworkspace/xcuserdata/cnwagu.xcuserdatad/UserInterfaceState.xcuserstate and b/iosApp/iosApp.xcworkspace/xcuserdata/cnwagu.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/iosApp/iosApp/ChessBoy.swift b/iosApp/iosApp/ChessBoy.swift index 99bd81c..29ac4a8 100644 --- a/iosApp/iosApp/ChessBoy.swift +++ b/iosApp/iosApp/ChessBoy.swift @@ -3,7 +3,7 @@ // iosApp // // Created by Chukwuemeka Nwagu on 22/06/2021. -// Copyright © 2021 orgName. All rights reserved. +// Copyright © 2021 Chukwuemeka Nwagu. All rights reserved. // import SwiftUI @@ -20,6 +20,10 @@ struct ChessBoy: App { MainView() .environmentObject(viewRouter) .environmentObject(environment) + .onAppear { environment.initialize() } + .onReceive(NotificationCenter.default.publisher(for: UIApplication.didEnterBackgroundNotification), perform: { _ in + environment.saveCurrentGame() + }) } } } diff --git a/iosApp/iosApp/ChessBoyEnvironment.swift b/iosApp/iosApp/ChessBoyEnvironment.swift index edf0a19..ae9ac7c 100644 --- a/iosApp/iosApp/ChessBoyEnvironment.swift +++ b/iosApp/iosApp/ChessBoyEnvironment.swift @@ -3,7 +3,7 @@ // iosApp // // Created by Chukwuemeka Nwagu on 20/07/2021. -// Copyright © 2021 orgName. All rights reserved. +// Copyright © 2021 Chukwuemeka Nwagu. All rights reserved. // import SwiftUI @@ -11,25 +11,32 @@ import sharedmodels class ChessBoyEnvironment: ObservableObject { + let mainViewModel = MainViewModel() let playViewModel = PlayViewModel() + func initialize() { + if (!playViewModel.isGameInitialized()) { + let game = mainViewModel.getLastGameOrDefault() + playViewModel.doInit(game: game) + } + } + func startNewGame(whitePlayer: Player, blackPlayer: Player) { let game = createNewGame(whitePlayer: whitePlayer, blackPlayer: blackPlayer) -// saveGame(playViewModel.game) + saveCurrentGame() playViewModel.doInit(game: game) } + func saveCurrentGame() { + mainViewModel.saveGame(game: playViewModel.game) + } + + func getGamesHistory() -> [String] { + mainViewModel.getGamesHistory() + } + func createNewGame(whitePlayer: Player, blackPlayer: Player) -> Game { - -// if (whitePlayer is BluetoothPlayer || blackPlayer is BluetoothPlayer) { -// throw Error -// } - - return Game( - id: "hiukb", - whitePlayer: whitePlayer, - blackPlayer: blackPlayer - ) + Game(whitePlayer: whitePlayer, blackPlayer: blackPlayer) } } diff --git a/iosApp/iosApp/Model/QuickAction.swift b/iosApp/iosApp/Model/QuickAction.swift index f0aedf7..ccb4735 100644 --- a/iosApp/iosApp/Model/QuickAction.swift +++ b/iosApp/iosApp/Model/QuickAction.swift @@ -3,7 +3,7 @@ // iosApp // // Created by Chukwuemeka Nwagu on 27/06/2021. -// Copyright © 2021 orgName. All rights reserved. +// Copyright © 2021 Chukwuemeka Nwagu. All rights reserved. // import Foundation diff --git a/iosApp/iosApp/Model/SideChoice.swift b/iosApp/iosApp/Model/SideChoice.swift index bcd084f..e7f53e7 100644 --- a/iosApp/iosApp/Model/SideChoice.swift +++ b/iosApp/iosApp/Model/SideChoice.swift @@ -3,7 +3,7 @@ // iosApp // // Created by Chukwuemeka Nwagu on 10/07/2021. -// Copyright © 2021 orgName. All rights reserved. +// Copyright © 2021 Chukwuemeka Nwagu. All rights reserved. // import Foundation diff --git a/iosApp/iosApp/Screens/History/HistoryView.swift b/iosApp/iosApp/Screens/History/HistoryView.swift index cd8d3a6..65f1249 100644 --- a/iosApp/iosApp/Screens/History/HistoryView.swift +++ b/iosApp/iosApp/Screens/History/HistoryView.swift @@ -3,20 +3,31 @@ // iosApp // // Created by Chukwuemeka Nwagu on 26/06/2021. -// Copyright © 2021 orgName. All rights reserved. +// Copyright © 2021 Chukwuemeka Nwagu. All rights reserved. // import SwiftUI +import sharedmodels struct HistoryView: View { @EnvironmentObject var viewRouter: ViewRouter + @EnvironmentObject var environment: ChessBoyEnvironment + + @State var games: [String] = [] var body: some View { VStack(alignment: .leading, spacing: 0) { TopBar(title: "History") - Text("History") + List { + ForEach(games, id: \.self) { game in + itemView(of: game) + } + } Spacer() } + .onAppear { + games = environment.getGamesHistory() + } .frame( minWidth: 0, maxWidth: .infinity, @@ -26,4 +37,10 @@ struct HistoryView: View { ) .padding() } + + private func itemView(of pgn: String) -> some View { + let whitePlayer = PGNKt.getHeaderValueFromPgn(name: PGNKt.PGN_HEADER_WHITE_PLAYER, pgn: pgn) ?? "" + let blackPlayer = PGNKt.getHeaderValueFromPgn(name: PGNKt.PGN_HEADER_BLACK_PLAYER, pgn: pgn) ?? "" + return Text("\(whitePlayer)(W) vs \(blackPlayer)(B)") + } } diff --git a/iosApp/iosApp/Screens/Main/HomeView.swift b/iosApp/iosApp/Screens/Main/HomeView.swift index eb0a556..6d33fe2 100644 --- a/iosApp/iosApp/Screens/Main/HomeView.swift +++ b/iosApp/iosApp/Screens/Main/HomeView.swift @@ -2,12 +2,8 @@ import SwiftUI import sharedmodels struct HomeView: View { - @EnvironmentObject - var viewRouter: ViewRouter - @EnvironmentObject - var environment: ChessBoyEnvironment - - let mainViewModel: MainViewModel = MainViewModel() + @EnvironmentObject var viewRouter: ViewRouter + @EnvironmentObject var environment: ChessBoyEnvironment var playActions: [QuickAction] { [ @@ -77,12 +73,6 @@ struct HomeView: View { alignment: .topLeading ) .padding() - .onAppear { - if (!environment.playViewModel.isGameInitialized()) { - let game = mainViewModel.getLastGameOrDefault() - environment.playViewModel.doInit(game: game) - } - } } } diff --git a/iosApp/iosApp/Screens/Main/MainView.swift b/iosApp/iosApp/Screens/Main/MainView.swift index 1a30311..a10c909 100644 --- a/iosApp/iosApp/Screens/Main/MainView.swift +++ b/iosApp/iosApp/Screens/Main/MainView.swift @@ -3,7 +3,7 @@ // iosApp // // Created by Chukwuemeka Nwagu on 07/07/2021. -// Copyright © 2021 orgName. All rights reserved. +// Copyright © 2021 Chukwuemeka Nwagu. All rights reserved. // import SwiftUI diff --git a/iosApp/iosApp/Screens/Navigation/Screen.swift b/iosApp/iosApp/Screens/Navigation/Screen.swift index adcfbd7..0d57a95 100644 --- a/iosApp/iosApp/Screens/Navigation/Screen.swift +++ b/iosApp/iosApp/Screens/Navigation/Screen.swift @@ -3,7 +3,7 @@ // iosApp // // Created by Chukwuemeka Nwagu on 07/07/2021. -// Copyright © 2021 orgName. All rights reserved. +// Copyright © 2021 Chukwuemeka Nwagu. All rights reserved. // enum Screen { diff --git a/iosApp/iosApp/Screens/Navigation/ViewRouter.swift b/iosApp/iosApp/Screens/Navigation/ViewRouter.swift index 30a09aa..8c4657e 100644 --- a/iosApp/iosApp/Screens/Navigation/ViewRouter.swift +++ b/iosApp/iosApp/Screens/Navigation/ViewRouter.swift @@ -3,7 +3,7 @@ // iosApp // // Created by Chukwuemeka Nwagu on 07/07/2021. -// Copyright © 2021 orgName. All rights reserved. +// Copyright © 2021 Chukwuemeka Nwagu. All rights reserved. // import SwiftUI diff --git a/iosApp/iosApp/Screens/NewGame/NewBluetoothGameView.swift b/iosApp/iosApp/Screens/NewGame/NewBluetoothGameView.swift index df50028..170e396 100644 --- a/iosApp/iosApp/Screens/NewGame/NewBluetoothGameView.swift +++ b/iosApp/iosApp/Screens/NewGame/NewBluetoothGameView.swift @@ -3,7 +3,7 @@ // iosApp // // Created by Chukwuemeka Nwagu on 26/06/2021. -// Copyright © 2021 orgName. All rights reserved. +// Copyright © 2021 Chukwuemeka Nwagu. All rights reserved. // import SwiftUI diff --git a/iosApp/iosApp/Screens/NewGame/NewGameView.swift b/iosApp/iosApp/Screens/NewGame/NewGameView.swift index 28888cb..1fd10b7 100644 --- a/iosApp/iosApp/Screens/NewGame/NewGameView.swift +++ b/iosApp/iosApp/Screens/NewGame/NewGameView.swift @@ -3,7 +3,7 @@ // iosApp // // Created by Chukwuemeka Nwagu on 26/06/2021. -// Copyright © 2021 orgName. All rights reserved. +// Copyright © 2021 Chukwuemeka Nwagu. All rights reserved. // import SwiftUI @@ -13,9 +13,9 @@ struct NewGameView: View { @EnvironmentObject var viewRouter: ViewRouter @EnvironmentObject var environment: ChessBoyEnvironment - let newGameViewModel: NewGameViewModel = NewGameViewModel() - @ObservedObject var selectedColor: Collector - @ObservedObject var selectedOpponent: Collector + private let newGameViewModel = NewGameViewModel() + @ObservedObject private var selectedColor: Collector + @ObservedObject private var selectedOpponent: Collector init() { selectedColor = newGameViewModel.selectedColor.collectAsObservable(initialValue: newGameViewModel.selectedColor.value as? ChessPieceColor) diff --git a/iosApp/iosApp/Screens/Play/PlayView.swift b/iosApp/iosApp/Screens/Play/PlayView.swift index 728f0b7..e9c3b62 100644 --- a/iosApp/iosApp/Screens/Play/PlayView.swift +++ b/iosApp/iosApp/Screens/Play/PlayView.swift @@ -3,27 +3,19 @@ // iosApp // // Created by Chukwuemeka Nwagu on 27/06/2021. -// Copyright © 2021 orgName. All rights reserved. +// Copyright © 2021 Chukwuemeka Nwagu. All rights reserved. // import SwiftUI import sharedmodels -// to match the typealias in the kotlin chess module -typealias Square = Int32 - struct PlayView: View { - @EnvironmentObject - var viewRouter: ViewRouter - - var playViewModel: PlayViewModel - @ObservedObject - var gameChanged: Collector - @ObservedObject - var pendingPromotion: Collector + @EnvironmentObject var viewRouter: ViewRouter - @State - private var showPromotionDialog = false + private let playViewModel: PlayViewModel + @ObservedObject private var gameChanged: Collector + @ObservedObject private var pendingPromotion: Collector + @State private var showPromotionDialog = false init(playViewModel: PlayViewModel) { self.playViewModel = playViewModel @@ -39,7 +31,7 @@ struct PlayView: View { PlayerDisplay(playViewModel: playViewModel, color: playViewModel.game.colorOnUserSideOfBoard.opposite()).padding(16) ChessBoardView(playViewModel: playViewModel) PlayerDisplay(playViewModel: playViewModel, color: playViewModel.game.colorOnUserSideOfBoard).padding(16) - Button(action: { playViewModel.undo() }, label: {Text("Undo") }).padding() + Button(action: { withAnimation { playViewModel.undo() } }, label: {Text("Undo") }).padding() } Spacer() } diff --git a/iosApp/iosApp/Screens/Play/SelectPromotionPiecePrompt.swift b/iosApp/iosApp/Screens/Play/SelectPromotionPiecePrompt.swift index af92981..17890ee 100644 --- a/iosApp/iosApp/Screens/Play/SelectPromotionPiecePrompt.swift +++ b/iosApp/iosApp/Screens/Play/SelectPromotionPiecePrompt.swift @@ -3,7 +3,7 @@ // iosApp // // Created by Chukwuemeka Nwagu on 21/07/2021. -// Copyright © 2021 orgName. All rights reserved. +// Copyright © 2021 Chukwuemeka Nwagu. All rights reserved. // import SwiftUI diff --git a/iosApp/iosApp/Screens/Settings/SettingsView.swift b/iosApp/iosApp/Screens/Settings/SettingsView.swift index 0812698..492a0e1 100644 --- a/iosApp/iosApp/Screens/Settings/SettingsView.swift +++ b/iosApp/iosApp/Screens/Settings/SettingsView.swift @@ -3,7 +3,7 @@ // iosApp // // Created by Chukwuemeka Nwagu on 07/07/2021. -// Copyright © 2021 orgName. All rights reserved. +// Copyright © 2021 Chukwuemeka Nwagu. All rights reserved. // import SwiftUI diff --git a/iosApp/iosApp/Util/Collector.swift b/iosApp/iosApp/Util/Collector.swift index f2bf53e..1b382ba 100644 --- a/iosApp/iosApp/Util/Collector.swift +++ b/iosApp/iosApp/Util/Collector.swift @@ -3,7 +3,7 @@ // iosApp // // Created by Chukwuemeka Nwagu on 20/07/2021. -// Copyright © 2021 orgName. All rights reserved. +// Copyright © 2021 Chukwuemeka Nwagu. All rights reserved. // import sharedmodels diff --git a/iosApp/iosApp/Util/ScopeFunc.swift b/iosApp/iosApp/Util/ScopeFunc.swift index 37f1cee..a7da7f6 100644 --- a/iosApp/iosApp/Util/ScopeFunc.swift +++ b/iosApp/iosApp/Util/ScopeFunc.swift @@ -3,7 +3,7 @@ // iosApp // // Created by Chukwuemeka Nwagu on 08/07/2021. -// Copyright © 2021 orgName. All rights reserved. +// Copyright © 2021 Chukwuemeka Nwagu. All rights reserved. // import SwiftUI diff --git a/iosApp/iosApp/Util/Stack.swift b/iosApp/iosApp/Util/Stack.swift index edd5cc5..8b34340 100644 --- a/iosApp/iosApp/Util/Stack.swift +++ b/iosApp/iosApp/Util/Stack.swift @@ -3,7 +3,7 @@ // iosApp // // Created by Chukwuemeka Nwagu on 08/07/2021. -// Copyright © 2021 orgName. All rights reserved. +// Copyright © 2021 Chukwuemeka Nwagu. All rights reserved. // struct Stack { diff --git a/iosApp/iosApp/Widget/ChessBoardView.swift b/iosApp/iosApp/Widget/ChessBoardView.swift index fcc15d6..769df27 100644 --- a/iosApp/iosApp/Widget/ChessBoardView.swift +++ b/iosApp/iosApp/Widget/ChessBoardView.swift @@ -3,22 +3,24 @@ // iosApp // // Created by Chukwuemeka Nwagu on 27/06/2021. -// Copyright © 2021 orgName. All rights reserved. +// Copyright © 2021 Chukwuemeka Nwagu. All rights reserved. // import SwiftUI import sharedmodels +// to match the typealias in the kotlin chess module +typealias Square = Int32 + struct ChessBoardView: View { var playViewModel: PlayViewModel - @ObservedObject - var boardChanged: Collector - @ObservedObject - var selectedSquare: Collector - @ObservedObject - var possibleMoves: Collector<[Move]> + @ObservedObject var boardChanged: Collector + @ObservedObject var selectedSquare: Collector + @ObservedObject var possibleMoves: Collector<[Move]> + + @Namespace private var boardNameSpace init(playViewModel: PlayViewModel) { self.playViewModel = playViewModel @@ -37,27 +39,32 @@ struct ChessBoardView: View { count: Int(game.board.numberOfColumns) ) + let squares = game.board.squaresMap as! Dictionary + + let positionsSorted = game.colorOnUserSideOfBoard == ChessPieceColor.white + ? squares.sorted(by: {$0.0 < $1.0}) + : squares.sorted(by: {$0.0 > $1.0}) + LazyVGrid(columns: columns, spacing: 0) { - ForEach(0.. some View { + Image(chessPiece.imageRes()) + .matchedGeometryEffect(id: chessPiece.id, in: boardNameSpace) + .zIndex(1) + } } struct ChessBoard_Previews: PreviewProvider { diff --git a/iosApp/iosApp/Widget/PlayerDisplay.swift b/iosApp/iosApp/Widget/PlayerDisplay.swift index fae019e..7a270a2 100644 --- a/iosApp/iosApp/Widget/PlayerDisplay.swift +++ b/iosApp/iosApp/Widget/PlayerDisplay.swift @@ -3,7 +3,7 @@ // iosApp // // Created by Chukwuemeka Nwagu on 05/07/2021. -// Copyright © 2021 orgName. All rights reserved. +// Copyright © 2021 Chukwuemeka Nwagu. All rights reserved. // import SwiftUI @@ -13,8 +13,7 @@ struct PlayerDisplay: View { var playViewModel: PlayViewModel var color: ChessPieceColor - @ObservedObject - var boardChanged: Collector + @ObservedObject var boardChanged: Collector init(playViewModel: PlayViewModel, color: ChessPieceColor) { self.playViewModel = playViewModel diff --git a/iosApp/iosApp/Widget/PlayerSelect.swift b/iosApp/iosApp/Widget/PlayerSelect.swift index 25b0b42..808c4af 100644 --- a/iosApp/iosApp/Widget/PlayerSelect.swift +++ b/iosApp/iosApp/Widget/PlayerSelect.swift @@ -3,7 +3,7 @@ // iosApp // // Created by Chukwuemeka Nwagu on 10/07/2021. -// Copyright © 2021 orgName. All rights reserved. +// Copyright © 2021 Chukwuemeka Nwagu. All rights reserved. // import SwiftUI diff --git a/iosApp/iosApp/Widget/QuickActionView.swift b/iosApp/iosApp/Widget/QuickActionView.swift index 8f9ee6f..bbcef62 100644 --- a/iosApp/iosApp/Widget/QuickActionView.swift +++ b/iosApp/iosApp/Widget/QuickActionView.swift @@ -3,7 +3,7 @@ // iosApp // // Created by Chukwuemeka Nwagu on 27/06/2021. -// Copyright © 2021 orgName. All rights reserved. +// Copyright © 2021 Chukwuemeka Nwagu. All rights reserved. // import SwiftUI diff --git a/iosApp/iosApp/Widget/RadioCard.swift b/iosApp/iosApp/Widget/RadioCard.swift index d00fa57..9a422d9 100644 --- a/iosApp/iosApp/Widget/RadioCard.swift +++ b/iosApp/iosApp/Widget/RadioCard.swift @@ -3,7 +3,7 @@ // iosApp // // Created by Chukwuemeka Nwagu on 09/07/2021. -// Copyright © 2021 orgName. All rights reserved. +// Copyright © 2021 Chukwuemeka Nwagu. All rights reserved. // import SwiftUI diff --git a/iosApp/iosApp/Widget/TopBar.swift b/iosApp/iosApp/Widget/TopBar.swift index 3fb8678..61522cf 100644 --- a/iosApp/iosApp/Widget/TopBar.swift +++ b/iosApp/iosApp/Widget/TopBar.swift @@ -3,7 +3,7 @@ // iosApp // // Created by Chukwuemeka Nwagu on 07/07/2021. -// Copyright © 2021 orgName. All rights reserved. +// Copyright © 2021 Chukwuemeka Nwagu. All rights reserved. // import SwiftUI diff --git a/iosApp/iosApp/Widget/WrappingHStack.swift b/iosApp/iosApp/Widget/WrappingHStack.swift index 795b08c..8d6ae15 100644 --- a/iosApp/iosApp/Widget/WrappingHStack.swift +++ b/iosApp/iosApp/Widget/WrappingHStack.swift @@ -3,7 +3,7 @@ // iosApp // // Created by Chukwuemeka Nwagu on 09/07/2021. -// Copyright © 2021 orgName. All rights reserved. +// Copyright © 2021 Chukwuemeka Nwagu. All rights reserved. // import SwiftUI diff --git a/sharedmodels/src/androidMain/kotlin/com/nwagu/chessboy/sharedmodels/presentation/BaseViewModel.kt b/sharedmodels/src/androidMain/kotlin/com/nwagu/chessboy/sharedmodels/presentation/BaseViewModel.kt index 964e795..2ed3f68 100644 --- a/sharedmodels/src/androidMain/kotlin/com/nwagu/chessboy/sharedmodels/presentation/BaseViewModel.kt +++ b/sharedmodels/src/androidMain/kotlin/com/nwagu/chessboy/sharedmodels/presentation/BaseViewModel.kt @@ -5,6 +5,8 @@ import android.widget.Toast import androidx.lifecycle.AndroidViewModel import androidx.lifecycle.viewModelScope import com.nwagu.chessboy.sharedmodels.ChessApplication +import com.nwagu.chessboy.sharedmodels.data.DatabaseDriverFactory +import com.nwagu.chessboy.sharedmodels.data.LocalGamesHistoryRepository import kotlinx.coroutines.CoroutineScope actual open class BaseViewModel: AndroidViewModel { @@ -13,13 +15,15 @@ actual open class BaseViewModel: AndroidViewModel { constructor(application: Application): super(application) actual val clientScope: CoroutineScope = viewModelScope + actual val gamesHistoryRepository by lazy { + LocalGamesHistoryRepository(DatabaseDriverFactory(getApplication())) + } + actual override fun onCleared() { super.onCleared() } actual fun showToast(message: String) { -// ContextCompat.getMainExecutor(getApplication()).execute { - Toast.makeText(getApplication(), message, Toast.LENGTH_LONG).show() -// } + Toast.makeText(getApplication(), message, Toast.LENGTH_LONG).show() } } \ No newline at end of file diff --git a/sharedmodels/src/commonMain/kotlin/com/nwagu/chessboy/sharedmodels/data/GamesHistoryRepository.kt b/sharedmodels/src/commonMain/kotlin/com/nwagu/chessboy/sharedmodels/data/GamesHistoryRepository.kt new file mode 100644 index 0000000..544d0ee --- /dev/null +++ b/sharedmodels/src/commonMain/kotlin/com/nwagu/chessboy/sharedmodels/data/GamesHistoryRepository.kt @@ -0,0 +1,12 @@ +package com.nwagu.chessboy.sharedmodels.data + +import com.nwagu.chessboy.GameHistory + +interface GamesHistoryRepository { + + fun addGame(id: String, pgn: String) + fun getLastGame(): GameHistory? + fun getMostRecentGames(numberOfGames: Int = 20): List + fun clearGamesHistory() + +} \ No newline at end of file diff --git a/sharedmodels/src/commonMain/kotlin/com/nwagu/chessboy/sharedmodels/data/LocalGamesHistoryRepository.kt b/sharedmodels/src/commonMain/kotlin/com/nwagu/chessboy/sharedmodels/data/LocalGamesHistoryRepository.kt new file mode 100644 index 0000000..6f75ee5 --- /dev/null +++ b/sharedmodels/src/commonMain/kotlin/com/nwagu/chessboy/sharedmodels/data/LocalGamesHistoryRepository.kt @@ -0,0 +1,29 @@ +package com.nwagu.chessboy.sharedmodels.data + +import com.nwagu.chessboy.ChessBoyDatabase +import com.nwagu.chessboy.GameHistory + +class LocalGamesHistoryRepository( + databaseDriverFactory: DatabaseDriverFactory +) : GamesHistoryRepository { + + private val database = ChessBoyDatabase(databaseDriverFactory.createDriver()) + private val dbQuery = database.gameHistoryQueries + + override fun addGame(id: String, pgn: String) { + dbQuery.insertGame(id, pgn) + } + + override fun getLastGame(): GameHistory? { + return dbQuery.selectLastGame().executeAsOneOrNull() + } + + override fun getMostRecentGames(numberOfGames: Int): List { + return dbQuery.mostRecentGames(numberOfGames.toLong()).executeAsList() + } + + override fun clearGamesHistory() { + dbQuery.removeAllGames() + } + +} \ No newline at end of file diff --git a/sharedmodels/src/commonMain/kotlin/com/nwagu/chessboy/sharedmodels/presentation/BaseViewModel.kt b/sharedmodels/src/commonMain/kotlin/com/nwagu/chessboy/sharedmodels/presentation/BaseViewModel.kt index ab4d3dc..d9171e4 100644 --- a/sharedmodels/src/commonMain/kotlin/com/nwagu/chessboy/sharedmodels/presentation/BaseViewModel.kt +++ b/sharedmodels/src/commonMain/kotlin/com/nwagu/chessboy/sharedmodels/presentation/BaseViewModel.kt @@ -2,11 +2,15 @@ package com.nwagu.chessboy.sharedmodels.presentation import com.nwagu.chess.model.Game import com.nwagu.chess.representation.* +import com.nwagu.chessboy.sharedmodels.data.LocalGamesHistoryRepository import com.nwagu.chessboy.sharedmodels.players.getPlayerWithId import kotlinx.coroutines.CoroutineScope expect open class BaseViewModel() { + val clientScope: CoroutineScope + protected val gamesHistoryRepository: LocalGamesHistoryRepository + protected open fun onCleared() fun showToast(message: String) diff --git a/sharedmodels/src/commonMain/kotlin/com/nwagu/chessboy/sharedmodels/presentation/MainViewModel.kt b/sharedmodels/src/commonMain/kotlin/com/nwagu/chessboy/sharedmodels/presentation/MainViewModel.kt index b139222..41e019c 100644 --- a/sharedmodels/src/commonMain/kotlin/com/nwagu/chessboy/sharedmodels/presentation/MainViewModel.kt +++ b/sharedmodels/src/commonMain/kotlin/com/nwagu/chessboy/sharedmodels/presentation/MainViewModel.kt @@ -5,7 +5,6 @@ import com.nwagu.chess.model.Game import com.nwagu.chess.model.Player import com.nwagu.chess.representation.* import com.nwagu.chessboy.sharedmodels.players.* -import kotlinx.coroutines.launch class MainViewModel: BaseViewModel() { @@ -47,29 +46,15 @@ class MainViewModel: BaseViewModel() { } fun saveGame(game: Game) { - clientScope.launch { - val history = getGamesHistory() - - while (history.size > 20) { - history.removeFirst() - } - - history.removeAll(history.filter { - getHeaderValueFromPgn(PGN_HEADER_GAME_ID, it) == game.id - }) - history.addLast(game.exportPGN()) - -// savePGNs(getApplication(), history.toList()) - } + gamesHistoryRepository.addGame(game.id, game.exportPGN()) } private fun getLastGamePgn(): String? { - return getGamesHistory().lastOrNull() + return gamesHistoryRepository.getLastGame()?.pgn } - fun getGamesHistory(): ArrayDeque { - return ArrayDeque() -// return ArrayDeque(getSavedPGNs(getApplication())) + fun getGamesHistory(): List { + return gamesHistoryRepository.getMostRecentGames(20).map { it.pgn } } } \ No newline at end of file diff --git a/sharedmodels/src/commonMain/kotlin/com/nwagu/chessboy/sharedmodels/presentation/PlayViewModel.kt b/sharedmodels/src/commonMain/kotlin/com/nwagu/chessboy/sharedmodels/presentation/PlayViewModel.kt index babeed6..1464ef6 100644 --- a/sharedmodels/src/commonMain/kotlin/com/nwagu/chessboy/sharedmodels/presentation/PlayViewModel.kt +++ b/sharedmodels/src/commonMain/kotlin/com/nwagu/chessboy/sharedmodels/presentation/PlayViewModel.kt @@ -109,7 +109,7 @@ class PlayViewModel: BaseViewModel() { } selectedSquare.value == null || possibleMoves.value.isEmpty() -> { - if (game.board.squareContainsOccupantColored(square, game.userColor)) { + if (game.board.squareContainsChessPieceColored(square, game.userColor)) { selectedSquare.value = square possibleMoves.value = game.board.getPossibleMovesFrom(square) } @@ -128,6 +128,15 @@ class PlayViewModel: BaseViewModel() { } + square == selectedSquare.value -> { + clearPossibleMoves() + } + + game.board.squareContainsChessPieceColored(square, game.userColor) -> { + selectedSquare.value = square + possibleMoves.value = game.board.getPossibleMovesFrom(square) + } + else -> { clearPossibleMoves() } diff --git a/sharedmodels/src/commonMain/sqldelight/com/nwagu/chessboy/GameHistory.sq b/sharedmodels/src/commonMain/sqldelight/com/nwagu/chessboy/GameHistory.sq index f4628a6..235e2a5 100644 --- a/sharedmodels/src/commonMain/sqldelight/com/nwagu/chessboy/GameHistory.sq +++ b/sharedmodels/src/commonMain/sqldelight/com/nwagu/chessboy/GameHistory.sq @@ -1,6 +1,18 @@ CREATE TABLE GameHistory ( + id integer NOT NULL PRIMARY KEY AUTOINCREMENT, + gameId TEXT NOT NULL UNIQUE, pgn TEXT NOT NULL ); -INSERT INTO GameHistory (pgn) -VALUES (""); \ No newline at end of file +insertGame: +INSERT OR REPLACE INTO GameHistory(id, gameId, pgn) +VALUES((SELECT id FROM GameHistory WHERE gameId = :gameId), :gameId, :pgn); + +selectLastGame: +SELECT * FROM GameHistory ORDER BY id DESC LIMIT 1; + +mostRecentGames: +SELECT * FROM GameHistory ORDER BY id DESC LIMIT :numberOfGames; + +removeAllGames: +DELETE FROM GameHistory; \ No newline at end of file diff --git a/sharedmodels/src/iosMain/kotlin/com/nwagu/chessboy/sharedmodels/presentation/BaseViewModel.kt b/sharedmodels/src/iosMain/kotlin/com/nwagu/chessboy/sharedmodels/presentation/BaseViewModel.kt index e0119ef..9b1317e 100644 --- a/sharedmodels/src/iosMain/kotlin/com/nwagu/chessboy/sharedmodels/presentation/BaseViewModel.kt +++ b/sharedmodels/src/iosMain/kotlin/com/nwagu/chessboy/sharedmodels/presentation/BaseViewModel.kt @@ -1,5 +1,7 @@ package com.nwagu.chessboy.sharedmodels.presentation +import com.nwagu.chessboy.sharedmodels.data.DatabaseDriverFactory +import com.nwagu.chessboy.sharedmodels.data.LocalGamesHistoryRepository import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.SupervisorJob import kotlinx.coroutines.cancelChildren @@ -9,6 +11,9 @@ actual open class BaseViewModel { val viewModelScope: CoroutineScope = CoroutineScope(ioDispatcher + viewModelJob) actual val clientScope: CoroutineScope = viewModelScope + actual val gamesHistoryRepository by lazy { + LocalGamesHistoryRepository(DatabaseDriverFactory()) + } protected actual open fun onCleared() { viewModelJob.cancelChildren()