Code Sketch
who
// === 100% WORKING REAL RULES & 3D PERSPECTIVE CHESS GAME ===
cleari()
originBottomLeft()
val initialBoard = Array(
Array("r", "n", "b", "q", "k", "b", "n", "r"),
Array("p", "p", "p", "p", "p", "p", "p", "p"),
Array(".", ".", ".", ".", ".", ".", ".", "."),
Array(".", ".", ".", ".", ".", ".", ".", "."),
Array(".", ".", ".", ".", ".", ".", ".", "."),
Array(".", ".", ".", ".", ".", ".", ".", "."),
Array("P", "P", "P", "P", "P", "P", "P", "P"),
Array("R", "N", "B", "Q", "K", "B", "N", "R")
)
var board = initialBoard
var selectedX = -1
var selectedY = -1
var turn = "WHITE"
var statusMessage = "White's Turn: Click a piece then destination square."
val tileSize = 65.0
val startX = (cwidth - (8 * tileSize)) / 2.0 - 50.0
val startY = 100.0
// Real Check Validation for all pieces including Pawn (Puda)
def isValidMove(piece: String, startX: Int, startY: Int, endX: Int, endY: Int): Boolean = {
val dx = (endX - startX).abs
val dy = (endY - startY).abs
val p = piece
p match {
case "P" => // White Pawn (Puda moves UP: +1 row)
if (startX == endX && board(endY)(endX) == ".") {
if (endY - startY == 1) return true
if (startY == 1 && endY - startY == 2 && board(2)(startX) == ".") return true
}
// Capture diagonally
if (dx == 1 && endY - startY == 1 && board(endY)(endX) != ".") return true
false
case "p" => // Black Pawn (Puda moves DOWN: -1 row)
if (startX == endX && board(endY)(endX) == ".") {
if (endY - startY == -1) return true
if (startY == 6 && endY - startY == -2 && board(5)(startX) == ".") return true
}
// Capture diagonally
if (dx == 1 && endY - startY == -1 && board(endY)(endX) != ".") return true
false
case "R" | "r" => // Rook (Hatti)
startX == endX || startY == endY
case "N" | "n" => // Knight (Ghoda)
(dx == 2 && dy == 1) || (dx == 1 && dy == 2)
case "B" | "b" => // Bishop (Unt)
dx == dy
case "Q" | "q" => // Queen (Rani)
(startX == endX || startY == endY) || (dx == dy)
case "K" | "k" => // King (Raja)
dx <= 1 && dy <= 1
case _ => false
}
}
onMouseClick { (x, y) =>
val bx = ((x - startX) / tileSize).toInt
val by = 7 - ((y - startY) / tileSize).toInt
if (bx >= 0 && bx < 8 && by >= 0 && by < 8) {
val clickedPiece = board(by)(bx)
if (selectedX == -1 && selectedY == -1) {
if (clickedPiece != ".") {
val isWhitePiece = clickedPiece.toUpperCase == clickedPiece
if ((turn == "WHITE" && isWhitePiece) || (turn == "BLACK" && !isWhitePiece)) {
selectedX = bx
selectedY = by
statusMessage = s"Selected $clickedPiece. Now click destination."
} else {
statusMessage = s"Not your piece! It's $turn's turn."
}
}
} else {
val movingPiece = board(selectedY)(selectedX)
val targetPiece = board(by)(bx)
val targetIsWhite = targetPiece != "." && targetPiece.toUpperCase == targetPiece
val movingIsWhite = movingPiece.toUpperCase == movingPiece
if (!(targetPiece != "." && targetIsWhite == movingIsWhite)) {
if (isValidMove(movingPiece, selectedX, selectedY, bx, by)) {
board(by)(bx) = movingPiece
board(selectedY)(selectedX) = "."
turn = if (turn == "WHITE") "BLACK" else "WHITE"
statusMessage = s"Move successful! Turn: $turn"
} else {
statusMessage = "Invalid move for this piece!"
}
} else {
statusMessage = "Cannot capture your own piece!"
}
selectedX = -1
selectedY = -1
}
}
}
def drawChessPiece(canvas: CanvasDraw, piece: String, x: Double, y: Double) {
val isWhite = piece.toUpperCase == piece
// 3D Shadow Base
canvas.fill(10, 10, 10, 100)
canvas.noStroke()
canvas.ellipse(x + tileSize / 2.0 + 4, y + 12, tileSize * 0.5, tileSize * 0.2)
if (isWhite) {
canvas.fill(245, 245, 245)
canvas.stroke(160, 160, 160)
} else {
canvas.fill(45, 45, 45)
canvas.stroke(90, 90, 90)
}
canvas.strokeWeight(2)
piece.toUpperCase match {
case "P" =>
canvas.ellipse(x + tileSize / 2.0, y + tileSize * 0.45, tileSize * 0.32, tileSize * 0.4)
canvas.ellipse(x + tileSize / 2.0, y + tileSize * 0.22, tileSize * 0.18, tileSize * 0.18)
case "R" =>
canvas.rect(x + tileSize * 0.3, y + tileSize * 0.25, tileSize * 0.4, tileSize * 0.5)
case "N" =>
canvas.rect(x + tileSize * 0.32, y + tileSize * 0.2, tileSize * 0.35, tileSize * 0.55)
canvas.ellipse(x + tileSize * 0.52, y + tileSize * 0.3, tileSize * 0.22, tileSize * 0.22)
case "B" =>
canvas.ellipse(x + tileSize / 2.0, y + tileSize * 0.45, tileSize * 0.35, tileSize * 0.48)
canvas.ellipse(x + tileSize / 2.0, y + tileSize * 0.18, tileSize * 0.16, tileSize * 0.16)
case "Q" =>
canvas.ellipse(x + tileSize / 2.0, y + tileSize * 0.45, tileSize * 0.4, tileSize * 0.52)
canvas.ellipse(x + tileSize / 2.0, y + tileSize * 0.15, tileSize * 0.22, tileSize * 0.22)
case "K" =>
canvas.ellipse(x + tileSize / 2.0, y + tileSize * 0.45, tileSize * 0.42, tileSize * 0.58)
canvas.rect(x + tileSize * 0.45, y + tileSize * 0.1, tileSize * 0.1, tileSize * 0.2)
case _ =>
}
canvas.fill(if (isWhite) 40 else 230, if (isWhite) 40 else 230, if (isWhite) 40 else 230)
canvas.text(piece, x + tileSize / 2.0 - 6, y + tileSize / 2.0 + 5)
}
def viewState(canvas: CanvasDraw) {
// 3D Background Gradient Style
canvas.fill(20, 24, 35)
canvas.noStroke()
canvas.rect(0, 0, cwidth, cheight)
// 3D Wooden Board Outer Base
canvas.fill(85, 50, 20)
canvas.rect(startX - 15, startY - 15, (8 * tileSize) + 30, (8 * tileSize) + 30)
var row = 0
while (row < 8) {
var col = 0
while (col < 8) {
val sqX = startX + (col * tileSize)
val sqY = startY + ((7 - row) * tileSize)
if ((row + col) % 2 == 0) {
canvas.fill(160, 115, 75)
} else {
canvas.fill(235, 205, 165)
}
if (col == selectedX && row == selectedY) {
canvas.fill(100, 200, 50)
}
canvas.noStroke()
canvas.rect(sqX, sqY, tileSize, tileSize)
val piece = board(row)(col)
if (piece != ".") {
drawChessPiece(canvas, piece, sqX, sqY)
}
col += 1
}
row += 1
}
// UI Panel
canvas.fill(255, 255, 255)
canvas.text(s"3D REAL-RULES CHESS | Turn: $turn", 40, cheight - 40)
canvas.text(statusMessage, 40, cheight - 15)
}
animateWithCanvasDraw { canvas =>
viewState(canvas)
}