Game Catur Emoji dengan AI
by NovaViper78489 lines16.7 KB
<!DOCTYPE html>
<html lang="id">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Game Catur Emoji dengan AI</title>
<style>
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
background: linear-gradient(135deg, #1e1e2f, #2d2b42);
color: #ffffff;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
min-height: 100vh;
margin: 0;
}
h1 {
margin-bottom: 5px;
font-size: 1.8rem;
color: #f1f1f1;
}
.controls {
margin-bottom: 15px;
display: flex;
gap: 10px;
align-items: center;
flex-wrap: wrap;
justify-content: center;
}
select, button {
padding: 8px 14px;
font-size: 0.95rem;
border-radius: 6px;
border: none;
background-color: #4e4376;
color: white;
cursor: pointer;
transition: background 0.2s;
}
select:hover, button:hover {
background-color: #5b4f88;
}
#status {
margin-bottom: 15px;
font-size: 1.1rem;
font-weight: bold;
color: #ffcc00;
min-height: 25px;
text-align: center;
}
#board {
display: grid;
grid-template-columns: repeat(8, 55px);
grid-template-rows: repeat(8, 55px);
border: 4px solid #443c68;
box-shadow: 0 8px 20px rgba(0,0,0,0.5);
border-radius: 4px;
}
.square {
display: flex;
align-items: center;
justify-content: center;
font-size: 32px;
cursor: pointer;
user-select: none;
transition: background-color 0.15s;
}
.light {
background-color: #f0d9b5;
}
.dark {
background-color: #b58863;
}
.selected {
background-color: #baca44 !important;
}
.highlight {
background-color: #79a632 !important;
}
@media (max-width: 500px) {
#board {
grid-template-columns: repeat(8, 42px);
grid-template-rows: repeat(8, 42px);
}
.square {
font-size: 24px;
}
}
</style>
</head>
<body>
<h1>♟️ Game Catur Emoji AI</h1>
<div class="controls">
<label for="difficulty">Level AI:</label>
<select id="difficulty">
<option value="easy">Mudah (Pemula)</option>
<option value="hard" selected>Sulit (Ahli)</option>
</select>
<button onclick="resetGame()">Mulai Baru</button>
</div>
<div id="status">Giliran Anda (Putih ⚪)</div>
<div id="board"></div>
<script>
// Inisialisasi Audio Web API untuk efek suara
const audioCtx = new (window.AudioContext || window.webkitAudioContext)();
function playSound(type) {
if (audioCtx.state === 'suspended') audioCtx.resume();
const osc = audioCtx.createOscillator();
const gain = audioCtx.createGain();
osc.connect(gain);
gain.connect(audioCtx.destination);
let now = audioCtx.currentTime;
if (type === 'move') {
osc.frequency.setValueAtTime(400, now);
gain.gain.setValueAtTime(0.1, now);
gain.gain.exponentialRampToValueAtTime(0.01, now + 0.1);
osc.start(now);
osc.stop(now + 0.1);
} else if (type === 'capture') {
osc.frequency.setValueAtTime(200, now);
osc.frequency.exponentialRampToValueAtTime(600, now + 0.15);
gain.gain.setValueAtTime(0.15, now);
gain.gain.exponentialRampToValueAtTime(0.01, now + 0.15);
osc.start(now);
osc.stop(now + 0.15);
} else if (type === 'end') {
osc.frequency.setValueAtTime(523.25, now);
osc.frequency.setValueAtTime(659.25, now + 0.1);
osc.frequency.setValueAtTime(783.99, now + 0.2);
gain.gain.setValueAtTime(0.1, now);
gain.gain.exponentialRampToValueAtTime(0.01, now + 0.4);
osc.start(now);
osc.stop(now + 0.4);
}
}
// Simbol Buah Catur (Putih vs Hitam)
const pieces = {
'R': '♖', 'N': '♘', 'B': '♗', 'Q': '♕', 'K': '♔', 'P': '♙',
'r': '♜', 'n': '♞', 'b': '♝', 'q': '♛', 'k': '♚', 'p': '♟'
};
let board = [
['r', 'n', 'b', 'q', 'k', 'b', 'n', 'r'],
['p', 'p', 'p', 'p', 'p', 'p', 'p', 'p'],
['', '', '', '', '', '', '', ''],
['', '', '', '', '', '', '', ''],
['', '', '', '', '', '', '', ''],
['', '', '', '', '', '', '', ''],
['P', 'P', 'P', 'P', 'P', 'P', 'P', 'P'],
['R', 'N', 'B', 'Q', 'K', 'B', 'N', 'R']
];
let turn = 'w'; // 'w' untuk putih (pemain), 'b' untuk hitam (AI)
let selectedSquare = null;
let validMoves = [];
let gameOver = false;
function isWhite(piece) {
return piece && piece === piece.toUpperCase();
}
function isBlack(piece) {
return piece && piece === piece.toLowerCase();
}
function createBoardUI() {
const boardEl = document.getElementById('board');
boardEl.innerHTML = '';
for (let r = 0; r < 8; r++) {
for (let c = 0; c < 8; c++) {
const square = document.createElement('div');
square.className = `square ${(r + c) % 2 === 0 ? 'light' : 'dark'}`;
square.dataset.row = r;
square.dataset.col = c;
const piece = board[r][c];
if (piece) {
square.textContent = pieces[piece];
}
if (selectedSquare && selectedSquare.r === r && selectedSquare.c === c) {
square.classList.add('selected');
}
if (validMoves.some(m => m.r === r && m.c === c)) {
square.classList.add('highlight');
}
square.addEventListener('click', () => handleSquareClick(r, c));
boardEl.appendChild(square);
}
}
}
function handleSquareClick(r, c) {
if (gameOver || turn !== 'w') return;
const piece = board[r][c];
if (selectedSquare) {
// Jika mengklik langkah yang valid, jalankan gerakan
const move = validMoves.find(m => m.r === r && m.c === c);
if (move) {
executeMove(selectedSquare.r, selectedSquare.c, r, c);
selectedSquare = null;
validMoves = [];
createBoardUI();
if (!gameOver) {
turn = 'b';
document.getElementById('status').textContent = "AI sedang berpikir... 🤖";
setTimeout(aiTurn, 400);
}
return;
}
}
// Pilih buah catur milik pemain (Putih)
if (piece && isWhite(piece)) {
selectedSquare = { r, c };
validMoves = getValidMoves(r, c, board);
createBoardUI();
} else {
selectedSquare = null;
validMoves = [];
createBoardUI();
}
}
function executeMove(sr, sc, dr, dc) {
const target = board[dr][dc];
board[dr][dc] = board[sr][sc];
board[sr][sc] = '';
// Promosi pion sederhana menjadi ratu
if (board[dr][dc] === 'P' && dr === 0) board[dr][dc] = 'Q';
if (board[dr][dc] === 'p' && dr === 7) board[dr][dc] = 'q';
if (target) {
playSound('capture');
} else {
playSound('move');
}
checkGameEnd();
}
// Logika Aturan Pergerakan Dasar Catur
function getValidMoves(r, c, currentBoard) {
const piece = currentBoard[r][c];
const moves = [];
if (!piece) return moves;
const isW = isWhite(piece);
const type = piece.toLowerCase();
function addSlideMoves(directions) {
for (let d of directions) {
let nr = r + d[0];
let nc = c + d[1];
while (nr >= 0 && nr < 8 && nc >= 0 && nc < 8) {
const target = currentBoard[nr][nc];
if (!target) {
moves.push({ r: nr, c: nc });
} else {
if (isW !== isWhite(target)) moves.push({ r: nr, c: nc });
break;
}
nr += d[0];
nc += d[1];
}
}
}
if (type === 'p') {
const dir = isW ? -1 : 1;
const startRow = isW ? 6 : 1;
// Maju 1 langkah
if (r + dir >= 0 && r + dir < 8 && !currentBoard[r + dir][c]) {
moves.push({ r: r + dir, c: c });
// Maju 2 langkah dari posisi awal
if (r === startRow && !currentBoard[r + 2 * dir][c]) {
moves.push({ r: r + 2 * dir, c: c });
}
}
// Makan diagonal
for (let dc of [-1, 1]) {
let nc = c + dc;
let nr = r + dir;
if (nc >= 0 && nc < 8 && nr >= 0 && nr < 8) {
const target = currentBoard[nr][nc];
if (target && isW !== isWhite(target)) {
moves.push({ r: nr, c: nc });
}
}
}
} else if (type === 'n') {
const knightMoves = [
[-2, -1], [-2, 1], [-1, -2], [-1, 2],
[1, -2], [1, 2], [2, -1], [2, 1]
];
for (let m of knightMoves) {
let nr = r + m[0], nc = c + m[1];
if (nr >= 0 && nr < 8 && nc >= 0 && nc < 8) {
const target = currentBoard[nr][nc];
if (!target || isW !== isWhite(target)) {
moves.push({ r: nr, c: nc });
}
}
}
} else if (type === 'b') {
addSlideMoves([[-1, -1], [-1, 1], [1, -1], [1, 1]]);
} else if (type === 'r') {
addSlideMoves([[-1, 0], [1, 0], [0, -1], [0, 1]]);
} else if (type === 'q') {
addSlideMoves([[-1, -1], [-1, 1], [1, -1], [1, 1], [-1, 0], [1, 0], [0, -1], [0, 1]]);
} else if (type === 'k') {
const kingMoves = [
[-1, -1], [-1, 0], [-1, 1],
[0, -1], [0, 1],
[1, -1], [1, 0], [1, 1]
];
for (let m of kingMoves) {
let nr = r + m[0], nc = c + m[1];
if (nr >= 0 && nr < 8 && nc >= 0 && nc < 8) {
const target = currentBoard[nr][nc];
if (!target || isW !== isWhite(target)) {
moves.push({ r: nr, c: nc });
}
}
}
}
return moves;
}
function getAllPossibleMoves(playerColor, currentBoard) {
let allMoves = [];
for (let r = 0; r < 8; r++) {
for (let c = 0; c < 8; c++) {
const piece = currentBoard[r][c];
if (piece && (playerColor === 'w' ? isWhite(piece) : isBlack(piece))) {
const moves = getValidMoves(r, c, currentBoard);
for (let m of moves) {
allMoves.push({ sr: r, sc: c, dr: m.r, dc: m.c });
}
}
}
}
return allMoves;
}
// AI Logic: Mudah & Sulit
const pieceValues = { p: 10, n: 30, b: 30, r: 50, q: 90, k: 900 };
function evaluateBoard(currentBoard) {
let score = 0;
for (let r = 0; r < 8; r++) {
for (let c = 0; c < 8; c++) {
const p = currentBoard[r][c];
if (p) {
let val = pieceValues[p.toLowerCase()] || 0;
if (isBlack(p)) score += val;
else score -= val;
}
}
}
return score;
}
function aiTurn() {
if (gameOver) return;
const difficulty = document.getElementById('difficulty').value;
const allMoves = getAllPossibleMoves('b', board);
if (allMoves.length === 0) {
checkGameEnd();
return;
}
let chosenMove = null;
if (difficulty === 'easy') {
// Pilih langkah acak
chosenMove = allMoves[Math.floor(Math.random() * allMoves.length)];
} else {
// Sulit: Evaluasi langkah terbaik (Greedy + menangkap prioritas tinggi)
let bestScore = -99999;
let scoredMoves = [];
for (let m of allMoves) {
// Simulasi langkah
let tempTarget = board[m.dr][m.dc];
board[m.dr][m.dc] = board[m.sr][m.sc];
board[m.sr][m.sc] = '';
let score = evaluateBoard(board);
// Kembalikan papan
board[m.sr][m.sc] = board[m.dr][m.dc];
board[m.dr][m.dc] = tempTarget;
if (score > bestScore) {
bestScore = score;
scoredMoves = [m];
} else if (score === bestScore) {
scoredMoves.push(m);
}
}
// Ambil salah satu dari langkah dengan skor terbaik
chosenMove = scoredMoves[Math.floor(Math.random() * scoredMoves.length)];
}
if (chosenMove) {
executeMove(chosenMove.sr, chosenMove.sc, chosenMove.dr, chosenMove.dc);
}
if (!gameOver) {
turn = 'w';
document.getElementById('status').textContent = "Giliran Anda (Putih ⚪)";
}
createBoardUI();
}
function checkGameEnd() {
let whiteKing = false;
let blackKing = false;
for (let r = 0; r < 8; r++) {
for (let c = 0; c < 8; c++) {
if (board[r][c] === 'K') whiteKing = true;
if (board[r][c] === 'k') blackKing = true;
}
}
if (!whiteKing) {
gameOver = true;
document.getElementById('status').textContent = "Game Selesai! AI Hitam Menang 🤖";
playSound('end');
} else if (!blackKing) {
gameOver = true;
document.getElementById('status').textContent = "Selamat! Anda Menang 🎉";
playSound('end');
}
}
function resetGame() {
board = [
['r', 'n', 'b', 'q', 'k', 'b', 'n', 'r'],
['p', 'p', 'p', 'p', 'p', 'p', 'p', 'p'],
['', '', '', '', '', '', '', ''],
['', '', '', '', '', '', '', ''],
['', '', '', '', '', '', '', ''],
['', '', '', '', '', '', '', ''],
['P', 'P', 'P', 'P', 'P', 'P', 'P', 'P'],
['R', 'N', 'B', 'Q', 'K', 'B', 'N', 'R']
];
turn = 'w';
selectedSquare = null;
validMoves = [];
gameOver = false;
document.getElementById('status').textContent = "Giliran Anda (Putih ⚪)";
createBoardUI();
}
// Render awal saat halaman dimuat
createBoardUI();
</script>
</body>
</html>Game Source: Game Catur Emoji dengan AI
Creator: NovaViper78
Libraries: none
Complexity: complex (489 lines, 16.7 KB)
The full source code is displayed above on this page.
Remix Instructions
To remix this game, copy the source code above and modify it. Add a ARCADELAB header at the top with "remix_of: game-catur-emoji-dengan-ai-novaviper78" to link back to the original. Then publish at arcadelab.ai/publish.