Skip to content

Commit a2edc4a

Browse files
Merge pull request #5 from infrareactive/infrareactive-patch-2
Update index.html
2 parents 4249ec9 + 9056aca commit a2edc4a

File tree

1 file changed

+199
-79
lines changed

1 file changed

+199
-79
lines changed

index.html

Lines changed: 199 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -3,126 +3,246 @@
33
<head>
44
<meta charset="utf-8">
55
<meta name="viewport" content="width=device-width, initial-scale=1">
6-
<title>Cyber Chess v10: Neural Link</title>
6+
<title>Cyber Chess v9.0: Gold Master</title>
77
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
8-
<script src="https://unpkg.com/peerjs@1.5.4/dist/peerjs.min.js"></script>
98
<style>
10-
:root { --neon-cyan: #00ffff; --neon-magenta: #ff00ff; --bg-dark: #0a0a0a; }
11-
body { background: #050505; color: #eee; font-family: 'Courier New', monospace; }
12-
#cyberChessSection { min-height: 100vh; padding: 20px 0; }
13-
.chess-title { font-size: 2rem; color: var(--neon-cyan); text-shadow: 0 0 10px var(--neon-cyan); text-align: center; }
14-
.chessboard { width: clamp(300px, 95vw, 500px); aspect-ratio: 1/1; display: grid; grid-template-columns: repeat(8, 1fr); border: 2px solid var(--neon-cyan); margin: auto; }
9+
:root { --neon-cyan: #00ffff; --neon-magenta: #ff00ff; --bg-dark: #0a0a0a; --alert-red: #ff3333; --glass: rgba(255, 255, 255, 0.05); }
10+
body { background: #111; color: #eee; font-family: 'Segoe UI', sans-serif; overflow-x: hidden; }
11+
#cyberChessSection { background: var(--bg-dark); min-height: 100vh; padding: 2rem 0; }
12+
.chess-title { font-size: 2.5rem; font-weight: 800; text-align: center; background: linear-gradient(45deg, var(--neon-cyan), var(--neon-magenta)); -webkit-background-clip: text; -webkit-text-fill-color: transparent; margin-bottom: 1rem; text-transform: uppercase; letter-spacing: 2px; }
13+
.scoreboard { display: flex; justify-content: center; gap: 1rem; margin-bottom: 1rem; }
14+
.score-box { background: var(--glass); border: 1px solid #333; padding: 0.5rem 1rem; border-radius: 4px; text-align: center; transition: 0.3s; flex: 1; max-width: 150px; }
15+
.score-box.active { border-color: currentColor; box-shadow: 0 0 15px currentColor; background: rgba(255,255,255,0.1); }
16+
.score-white { color: #fff; } .score-black { color: var(--neon-magenta); }
17+
.status-display { text-align: center; font-size: 1rem; color: #888; min-height: 1.5em; margin-bottom: 10px; }
18+
.chessboard-container { display: flex; justify-content: center; margin: 1rem 0; }
19+
.chessboard { width: clamp(300px, 95vw, 520px); aspect-ratio: 1/1; display: grid; grid-template-columns: repeat(8, 1fr); border: 4px solid var(--neon-cyan); background: #000; box-shadow: 0 0 20px rgba(0, 255, 255, 0.2); }
1520
.square { width: 100%; height: 100%; display: flex; align-items: center; justify-content: center; cursor: pointer; position: relative; }
16-
.light { background: #1a1a1a; } .dark { background: #0a0a0a; }
17-
.selected { background: rgba(0, 255, 255, 0.3) !important; }
18-
.last-move { background: rgba(255, 255, 0, 0.1) !important; }
19-
.piece { font-size: 2.5rem; user-select: none; }
20-
.white { color: #fff; } .black { color: var(--neon-magenta); }
21-
#connectionPanel { max-width: 500px; margin: 10px auto; border: 1px solid #333; padding: 15px; border-radius: 8px; }
21+
.square.light { background: #2a2a2a; } .square.dark { background: #1a1a1a; }
22+
.square.selected { background: rgba(0, 255, 255, 0.3) !important; }
23+
.square.last-move { background: rgba(255, 255, 0, 0.15) !important; border: 1px inset rgba(255, 255, 0, 0.3); }
24+
.square.valid-move::after { content: ''; position: absolute; width: 12px; height: 12px; background: rgba(0, 255, 0, 0.4); border-radius: 50%; }
25+
.piece { font-size: clamp(2rem, 8vw, 3rem); user-select: none; z-index: 2; cursor: grab; }
26+
.piece.white { color: #fff; text-shadow: 0 0 8px rgba(255,255,255,0.4); }
27+
.piece.black { color: var(--neon-magenta); text-shadow: 0 0 8px rgba(255,0,255,0.4); }
28+
.cyber-btn { background: #000; border: 1px solid var(--neon-cyan); color: var(--neon-cyan); padding: 0.4rem 1rem; text-transform: uppercase; cursor: pointer; transition: 0.3s; font-size: 0.8rem; }
29+
.cyber-btn:hover { background: var(--neon-cyan); color: #000; box-shadow: 0 0 10px var(--neon-cyan); }
2230
</style>
2331
</head>
2432
<body>
25-
<div id="cyberChessSection">
26-
<h2 class="chess-title">CYBER CHESS v10 // MULTIPLAYER</h2>
27-
28-
<div id="connectionPanel">
29-
<div id="status" class="text-warning mb-2 small">System: Offline</div>
30-
<div id="myIdDisplay" class="text-info mb-2" style="cursor:pointer" onclick="copyId()">ID: Loading...</div>
31-
<div class="input-group input-group-sm">
32-
<input type="text" id="peerIdInput" class="form-control bg-dark text-white border-secondary" placeholder="Friend's ID">
33-
<button class="btn btn-outline-cyan text-info" onclick="network.connectToPeer()">LINK</button>
33+
<section id="cyberChessSection">
34+
<div class="container text-center">
35+
<h2 class="chess-title">Cyber Chess v9</h2>
36+
<div class="scoreboard">
37+
<div class="score-box score-white" id="scoreWhite">White: 0</div>
38+
<div class="score-box score-black" id="scoreBlack">Black: 0</div>
39+
</div>
40+
<div class="status-display" id="statusDisplay">System Ready</div>
41+
<div class="mb-3">
42+
<button class="cyber-btn" onclick="game.reset()">Reset</button>
43+
<button class="cyber-btn" onclick="game.undo()">Undo</button>
44+
<button class="cyber-btn" onclick="game.setMode('ai')" id="btnAI">AI Mode</button>
45+
</div>
46+
<div class="chessboard-container">
47+
<div class="chessboard" id="chessboard"></div>
3448
</div>
3549
</div>
36-
37-
<div class="chessboard" id="chessboard"></div>
38-
</div>
50+
</section>
3951

4052
<script>
53+
const SoundSystem = {
54+
ctx: null,
55+
init() { if (!this.ctx) this.ctx = new (window.AudioContext || window.webkitAudioContext)(); if(this.ctx.state === 'suspended') this.ctx.resume(); },
56+
play(freq, type='sine', dur=0.1) {
57+
this.init(); const osc = this.ctx.createOscillator(); const g = this.ctx.createGain();
58+
osc.type = type; osc.frequency.setValueAtTime(freq, this.ctx.currentTime);
59+
g.gain.setValueAtTime(0.1, this.ctx.currentTime); g.gain.exponentialRampToValueAtTime(0.01, this.ctx.currentTime + dur);
60+
osc.connect(g); g.connect(this.ctx.destination); osc.start(); osc.stop(this.ctx.currentTime + dur);
61+
}
62+
};
63+
4164
const game = {
42-
board: [], turn: 'W', myRole: null, // 'W' or 'B'
65+
board: [], turn: 'W', history: [], mode: 'pvp', lastMove: null, scores: {W:0, B:0},
66+
vals: {P:10, N:30, B:30, R:50, Q:90, K:900},
67+
pst: {
68+
P: [[0,0,0,0,0,0,0,0],[5,5,5,5,5,5,5,5],[1,1,2,3,3,2,1,1],[0.5,0.5,1,2.5,2.5,1,0.5,0.5],[0,0,0,2,2,0,0,0],[0.5,-0.5,-1,0,0,-1,-0.5,0.5],[0.5,1,1,-2,-2,1,1,0.5],[0,0,0,0,0,0,0,0]],
69+
N: [[-5,-4,-3,-3,-3,-3,-4,-5],[-4,-2,0,0,0,0,-2,-4],[-3,0,1,1.5,1.5,1,0,-3],[-3,0.5,1.5,2,2,1.5,0.5,-3],[-3,0,1.5,2,2,1.5,0,-3],[-3,0.5,1,1.5,1.5,1,0.5,-3],[-4,-2,0,0.5,0.5,0,-2,-4],[-5,-4,-3,-3,-3,-3,-4,-5]]
70+
},
4371
syms: {W:{K:'♔',Q:'♕',R:'♖',B:'♗',N:'♘',P:'♙'}, B:{K:'♚',Q:'♛',R:'♜',B:'♝',N:'♞',P:'♟'}},
4472

4573
init() {
4674
this.board = [['r','n','b','q','k','b','n','r'],['p','p','p','p','p','p','p','p'],[null,null,null,null,null,null,null,null],[null,null,null,null,null,null,null,null],[null,null,null,null,null,null,null,null],[null,null,null,null,null,null,null,null],['P','P','P','P','P','P','P','P'],['R','N','B','Q','K','B','N','R']];
47-
this.render();
75+
this.turn = 'W'; this.history = []; this.lastMove = null; this.render(); this.updateUI();
76+
},
77+
78+
evaluate() {
79+
let s = 0;
80+
for(let r=0; r<8; r++) for(let c=0; c<8; c++) {
81+
let p = this.board[r][c]; if(!p) continue;
82+
let v = this.vals[p.toUpperCase()] + (this.pst[p.toUpperCase()] ? this.pst[p.toUpperCase()][p === p.toUpperCase() ? r : 7-r][c] : 0);
83+
s += (p === p.toUpperCase() ? v : -v);
84+
}
85+
return s;
86+
},
87+
88+
minimax(depth, alpha, beta, isMax) {
89+
if(depth === 0) return -this.evaluate();
90+
let moves = this.getAllMoves(isMax ? 'B' : 'W');
91+
if(!moves.length) return isMax ? -1000 : 1000;
92+
let best = isMax ? -Infinity : Infinity;
93+
for(let m of moves) {
94+
let old = this.board[m.to.r][m.to.c];
95+
this.board[m.to.r][m.to.c] = this.board[m.from.r][m.from.c];
96+
this.board[m.from.r][m.from.c] = null;
97+
let score = this.minimax(depth-1, alpha, beta, !isMax);
98+
this.board[m.from.r][m.from.c] = this.board[m.to.r][m.to.c];
99+
this.board[m.to.r][m.to.c] = old;
100+
if(isMax) { best = Math.max(best, score); alpha = Math.max(alpha, best); }
101+
else { best = Math.min(best, score); beta = Math.min(beta, best); }
102+
if(beta <= alpha) break;
103+
}
104+
return best;
105+
},
106+
107+
triggerAI() {
108+
setTimeout(() => {
109+
let moves = this.getAllMoves('B');
110+
let bestM = null, bestS = -Infinity;
111+
moves.sort(() => Math.random() - 0.5);
112+
for(let m of moves) {
113+
let old = this.board[m.to.r][m.to.c];
114+
this.board[m.to.r][m.to.c] = this.board[m.from.r][m.from.c];
115+
this.board[m.from.r][m.from.c] = null;
116+
let s = this.minimax(2, -Infinity, Infinity, false);
117+
this.board[m.from.r][m.from.c] = this.board[m.to.r][m.to.c];
118+
this.board[m.to.r][m.to.c] = old;
119+
if(s > bestS) { bestS = s; bestM = m; }
120+
}
121+
if(bestM) this.move(bestM.from, bestM.to);
122+
}, 300);
123+
},
124+
125+
getAllMoves(color) {
126+
let moves = [];
127+
for(let r=0; r<8; r++) for(let c=0; c<8; c++) {
128+
let p = this.board[r][c];
129+
if(p && (color==='W' ? p===p.toUpperCase() : p===p.toLowerCase())) {
130+
for(let tr=0; tr<8; tr++) for(let tc=0; tc<8; tc++) {
131+
if(this.isLegal({r,c}, {r:tr, c:tc})) moves.push({from:{r,c}, to:{r:tr, c:tc}});
132+
}
133+
}
134+
}
135+
return moves;
136+
},
137+
138+
isLegal(f, t) {
139+
let p = this.board[f.r][f.c]; if(!p) return false;
140+
let target = this.board[t.r][t.c];
141+
if(target && (p===p.toUpperCase()) === (target===target.toUpperCase())) return false;
142+
let dx = t.c-f.c, dy = t.r-f.r, type = p.toUpperCase();
143+
144+
// Basic movement logic
145+
if(type==='P') {
146+
let dir = p==='P' ? -1 : 1;
147+
if(dx===0 && dy===dir && !target) {}
148+
else if(dx===0 && dy===2*dir && f.r===(p==='P'?6:1) && !target && !this.board[f.r+dir][f.c]) {}
149+
else if(Math.abs(dx)===1 && dy===dir && target) {}
150+
else return false;
151+
} else if(type==='R') { if(dx!==0 && dy!==0 || !this.pathClear(f,t)) return false; }
152+
else if(type==='B') { if(Math.abs(dx)!==Math.abs(dy) || !this.pathClear(f,t)) return false; }
153+
else if(type==='Q') { if((dx!==0 && dy!==0 && Math.abs(dx)!==Math.abs(dy)) || !this.pathClear(f,t)) return false; }
154+
else if(type==='N') { if(!(Math.abs(dx)===2 && Math.abs(dy)===1 || Math.abs(dx)===1 && Math.abs(dy)===2)) return false; }
155+
else if(type==='K') { if(Math.abs(dx)>1 || Math.abs(dy)>1) return false; }
156+
157+
// King Safety
158+
let old = this.board[t.r][t.c];
159+
this.board[t.r][t.c] = this.board[f.r][f.c]; this.board[f.r][f.c] = null;
160+
let safe = !this.inDanger(p===p.toUpperCase() ? 'W':'B');
161+
this.board[f.r][f.c] = this.board[t.r][t.c]; this.board[t.r][t.c] = old;
162+
return safe;
48163
},
49164

50-
move(f, t, remote = false) {
51-
// If it's a remote move, or it's my turn and I'm moving my color
52-
this.board[t.r][t.c] = this.board[f.r][f.c];
53-
this.board[f.r][f.c] = null;
54-
this.turn = this.turn === 'W' ? 'B' : 'W';
55-
this.render();
56-
if(!remote && network.conn) {
57-
network.conn.send({type: 'MOVE', f, t});
165+
pathClear(f, t) {
166+
let dx = Math.sign(t.c-f.c), dy = Math.sign(t.r-f.r);
167+
let c = f.c+dx, r = f.r+dy;
168+
while(c!==t.c || r!==t.r) { if(this.board[r][c]) return false; c+=dx; r+=dy; }
169+
return true;
170+
},
171+
172+
inDanger(color) {
173+
let kr, kc;
174+
for(let r=0; r<8; r++) for(let c=0; c<8; c++) if(this.board[r][c]===(color==='W'?'K':'k')) { kr=r; kc=c; }
175+
for(let r=0; r<8; r++) for(let c=0; c<8; c++) {
176+
let p = this.board[r][c];
177+
if(p && (color==='W' ? p===p.toLowerCase() : p===p.toUpperCase())) {
178+
// Check if this piece can hit the king (Simplified geometry check)
179+
let dx = kc-c, dy = kr-r, type = p.toUpperCase();
180+
let canHit = false;
181+
if(type==='P') canHit = (Math.abs(dx)===1 && dy===(p==='P'?-1:1));
182+
else if(type==='R') canHit = (dx===0 || dy===0) && this.pathClear({r,c},{r:kr,c:kc});
183+
else if(type==='B') canHit = (Math.abs(dx)===Math.abs(dy)) && this.pathClear({r,c},{r:kr,c:kc});
184+
else if(type==='Q') canHit = (dx===0 || dy===0 || Math.abs(dx)===Math.abs(dy)) && this.pathClear({r,c},{r:kr,c:kc});
185+
else if(type==='N') canHit = (Math.abs(dx)===2 && Math.abs(dy)===1 || Math.abs(dx)===1 && Math.abs(dy)===2);
186+
else if(type==='K') canHit = (Math.abs(dx)<=1 && Math.abs(dy)<=1);
187+
if(canHit) return true;
188+
}
58189
}
190+
return false;
191+
},
192+
193+
move(f, t) {
194+
this.history.push(JSON.stringify(this.board));
195+
let target = this.board[t.r][t.c];
196+
if(target) { this.scores[this.turn] += this.vals[target.toUpperCase()]; SoundSystem.play(200, 'square'); }
197+
else SoundSystem.play(400);
198+
199+
this.board[t.r][t.c] = this.board[f.r][f.c]; this.board[f.r][f.c] = null;
200+
// Promotion
201+
if(this.board[t.r][t.c].toUpperCase()==='P' && (t.r===0 || t.r===7)) this.board[t.r][t.c] = this.turn==='W'?'Q':'q';
202+
203+
this.lastMove = {f, t};
204+
this.turn = this.turn==='W' ? 'B' : 'W';
205+
this.render(); this.updateUI();
206+
if(this.mode==='ai' && this.turn==='B') this.triggerAI();
59207
},
60208

61209
render() {
62210
const el = document.getElementById('chessboard'); el.innerHTML = '';
63211
for(let r=0; r<8; r++) for(let c=0; c<8; c++) {
64212
const sq = document.createElement('div');
65213
sq.className = `square ${(r+c)%2?'dark':'light'}`;
214+
if(this.selected && this.selected.r===r && this.selected.c===c) sq.classList.add('selected');
215+
if(this.lastMove && ((this.lastMove.f.r===r && this.lastMove.f.c===c) || (this.lastMove.t.r===r && this.lastMove.t.c===c))) sq.classList.add('last-move');
216+
66217
let p = this.board[r][c];
67218
if(p) {
68219
const pEl = document.createElement('div');
69220
pEl.className = `piece ${p===p.toUpperCase()?'white':'black'}`;
70221
pEl.textContent = this.syms[p===p.toUpperCase()?'W':'B'][p.toUpperCase()];
71222
sq.appendChild(pEl);
72223
}
224+
if(this.selected && this.isLegal(this.selected, {r,c})) sq.classList.add('valid-move');
73225
sq.onclick = () => {
74-
if(this.myRole && this.turn !== this.myRole) return; // Not your turn
75-
if(p && (this.turn === 'W' ? p===p.toUpperCase() : p===p.toLowerCase())) {
76-
this.selected = {r,c}; this.render();
77-
} else if(this.selected) {
78-
this.move(this.selected, {r,c});
79-
this.selected = null;
80-
}
226+
SoundSystem.init();
227+
if(p && (this.turn==='W' ? p===p.toUpperCase() : p===p.toLowerCase())) { this.selected = {r,c}; this.render(); }
228+
else if(this.selected) { if(this.isLegal(this.selected, {r,c})) this.move(this.selected, {r,c}); this.selected = null; this.render(); }
81229
};
82230
el.appendChild(sq);
83231
}
84-
}
85-
};
86-
87-
const network = {
88-
peer: null, conn: null,
89-
init() {
90-
this.peer = new Peer();
91-
this.peer.on('open', (id) => {
92-
document.getElementById('myIdDisplay').innerText = "MY ID (Click to Copy): " + id;
93-
document.getElementById('status').innerText = "System: Waiting for peer...";
94-
});
95-
this.peer.on('connection', (c) => {
96-
this.conn = c;
97-
game.myRole = 'W'; // Host is White
98-
this.setupHandlers();
99-
});
100232
},
101-
connectToPeer() {
102-
const id = document.getElementById('peerIdInput').value;
103-
this.conn = this.peer.connect(id);
104-
game.myRole = 'B'; // Joiner is Black
105-
this.setupHandlers();
233+
234+
updateUI() {
235+
document.getElementById('scoreWhite').textContent = `White: ${this.scores.W}`;
236+
document.getElementById('scoreBlack').textContent = `Black: ${this.scores.B}`;
237+
document.getElementById('statusDisplay').textContent = this.turn==='W' ? "White's Turn" : "Black's Turn (Analyzing...)";
106238
},
107-
setupHandlers() {
108-
this.conn.on('open', () => {
109-
document.getElementById('status').innerText = "System: NEURAL LINK ESTABLISHED";
110-
document.getElementById('status').className = "text-success mb-2 small";
111-
});
112-
this.conn.on('data', (data) => {
113-
if(data.type === 'MOVE') game.move(data.f, data.t, true);
114-
});
115-
}
116-
};
117239

118-
function copyId() {
119-
const id = document.getElementById('myIdDisplay').innerText.split(': ')[1];
120-
navigator.clipboard.writeText(id);
121-
alert("ID Copied! Send this to your friend.");
122-
}
240+
setMode(m) { this.mode = m; this.init(); },
241+
undo() { if(this.history.length) { this.board = JSON.parse(this.history.pop()); this.turn = this.turn==='W'?'B':'W'; this.render(); this.updateUI(); } },
242+
reset() { this.init(); }
243+
};
123244

124245
game.init();
125-
network.init();
126246
</script>
127247
</body>
128248
</html>

0 commit comments

Comments
 (0)