Chess-Web / templates /index.html
dpv007's picture
Upload folder using huggingface_hub
cf6364c verified
Raw
History Blame Contribute Delete
13.4 kB
<!DOCTYPE html>
<html>
<head>
<title>Neural Chess Engine</title>
<link rel="stylesheet" href="https://unpkg.com/@chrisoakman/chessboardjs@1.0.0/dist/chessboard-1.0.0.min.css" />
<script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
<script src="https://unpkg.com/@chrisoakman/chessboardjs@1.0.0/dist/chessboard-1.0.0.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/chess.js/0.10.3/chess.min.js"></script>
<link href="https://fonts.googleapis.com/css2?family=Outfit:wght@400;700&display=swap" rel="stylesheet">
<style>
body {
font-family: 'Outfit', sans-serif;
background: linear-gradient(135deg, #0f2027, #203a43, #2c5364);
color: white;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 100vh;
margin: 0;
}
.game-container {
display: flex;
align-items: center;
gap: 15px;
margin-bottom: 20px;
}
#board {
width: 500px;
box-shadow: 0 15px 35px rgba(0,0,0,0.5);
border-radius: 4px;
overflow: hidden;
border: 4px solid #fff;
}
.eval-bar-container {
width: 30px;
height: 500px;
background-color: #333;
border-radius: 4px;
border: 4px solid #fff;
position: relative;
overflow: hidden;
display: flex;
flex-direction: column-reverse;
box-shadow: 0 15px 35px rgba(0,0,0,0.5);
}
.eval-bar-fill {
width: 100%;
height: 50%; /* starts at 0.0 */
background-color: #fff;
transition: height 0.8s cubic-bezier(0.4, 0, 0.2, 1);
}
.eval-marker {
position: absolute;
top: 50%;
left: 0;
width: 100%;
height: 2px;
background-color: #ff5e7e;
z-index: 10;
}
h1 {
font-weight: 700;
font-size: 2.5rem;
margin-bottom: 10px;
text-shadow: 2px 2px 10px rgba(0,0,0,0.5);
}
.status-panel {
padding: 15px 30px;
background: rgba(255, 255, 255, 0.1);
backdrop-filter: blur(10px);
border-radius: 12px;
font-size: 1.3rem;
min-width: 350px;
text-align: center;
box-shadow: 0 8px 32px 0 rgba(31, 38, 135, 0.37);
border: 1px solid rgba(255, 255, 255, 0.18);
}
.controls-panel {
display: flex;
gap: 15px;
margin-top: 20px;
}
.styled-select {
padding: 10px 15px;
font-size: 1.1rem;
font-family: 'Outfit', sans-serif;
color: #fff;
background: rgba(255, 255, 255, 0.1);
border: 1px solid rgba(255, 255, 255, 0.18);
border-radius: 8px;
cursor: pointer;
backdrop-filter: blur(10px);
}
.styled-select option {
background: #203a43;
color: #fff;
}
.btn-reset {
padding: 10px 25px;
font-size: 1.1rem;
font-family: 'Outfit', sans-serif;
color: white;
background: #e94560;
border: none;
border-radius: 8px;
cursor: pointer;
transition: all 0.2s ease;
}
.btn-reset:hover {
background: #ff5e7e;
transform: translateY(-2px);
box-shadow: 0 5px 15px rgba(233, 69, 96, 0.4);
}
.loading-bar-container {
width: 100%;
height: 6px;
background-color: rgba(255, 255, 255, 0.1);
border-radius: 3px;
overflow: hidden;
margin-top: 15px;
display: none;
}
.loading-bar {
width: 0%;
height: 100%;
background: #00ff88;
box-shadow: 0 0 10px #00ff88;
transition: width 0.1s linear;
}
</style>
</head>
<body>
<h1>โ™Ÿ๏ธ Neural Chess Engine</h1>
<div class="game-container">
<div class="eval-bar-container" title="Neural Network Evaluation">
<div class="eval-bar-fill" id="evalBar"></div>
<div class="eval-marker"></div>
</div>
<div id="board"></div>
</div>
<div class="status-panel">
<div id="status">Your turn (White)</div>
<div class="loading-bar-container" id="loadingBar">
<div class="loading-bar"></div>
</div>
</div>
<div class="controls-panel" style="flex-wrap: wrap; justify-content: center;">
<select id="whitePlayerSelect" class="styled-select" onchange="resetGame()">
<option value="human">White: Human</option>
<option value="neural">White: Neural Network</option>
<option value="veloct">White: VeloCT Ultimate</option>
</select>
<select id="blackPlayerSelect" class="styled-select" onchange="resetGame()">
<option value="neural" selected>Black: Neural Network</option>
<option value="human">Black: Human</option>
<option value="veloct">Black: VeloCT Ultimate</option>
</select>
<button class="btn-reset" onclick="resetGame()">Restart Game</button>
</div>
<script>
var board = null;
var game = new Chess();
var $status = $('#status');
var history_moves = ["<bos>"];
var progressInterval;
var whitePlayer = "human";
var blackPlayer = "neural";
function isHumanTurn() {
var turn = game.turn(); // 'w' or 'b'
if (turn === 'w' && whitePlayer === 'human') return true;
if (turn === 'b' && blackPlayer === 'human') return true;
return false;
}
function getEngineChoice() {
return game.turn() === 'w' ? whitePlayer : blackPlayer;
}
function getPlayerName(engineCode) {
if (engineCode === 'neural') return "Neural Network";
if (engineCode === 'veloct') return "VeloCT Ultimate";
return "Human";
}
function onDragStart (source, piece, position, orientation) {
if (game.game_over()) return false;
// Only allow dragging if it is a human's turn
if (!isHumanTurn()) return false;
// Only allow the human's color to be dragged
if (game.turn() === 'w' && piece.search(/^b/) !== -1) return false;
if (game.turn() === 'b' && piece.search(/^w/) !== -1) return false;
}
function getAiMove() {
if (game.game_over()) return;
var engineChoice = getEngineChoice();
var engineName = getPlayerName(engineChoice);
$status.text(engineName + " is calculating best move...");
$('#loadingBar').show();
$('.loading-bar').css('width', '0%');
var progress = 0;
if(progressInterval) clearInterval(progressInterval);
progressInterval = setInterval(function() {
progress += (95 - progress) * 0.05;
$('.loading-bar').css('width', progress + '%');
}, 100);
// Make API Call
$.ajax({
url: '/move',
type: 'POST',
contentType: 'application/json',
data: JSON.stringify({ history: history_moves, fen: game.fen(), engine_choice: engineChoice }),
success: function(response) {
clearInterval(progressInterval);
$('.loading-bar').css('width', '100%');
setTimeout(function() {
$('#loadingBar').hide();
if (response.ai_move) {
game.move(response.ai_move, {sloppy: true});
history_moves.push(response.ai_move);
board.position(game.fen());
if(game.game_over()) {
if (game.in_checkmate()) {
var winner = game.turn() === 'w' ? 'Black' : 'White';
$status.html("<span style='color: #ff5e7e'><b>Game Over! " + winner + " won by Checkmate! ๐Ÿ’€</b></span>");
} else {
$status.html("<b>Game Over! Draw.</b>");
}
// Save the game PGN
$.ajax({
url: '/save_pgn',
type: 'POST',
contentType: 'application/json',
data: JSON.stringify({ pgn: game.pgn() })
});
} else {
$status.html(engineName + " played <b>" + response.ai_move + "</b>. " + (isHumanTurn() ? "Your turn!" : "Next AI's turn..."));
// Auto-play loop for AI vs AI
if (!isHumanTurn()) {
setTimeout(getAiMove, 500);
}
}
} else if (response.error) {
$status.text(response.error);
}
if (response.eval !== undefined) {
var heightPercent = ((response.eval + 1.0) / 2.0) * 100;
heightPercent = Math.max(0, Math.min(100, heightPercent));
$('#evalBar').css('height', heightPercent + '%');
}
}, 300);
},
error: function() {
clearInterval(progressInterval);
$('#loadingBar').hide();
$status.text("Error communicating with AI server.");
}
});
}
function onDrop (source, target) {
// see if the move is legal
var move = game.move({
from: source,
to: target,
promotion: 'q' // NOTE: always promote to a queen for simplicity
});
// illegal move
if (move === null) return 'snapback';
var uci_move = source + target;
if (move.flags.includes('p') || move.flags.includes('cp')) uci_move += 'q';
history_moves.push(uci_move);
if (game.game_over()) {
if (game.in_checkmate()) {
var winner = game.turn() === 'w' ? 'Black' : 'White';
$status.html("<span style='color: #00ff88'><b>Game Over! " + winner + " won by Checkmate! ๐ŸŽ‰</b></span>");
} else {
$status.html("<b>Game Over! Draw.</b>");
}
// Save the game PGN
$.ajax({
url: '/save_pgn',
type: 'POST',
contentType: 'application/json',
data: JSON.stringify({ pgn: game.pgn() })
});
return;
}
if (!isHumanTurn()) {
getAiMove();
}
}
function onSnapEnd () {
board.position(game.fen());
}
function resetGame() {
whitePlayer = $('#whitePlayerSelect').val();
blackPlayer = $('#blackPlayerSelect').val();
game.reset();
// Flip board so human is at the bottom if possible
if (whitePlayer === 'human') board.orientation('white');
else if (blackPlayer === 'human') board.orientation('black');
else board.orientation('white'); // AI vs AI default orientation
board.start();
history_moves = ["<bos>"];
$('#loadingBar').hide();
$('#evalBar').css('height', '50%');
if (isHumanTurn()) {
$status.text("Your turn!");
} else {
$status.text("Starting Match...");
getAiMove();
}
}
var config = {
draggable: true,
position: 'start',
orientation: 'white',
onDragStart: onDragStart,
onDrop: onDrop,
onSnapEnd: onSnapEnd,
pieceTheme: 'https://chessboardjs.com/img/chesspieces/wikipedia/{piece}.png'
};
board = Chessboard('board', config);
// Initialize the game completely
$(document).ready(function() {
resetGame();
});
</script>
</body>
</html>