diff --git a/build.gradle.kts b/build.gradle.kts index e69e6f8..6c63aef 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -9,7 +9,7 @@ korge { targetJvm() targetJs() targetAndroid() - + icon = File(rootDir,"icon.png") serializationJson() jvmMainClassName = "MainKt" } @@ -17,24 +17,15 @@ kotlin { sourceSets { val commonMain by getting { dependencies { - implementation("io.ktor:ktor-client-core:2.1.0") - implementation("io.ktor:ktor-client-json:2.1.0") - implementation("io.ktor:ktor-client-serialization:2.1.0") implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.2") - implementation("com.squareup.okhttp3:okhttp:4.9.2") } } val jvmMain by getting { dependencies { - implementation("io.ktor:ktor-client-cio:2.1.0") - implementation("com.squareup.okhttp3:okhttp:4.9.2") } } val jsMain by getting { dependencies { - implementation("io.ktor:ktor-http-cio:1.6.0") - implementation("io.ktor:ktor-client-js:1.6.0") - implementation("com.squareup.okhttp3:okhttp:4.9.2") } } @@ -42,8 +33,9 @@ kotlin { } dependencies { add("commonMainApi", project(":deps")) - add("commonMainApi", "com.squareup.okhttp3:okhttp:4.9.2") + } repositories { mavenCentral() + maven("https://jitpack.io") } diff --git a/icon.png b/icon.png new file mode 100644 index 0000000..c1b6e9b Binary files /dev/null and b/icon.png differ diff --git a/src/commonMain/kotlin/Ai.kt b/src/commonMain/kotlin/Ai.kt deleted file mode 100644 index b4e662b..0000000 --- a/src/commonMain/kotlin/Ai.kt +++ /dev/null @@ -1,99 +0,0 @@ -import io.ktor.client.* -import io.ktor.client.request.* -import io.ktor.client.statement.* -import io.ktor.client.engine.* -class Ai { - init { - println("Ai created") - } - var fn = "rnbqkbnr/pppppp1p/8/6p1/5P2/8/PPPPP1PP/RNBQKBNR w KQkq - 0 1" - fun piecesListToFEN(piecesList: List>>): String { - val board = Array(8) { Array(8) { '.' } } - - // Place pieces on the board - for (piece in piecesList) { - val pieceType = piece.first - val (x, y) = piece.second - board[y][x] = when (pieceType) { - "WhitePawn" -> 'P' - "WhiteRook" -> 'R' - "WhiteKnight" -> 'N' - "WhiteBishop" -> 'B' - "WhiteQueen" -> 'Q' - "WhiteKing" -> 'K' - "BlackPawn" -> 'p' - "BlackRook" -> 'r' - "BlackKnight" -> 'n' - "BlackBishop" -> 'b' - "BlackQueen" -> 'q' - "BlackKing" -> 'k' - else -> '.' - } - } - - // Convert board to FEN - val fen = StringBuilder() - for (row in board) { - var emptyCount = 0 - for (cell in row) { - if (cell == '.') { - emptyCount++ - } else { - if (emptyCount > 0) { - fen.append(emptyCount) - emptyCount = 0 - } - fen.append(cell) - } - } - if (emptyCount > 0) { - fen.append(emptyCount) - } - fen.append('/') - } - fen.setLength(fen.length - 1) // Remove the last '/' - - // Add default FEN fields (assuming it's the white's turn and default castling rights and en passant) - //fen.append(" w KQkq - 0 1") - if (whiteTurn){ - fen.append(" w KQkq - 0 1") - } - else{ - fen.append(" b KQkq - 0 1") - } - fn = fen.toString() - return fen.toString() - } - - suspend fun exampleRequest() { - println("Example request") - - // Define FEN and other options - val fen = "8/1P1R4/n1r2B2/3Pp3/1k4P1/6K1/Bppr1P2/2q5 w - - 0 1" - val variants = 1 // max: 5, default: 1 - val depth = 12 // max: 18, default: 12 - val maxThinkingTime = 50 // max: 100, default: 50 (ms) - val searchmoves = "" // evaluate specific moves only, e.g., 'd2d4 e2e4' - - // Initialize HttpClient - val client = HttpClient() - - // Make the POST request - val response = client.post("https://chess-api.com/v1") { - setBody( - """ - { - "fen": "$fen", - "variants": $variants, - "depth": $depth, - "maxThinkingTime": $maxThinkingTime, - "searchmoves": "$searchmoves" - } - """.trimIndent() - ) - } - - // Print the response - println(response.bodyAsText()) - } -} diff --git a/src/commonMain/kotlin/ChessAi.kt b/src/commonMain/kotlin/ChessAi.kt new file mode 100644 index 0000000..45acaa0 --- /dev/null +++ b/src/commonMain/kotlin/ChessAi.kt @@ -0,0 +1,148 @@ +import korlibs.io.lang.* +import korlibs.io.net.http.* +import korlibs.io.stream.* +import kotlinx.serialization.json.* + +class ChessAi { + fun piecesListToFEN(piecesList: List>>): String { + val board = Array(8) { Array(8) { '.' } } + + // Place pieces on the board + for (piece in piecesList) { + val pieceType = piece.first + val (x, y) = piece.second + board[y][x] = + when (pieceType) { + "WhitePawn" -> 'P' + "WhiteRook" -> 'R' + "WhiteKnight" -> 'N' + "WhiteBishop" -> 'B' + "WhiteQueen" -> 'Q' + "WhiteKing" -> 'K' + "BlackPawn" -> 'p' + "BlackRook" -> 'r' + "BlackKnight" -> 'n' + "BlackBishop" -> 'b' + "BlackQueen" -> 'q' + "BlackKing" -> 'k' + else -> '.' + } + } + + // Convert board to FEN + val fen = StringBuilder() + for (row in board) { + var emptyCount = 0 + for (cell in row) { + if (cell == '.') { + emptyCount++ + } else { + if (emptyCount > 0) { + fen.append(emptyCount) + emptyCount = 0 + } + fen.append(cell) + } + } + if (emptyCount > 0) { + fen.append(emptyCount) + } + fen.append('/') + } + fen.setLength(fen.length - 1) // Remove the last '/' + + // Add default FEN fields (assuming it's the white's turn and default castling rights and en + // passant) + // fen.append(" w KQkq - 0 1") + if (whiteTurn) { + fen.append(" w KQkq - 0 1") + } else { + fen.append(" b KQkq - 0 1") + } + return fen.toString() + } + + suspend fun postBestMove(fen: String): String { + val client = HttpClient() + val url = "http://192.168.178.54:5000/best_move" + // Create JSON object + val json = JsonObject(mapOf("fen" to JsonPrimitive(fen))) + val jsonString = Json.encodeToString(JsonObject.serializer(), json) + + return try { + val response = client.requestAsBytes( + url = url, + method = Http.Methods.POST, + content = jsonString.openAsync(), + headers = Http.Headers( + "Content-Type" to "application/json", + "Content-Length" to jsonString.length.toString() + ) + ) + val responseString = response.content.decodeToString() + val jsonResponse = Json.parseToJsonElement(responseString).jsonObject + jsonResponse["best_move"]?.jsonPrimitive?.content ?: "No best_move found" + + } catch (e: IOException) { + "Request failed: ${e.message}" + } + } + + fun convertMoveToPosition(move: String) { + var old_x: Int = 9 + var old_y: Int = 9 + var new_x: Int = 9 + var new_y: Int = 9 + when (move[0]) { + 'a' -> old_x = 0 + 'b' -> old_x = 1 + 'c' -> old_x = 2 + 'd' -> old_x = 3 + 'e' -> old_x = 4 + 'f' -> old_x = 5 + 'g' -> old_x = 6 + 'h' -> old_x = 7 + } + when (move[1]) { + '1' -> old_y = 7 + '2' -> old_y = 6 + '3' -> old_y = 5 + '4' -> old_y = 4 + '5' -> old_y = 3 + '6' -> old_y = 2 + '7' -> old_y = 1 + '8' -> old_y = 0 + } + when (move[2]) { + 'a' -> new_x = 0 + 'b' -> new_x = 1 + 'c' -> new_x = 2 + 'd' -> new_x = 3 + 'e' -> new_x = 4 + 'f' -> new_x = 5 + 'g' -> new_x = 6 + 'h' -> new_x = 7 + } + when (move[3]) { + '1' -> new_y = 7 + '2' -> new_y = 6 + '3' -> new_y = 5 + '4' -> new_y = 4 + '5' -> new_y = 3 + '6' -> new_y = 2 + '7' -> new_y = 1 + '8' -> new_y = 0 + } + println("Old position: $old_x, $old_y") + println("New position: $new_x, $new_y") + for (piece in pieces){ + if (piece.cx == old_x && piece.cy == old_y && old_x != 9 && old_y != 9 && new_x != 9 && new_y != 9){ + figurBewegen(piece, new_x, new_y) + whiteTurn = !whiteTurn + } + } + + } +} + + diff --git a/src/commonMain/kotlin/Main.kt b/src/commonMain/kotlin/Main.kt index f216823..bf57e5e 100644 --- a/src/commonMain/kotlin/Main.kt +++ b/src/commonMain/kotlin/Main.kt @@ -1,9 +1,9 @@ @file:OptIn(KorgeExperimental::class) -import korlibs.event.* import korlibs.image.bitmap.* import korlibs.image.color.* import korlibs.image.format.* +import korlibs.io.async.* import korlibs.io.file.std.* import korlibs.korge.* import korlibs.korge.annotations.* @@ -43,6 +43,7 @@ suspend fun main() = sceneContainer.changeTo { MyScene(sceneContainer) } } + class MyScene(private val cont: SceneContainer) : PixelatedScene(512, 512) { /** @@ -70,8 +71,7 @@ class MyScene(private val cont: SceneContainer) : PixelatedScene(512, 512) { // add pieces to board state handlePieceMovement() - var ai = Ai() - ai.exampleRequest() + var chessAi = ChessAi() } private fun SContainer.handlePieceMovement() { @@ -89,81 +89,84 @@ class MyScene(private val cont: SceneContainer) : PixelatedScene(512, 512) { newPosition = Pair(this.globalMousePos.x.toInt() / 64, this.globalMousePos.y.toInt() / 64) }) { info -> - error = false - - // When dragging starts - if (info.start) { - // Iterate through pieces to find the selected piece - // //println("Start dragging...") - // Set king position - val pieceAtCurrentPos = - schachbrett!!.findPiece(newPosition!!.first, newPosition!!.second) - - if (schachbrett!!.findPiece(newPosition!!.first, newPosition!!.second) != - null) { - currentPos = newPosition - selectedPiece = pieceAtCurrentPos - } + error = false + + // When dragging starts + if (info.start) { + // Iterate through pieces to find the selected piece + // //println("Start dsragging...") + // Set king position + val pieceAtCurrentPos = + schachbrett!!.findPiece(newPosition!!.first, newPosition!!.second) + + if (schachbrett!!.findPiece(newPosition!!.first, newPosition!!.second) != + null + ) { + currentPos = newPosition + selectedPiece = pieceAtCurrentPos } + } - // When dragging ends - if (info.end && selectedPiece != null) { - // //println("End dragging...") - // Check if newPosition is within the game board - if (newPosition!!.first < 0 || - newPosition!!.first >= 8 || - newPosition!!.second < 0 || - newPosition!!.second >= 8) { - error = true - // Reset variables + // When dragging ends + if (info.end && selectedPiece != null) { + // //println("End dragging...") + // Check if newPosition is within the game board + if (newPosition!!.first < 0 || + newPosition!!.first >= 8 || + newPosition!!.second < 0 || + newPosition!!.second >= 8 + ) { + error = true + // Reset variables + selectedPiece = null + newPosition = null + currentPos = null + } + // Perform the move if no error + if (!error) { + if (selectedPiece!!.moveChecker(currentPos!!, newPosition!!, true)) { + figurBewegen( + selectedPiece!!, newPosition!!.first, newPosition!!.second + ) selectedPiece = null - newPosition = null - currentPos = null } - // Perform the move if no error - if (!error) { - if (selectedPiece!!.moveChecker(currentPos!!, newPosition!!, true)) { - figurBewegen( - selectedPiece!!, newPosition!!.first, newPosition!!.second) - selectedPiece = null - } - - // Check if king is in Check - inCheck() - - // Reset variables - selectedPiece = null - newPosition = null - currentPos = null + + // Check if king is in Check + inCheck() + + // Reset variables + selectedPiece = null + newPosition = null + currentPos = null + } + + error = false + var moved = false + println("b") + if (!moved) { + // pieces list with the name of all the pieces and their + // position + var piecesList = mutableListOf>>() + for (piece in pieces) { + piecesList.add( + Pair(piece.kind.toString(), Pair(piece.cx, piece.cy)) + ) } - error = false - var moved = false - println("b") - sceneContainer.keys { - justDown(Key.SPACE) { - if (!moved) { - // pieces list with the name of all the pieces and their - // position - var piecesList = mutableListOf>>() - for (piece in pieces) { - piecesList.add( - Pair(piece.kind.toString(), Pair(piece.cx, piece.cy))) - } - println(piecesList) - - var ai = Ai() - - var fen = ai.piecesListToFEN(piecesList) - println(fen) - moved = true - } - } + var chessAi = ChessAi() + var fen = chessAi.piecesListToFEN(piecesList) + launch { + val response = chessAi.postBestMove(fen) + println(chessAi.convertMoveToPosition(response)) } - // make a list where all pieces are stored with their positions + moved = true + } + // make a list where all pieces are stored with their positions + } + } } } } diff --git a/src/commonMain/kotlin/Piece.kt b/src/commonMain/kotlin/Piece.kt index 70ab90e..f108933 100644 --- a/src/commonMain/kotlin/Piece.kt +++ b/src/commonMain/kotlin/Piece.kt @@ -581,13 +581,9 @@ class Piece( } } - - - return false } - fun removePiece(piece: Piece) { println("Pieces list before removal: $pieces") pieces.remove(piece)