diff --git a/chess-game/.gitignore b/chess-game/.gitignore new file mode 100644 index 000000000..58f7f18ac --- /dev/null +++ b/chess-game/.gitignore @@ -0,0 +1,11 @@ +*.iml +.gradle +/local.properties +/.idea +.DS_Store +/build +/captures +.externalNativeBuild +.cxx +local.properties +app/build/ diff --git a/chess-game/app/build.gradle b/chess-game/app/build.gradle new file mode 100644 index 000000000..663cf6abd --- /dev/null +++ b/chess-game/app/build.gradle @@ -0,0 +1,38 @@ +plugins { + id 'com.android.application' + id 'org.jetbrains.kotlin.android' +} + +android { + namespace 'com.devin.chess' + compileSdk 34 + + defaultConfig { + applicationId "com.devin.chess" + minSdk 26 + targetSdk 34 + versionCode 1 + versionName "1.0" + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + } + } + compileOptions { + sourceCompatibility JavaVersion.VERSION_17 + targetCompatibility JavaVersion.VERSION_17 + } + kotlinOptions { + jvmTarget = '17' + } +} + +dependencies { + implementation 'androidx.core:core-ktx:1.12.0' + implementation 'androidx.appcompat:appcompat:1.6.1' + implementation 'com.google.android.material:material:1.11.0' + implementation 'androidx.constraintlayout:constraintlayout:2.1.4' +} diff --git a/chess-game/app/proguard-rules.pro b/chess-game/app/proguard-rules.pro new file mode 100644 index 000000000..fb164d666 --- /dev/null +++ b/chess-game/app/proguard-rules.pro @@ -0,0 +1 @@ +# Add project specific ProGuard rules here. diff --git a/chess-game/app/src/main/AndroidManifest.xml b/chess-game/app/src/main/AndroidManifest.xml new file mode 100644 index 000000000..c0df9fb63 --- /dev/null +++ b/chess-game/app/src/main/AndroidManifest.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + + + diff --git a/chess-game/app/src/main/java/com/devin/chess/ChessBoardView.kt b/chess-game/app/src/main/java/com/devin/chess/ChessBoardView.kt new file mode 100644 index 000000000..5d657d6df --- /dev/null +++ b/chess-game/app/src/main/java/com/devin/chess/ChessBoardView.kt @@ -0,0 +1,236 @@ +package com.devin.chess + +import android.content.Context +import android.graphics.Canvas +import android.graphics.Color +import android.graphics.Paint +import android.graphics.Typeface +import android.util.AttributeSet +import android.view.MotionEvent +import android.view.View + +class ChessBoardView @JvmOverloads constructor( + context: Context, + attrs: AttributeSet? = null, + defStyleAttr: Int = 0 +) : View(context, attrs, defStyleAttr) { + + private val lightSquare = Paint().apply { color = Color.parseColor("#F0D9B5") } + private val darkSquare = Paint().apply { color = Color.parseColor("#B58863") } + private val selectedPaint = Paint().apply { color = Color.parseColor("#7BF06292") } + private val validMovePaint = Paint().apply { + color = Color.parseColor("#6044CC44") + style = Paint.Style.FILL + } + private val lastMovePaint = Paint().apply { color = Color.parseColor("#40FFFF00") } + private val checkPaint = Paint().apply { color = Color.parseColor("#80FF0000") } + private val piecePaint = Paint().apply { + textAlign = Paint.Align.CENTER + typeface = Typeface.DEFAULT_BOLD + isAntiAlias = true + } + private val coordinatePaint = Paint().apply { + color = Color.parseColor("#80000000") + textAlign = Paint.Align.CENTER + isAntiAlias = true + } + + private var squareSize = 0f + private var boardOffset = 0f + var model: ChessModel? = null + private var selectedPos: Position? = null + private var validMoves: List = emptyList() + + var onMoveListener: (() -> Unit)? = null + + private val pieceSymbols = mapOf( + PieceType.KING to ("♔" to "♚"), + PieceType.QUEEN to ("♕" to "♛"), + PieceType.ROOK to ("♖" to "♜"), + PieceType.BISHOP to ("♗" to "♝"), + PieceType.KNIGHT to ("♘" to "♞"), + PieceType.PAWN to ("♙" to "♟") + ) + + override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { + val size = minOf( + MeasureSpec.getSize(widthMeasureSpec), + MeasureSpec.getSize(heightMeasureSpec) + ) + setMeasuredDimension(size, size) + } + + override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) { + super.onSizeChanged(w, h, oldw, oldh) + val boardSize = minOf(w, h) + squareSize = boardSize / 8.4f + boardOffset = squareSize * 0.2f + piecePaint.textSize = squareSize * 0.78f + coordinatePaint.textSize = squareSize * 0.18f + } + + override fun onDraw(canvas: Canvas) { + super.onDraw(canvas) + val game = model ?: return + + drawBoard(canvas, game) + drawPieces(canvas, game) + drawCoordinates(canvas) + } + + private fun drawBoard(canvas: Canvas, game: ChessModel) { + val lastMove = game.lastMove + val kingPos = if (game.isCurrentPlayerInCheck()) { + findKingPosition(game, game.currentTurn) + } else null + + for (row in 0..7) { + for (col in 0..7) { + val x = boardOffset + col * squareSize + val y = boardOffset + row * squareSize + val isLight = (row + col) % 2 == 0 + canvas.drawRect(x, y, x + squareSize, y + squareSize, if (isLight) lightSquare else darkSquare) + + // Highlight last move + if (lastMove != null && + ((row == lastMove.from.row && col == lastMove.from.col) || + (row == lastMove.to.row && col == lastMove.to.col))) { + canvas.drawRect(x, y, x + squareSize, y + squareSize, lastMovePaint) + } + + // Highlight check + if (kingPos != null && row == kingPos.row && col == kingPos.col) { + canvas.drawRect(x, y, x + squareSize, y + squareSize, checkPaint) + } + + // Highlight selected + val sel = selectedPos + if (sel != null && row == sel.row && col == sel.col) { + canvas.drawRect(x, y, x + squareSize, y + squareSize, selectedPaint) + } + + // Valid move indicators + val pos = Position(row, col) + if (pos in validMoves) { + val piece = game.getPiece(row, col) + if (piece != null) { + // Capture indicator — ring around the square + val ringPaint = Paint().apply { + color = Color.parseColor("#6044CC44") + style = Paint.Style.STROKE + strokeWidth = squareSize * 0.08f + } + canvas.drawRect( + x + squareSize * 0.04f, y + squareSize * 0.04f, + x + squareSize * 0.96f, y + squareSize * 0.96f, ringPaint + ) + } else { + // Move indicator — small circle + canvas.drawCircle( + x + squareSize / 2, y + squareSize / 2, + squareSize * 0.15f, validMovePaint + ) + } + } + } + } + } + + private fun drawPieces(canvas: Canvas, game: ChessModel) { + for (row in 0..7) { + for (col in 0..7) { + val piece = game.getPiece(row, col) ?: continue + val x = boardOffset + col * squareSize + squareSize / 2 + val y = boardOffset + row * squareSize + squareSize * 0.72f + val symbol = pieceSymbols[piece.type] ?: continue + val text = if (piece.color == PieceColor.WHITE) symbol.first else symbol.second + + // Draw outline for visibility + piecePaint.color = if (piece.color == PieceColor.WHITE) Color.BLACK else Color.parseColor("#333333") + piecePaint.style = Paint.Style.STROKE + piecePaint.strokeWidth = squareSize * 0.03f + canvas.drawText(text, x, y, piecePaint) + + // Draw fill + piecePaint.color = if (piece.color == PieceColor.WHITE) Color.WHITE else Color.BLACK + piecePaint.style = Paint.Style.FILL + canvas.drawText(text, x, y, piecePaint) + } + } + } + + private fun drawCoordinates(canvas: Canvas) { + val files = "abcdefgh" + val ranks = "87654321" + for (i in 0..7) { + // File labels (bottom) + canvas.drawText( + files[i].toString(), + boardOffset + i * squareSize + squareSize / 2, + boardOffset + 8 * squareSize + squareSize * 0.18f, + coordinatePaint + ) + // Rank labels (left) + coordinatePaint.textAlign = Paint.Align.RIGHT + canvas.drawText( + ranks[i].toString(), + boardOffset - squareSize * 0.05f, + boardOffset + i * squareSize + squareSize * 0.6f, + coordinatePaint + ) + coordinatePaint.textAlign = Paint.Align.CENTER + } + } + + private fun findKingPosition(game: ChessModel, color: PieceColor): Position? { + for (r in 0..7) { + for (c in 0..7) { + val piece = game.getPiece(r, c) + if (piece != null && piece.type == PieceType.KING && piece.color == color) { + return Position(r, c) + } + } + } + return null + } + + override fun onTouchEvent(event: MotionEvent): Boolean { + if (event.action != MotionEvent.ACTION_DOWN) return true + val game = model ?: return true + if (game.gameOver) return true + + val col = kotlin.math.floor((event.x - boardOffset) / squareSize).toInt() + val row = kotlin.math.floor((event.y - boardOffset) / squareSize).toInt() + if (row !in 0..7 || col !in 0..7) return true + + val tappedPos = Position(row, col) + val sel = selectedPos + + if (sel != null && tappedPos in validMoves) { + game.makeMove(sel, tappedPos) + selectedPos = null + validMoves = emptyList() + invalidate() + onMoveListener?.invoke() + return true + } + + val piece = game.getPiece(row, col) + if (piece != null && piece.color == game.currentTurn) { + selectedPos = tappedPos + validMoves = game.getValidMoves(tappedPos) + } else { + selectedPos = null + validMoves = emptyList() + } + + invalidate() + return true + } + + fun clearSelection() { + selectedPos = null + validMoves = emptyList() + invalidate() + } +} diff --git a/chess-game/app/src/main/java/com/devin/chess/ChessModel.kt b/chess-game/app/src/main/java/com/devin/chess/ChessModel.kt new file mode 100644 index 000000000..26a6d9280 --- /dev/null +++ b/chess-game/app/src/main/java/com/devin/chess/ChessModel.kt @@ -0,0 +1,393 @@ +package com.devin.chess + +enum class PieceType { + KING, QUEEN, ROOK, BISHOP, KNIGHT, PAWN +} + +enum class PieceColor { + WHITE, BLACK; + + fun opposite(): PieceColor = if (this == WHITE) BLACK else WHITE +} + +data class ChessPiece( + val type: PieceType, + val color: PieceColor +) + +data class Position(val row: Int, val col: Int) { + fun isValid(): Boolean = row in 0..7 && col in 0..7 +} + +data class Move(val from: Position, val to: Position) + +class ChessModel { + + private val board = Array>(8) { arrayOfNulls(8) } + var currentTurn: PieceColor = PieceColor.WHITE + private set + var gameOver: Boolean = false + private set + var winner: PieceColor? = null + private set + var lastMove: Move? = null + private set + private var whiteKingMoved = false + private var blackKingMoved = false + private var whiteRookAMoved = false + private var whiteRookHMoved = false + private var blackRookAMoved = false + private var blackRookHMoved = false + + init { + setupBoard() + } + + private fun setupBoard() { + val backRow = arrayOf( + PieceType.ROOK, PieceType.KNIGHT, PieceType.BISHOP, PieceType.QUEEN, + PieceType.KING, PieceType.BISHOP, PieceType.KNIGHT, PieceType.ROOK + ) + for (col in 0..7) { + board[0][col] = ChessPiece(backRow[col], PieceColor.BLACK) + board[1][col] = ChessPiece(PieceType.PAWN, PieceColor.BLACK) + board[6][col] = ChessPiece(PieceType.PAWN, PieceColor.WHITE) + board[7][col] = ChessPiece(backRow[col], PieceColor.WHITE) + } + } + + fun getPiece(row: Int, col: Int): ChessPiece? { + if (row !in 0..7 || col !in 0..7) return null + return board[row][col] + } + + fun makeMove(from: Position, to: Position): Boolean { + if (gameOver) return false + val piece = board[from.row][from.col] ?: return false + if (piece.color != currentTurn) return false + if (!isValidMove(from, to)) return false + + // Handle castling + if (piece.type == PieceType.KING && kotlin.math.abs(to.col - from.col) == 2) { + performCastling(from, to) + } else { + // Handle en passant capture + if (piece.type == PieceType.PAWN && to.col != from.col && board[to.row][to.col] == null) { + board[from.row][to.col] = null + } + + board[to.row][to.col] = piece + board[from.row][from.col] = null + } + + // Pawn promotion — auto-promote to queen + if (piece.type == PieceType.PAWN && (to.row == 0 || to.row == 7)) { + board[to.row][to.col] = ChessPiece(PieceType.QUEEN, piece.color) + } + + updateCastlingFlags(piece, from) + + lastMove = Move(from, to) + currentTurn = currentTurn.opposite() + + checkGameState() + return true + } + + private fun performCastling(kingFrom: Position, kingTo: Position) { + val piece = board[kingFrom.row][kingFrom.col]!! + board[kingTo.row][kingTo.col] = piece + board[kingFrom.row][kingFrom.col] = null + + if (kingTo.col == 6) { + // Kingside + board[kingFrom.row][5] = board[kingFrom.row][7] + board[kingFrom.row][7] = null + } else if (kingTo.col == 2) { + // Queenside + board[kingFrom.row][3] = board[kingFrom.row][0] + board[kingFrom.row][0] = null + } + } + + private fun updateCastlingFlags(piece: ChessPiece, from: Position) { + if (piece.type == PieceType.KING) { + if (piece.color == PieceColor.WHITE) whiteKingMoved = true + else blackKingMoved = true + } + if (piece.type == PieceType.ROOK) { + when { + piece.color == PieceColor.WHITE && from.row == 7 && from.col == 0 -> whiteRookAMoved = true + piece.color == PieceColor.WHITE && from.row == 7 && from.col == 7 -> whiteRookHMoved = true + piece.color == PieceColor.BLACK && from.row == 0 && from.col == 0 -> blackRookAMoved = true + piece.color == PieceColor.BLACK && from.row == 0 && from.col == 7 -> blackRookHMoved = true + } + } + } + + fun getValidMoves(pos: Position): List { + val piece = board[pos.row][pos.col] ?: return emptyList() + if (piece.color != currentTurn) return emptyList() + return getAllPossibleMoves(pos).filter { to -> + !wouldBeInCheck(pos, to, piece.color) + } + } + + private fun isValidMove(from: Position, to: Position): Boolean { + return to in getValidMoves(from) + } + + private fun getAllPossibleMoves(pos: Position): List { + val piece = board[pos.row][pos.col] ?: return emptyList() + return when (piece.type) { + PieceType.PAWN -> getPawnMoves(pos, piece.color) + PieceType.KNIGHT -> getKnightMoves(pos, piece.color) + PieceType.BISHOP -> getBishopMoves(pos, piece.color) + PieceType.ROOK -> getRookMoves(pos, piece.color) + PieceType.QUEEN -> getBishopMoves(pos, piece.color) + getRookMoves(pos, piece.color) + PieceType.KING -> getKingMoves(pos, piece.color) + } + } + + private fun getPawnMoves(pos: Position, color: PieceColor): List { + val moves = mutableListOf() + val direction = if (color == PieceColor.WHITE) -1 else 1 + val startRow = if (color == PieceColor.WHITE) 6 else 1 + + // Forward one + val oneForward = Position(pos.row + direction, pos.col) + if (oneForward.isValid() && board[oneForward.row][oneForward.col] == null) { + moves.add(oneForward) + // Forward two from start + if (pos.row == startRow) { + val twoForward = Position(pos.row + 2 * direction, pos.col) + if (board[twoForward.row][twoForward.col] == null) { + moves.add(twoForward) + } + } + } + + // Diagonal captures + for (dc in listOf(-1, 1)) { + val capture = Position(pos.row + direction, pos.col + dc) + if (capture.isValid()) { + val target = board[capture.row][capture.col] + if (target != null && target.color != color) { + moves.add(capture) + } + // En passant + if (target == null && isEnPassant(pos, capture, color)) { + moves.add(capture) + } + } + } + return moves + } + + private fun isEnPassant(from: Position, to: Position, color: PieceColor): Boolean { + val last = lastMove ?: return false + val lastPiece = board[last.to.row][last.to.col] ?: return false + if (lastPiece.type != PieceType.PAWN) return false + if (kotlin.math.abs(last.from.row - last.to.row) != 2) return false + if (last.to.row != from.row) return false + if (last.to.col != to.col) return false + return true + } + + private fun getKnightMoves(pos: Position, color: PieceColor): List { + val offsets = listOf( + -2 to -1, -2 to 1, -1 to -2, -1 to 2, + 1 to -2, 1 to 2, 2 to -1, 2 to 1 + ) + return offsets.map { (dr, dc) -> Position(pos.row + dr, pos.col + dc) } + .filter { it.isValid() && (board[it.row][it.col] == null || board[it.row][it.col]!!.color != color) } + } + + private fun getSlidingMoves(pos: Position, color: PieceColor, directions: List>): List { + val moves = mutableListOf() + for ((dr, dc) in directions) { + var r = pos.row + dr + var c = pos.col + dc + while (r in 0..7 && c in 0..7) { + val target = board[r][c] + if (target == null) { + moves.add(Position(r, c)) + } else { + if (target.color != color) moves.add(Position(r, c)) + break + } + r += dr + c += dc + } + } + return moves + } + + private fun getBishopMoves(pos: Position, color: PieceColor): List { + return getSlidingMoves(pos, color, listOf(-1 to -1, -1 to 1, 1 to -1, 1 to 1)) + } + + private fun getRookMoves(pos: Position, color: PieceColor): List { + return getSlidingMoves(pos, color, listOf(-1 to 0, 1 to 0, 0 to -1, 0 to 1)) + } + + private fun getKingMoves(pos: Position, color: PieceColor): List { + val moves = mutableListOf() + for (dr in -1..1) { + for (dc in -1..1) { + if (dr == 0 && dc == 0) continue + val to = Position(pos.row + dr, pos.col + dc) + if (to.isValid() && (board[to.row][to.col] == null || board[to.row][to.col]!!.color != color)) { + moves.add(to) + } + } + } + // Castling + moves.addAll(getCastlingMoves(pos, color)) + return moves + } + + private fun getCastlingMoves(kingPos: Position, color: PieceColor): List { + val moves = mutableListOf() + if (isInCheck(color)) return moves + + val row = kingPos.row + val kingMoved = if (color == PieceColor.WHITE) whiteKingMoved else blackKingMoved + + if (kingMoved) return moves + + // Kingside + val rookHMoved = if (color == PieceColor.WHITE) whiteRookHMoved else blackRookHMoved + if (!rookHMoved && board[row][5] == null && board[row][6] == null) { + val rook = board[row][7] + if (rook != null && rook.type == PieceType.ROOK && rook.color == color) { + if (!isSquareAttacked(Position(row, 5), color.opposite()) && + !isSquareAttacked(Position(row, 6), color.opposite())) { + moves.add(Position(row, 6)) + } + } + } + + // Queenside + val rookAMoved = if (color == PieceColor.WHITE) whiteRookAMoved else blackRookAMoved + if (!rookAMoved && board[row][1] == null && board[row][2] == null && board[row][3] == null) { + val rook = board[row][0] + if (rook != null && rook.type == PieceType.ROOK && rook.color == color) { + if (!isSquareAttacked(Position(row, 2), color.opposite()) && + !isSquareAttacked(Position(row, 3), color.opposite())) { + moves.add(Position(row, 2)) + } + } + } + + return moves + } + + private fun isSquareAttacked(pos: Position, byColor: PieceColor): Boolean { + for (r in 0..7) { + for (c in 0..7) { + val piece = board[r][c] ?: continue + if (piece.color != byColor) continue + val attackerPos = Position(r, c) + val rawMoves = when (piece.type) { + PieceType.PAWN -> { + val dir = if (byColor == PieceColor.WHITE) -1 else 1 + listOf(Position(r + dir, c - 1), Position(r + dir, c + 1)) + .filter { it.isValid() } + } + PieceType.KNIGHT -> getKnightMoves(attackerPos, byColor) + PieceType.BISHOP -> getBishopMoves(attackerPos, byColor) + PieceType.ROOK -> getRookMoves(attackerPos, byColor) + PieceType.QUEEN -> getBishopMoves(attackerPos, byColor) + getRookMoves(attackerPos, byColor) + PieceType.KING -> { + val kingMoves = mutableListOf() + for (dr in -1..1) { + for (dc in -1..1) { + if (dr == 0 && dc == 0) continue + val to = Position(r + dr, c + dc) + if (to.isValid()) kingMoves.add(to) + } + } + kingMoves + } + } + if (pos in rawMoves) return true + } + } + return false + } + + private fun isInCheck(color: PieceColor): Boolean { + val kingPos = findKing(color) ?: return false + return isSquareAttacked(kingPos, color.opposite()) + } + + private fun findKing(color: PieceColor): Position? { + for (r in 0..7) { + for (c in 0..7) { + val piece = board[r][c] + if (piece != null && piece.type == PieceType.KING && piece.color == color) { + return Position(r, c) + } + } + } + return null + } + + private fun wouldBeInCheck(from: Position, to: Position, color: PieceColor): Boolean { + val captured = board[to.row][to.col] + val moving = board[from.row][from.col] + + // Handle en passant capture in simulation + var enPassantCaptured: ChessPiece? = null + var enPassantPos: Position? = null + if (moving?.type == PieceType.PAWN && to.col != from.col && captured == null) { + enPassantPos = Position(from.row, to.col) + enPassantCaptured = board[from.row][to.col] + board[from.row][to.col] = null + } + + board[to.row][to.col] = moving + board[from.row][from.col] = null + + val inCheck = isInCheck(color) + + board[from.row][from.col] = moving + board[to.row][to.col] = captured + if (enPassantPos != null) { + board[enPassantPos.row][enPassantPos.col] = enPassantCaptured + } + + return inCheck + } + + private fun checkGameState() { + val hasValidMove = (0..7).any { r -> + (0..7).any { c -> + val piece = board[r][c] + piece != null && piece.color == currentTurn && getValidMoves(Position(r, c)).isNotEmpty() + } + } + if (!hasValidMove) { + gameOver = true + winner = if (isInCheck(currentTurn)) currentTurn.opposite() else null + } + } + + fun isCurrentPlayerInCheck(): Boolean = isInCheck(currentTurn) + + fun reset() { + for (r in 0..7) for (c in 0..7) board[r][c] = null + currentTurn = PieceColor.WHITE + gameOver = false + winner = null + lastMove = null + whiteKingMoved = false + blackKingMoved = false + whiteRookAMoved = false + whiteRookHMoved = false + blackRookAMoved = false + blackRookHMoved = false + setupBoard() + } +} diff --git a/chess-game/app/src/main/java/com/devin/chess/MainActivity.kt b/chess-game/app/src/main/java/com/devin/chess/MainActivity.kt new file mode 100644 index 000000000..a3584315f --- /dev/null +++ b/chess-game/app/src/main/java/com/devin/chess/MainActivity.kt @@ -0,0 +1,65 @@ +package com.devin.chess + +import android.os.Bundle +import android.widget.Button +import android.widget.TextView +import androidx.appcompat.app.AlertDialog +import androidx.appcompat.app.AppCompatActivity + +class MainActivity : AppCompatActivity() { + + private lateinit var chessBoard: ChessBoardView + private lateinit var statusText: TextView + private lateinit var turnIndicator: TextView + private lateinit var newGameButton: Button + + private val chessModel = ChessModel() + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_main) + + chessBoard = findViewById(R.id.chessBoard) + statusText = findViewById(R.id.statusText) + turnIndicator = findViewById(R.id.turnIndicator) + newGameButton = findViewById(R.id.newGameButton) + + chessBoard.model = chessModel + chessBoard.onMoveListener = { updateStatus() } + + newGameButton.setOnClickListener { + chessModel.reset() + chessBoard.clearSelection() + updateStatus() + } + + updateStatus() + } + + private fun updateStatus() { + if (chessModel.gameOver) { + val message = when (chessModel.winner) { + PieceColor.WHITE -> "White wins by checkmate!" + PieceColor.BLACK -> "Black wins by checkmate!" + null -> "Stalemate — it's a draw!" + } + statusText.text = message + turnIndicator.text = "Game Over" + + AlertDialog.Builder(this) + .setTitle("Game Over") + .setMessage(message) + .setPositiveButton("New Game") { _, _ -> + chessModel.reset() + chessBoard.clearSelection() + updateStatus() + } + .setNegativeButton("OK", null) + .show() + } else { + val turnStr = if (chessModel.currentTurn == PieceColor.WHITE) "White" else "Black" + turnIndicator.text = "$turnStr's Turn" + statusText.text = if (chessModel.isCurrentPlayerInCheck()) "Check!" else "" + } + } +} diff --git a/chess-game/app/src/main/res/drawable/ic_launcher_foreground.xml b/chess-game/app/src/main/res/drawable/ic_launcher_foreground.xml new file mode 100644 index 000000000..675119048 --- /dev/null +++ b/chess-game/app/src/main/res/drawable/ic_launcher_foreground.xml @@ -0,0 +1,14 @@ + + + + + + diff --git a/chess-game/app/src/main/res/layout/activity_main.xml b/chess-game/app/src/main/res/layout/activity_main.xml new file mode 100644 index 000000000..12b759cff --- /dev/null +++ b/chess-game/app/src/main/res/layout/activity_main.xml @@ -0,0 +1,58 @@ + + + + + + + + + + + +