diff --git a/package-lock.json b/package-lock.json index dfce20c..c7c4d0c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5,6 +5,7 @@ "packages": { "": { "dependencies": { + "@chrisoakman/chessboardjs": "^1.0.0", "@emotion/react": "^11.11.4", "@emotion/styled": "^11.11.0", "@mui/material": "^5.7.0", @@ -13,7 +14,9 @@ "@testing-library/user-event": "^13.5.0", "axios": "^1.6.5", "buffer": "^6.0.3", + "chessboardjs": "^0.0.1", "date-fns": "^3.6.0", + "jquery": "^3.7.1", "jwt-decode": "^4.0.0", "react": "^18.2.0", "react-dom": "^18.2.0", @@ -2043,6 +2046,14 @@ "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==" }, + "node_modules/@chrisoakman/chessboardjs": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@chrisoakman/chessboardjs/-/chessboardjs-1.0.0.tgz", + "integrity": "sha512-JHXHoQwwc86xW3F0YIdFcEWLnPldee5mHkqwJbOTeDh5gvNmYXyBj6AkeecDkj2WtORF959yaWYlpyZHUl3LCQ==", + "dependencies": { + "jquery": ">=3.4.1" + } + }, "node_modules/@colors/colors": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", @@ -6874,6 +6885,11 @@ "resolved": "https://registry.npmjs.org/check-types/-/check-types-11.2.3.tgz", "integrity": "sha512-+67P1GkJRaxQD6PKK0Et9DhwQB+vGg3PM5+aavopCpZT1lj9jeqfvpgTLAWErNj8qApkkmXlu/Ug74kmhagkXg==" }, + "node_modules/chessboardjs": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/chessboardjs/-/chessboardjs-0.0.1.tgz", + "integrity": "sha512-VK8mGqWQ4fk3rKre5T17F9yIxJRP/L+oS29zXL0nuhQfY3rAoKcdyPZziR2S7AfNhqPL45VmdhdspcAFR9CXww==" + }, "node_modules/chokidar": { "version": "3.5.3", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", @@ -13728,6 +13744,11 @@ "jiti": "bin/jiti.js" } }, + "node_modules/jquery": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.7.1.tgz", + "integrity": "sha512-m4avr8yL8kmFN8psrbFFFmB/If14iN5o9nw/NgnnM+kybDJpRsAynV2BsfpTYrTRysYUdADVD7CkUUizgkpLfg==" + }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", diff --git a/package.json b/package.json index 2153329..ec8715a 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,6 @@ { "dependencies": { + "@chrisoakman/chessboardjs": "^1.0.0", "@emotion/react": "^11.11.4", "@emotion/styled": "^11.11.0", "@mui/material": "^5.7.0", @@ -7,8 +8,10 @@ "@testing-library/react": "^13.4.0", "@testing-library/user-event": "^13.5.0", "axios": "^1.6.5", - "date-fns": "^3.6.0", "buffer": "^6.0.3", + "chessboardjs": "^0.0.1", + "date-fns": "^3.6.0", + "jquery": "^3.7.1", "jwt-decode": "^4.0.0", "react": "^18.2.0", "react-dom": "^18.2.0", diff --git a/public/img/chesspieces/wikipedia/bB.png b/public/img/chesspieces/wikipedia/bB.png new file mode 100644 index 0000000..be3007d Binary files /dev/null and b/public/img/chesspieces/wikipedia/bB.png differ diff --git a/public/img/chesspieces/wikipedia/bK.png b/public/img/chesspieces/wikipedia/bK.png new file mode 100644 index 0000000..de9880c Binary files /dev/null and b/public/img/chesspieces/wikipedia/bK.png differ diff --git a/public/img/chesspieces/wikipedia/bN.png b/public/img/chesspieces/wikipedia/bN.png new file mode 100644 index 0000000..e31a6d0 Binary files /dev/null and b/public/img/chesspieces/wikipedia/bN.png differ diff --git a/public/img/chesspieces/wikipedia/bP.png b/public/img/chesspieces/wikipedia/bP.png new file mode 100644 index 0000000..afa0c9d Binary files /dev/null and b/public/img/chesspieces/wikipedia/bP.png differ diff --git a/public/img/chesspieces/wikipedia/bQ.png b/public/img/chesspieces/wikipedia/bQ.png new file mode 100644 index 0000000..4649bb8 Binary files /dev/null and b/public/img/chesspieces/wikipedia/bQ.png differ diff --git a/public/img/chesspieces/wikipedia/bR.png b/public/img/chesspieces/wikipedia/bR.png new file mode 100644 index 0000000..c7eb127 Binary files /dev/null and b/public/img/chesspieces/wikipedia/bR.png differ diff --git a/public/img/chesspieces/wikipedia/wB.png b/public/img/chesspieces/wikipedia/wB.png new file mode 100644 index 0000000..70e0e14 Binary files /dev/null and b/public/img/chesspieces/wikipedia/wB.png differ diff --git a/public/img/chesspieces/wikipedia/wK.png b/public/img/chesspieces/wikipedia/wK.png new file mode 100644 index 0000000..bbf5664 Binary files /dev/null and b/public/img/chesspieces/wikipedia/wK.png differ diff --git a/public/img/chesspieces/wikipedia/wN.png b/public/img/chesspieces/wikipedia/wN.png new file mode 100644 index 0000000..237250c Binary files /dev/null and b/public/img/chesspieces/wikipedia/wN.png differ diff --git a/public/img/chesspieces/wikipedia/wP.png b/public/img/chesspieces/wikipedia/wP.png new file mode 100644 index 0000000..5f9315c Binary files /dev/null and b/public/img/chesspieces/wikipedia/wP.png differ diff --git a/public/img/chesspieces/wikipedia/wQ.png b/public/img/chesspieces/wikipedia/wQ.png new file mode 100644 index 0000000..c3dfc15 Binary files /dev/null and b/public/img/chesspieces/wikipedia/wQ.png differ diff --git a/public/img/chesspieces/wikipedia/wR.png b/public/img/chesspieces/wikipedia/wR.png new file mode 100644 index 0000000..cc69760 Binary files /dev/null and b/public/img/chesspieces/wikipedia/wR.png differ diff --git a/src/index.js b/src/index.js index f25b4ae..123507c 100644 --- a/src/index.js +++ b/src/index.js @@ -28,6 +28,10 @@ import UserSettings from './User/Settings/UserSettings'; import AnimatedBackground from "./AnimatedBackground"; import AddBotForm from "./forms/AddBotForm"; import BotList from "./lists/BotList"; +import Chess from "./visualization/chess.js"; +import $ from 'jquery'; // Import jQuery +window.$ = $; // Make jQuery available globally + const games = [{name:'Szachy', id:1}, {name:'Warcaby', id:2}, {name:'Scrabble', id:3}, {name:'ChiƄczyk', id:4}, {name:'Go', id:5}] @@ -120,6 +124,10 @@ const router = createBrowserRouter([ path: "/bots", element: }, + { + path: "/chess", + element: + }, ]); const root = ReactDOM.createRoot(document.getElementById('root')); diff --git a/src/visualization/chess.js b/src/visualization/chess.js new file mode 100644 index 0000000..a9c3e76 --- /dev/null +++ b/src/visualization/chess.js @@ -0,0 +1,142 @@ +import React, { useEffect, useRef, useState } from 'react'; +import Chessboard from 'chessboardjs'; +import './chessboard-1.0.0.min.css'; +import FileMoves from './moves.txt'; +import './chess.scss' + +const parseMoves = (gameLog) => { + const lines = gameLog.trim().split('\n'); + const moves = []; + + for (let i = 0; i < lines.length; i++) { + const currentLine = lines[i].trim(); + + if (currentLine === '1' || currentLine === '0') { + const fromMove = lines[i + 1].trim().split(' ').join('-'); + const toMove = lines[i + 2].trim().split(' ').join('-'); + if (!moves.includes(fromMove)) { + moves.push(fromMove); + } + if (!moves.includes(toMove)) { + moves.push(toMove); + } + i += 2; + } else if (currentLine === '-1') { + break; + } + } + return moves.slice(1); // Return list without the first element +} + +const ChessComponent = () => { + const [moves, setMoves] = useState([]); + const boardRef = useRef(null); + const [currentMove, setCurrentMove] = useState(0); + const [board, setBoard] = useState(null); + const listRef = useRef(null); + + useEffect(() => { + // Fetch and parse the moves from the file + fetch(FileMoves) // Adjust the path to where the moves file is located + .then((response) => response.text()) + .then((text) => { + const parsedMoves = parseMoves(text); + setMoves(parsedMoves); + }); + }, []); + + useEffect(() => { + const board = Chessboard(boardRef.current, 'start'); + setBoard(board); + + // Clean up the board on unmount + return () => { + board.destroy(); + }; + }, []); + + const handleNextMove = () => { + if (currentMove < moves.length) { + board.move(moves[currentMove]); + setCurrentMove(currentMove + 1); + scrollToCurrentMove(currentMove + 1); + } + }; + + const handlePrevMove = () => { + if (currentMove > 0) { + const tempDiv = document.createElement('div'); + tempDiv.style.position = 'absolute'; + tempDiv.style.left = '-9999px'; + document.body.appendChild(tempDiv); + + const newBoard = Chessboard(tempDiv, 'start'); + for (let i = 0; i < currentMove - 1; i++) { + newBoard.move(moves[i]); + } + board.position(newBoard.fen()); + newBoard.destroy(); + document.body.removeChild(tempDiv); + + setCurrentMove(currentMove - 1); + scrollToCurrentMove(currentMove - 1); + } + }; + + const handleMoveClick = (moveIndex) => { + const tempDiv = document.createElement('div'); + tempDiv.style.position = 'absolute'; + tempDiv.style.left = '-9999px'; + document.body.appendChild(tempDiv); + + const newBoard = Chessboard(tempDiv, 'start'); + for (let i = 0; i < moveIndex; i++) { + newBoard.move(moves[i]); + } + board.position(newBoard.fen()); + newBoard.destroy(); + document.body.removeChild(tempDiv); + + setCurrentMove(moveIndex); + scrollToCurrentMove(moveIndex); + }; + + const scrollToCurrentMove = (moveIndex) => { + if (listRef.current) { + const currentMoveElement = listRef.current.children[moveIndex]; + if (currentMoveElement) { + currentMoveElement.scrollIntoView({ + behavior: 'smooth', + block: 'nearest', + }); + } + } + }; + + return ( +
+
+
+
+ + +
+
+
+
    + {moves.map((move, index) => ( +
  • handleMoveClick(index)} + className={`move-item ${index === currentMove ? 'current-move' : ''}`} + > + {`${index + 1}. ${move}`} +
  • + ))} +
+
+
+ ); +}; + +export default ChessComponent; diff --git a/src/visualization/chess.scss b/src/visualization/chess.scss new file mode 100644 index 0000000..ec3cadf --- /dev/null +++ b/src/visualization/chess.scss @@ -0,0 +1,115 @@ + .chess-container { + display: flex; + justify-content: center; + align-items: center; + background: rgba(0, 0, 0, 0.4); // Semi-transparent background to highlight content + border-radius: 10px; + padding: 20px; + height: 100vh; + } + + .chessboard-container { + position: relative; + width: 650px; + height: 700px; + margin-bottom: 20px; + border-radius: 8px; + overflow: hidden; + background: rgba(22, 17, 17, 0.8); + display: flex; + flex-direction: column; + align-items: center; + justify-content: space-around; + // opacity: 0.6; + + } + + .chessboard { + width: 500px; + height: 500px; + display: flex; + flex-direction: column; + align-items: center; + justify-self: center; + box-shadow: 0 5px 15px rgba(200, 200, 200, 0.5) + } + + .buttons { + margin-top: 10px; + text-align: center; + width: 70%; + height: 40px; + font-size: 15px; + } + + .buttons button { + background-color: #14980D; + /* Main Primary color */ + border: none; + color: white; + padding: 10px 24px; + text-align: center; + text-decoration: none; + display: inline-block; + font-size: 16px; + margin: 4px 2px; + cursor: pointer; + border-radius: 12px; + transition: background-color 0.3s ease; + letter-spacing: 1px; + /* Slight spacing for a tech look */ + } + + .buttons button:hover { + background-color: #185515; + /* Primary color 4 for hover */ + } + + .moves-list-container { + position: relative; + margin-left: 20px; + width: 300px; + height: 700px; + overflow-y: auto; + background-color: #111; + padding: 10px; + border-radius: 8px; + box-shadow: 0 10px 30px rgba(0, 0, 0, 0.5); + /* Custom scrollbar styles */ + scrollbar-width: thin; + /* For Firefox */ + scrollbar-color: #14980D #333; + /* For Firefox */ + } + + .moves-list { + list-style-type: none; + padding: 0; + margin: 0; + background-color: #222; + background: rgba(0, 0, 0, 0.6); + } + + .move-item { + padding: 5px 10px; + cursor: pointer; + color: #14980D; + /* Primary color 2 */ + background-color: transparent; + border-radius: 4px; + transition: background-color 0.3s, color 0.3s; + background-color: #222; + margin: 5px; + font-size: 25px; + letter-spacing: 1px; + } + + .move-item:hover { + background-color: #f0f0f0; + } + + .move-item.current-move { + background-color: #d3d3d3; + color: #185515; + /* Main Primary color */ + } \ No newline at end of file diff --git a/src/visualization/chessboard-1.0.0.min.css b/src/visualization/chessboard-1.0.0.min.css new file mode 100644 index 0000000..73f844a --- /dev/null +++ b/src/visualization/chessboard-1.0.0.min.css @@ -0,0 +1,2 @@ +/*! chessboard.js v1.0.0 | (c) 2019 Chris Oakman | MIT License chessboardjs.com/license */ +.clearfix-7da63{clear:both}.board-b72b1{border:2px solid #404040;box-sizing:content-box}.square-55d63{float:left;position:relative;-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.white-1e1d7{background-color:#f0d9b5;color:#b58863}.black-3c85d{background-color:#b58863;color:#f0d9b5}.highlight1-32417,.highlight2-9c5d2{box-shadow:inset 0 0 3px 3px #ff0}.notation-322f9{cursor:default;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;position:absolute}.alpha-d2270{bottom:1px;right:3px}.numeric-fc462{top:2px;left:2px} \ No newline at end of file diff --git a/src/visualization/moves.txt b/src/visualization/moves.txt new file mode 100644 index 0000000..8e189dd --- /dev/null +++ b/src/visualization/moves.txt @@ -0,0 +1,164 @@ +0 +-1 -1 +g2 g4 +1 +g2 g4 +g8 f6 +0 +g8 f6 +d2 d4 +1 +d2 d4 +f6 g4 +0 +f6 g4 +f1 g2 +1 +f1 g2 +e7 e5 +0 +e7 e5 +g2 f1 +1 +g2 f1 +e5 d4 +0 +e5 d4 +g1 f3 +1 +g1 f3 +f8 b4 +0 +f8 b4 +b1 d2 +1 +b1 d2 +b4 d2 +0 +b4 d2 +d1 d2 +1 +d1 d2 +b8 c6 +0 +b8 c6 +f3 g5 +1 +f3 g5 +d7 d5 +0 +d7 d5 +d2 d3 +1 +d2 d3 +e8 g8 +0 +e8 g8 +d3 a6 +1 +d3 a6 +b7 a6 +0 +b7 a6 +e2 e4 +1 +e2 e4 +d5 e4 +0 +d5 e4 +f1 e2 +1 +f1 e2 +g4 e5 +0 +g4 e5 +e1 d1 +1 +e1 d1 +c8 f5 +0 +c8 f5 +e2 a6 +1 +e2 a6 +f5 g4 +0 +f5 g4 +g5 f3 +1 +g5 f3 +g4 f3 +0 +g4 f3 +d1 d2 +1 +d1 d2 +f3 h1 +0 +f3 h1 +c2 c3 +1 +c2 c3 +d8 g5 +0 +d8 g5 +d2 c2 +1 +d2 c2 +d4 d3 +0 +d4 d3 +a6 d3 +1 +a6 d3 +e4 d3 +0 +e4 d3 +c2 b1 +1 +c2 b1 +g5 f5 +0 +g5 f5 +a2 a4 +1 +a2 a4 +f5 f2 +0 +f5 f2 +b1 a2 +1 +b1 a2 +f2 h2 +0 +f2 h2 +a2 b1 +1 +a2 b1 +h2 c2 +0 +h2 c2 +b1 a2 +1 +b1 a2 +c2 a4 +0 +c2 a4 +a2 b1 +1 +a2 b1 +a4 c2 +0 +a4 c2 +b1 a2 +1 +b1 a2 +h1 d5 +0 +h1 d5 +a2 a3 +1 +a2 a3 +c2 b3 +-1 +1 \ No newline at end of file