💡 Tip: Highlight any text on this page to listen to it.
<!DOCTYPE html>
<html>
<head>
<title>Project 3: Notation Input Trainer</title>
<link rel="stylesheet"
href="https://unpkg.com/@chrisoakman/chessboardjs@1.0.0/dist/chessboard-1.0.0.min.css">
<style>
body {
font-family: sans-serif;
display: flex;
flex-direction: column;
align-items: center;
background-color: #f4f4f4;
padding: 20px;
}
h1 { margin-bottom: 10px; }
/* Responsive Board Container */
#myBoard {
width: 90%;
max-width: 500px;
margin: 20px auto;
}
/* Input Controls */
.input-container {
display: flex;
gap: 10px;
margin-bottom: 20px;
width: 90%;
max-width: 500px;
}
#moveInput {
flex-grow: 1;
padding: 12px;
font-size: 18px;
border: 2px solid #ccc;
border-radius: 4px;
}
#submitBtn {
padding: 10px 20px;
font-size: 16px;
background-color: #4CAF50;
color: white;
border: none;
cursor: pointer;
border-radius: 4px;
}
/* Status & History */
#status { font-weight: bold; margin-bottom: 10px; color: #333; }
#pgn-output {
background: #fff;
padding: 15px;
border: 1px solid #ddd;
width: 90%;
max-width: 500px;
min-height: 50px;
font-family: monospace;
font-size: 14px;
}
</style>
</head>
<body>
<h1>♟️ Type & Play</h1>
<div id="status">White to move</div>
<div id="myBoard"></div>
<div class="input-container">
<input type="text" id="moveInput" placeholder="Type move (e.g. e4, Nf3)..." autofocus>
<button id="submitBtn">Move</button>
</div>
<div id="pgn-output"></div>
<br>
<button id="resetBtn" style="padding: 8px 16px; cursor: pointer;">Reset Game</button>
<script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/chess.js/0.10.3/chess.min.js"></script>
<script src="https://unpkg.com/@chrisoakman/chessboardjs@1.0.0/dist/chessboard-1.0.0.min.js"></script>
<script>
// --- 1. SETUP ---
var board = null;
var game = new Chess();
// Configuration: Local images + Responsive + No Dragging
var config = {
position: 'start',
draggable: false, // Strictly no dragging!
pieceTheme: 'img/chesspieces/wikipedia/{piece}.png'
};
// Initialize Board
board = Chessboard('myBoard', config);
window.addEventListener('resize', board.resize); // Responsive fix
// DOM Elements
const moveInput = document.getElementById('moveInput');
const statusDisplay = document.getElementById('status');
const pgnDisplay = document.getElementById('pgn-output');
// --- 2. CORE LOGIC ---
function handleMove() {
const moveText = moveInput.value.trim();
if (!moveText) return;
// Try to make the move in the game logic
// chess.js requires SAN (Standard Algebraic Notation) by default
const move = game.move(moveText);
if (move === null) {
// INVALID MOVE
speak("Invalid move");
// Shake the input box to show error visually (optional CSS trick)
moveInput.style.borderColor = "red";
setTimeout(() => moveInput.style.borderColor = "#ccc", 500);
return;
}
// VALID MOVE
board.position(game.fen()); // Update board
speak(move.san); // Voice notation
updateStatus(); // Update turn info
// Clear input for next turn
moveInput.value = '';
moveInput.focus();
}
function updateStatus() {
let status = '';
let moveColor = (game.turn() === 'b') ? 'Black' : 'White';
// Check for Checkmate / Draw
if (game.in_checkmate()) {
status = 'Game over, ' + moveColor + ' is in checkmate.';
speak("Checkmate!");
} else if (game.in_draw()) {
status = 'Game over, drawn position';
speak("Draw!");
} else {
status = moveColor + ' to move';
if (game.in_check()) {
status += ', ' + moveColor + ' is in check';
speak("Check!");
}
}
statusDisplay.innerText = status;
pgnDisplay.innerHTML = game.pgn(); // Show full history
}
function speak(text) {
if ('speechSynthesis' in window) {
const ut = new SpeechSynthesisUtterance(text);
window.speechSynthesis.speak(ut);
}
}
// --- 3. EVENT LISTENERS ---
// Submit button click
document.getElementById('submitBtn').addEventListener('click', handleMove);
// "Enter" key in input box
moveInput.addEventListener('keydown', (e) => {
if (e.key === 'Enter') {
handleMove();
}
});
// Reset Game
document.getElementById('resetBtn').addEventListener('click', () => {
game.reset();
board.start();
moveInput.value = '';
updateStatus();
speak("Game reset");
moveInput.focus();
});
// Initial Status
updateStatus();
</script>
</body>
</html>