const assets = [ "wk.webp", "wq.webp", "wr.png", "wb.webp", "wn.png", "wp.png", "bk.webp", "bq.png", "br.webp", "bb.webp", "bn.webp", "bp.png" ].map(x => "./assets/pieces/" + x); let hoveringPiece = -1; const bitboards = [ 16n, 8n, 129n, 36n, 66n, 65280n, 1152921504606846976n, 576460752303423488n, 9295429630892703744n, 2594073385365405696n, 4755801206503243776n, 71776119061217280n, ]; const WHITE_KING = 0; const WHITE_QUEEN = 1; const WHITE_ROOK = 2; const WHITE_BISHOP = 3; const WHITE_KNIGHT = 4; const WHITE_PAWN = 5; const BLACK_KING = 6; const BLACK_QUEEN = 7; const BLACK_ROOK = 8; const BLACK_BISHOP = 9; const BLACK_KNIGHT = 10; const BLACK_PAWN = 11; let counting_bitboard = 0n; function trackBitboard(i, selected, output) { const mask = 1n << BigInt(i); if (selected) counting_bitboard |= mask; else counting_bitboard &= ~mask; output.textContent = counting_bitboard.toString(); } function checkForPiece(square, bitIndex, set = true) { for (let i = 0; i < bitboards.length; i++) { const mask = bitboards[i]; if ((mask >> BigInt(bitIndex)) & 1n) { if (set) square.style.backgroundImage = `url(${assets[i]})`; return i; } } return null; } function isYourTurn(piece) { if (turn == "w") return piece < 6; return piece >= 6; } const selectedAction = trackBitboard; window.onkeydown = (e) => { if (e.key == 'b') { console.log(` position.bitboards[WHITE_KING] = ${bitboards[0].toString()}ULL; position.bitboards[WHITE_QUEEN] = ${bitboards[1].toString()}ULL; position.bitboards[WHITE_ROOK] = ${bitboards[2].toString()}ULL; position.bitboards[WHITE_BISHOP] = ${bitboards[3].toString()}ULL; position.bitboards[WHITE_KNIGHT] = ${bitboards[4].toString()}ULL; position.bitboards[WHITE_PAWN] = ${bitboards[5].toString()}ULL; position.bitboards[BLACK_KING] = ${bitboards[6].toString()}ULL; position.bitboards[BLACK_QUEEN] = ${bitboards[7].toString()}ULL; position.bitboards[BLACK_ROOK] = ${bitboards[8].toString()}ULL; position.bitboards[BLACK_BISHOP] = ${bitboards[9].toString()}ULL; position.bitboards[BLACK_KNIGHT] = ${bitboards[10].toString()}ULL; position.bitboards[BLACK_PAWN] = ${bitboards[11].toString()}ULL; `) } } let validMoves = {}; let renderingMoves = []; let pickedUpFrom = -1; function updateRenderingMoves() { for (let i = 0; i < 64; i++) { const square = document.getElementById(`square-${i}`); if (renderingMoves.includes(i)) square.children[0].classList.add("possible_move"); else square.children[0].classList.remove("possible_move"); } } function handleTransmission(data) { data = data.join(""); for (let i = 0; i < data.length / 4; i++) { const moveData = data.slice(4 * i, 4 * i + 4); let from = parseInt(moveData.slice(0, 2)); let to = parseInt(moveData.slice(2)); console.log(from, to, moveData); if (validMoves[from] == undefined) validMoves[from] = [] validMoves[from].push(to); } } function calculateFen() { let fen = "" let empty = 0; for (let i = 7; i >= 0; i--) { for (let j = 0; j < 8; j++) { const sqr = document.getElementById(`square-${8 * i + j}`).style.backgroundImage; if (sqr.length == 0 || sqr.includes("none")) { empty++; continue; } if (empty != 0) { fen += empty.toString(); } empty = 0; let p = sqr[22]; if (sqr[21] == "w") p = sqr[22].toUpperCase(); fen += p; } if (empty != 0) { fen += empty.toString(); } if (i == 0) continue; empty = 0; fen += "/"; } return fen; } let turn = "w"; let castling = "KQkq"; let passant_square = "-"; let halfmove = 0; let fullmove = 1; let socket; let old_fen = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1"; function checkMoveMade(pieceMoved) { let new_fen = calculateFen(); if (new_fen == old_fen.split(" ")[0]) return; old_fen = new_fen; halfmove++; console.log(pieceMoved) if (pieceMoved == WHITE_PAWN || pieceMoved == BLACK_PAWN) halfmove = 0; if (turn == "b") fullmove++; turn = turn == "w" ? "b" : "w"; old_fen = `${new_fen} ${turn} ${castling} ${passant_square} ${halfmove} ${fullmove}`; validMoves = {}; console.log(old_fen); socket.send(old_fen); } function connectSocket() { socket = new WebSocket("ws://localhost:3456"); let data = []; socket.onmessage = e => { console.log(e); if (e.data == "END-TRANSMISSION") { handleTransmission(data); data = []; } else { data.push(e.data); } } socket.onopen = () => { console.log(old_fen); socket.send(old_fen); } socket.onerror = e => { console.log("error", e); }; } window.onload = () => { connectSocket(); socket.onclose = e => { console.log("closed", e.code, e.reason); }; const output = document.getElementById("output"); const board = document.getElementById("board"); for (let i = 0; i < 64; i++) { if (i % 8 == 0) { const label = document.createElement("div"); label.classList.add("label"); label.textContent = 8 - Math.round(i / 8); board.appendChild(label); } const square = document.createElement("div"); square.classList.add("square"); const renderingMoveMarker = document.createElement("div"); renderingMoveMarker.classList.add("rendering_marker"); square.appendChild(renderingMoveMarker); const shift = Math.floor(i / 8); square.classList.add((i + shift) % 2 ? "dark" : "light"); const bitIndex = (i % 8) - 8 * Math.floor(i / 8) + 56; square.id = 'square-' + bitIndex.toString(); checkForPiece(square, bitIndex); square.onclick = (e) => { if (e.ctrlKey) { const selected = square.classList.contains("selected"); selectedAction(bitIndex, !selected, output); if (selected) square.classList.remove("selected"); else square.classList.add("selected"); return; } const piece = checkForPiece(square, bitIndex, false); const sqr_id = parseInt(square.id.slice(7)); if (hoveringPiece == -1) { if (piece == null) return; if (!isYourTurn(piece)) return; if (validMoves[bitIndex]) renderingMoves = validMoves[bitIndex]; setHoverpiece(piece); pickedUpFrom = sqr_id; square.style.backgroundImage = `none`; bitboards[piece] &= ~(1n << BigInt(bitIndex)); } else { if (sqr_id != pickedUpFrom && !renderingMoves.includes(sqr_id)) return; renderingMoves = []; square.style.backgroundImage = `url(${assets[hoveringPiece]})`; if (piece) bitboards[piece] &= ~(1n << BigInt(bitIndex)); bitboards[hoveringPiece] |= (1n << BigInt(bitIndex)); setHoverpiece(-1); } console.log(piece, hoveringPiece, square, renderingMoves); updateRenderingMoves(); }; board.appendChild(square); } const label = document.createElement("div"); label.classList.add("horizontal_label"); board.appendChild(label); for (let i = 0; i < 8; i++) { const label = document.createElement("div"); label.classList.add("horizontal_label"); label.textContent = ["a", "b", "c", "d", "e", "f", "g", "h"][i]; board.appendChild(label); } const mouse = document.getElementById("mouse"); function setHoverpiece(i) { let oldHoveringPiece = hoveringPiece; hoveringPiece = i; if (i < 0) { mouse.style.backgroundImage = `none`; checkMoveMade(oldHoveringPiece); return; } mouse.style.backgroundImage = `url(${assets[i]})`; } window.onmousemove = (e) => { const x = e.clientX; const y = e.clientY; mouse.style.left = x.toString() + 'px'; mouse.style.top = y.toString() + 'px'; } }