api-ix commited on
Commit
2ea4a8e
·
verified ·
1 Parent(s): 8d33b1b

Update index.html

Browse files
Files changed (1) hide show
  1. index.html +195 -168
index.html CHANGED
@@ -13,6 +13,7 @@
13
  --text-color: #e0e0e0;
14
  --accent-color: #4caf50;
15
  --panel-bg: #333;
 
16
  }
17
 
18
  body {
@@ -24,73 +25,117 @@
24
  align-items: center;
25
  margin: 0;
26
  padding: 10px;
 
27
  }
28
 
29
- h1 { margin-bottom: 20px; text-align: center; }
30
 
31
  .container {
32
  display: flex;
33
  flex-direction: column;
34
- gap: 20px;
35
  justify-content: center;
36
  align-items: center;
37
  max-width: 900px;
38
  width: 100%;
39
  }
40
 
41
- /* DEBUG / ERROR LOG */
42
- #debug-log {
43
- width: 100%;
44
- max-width: 400px;
45
- color: #ff5252;
46
- font-family: monospace;
47
- font-size: 12px;
48
- background: #2a0000;
49
- padding: 5px;
50
- border-radius: 4px;
51
- display: none; /* Hidden unless error */
52
- margin-bottom: 10px;
53
- white-space: pre-wrap;
54
- }
55
-
56
  #board {
57
  width: 100%;
58
- max-width: 400px;
59
  aspect-ratio: 1 / 1;
60
  margin: 0 auto;
61
  background-color: #303030;
62
- border: 2px solid #555;
63
  display: flex;
64
  align-items: center;
65
  justify-content: center;
66
  color: #777;
67
  }
68
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
69
  .panel {
70
  width: 100%;
71
- max-width: 400px;
72
  background: var(--panel-bg);
73
- padding: 20px;
74
  border-radius: 8px;
75
  box-sizing: border-box;
76
  display: flex;
77
  flex-direction: column;
78
- gap: 15px;
79
  }
80
 
81
- .stats-box {
82
- background: #444;
83
- padding: 10px;
84
- border-radius: 5px;
85
- border-left: 4px solid var(--accent-color);
 
 
 
 
 
 
 
 
 
 
86
  }
87
 
88
- .stats-label { font-size: 0.85em; color: #aaa; display: block; margin-bottom: 5px; }
89
- .stats-value { font-size: 1.1em; font-weight: bold; }
90
- #best-line { font-family: monospace; color: #81c784; word-break: break-all; }
91
-
92
- .controls { display: flex; gap: 10px; margin-top: auto; }
 
 
 
 
 
 
 
 
 
93
 
 
94
  button {
95
  flex: 1;
96
  padding: 12px;
@@ -102,60 +147,52 @@
102
  background-color: #555;
103
  font-size: 16px;
104
  }
105
- button:hover { opacity: 0.9; }
106
- #flipBtn { background-color: var(--accent-color); }
107
-
108
- .status-indicator {
109
- display: inline-block;
110
- width: 10px;
111
- height: 10px;
112
- border-radius: 50%;
113
- background-color: #ccc;
114
- margin-right: 5px;
115
- }
116
- .status-indicator.ready { background-color: var(--accent-color); }
117
- .status-indicator.thinking { background-color: #ffeb3b; animation: pulse 1s infinite; }
118
- @keyframes pulse { 0% { opacity: 1; } 50% { opacity: 0.5; } 100% { opacity: 1; } }
119
  </style>
120
  </head>
121
  <body>
122
 
123
- <h1>♟️ Arcane Chess Analyzer</h1>
124
 
125
  <div id="debug-log"></div>
126
 
127
  <div class="container">
128
- <div id="board">
129
- <div style="text-align:center;">
130
- Loading Libraries...<br>
131
- <small>If this stays here, turn off Brave Shields</small>
 
132
  </div>
133
- </div>
134
-
135
- <div class="panel">
136
- <div style="display: flex; align-items: center; justify-content: space-between;">
137
- <h3>Engine Analysis</h3>
138
- <div><span id="engineStatus" class="status-indicator"></span><span id="engineText">Initializing...</span></div>
139
- </div>
140
-
141
- <div class="stats-box">
142
- <span class="stats-label">Evaluation</span>
143
- <span class="stats-value" id="evaluation">0.00</span>
144
  </div>
 
145
 
146
- <div class="stats-box">
147
- <span class="stats-label">Best Move Sequence</span>
148
- <span class="stats-value" id="best-line">Waiting for engine...</span>
149
- </div>
150
 
151
- <div class="stats-box">
152
- <span class="stats-label">Game Status</span>
153
- <span class="stats-value" id="gameStatus">White to move</span>
 
 
 
 
 
 
 
154
  </div>
155
 
156
  <div class="controls">
157
- <button id="resetBtn">Reset</button>
158
- <button id="flipBtn">Flip Board</button>
159
  </div>
160
  </div>
161
  </div>
@@ -165,41 +202,23 @@
165
  <script src="https://cdnjs.cloudflare.com/ajax/libs/chessboard-js/1.0.0/chessboard-1.0.0.min.js"></script>
166
 
167
  <script>
168
- // GLOBAL ERROR HANDLER
169
- window.onerror = function(msg, url, line) {
170
- const log = document.getElementById('debug-log');
171
- log.style.display = 'block';
172
- log.innerHTML += `ERROR: ${msg}<br>Line: ${line}<br>Check your internet or Brave Shields.<br><br>`;
173
- return false;
174
  };
175
 
176
- // --- CONFIGURATION ---
177
  const STOCKFISH_PATH = 'https://cdnjs.cloudflare.com/ajax/libs/stockfish.js/10.0.0/stockfish.js';
178
-
179
- let board = null;
180
- let game = null; // initialized in initGame
181
- let engine = null;
182
 
183
- // UI Selectors
184
- let $status, $evaluation, $bestLine, $engineStatus, $engineText;
 
 
185
 
186
  function initGame() {
187
- // CHECK DEPENDENCIES
188
- if (typeof $ === 'undefined') { throw new Error("jQuery failed to load."); }
189
- if (typeof Chess === 'undefined') { throw new Error("Chess.js failed to load."); }
190
- if (typeof Chessboard === 'undefined') { throw new Error("Chessboard.js failed to load."); }
191
-
192
- console.log("Libraries loaded. Starting Game...");
193
-
194
- // Init Variables
195
  game = new Chess();
196
- $status = $('#gameStatus');
197
- $evaluation = $('#evaluation');
198
- $bestLine = $('#best-line');
199
- $engineStatus = $('#engineStatus');
200
- $engineText = $('#engineText');
201
-
202
- // 1. CONFIGURE BOARD
203
  const config = {
204
  draggable: true,
205
  position: 'start',
@@ -209,78 +228,115 @@
209
  pieceTheme: 'https://chessboardjs.com/img/chesspieces/wikipedia/{piece}.png'
210
  };
211
 
212
- // 2. CREATE BOARD
213
- $('#board').empty(); // Clear loading text
214
  board = Chessboard('board', config);
 
215
 
216
- // Resize fix
217
- setTimeout(() => {
218
- if(board) board.resize();
219
- }, 200);
220
-
221
- // 3. START ENGINE
222
  initStockfish();
223
- updateStatus();
 
 
 
 
 
 
 
 
 
 
224
 
225
- $(window).resize(board.resize);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
226
  }
227
 
228
- // --- ENGINE LOGIC ---
 
 
 
 
 
 
 
 
 
 
229
  function initStockfish() {
230
  try {
231
  const blob = new Blob([`importScripts('${STOCKFISH_PATH}')`], {type: 'application/javascript'});
232
  const url = URL.createObjectURL(blob);
233
-
234
  engine = new Worker(url);
235
 
236
  engine.onmessage = function(event) {
237
  const line = event.data;
238
 
239
  if (line === 'uciok') {
240
- $engineStatus.addClass('ready');
241
- $engineText.text('Engine Ready');
242
  }
243
 
244
  if (line.startsWith('info') && line.includes('score cp')) {
 
245
  const matchScore = line.match(/score cp (-?\d+)/);
246
  const matchMate = line.match(/score mate (-?\d+)/);
 
 
247
  const matchPv = line.match(/ pv (.+)/);
248
 
249
  if (matchMate) {
250
- $evaluation.text(`Mate in ${Math.abs(matchMate[1])}`);
251
- $evaluation.css('color', '#f44336');
252
  } else if (matchScore) {
253
  const score = parseInt(matchScore[1]) / 100;
254
  const finalScore = game.turn() === 'b' ? -score : score;
255
- $evaluation.text(finalScore > 0 ? `+${finalScore}` : finalScore);
256
- $evaluation.css('color', finalScore >= 0 ? '#4caf50' : '#f44336');
257
  }
258
 
259
  if (matchPv) {
260
- $bestLine.text(matchPv[1]);
 
 
 
 
 
261
  }
262
  }
263
  };
264
-
265
  engine.postMessage('uci');
266
  engine.postMessage('isready');
267
- } catch (e) {
268
- $engineText.text('Engine Error');
269
- throw new Error("Engine Init: " + e.message);
270
  }
271
  }
272
 
273
  function analyzePosition() {
274
- if (!engine) return;
275
- $engineStatus.removeClass('ready').addClass('thinking');
276
- $engineText.text('Calculating...');
277
- engine.postMessage(`position fen ${game.fen()}`);
278
- engine.postMessage('go depth 15');
 
279
  }
280
 
281
- // --- GAME LOGIC ---
282
  function onDragStart(source, piece) {
283
  if (game.game_over()) return false;
 
284
  if ((game.turn() === 'w' && piece.search(/^b/) !== -1) ||
285
  (game.turn() === 'b' && piece.search(/^w/) !== -1)) {
286
  return false;
@@ -296,7 +352,7 @@
296
 
297
  if (move === null) return 'snapback';
298
 
299
- updateStatus();
300
  analyzePosition();
301
  }
302
 
@@ -304,47 +360,18 @@
304
  board.position(game.fen());
305
  }
306
 
307
- function updateStatus() {
308
- let status = '';
309
- let moveColor = game.turn() === 'b' ? 'Black' : 'White';
310
-
311
- if (game.in_checkmate()) {
312
- status = `Game over, ${moveColor} is in checkmate.`;
313
- } else if (game.in_draw()) {
314
- status = 'Game over, drawn position';
315
- } else {
316
- status = `${moveColor} to move`;
317
- if (game.in_check()) status += `, ${moveColor} is in check`;
318
- }
319
-
320
- $status.text(status);
321
- }
322
 
323
- // --- EVENTS ---
324
- // We use window.onload to be absolutely sure images/scripts are done
325
- window.addEventListener('load', function() {
326
- try {
327
- initGame();
328
-
329
- // Button Listeners
330
- document.getElementById('resetBtn').addEventListener('click', function() {
331
- game.reset();
332
- board.start();
333
- document.getElementById('best-line').innerText = '...';
334
- document.getElementById('evaluation').innerText = '0.00';
335
- updateStatus();
336
- });
337
-
338
- document.getElementById('flipBtn').addEventListener('click', function() {
339
- board.flip();
340
- });
341
-
342
- } catch (e) {
343
- // This catches the errors thrown in initGame
344
- document.getElementById('debug-log').style.display = 'block';
345
- document.getElementById('debug-log').innerHTML += `CRITICAL: ${e.message}<br>`;
346
- }
347
  });
 
348
  </script>
349
  </body>
350
  </html>
 
13
  --text-color: #e0e0e0;
14
  --accent-color: #4caf50;
15
  --panel-bg: #333;
16
+ --highlight: #00e5ff;
17
  }
18
 
19
  body {
 
25
  align-items: center;
26
  margin: 0;
27
  padding: 10px;
28
+ user-select: none; /* Prevent text selection while tapping */
29
  }
30
 
31
+ h1 { margin-bottom: 15px; text-align: center; font-size: 1.5rem; }
32
 
33
  .container {
34
  display: flex;
35
  flex-direction: column;
36
+ gap: 15px;
37
  justify-content: center;
38
  align-items: center;
39
  max-width: 900px;
40
  width: 100%;
41
  }
42
 
43
+ /* --- BOARD --- */
 
 
 
 
 
 
 
 
 
 
 
 
 
 
44
  #board {
45
  width: 100%;
46
+ max-width: 380px;
47
  aspect-ratio: 1 / 1;
48
  margin: 0 auto;
49
  background-color: #303030;
50
+ border: 3px solid #555;
51
  display: flex;
52
  align-items: center;
53
  justify-content: center;
54
  color: #777;
55
  }
56
 
57
+ /* --- TURN SWITCHER UI --- */
58
+ .turn-controls {
59
+ display: flex;
60
+ gap: 15px;
61
+ justify-content: center;
62
+ width: 100%;
63
+ max-width: 380px;
64
+ margin-bottom: 5px;
65
+ }
66
+
67
+ .turn-card {
68
+ flex: 1;
69
+ background: #444;
70
+ padding: 10px;
71
+ border-radius: 8px;
72
+ display: flex;
73
+ align-items: center;
74
+ justify-content: center;
75
+ gap: 10px;
76
+ cursor: pointer;
77
+ border: 2px solid transparent;
78
+ opacity: 0.5;
79
+ transition: all 0.3s ease;
80
+ }
81
+
82
+ .turn-card img { height: 35px; }
83
+ .turn-card span { font-weight: bold; }
84
+
85
+ /* Active Turn Styles */
86
+ .turn-card.active {
87
+ opacity: 1;
88
+ background: #505050;
89
+ border-color: var(--accent-color);
90
+ box-shadow: 0 0 10px rgba(76, 175, 80, 0.3);
91
+ }
92
+
93
+ /* --- ANALYSIS PANEL --- */
94
  .panel {
95
  width: 100%;
96
+ max-width: 380px;
97
  background: var(--panel-bg);
98
+ padding: 15px;
99
  border-radius: 8px;
100
  box-sizing: border-box;
101
  display: flex;
102
  flex-direction: column;
103
+ gap: 12px;
104
  }
105
 
106
+ .best-move-box {
107
+ background: #2a2a2a;
108
+ padding: 15px;
109
+ border-radius: 8px;
110
+ text-align: center;
111
+ border: 1px solid #555;
112
+ }
113
+
114
+ .best-move-label { display: block; color: #888; font-size: 0.8em; margin-bottom: 5px; }
115
+ .best-move-text {
116
+ font-size: 1.8em;
117
+ font-weight: bold;
118
+ color: var(--highlight);
119
+ font-family: monospace;
120
+ letter-spacing: 2px;
121
  }
122
 
123
+ .eval-bar {
124
+ height: 6px;
125
+ background: #555;
126
+ border-radius: 3px;
127
+ overflow: hidden;
128
+ margin-top: 5px;
129
+ position: relative;
130
+ }
131
+ .eval-fill {
132
+ height: 100%;
133
+ width: 50%;
134
+ background: var(--highlight);
135
+ transition: width 0.5s ease;
136
+ }
137
 
138
+ .controls { display: flex; gap: 10px; margin-top: 5px; }
139
  button {
140
  flex: 1;
141
  padding: 12px;
 
147
  background-color: #555;
148
  font-size: 16px;
149
  }
150
+ button:active { transform: scale(0.98); }
151
+ #flipBtn { background-color: #008CBA; }
152
+
153
+ /* Error Log */
154
+ #debug-log { display:none; color:red; background:#300; padding:10px; width:100%; font-size:12px;}
155
+
 
 
 
 
 
 
 
 
156
  </style>
157
  </head>
158
  <body>
159
 
160
+ <h1>♟️ Arcane Chess</h1>
161
 
162
  <div id="debug-log"></div>
163
 
164
  <div class="container">
165
+
166
+ <div class="turn-controls">
167
+ <div id="turn-w" class="turn-card active" onclick="forceTurn('w')">
168
+ <img src="https://chessboardjs.com/img/chesspieces/wikipedia/wK.png" alt="White">
169
+ <span>White</span>
170
  </div>
171
+ <div id="turn-b" class="turn-card" onclick="forceTurn('b')">
172
+ <img src="https://chessboardjs.com/img/chesspieces/wikipedia/bK.png" alt="Black">
173
+ <span>Black</span>
 
 
 
 
 
 
 
 
174
  </div>
175
+ </div>
176
 
177
+ <div id="board">
178
+ <div style="text-align:center;">Loading...<br><small>If stuck, check connection</small></div>
179
+ </div>
 
180
 
181
+ <div class="panel">
182
+
183
+ <div class="best-move-box">
184
+ <span class="best-move-label">BEST MOVE</span>
185
+ <div id="best-move" class="best-move-text">...</div>
186
+
187
+ <div style="display:flex; justify-content:space-between; margin-top:10px; font-size:0.9em; color:#aaa;">
188
+ <span>Eval: <span id="eval-score" style="color:white">0.00</span></span>
189
+ <span id="engineStatus">Init...</span>
190
+ </div>
191
  </div>
192
 
193
  <div class="controls">
194
+ <button id="resetBtn">Reset Board</button>
195
+ <button id="flipBtn">Flip View</button>
196
  </div>
197
  </div>
198
  </div>
 
202
  <script src="https://cdnjs.cloudflare.com/ajax/libs/chessboard-js/1.0.0/chessboard-1.0.0.min.js"></script>
203
 
204
  <script>
205
+ // --- ERROR HANDLING ---
206
+ window.onerror = function(msg) {
207
+ $('#debug-log').show().text("Err: " + msg);
 
 
 
208
  };
209
 
210
+ // --- CONFIG ---
211
  const STOCKFISH_PATH = 'https://cdnjs.cloudflare.com/ajax/libs/stockfish.js/10.0.0/stockfish.js';
212
+ let board, game, engine;
 
 
 
213
 
214
+ // --- INIT ---
215
+ $(document).ready(function() {
216
+ initGame();
217
+ });
218
 
219
  function initGame() {
 
 
 
 
 
 
 
 
220
  game = new Chess();
221
+
 
 
 
 
 
 
222
  const config = {
223
  draggable: true,
224
  position: 'start',
 
228
  pieceTheme: 'https://chessboardjs.com/img/chesspieces/wikipedia/{piece}.png'
229
  };
230
 
231
+ $('#board').empty();
 
232
  board = Chessboard('board', config);
233
+ $(window).resize(board.resize);
234
 
 
 
 
 
 
 
235
  initStockfish();
236
+ updateUI();
237
+ }
238
+
239
+ // --- TURN CONTROL LOGIC ---
240
+ function forceTurn(color) {
241
+ // Only switch if it's not already that color's turn
242
+ if (game.turn() === color) return;
243
+
244
+ // 1. Get current FEN
245
+ let fen = game.fen();
246
+ let parts = fen.split(' ');
247
 
248
+ // 2. Manipulate the active color (2nd part of FEN string)
249
+ parts[1] = color;
250
+
251
+ // 3. Clear En Passant target (3rd part) to avoid logic errors when swapping turns
252
+ parts[3] = '-';
253
+
254
+ // 4. Rebuild FEN
255
+ let newFen = parts.join(' ');
256
+
257
+ // 5. Load into game
258
+ let result = game.load(newFen);
259
+
260
+ if(result) {
261
+ board.position(newFen);
262
+ updateUI();
263
+ analyzePosition(); // Re-analyze for the new player
264
+ } else {
265
+ console.log("Cannot switch turn: Illegal position");
266
+ }
267
  }
268
 
269
+ function updateUI() {
270
+ // Update Turn Cards
271
+ $('.turn-card').removeClass('active');
272
+ if (game.turn() === 'w') {
273
+ $('#turn-w').addClass('active');
274
+ } else {
275
+ $('#turn-b').addClass('active');
276
+ }
277
+ }
278
+
279
+ // --- ENGINE ---
280
  function initStockfish() {
281
  try {
282
  const blob = new Blob([`importScripts('${STOCKFISH_PATH}')`], {type: 'application/javascript'});
283
  const url = URL.createObjectURL(blob);
 
284
  engine = new Worker(url);
285
 
286
  engine.onmessage = function(event) {
287
  const line = event.data;
288
 
289
  if (line === 'uciok') {
290
+ $('#engineStatus').text('Ready').css('color', '#4caf50');
 
291
  }
292
 
293
  if (line.startsWith('info') && line.includes('score cp')) {
294
+ // Parse Score
295
  const matchScore = line.match(/score cp (-?\d+)/);
296
  const matchMate = line.match(/score mate (-?\d+)/);
297
+
298
+ // Parse Best Move
299
  const matchPv = line.match(/ pv (.+)/);
300
 
301
  if (matchMate) {
302
+ $('#eval-score').text(`M${Math.abs(matchMate[1])}`).css('color', '#ff5252');
 
303
  } else if (matchScore) {
304
  const score = parseInt(matchScore[1]) / 100;
305
  const finalScore = game.turn() === 'b' ? -score : score;
306
+ const sign = finalScore > 0 ? '+' : '';
307
+ $('#eval-score').text(`${sign}${finalScore}`).css('color', finalScore >= 0 ? '#4caf50' : '#ff5252');
308
  }
309
 
310
  if (matchPv) {
311
+ // SPLIT the line and take only the first move
312
+ let moves = matchPv[1].split(' ');
313
+ let bestMove = moves[0];
314
+
315
+ // Make it look pretty (e.g., e2e4)
316
+ $('#best-move').html(`➜ ${bestMove}`);
317
  }
318
  }
319
  };
 
320
  engine.postMessage('uci');
321
  engine.postMessage('isready');
322
+ } catch(e) {
323
+ $('#engineStatus').text('Offline');
 
324
  }
325
  }
326
 
327
  function analyzePosition() {
328
+ $('#best-move').text('...');
329
+ $('#engineStatus').text('Thinking...');
330
+ if(engine) {
331
+ engine.postMessage(`position fen ${game.fen()}`);
332
+ engine.postMessage('go depth 15');
333
+ }
334
  }
335
 
336
+ // --- CHESS LOGIC ---
337
  function onDragStart(source, piece) {
338
  if (game.game_over()) return false;
339
+ // Strict movement: only allow moving the piece whose turn it is
340
  if ((game.turn() === 'w' && piece.search(/^b/) !== -1) ||
341
  (game.turn() === 'b' && piece.search(/^w/) !== -1)) {
342
  return false;
 
352
 
353
  if (move === null) return 'snapback';
354
 
355
+ updateUI();
356
  analyzePosition();
357
  }
358
 
 
360
  board.position(game.fen());
361
  }
362
 
363
+ // --- BUTTONS ---
364
+ $('#resetBtn').click(function() {
365
+ game.reset();
366
+ board.start();
367
+ $('#best-move').text('...');
368
+ updateUI();
369
+ });
 
 
 
 
 
 
 
 
370
 
371
+ $('#flipBtn').click(function() {
372
+ board.flip();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
373
  });
374
+
375
  </script>
376
  </body>
377
  </html>