mirror of
				https://codeberg.org/ashley/poke
				synced 2025-07-17 16:52:11 +00:00 
			
		
		
		
	add games hub
This commit is contained in:
		
							parent
							
								
									64a19da8c4
								
							
						
					
					
						commit
						9fe5ad8725
					
				
							
								
								
									
										884
									
								
								html/gamehub.ejs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										884
									
								
								html/gamehub.ejs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,884 @@ | ||||
| 
 | ||||
| <% if (!game) { %>  | ||||
| 
 | ||||
| <!DOCTYPE html> | ||||
| <html lang="en"> | ||||
| <head> | ||||
|   <meta charset="UTF-8"> | ||||
|   <link href="/css/yt-ukraine.svg?v=3" rel=icon> | ||||
|   <link rel="manifest" href="/manifest.json"> | ||||
|   <meta content="▶▶ Poke Games" property=og:title> | ||||
|   <meta content="Play games on poke!" property=twitter:description> | ||||
|  <meta content="https://cdn.glitch.global/d68d17bb-f2c0-4bc3-993f-50902734f652/aa70111e-5bcd-4379-8b23-332a33012b78.image.png?v=1701898829884" property="og:image"  /> | ||||
|   <meta content="summary_large_image" name="twitter:card" /> | ||||
|   <meta name="viewport" content="width=device-width, initial-scale=1.0"> | ||||
|   <style> | ||||
|     body { | ||||
|       margin: 0; | ||||
|       font-family: 'Arial', sans-serif; | ||||
|       display: flex; | ||||
|       align-items: center; | ||||
|       justify-content: center; | ||||
|       min-height: 100vh; | ||||
|       background: linear-gradient(135deg, #2c3e50, #34495e); | ||||
|       color: #fff; | ||||
|     } | ||||
| 
 | ||||
|     .container { | ||||
|       text-align: center; | ||||
|       padding: 20px; | ||||
|     } | ||||
| 
 | ||||
|     h1 { | ||||
|       margin-top: 0; | ||||
|     } | ||||
| 
 | ||||
|     .game-container { | ||||
|       display: flex; | ||||
|       gap: 20px; | ||||
|       justify-content: center; | ||||
|       flex-wrap: wrap; | ||||
|     } | ||||
| 
 | ||||
|     .game { | ||||
|       flex: 0 0 300px; | ||||
|       padding: 20px; | ||||
|       border: 2px solid #fff; | ||||
|       border-radius: 10px; | ||||
|       background: rgba(255, 255, 255, 0.1); | ||||
|       transition: background 0.3s ease; | ||||
|       text-decoration: none; | ||||
|       color: #fff; | ||||
|       display: flex; | ||||
|       flex-direction: column; | ||||
|       align-items: center; | ||||
|     } | ||||
| 
 | ||||
|     .game:hover { | ||||
|       background: rgba(255, 255, 255, 0.2); | ||||
|     } | ||||
| 
 | ||||
|     canvas { | ||||
|       border: 1px solid #fff; | ||||
|       visibility: collapse; | ||||
|     } | ||||
| 
 | ||||
|     .board { | ||||
|       display: grid; | ||||
|       grid-template-columns: repeat(3, 100px); | ||||
|       grid-gap: 5px; | ||||
|       margin-top: 20px; | ||||
|     } | ||||
| 
 | ||||
|     .cell { | ||||
|       width: 100px; | ||||
|       height: 100px; | ||||
|       border: 1px solid #fff; | ||||
|       font-size: 2em; | ||||
|       cursor: pointer; | ||||
|     } | ||||
|   </style> | ||||
|   <title>Games Hub</title> | ||||
| </head> | ||||
| <body> | ||||
|   <div class="container"> | ||||
|     <h1>Poke! Games Hub</h1> | ||||
|      | ||||
|     <div class="game-container"> | ||||
|       <a href="?game=snake" class="game"> | ||||
|         <h2>Snake</h2> | ||||
|         <canvas id="snakeCanvas"></canvas> | ||||
|       </a> | ||||
| 
 | ||||
|       <a href="?game=tic-tac-toe" class="game"> | ||||
|         <h2>Tic-Tac-Toe</h2> | ||||
|         <div id="message"></div> | ||||
|         <div class="board" id="board"></div> | ||||
|       </a> | ||||
| 
 | ||||
|       <a href="?game=sudoku" class="game"> | ||||
|         <h2>Sudoku</h2> | ||||
|         <div id="sudokuMessage"></div> | ||||
|         <div class="board" id="sudokuBoard"></div> | ||||
|       </a> | ||||
| 
 | ||||
|       <a href="?game=pong" class="game"> | ||||
|         <h2>Ping-Pong</h2> | ||||
|         <div id="pingPongMessage"></div> | ||||
|         <div class="board" id="pingPongBoard"></div> | ||||
|       </a> | ||||
|     </div> | ||||
|   </div> | ||||
| </body> | ||||
| </html> | ||||
|                                              		 	               <% } %>    | ||||
| <% if (game === "snake") { %>  | ||||
|   <!DOCTYPE html> | ||||
| <html lang="en"> | ||||
| <head> | ||||
|   <link href="/css/yt-ukraine.svg?v=3" rel=icon> | ||||
|   <meta charset="UTF-8"> | ||||
|   <meta name="viewport" content="width=device-width, initial-scale=1.0"> | ||||
|   <style> | ||||
|     html, body { | ||||
|       height: 100%; | ||||
|       margin: 0; | ||||
|       overflow: hidden; | ||||
|     } | ||||
|     canvas { | ||||
|       border: 1px solid #000; | ||||
|       display: block; | ||||
|       position: absolute; | ||||
|     } | ||||
|   </style> | ||||
|   <title>Snake</title> | ||||
| </head> | ||||
| <body> | ||||
|   <canvas id="snakeCanvas" width="400" height="400"></canvas> | ||||
|  <script type="text/javascript"> | ||||
| <!--//--><![CDATA[//><!-- | ||||
| /** | ||||
|  * @licstart The following is the entire license notice for the JavaScript | ||||
|  * code in this page. | ||||
|  * | ||||
|  *  Copyright (C) 2021-2024 POKETUBE (https://codeberg.org/Ashley/poketube) | ||||
|  * | ||||
|  * The JavaScript code in this page is free software: you can redistribute | ||||
|  * it and/or modify it under the terms of the GNU General Public License | ||||
|  * (GNU GPL) as published by the Free Software Foundation, either version 3 | ||||
|  * of the License, or (at your option) any later version.  The code is | ||||
|  * distributed WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU GPL | ||||
|  * for more details. | ||||
|  * | ||||
|  * As additional permission under GNU GPL version 3 section 7, you may | ||||
|  * distribute non-source (e.g., minimized or compacted) forms of that code | ||||
|  * without the copy of the GNU GPL normally required by section 4, provided | ||||
|  * you include this license notice and a URL through which recipients can | ||||
|  * access the Corresponding Source. | ||||
|  * | ||||
|  * @licend The above is the entire license notice for the JavaScript code | ||||
|  * in this page. | ||||
|  */ | ||||
| 
 | ||||
| //--><!]]> | ||||
| </script> | ||||
|   <script> | ||||
|     const canvas = document.getElementById("snakeCanvas"); | ||||
|     const ctx = canvas.getContext("2d"); | ||||
|     canvas.width = window.innerWidth; | ||||
|     canvas.height = window.innerHeight; | ||||
|     // Initial snake position and size | ||||
|     let snake = [ | ||||
|   { x: canvas.width / 2, y: canvas.height / 2 }, | ||||
|   { x: canvas.width / 2, y: canvas.height / 2 + 10 }, | ||||
|   { x: canvas.width / 2, y: canvas.height / 2 + 20 } | ||||
| ]; | ||||
| 
 | ||||
| 
 | ||||
|     let direction = "down"; // Initial direction | ||||
| 
 | ||||
|     // Initial food position | ||||
|     let food = { x: 200, y: 200 }; | ||||
| 
 | ||||
|     function draw() { | ||||
|       // Clear the canvas | ||||
|       ctx.clearRect(0, 0, canvas.width, canvas.height); | ||||
| 
 | ||||
|       // Draw the snake | ||||
|       ctx.fillStyle = "#00F"; | ||||
|       snake.forEach(segment => { | ||||
|         ctx.fillRect(segment.x, segment.y, 10, 10); | ||||
|       }); | ||||
| 
 | ||||
|       // Draw the food | ||||
|       ctx.fillStyle = "#F00"; | ||||
|       ctx.fillRect(food.x, food.y, 10, 10); | ||||
|     } | ||||
| 
 | ||||
|     function move() { | ||||
|       const head = { ...snake[0] }; // Create a new object for the head | ||||
| 
 | ||||
|       // Move the head based on the direction | ||||
|       if (direction === "up") head.y -= 10; | ||||
|       else if (direction === "down") head.y += 10; | ||||
|       else if (direction === "left") head.x -= 10; | ||||
|       else if (direction === "right") head.x += 10; | ||||
| 
 | ||||
|       // Add the new head to the front of the snake | ||||
|       snake.unshift(head); | ||||
| 
 | ||||
|       // Check if the snake has eaten the food | ||||
|       if (head.x === food.x && head.y === food.y) { | ||||
|         // Generate new food | ||||
|         food.x = Math.floor(Math.random() * (canvas.width / 10)) * 10; | ||||
|         food.y = Math.floor(Math.random() * (canvas.height / 10)) * 10; | ||||
|       } else { | ||||
|         // If not eaten, remove the tail | ||||
|         snake.pop(); | ||||
|       } | ||||
|     } | ||||
| function checkCollision() { | ||||
|   const head = snake[0]; | ||||
| 
 | ||||
|   // Check if the snake hits the walls | ||||
|   if (head.x < 0 || head.x >= canvas.width || head.y < 0 || head.y >= canvas.height) { | ||||
|     alert("Game Over!"); | ||||
|     resetGame(); | ||||
|   } | ||||
| 
 | ||||
|   // Check if the snake collides with itself | ||||
|   for (let i = 1; i < snake.length; i++) { | ||||
|     if (head.x === snake[i].x && head.y === snake[i].y) { | ||||
|        resetGame(); | ||||
|     } | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| function resetGame() { | ||||
|   const middleX = Math.floor(canvas.width / 2 / 10) * 10; | ||||
|   const middleY = Math.floor(canvas.height / 2 / 10) * 10; | ||||
| 
 | ||||
|   snake = [ | ||||
|     { x: middleX, y: middleY }, | ||||
|     { x: middleX, y: middleY + 10 }, | ||||
|     { x: middleX, y: middleY + 20 } | ||||
|   ]; | ||||
| 
 | ||||
|   direction = "down"; | ||||
| 
 | ||||
|   food = { x: 200, y: 200 }; | ||||
| } | ||||
| 
 | ||||
|     function gameLoop() { | ||||
|       move(); | ||||
|       checkCollision(); | ||||
|       draw(); | ||||
|     } | ||||
| 
 | ||||
|     // Set up keyboard event listeners | ||||
|     window.addEventListener("keydown", e => { | ||||
|       if (e.key === "ArrowUp" && direction !== "down") { | ||||
|         direction = "up"; | ||||
|       } else if (e.key === "ArrowDown" && direction !== "up") { | ||||
|         direction = "down"; | ||||
|       } else if (e.key === "ArrowLeft" && direction !== "right") { | ||||
|         direction = "left"; | ||||
|       } else if (e.key === "ArrowRight" && direction !== "left") { | ||||
|         direction = "right"; | ||||
|       } | ||||
|     }); | ||||
| 
 | ||||
|     // Set up the game loop | ||||
|     setInterval(gameLoop, 100); | ||||
|   </script> | ||||
| </body> | ||||
| </html> | ||||
| 
 | ||||
|                                              		 	               <% } %>    | ||||
| <% if (game === "tic-tac-toe") { %>  | ||||
| <!DOCTYPE html> | ||||
| <html lang="en"> | ||||
| <head> | ||||
|   <meta charset="UTF-8"> | ||||
|   <link href="/css/yt-ukraine.svg?v=3" rel=icon> | ||||
|   <meta name="viewport" content="width=device-width, initial-scale=1.0"> | ||||
|   <style> | ||||
|     body { | ||||
|       font-family: Arial, sans-serif; | ||||
|       text-align: center; | ||||
|       display: flex; | ||||
|       align-items: center; | ||||
|       justify-content: center; | ||||
|       height: 100vh; | ||||
|       margin: 0; | ||||
|     } | ||||
|     .container { | ||||
|       text-align: left; | ||||
|       margin-top: 20px; | ||||
|       margin-left: 20px; | ||||
|     } | ||||
|     .board { | ||||
|       display: grid; | ||||
|       grid-template-columns: repeat(3, 100px); | ||||
|       grid-gap: 5px; | ||||
|       margin: 20px auto; | ||||
|     } | ||||
|     .cell { | ||||
|       width: 100px; | ||||
|       height: 100px; | ||||
|       border: 1px solid #ccc; | ||||
|       font-size: 2em; | ||||
|       cursor: pointer; | ||||
|     } | ||||
|   </style> | ||||
|   <title>Tic-Tac-Toe</title> | ||||
| </head> | ||||
| <body> | ||||
|   <div class="container"> | ||||
|     <h1>Tic-Tac-Toe</h1> | ||||
|     <div id="message"></div> | ||||
|     <div class="board" id="board"></div> | ||||
|   </div> | ||||
|   <script type="text/javascript"> | ||||
| <!--//--><![CDATA[//><!-- | ||||
| /** | ||||
|  * @licstart The following is the entire license notice for the JavaScript | ||||
|  * code in this page. | ||||
|  * | ||||
|  *  Copyright (C) 2021-2024 POKETUBE (https://codeberg.org/Ashley/poketube) | ||||
|  * | ||||
|  * The JavaScript code in this page is free software: you can redistribute | ||||
|  * it and/or modify it under the terms of the GNU General Public License | ||||
|  * (GNU GPL) as published by the Free Software Foundation, either version 3 | ||||
|  * of the License, or (at your option) any later version.  The code is | ||||
|  * distributed WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU GPL | ||||
|  * for more details. | ||||
|  * | ||||
|  * As additional permission under GNU GPL version 3 section 7, you may | ||||
|  * distribute non-source (e.g., minimized or compacted) forms of that code | ||||
|  * without the copy of the GNU GPL normally required by section 4, provided | ||||
|  * you include this license notice and a URL through which recipients can | ||||
|  * access the Corresponding Source. | ||||
|  * | ||||
|  * @licend The above is the entire license notice for the JavaScript code | ||||
|  * in this page. | ||||
|  */ | ||||
| 
 | ||||
| //--><!]]> | ||||
| </script> | ||||
|   <script> | ||||
|     const boardElement = document.getElementById("board"); | ||||
|     const messageElement = document.getElementById("message"); | ||||
|     let currentPlayer = "X"; | ||||
|     let board = ["", "", "", "", "", "", "", "", ""]; | ||||
| 
 | ||||
|     function checkWinner() { | ||||
|       const winningCombinations = [ | ||||
|         [0, 1, 2], [3, 4, 5], [6, 7, 8], // Rows | ||||
|         [0, 3, 6], [1, 4, 7], [2, 5, 8], // Columns | ||||
|         [0, 4, 8], [2, 4, 6]             // Diagonals | ||||
|       ]; | ||||
| 
 | ||||
|       for (const combination of winningCombinations) { | ||||
|         const [a, b, c] = combination; | ||||
|         if (board[a] && board[a] === board[b] && board[a] === board[c]) { | ||||
|           return board[a]; | ||||
|         } | ||||
|       } | ||||
| 
 | ||||
|       return null; | ||||
|     } | ||||
| 
 | ||||
|     function checkDraw() { | ||||
|       return !board.includes(""); | ||||
|     } | ||||
| 
 | ||||
|     function handleClick(index) { | ||||
|       if (board[index] === "" && !checkWinner() && !checkDraw()) { | ||||
|         board[index] = currentPlayer; | ||||
|         renderBoard(); | ||||
|         const winner = checkWinner(); | ||||
|         if (winner) { | ||||
|           messageElement.textContent = `Player ${winner} wins!`; | ||||
|         } else if (checkDraw()) { | ||||
|           messageElement.textContent = "It's a draw!"; | ||||
|         } else { | ||||
|           currentPlayer = currentPlayer === "X" ? "O" : "X"; | ||||
|           messageElement.textContent = `Player ${currentPlayer}'s turn`; | ||||
|           if (currentPlayer === "O") { | ||||
|             setTimeout(makeComputerMove, 1000); // AI waits for 1 second | ||||
|           } | ||||
|         } | ||||
|       } | ||||
|     } | ||||
| 
 | ||||
|     function makeComputerMove() { | ||||
|       // Simple AI: Randomly choose an empty cell for the computer's move | ||||
|       const emptyCells = board.reduce((acc, value, index) => { | ||||
|         if (value === "") { | ||||
|           acc.push(index); | ||||
|         } | ||||
|         return acc; | ||||
|       }, []); | ||||
| 
 | ||||
|       if (emptyCells.length > 0) { | ||||
|         const randomIndex = Math.floor(Math.random() * emptyCells.length); | ||||
|         const computerMove = emptyCells[randomIndex]; | ||||
|         board[computerMove] = currentPlayer; | ||||
|         renderBoard(); | ||||
|         const winner = checkWinner(); | ||||
|         if (winner) { | ||||
|           messageElement.textContent = `Player ${winner} wins!`; | ||||
|         } else if (checkDraw()) { | ||||
|           messageElement.textContent = "It's a draw!"; | ||||
|         } else { | ||||
|           currentPlayer = currentPlayer === "X" ? "O" : "X"; | ||||
|           messageElement.textContent = `Player ${currentPlayer}'s turn`; | ||||
|         } | ||||
|       } | ||||
|     } | ||||
| 
 | ||||
|     function renderBoard() { | ||||
|       boardElement.innerHTML = ""; | ||||
|       board.forEach((value, index) => { | ||||
|         const cell = document.createElement("div"); | ||||
|         cell.classList.add("cell"); | ||||
|         cell.textContent = value; | ||||
|         cell.addEventListener("click", () => handleClick(index)); | ||||
|         boardElement.appendChild(cell); | ||||
|       }); | ||||
|     } | ||||
| 
 | ||||
|     function resetGame() { | ||||
|       currentPlayer = "X"; | ||||
|       board = ["", "", "", "", "", "", "", "", ""]; | ||||
|       messageElement.textContent = `Player ${currentPlayer}'s turn`; | ||||
|       renderBoard(); | ||||
| 
 | ||||
|       // If AI is the starting player, make the first move | ||||
|       if (currentPlayer === "O") { | ||||
|         setTimeout(makeComputerMove, 1000); // AI waits for 1 second | ||||
|       } | ||||
|     } | ||||
| 
 | ||||
|     // Initial setup | ||||
|     resetGame(); | ||||
|   </script> | ||||
| </body> | ||||
| </html> | ||||
| 
 | ||||
| 
 | ||||
|                                              		 	               <% } %>    | ||||
| <% if (game === "pong") { %>  | ||||
|   <!DOCTYPE html> | ||||
| <html lang="en"> | ||||
| <head> | ||||
|   <meta charset="UTF-8"> | ||||
|   <link href="/css/yt-ukraine.svg?v=3" rel=icon> | ||||
|   <meta name="viewport" content="width=device-width, initial-scale=1.0"> | ||||
|   <style> | ||||
|     body { | ||||
|       margin: 0; | ||||
|       display: flex; | ||||
|       flex-direction: column; | ||||
|       align-items: center; | ||||
|       justify-content: space-between; | ||||
|       height: 100vh; | ||||
|       background: #000; | ||||
|       color: #fff; | ||||
|       font-family: 'Arial', sans-serif; | ||||
|     } | ||||
| 
 | ||||
|     canvas { | ||||
|       border: 1px solid #fff; | ||||
|     } | ||||
| 
 | ||||
|     #controls { | ||||
|       margin-bottom: 20px; | ||||
|     } | ||||
| 
 | ||||
|     #score { | ||||
|       position: absolute; | ||||
|       top: 10px; | ||||
|       left: 10px; | ||||
|     } | ||||
|   </style> | ||||
|   <title>Pong</title> | ||||
| </head> | ||||
| <body> | ||||
|   <canvas id="pongCanvas" width="800" height="400"></canvas> | ||||
|   <div id="controls"> | ||||
|     <p> | ||||
|        Press space to start | ||||
|     </p> | ||||
|     <p>Left Paddle Controls: W (Up) and S (Down)</p> | ||||
|     <p>Right Paddle Controls: Arrow Up (Up) and Arrow Down (Down)</p> | ||||
|   </div> | ||||
|   <script type="text/javascript"> | ||||
| <!--//--><![CDATA[//><!-- | ||||
| /** | ||||
|  * @licstart The following is the entire license notice for the JavaScript | ||||
|  * code in this page. | ||||
|  * | ||||
|  *  Copyright (C) 2021-2024 POKETUBE (https://codeberg.org/Ashley/poketube) | ||||
|  * | ||||
|  * The JavaScript code in this page is free software: you can redistribute | ||||
|  * it and/or modify it under the terms of the GNU General Public License | ||||
|  * (GNU GPL) as published by the Free Software Foundation, either version 3 | ||||
|  * of the License, or (at your option) any later version.  The code is | ||||
|  * distributed WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU GPL | ||||
|  * for more details. | ||||
|  * | ||||
|  * As additional permission under GNU GPL version 3 section 7, you may | ||||
|  * distribute non-source (e.g., minimized or compacted) forms of that code | ||||
|  * without the copy of the GNU GPL normally required by section 4, provided | ||||
|  * you include this license notice and a URL through which recipients can | ||||
|  * access the Corresponding Source. | ||||
|  * | ||||
|  * @licend The above is the entire license notice for the JavaScript code | ||||
|  * in this page. | ||||
|  */ | ||||
| 
 | ||||
| //--><!]]> | ||||
| </script> | ||||
|   <script> | ||||
|     const canvas = document.getElementById("pongCanvas"); | ||||
|     const ctx = canvas.getContext("2d"); | ||||
| 
 | ||||
|     const paddleWidth = 10; | ||||
|     const paddleHeight = 60; | ||||
|     const ballSize = 10; | ||||
|     const paddleSpeed = 5; | ||||
|     const maxScore = 5; // Adjust this to set the score threshold for game restart | ||||
| 
 | ||||
|     let leftPaddleY = canvas.height / 2 - paddleHeight / 2; | ||||
|     let rightPaddleY = canvas.height / 2 - paddleHeight / 2; | ||||
| 
 | ||||
|     let ballX = canvas.width / 2; | ||||
|     let ballY = canvas.height / 2; | ||||
|     let ballSpeedX = 0; | ||||
|     let ballSpeedY = 0; | ||||
| 
 | ||||
|     let leftScore = 0; | ||||
|     let rightScore = 0; | ||||
| 
 | ||||
|     let leftPaddleUp = false; | ||||
|     let leftPaddleDown = false; | ||||
|     let rightPaddleUp = false; | ||||
|     let rightPaddleDown = false; | ||||
| 
 | ||||
|     let gameActive = false; | ||||
| 
 | ||||
|     function drawPaddle(x, y) { | ||||
|       ctx.fillStyle = "#fff"; | ||||
|       ctx.fillRect(x, y, paddleWidth, paddleHeight); | ||||
|     } | ||||
| 
 | ||||
|     function drawBall() { | ||||
|       ctx.fillStyle = "#fff"; | ||||
|       ctx.beginPath(); | ||||
|       ctx.arc(ballX, ballY, ballSize, 0, Math.PI * 2); | ||||
|       ctx.fill(); | ||||
|     } | ||||
| 
 | ||||
|     function movePaddle() { | ||||
|       if (gameActive) { | ||||
|         document.addEventListener("keydown", function(event) { | ||||
|           switch (event.key) { | ||||
|             case "ArrowUp": | ||||
|               rightPaddleUp = true; | ||||
|               break; | ||||
|             case "ArrowDown": | ||||
|               rightPaddleDown = true; | ||||
|               break; | ||||
|             case "w": | ||||
|               leftPaddleUp = true; | ||||
|               break; | ||||
|             case "s": | ||||
|               leftPaddleDown = true; | ||||
|               break; | ||||
|           } | ||||
|         }); | ||||
| 
 | ||||
|         document.addEventListener("keyup", function(event) { | ||||
|           switch (event.key) { | ||||
|             case "ArrowUp": | ||||
|               rightPaddleUp = false; | ||||
|               break; | ||||
|             case "ArrowDown": | ||||
|               rightPaddleDown = false; | ||||
|               break; | ||||
|             case "w": | ||||
|               leftPaddleUp = false; | ||||
|               break; | ||||
|             case "s": | ||||
|               leftPaddleDown = false; | ||||
|               break; | ||||
|           } | ||||
|         }); | ||||
| 
 | ||||
|         if (leftPaddleUp && leftPaddleY > 0) leftPaddleY -= paddleSpeed; | ||||
|         if (leftPaddleDown && leftPaddleY < canvas.height - paddleHeight) leftPaddleY += paddleSpeed; | ||||
| 
 | ||||
|         if (rightPaddleUp && rightPaddleY > 0) rightPaddleY -= paddleSpeed; | ||||
|         if (rightPaddleDown && rightPaddleY < canvas.height - paddleHeight) rightPaddleY += paddleSpeed; | ||||
|       } | ||||
|     } | ||||
| 
 | ||||
|     function moveBall() { | ||||
|       if (gameActive) { | ||||
|         ballX += ballSpeedX; | ||||
|         ballY += ballSpeedY; | ||||
| 
 | ||||
|         // Ball hits top or bottom | ||||
|         if (ballY < 0 || ballY > canvas.height) { | ||||
|           ballSpeedY = -ballSpeedY; | ||||
|         } | ||||
| 
 | ||||
|         // Ball hits left paddle | ||||
|         if (ballX - ballSize < paddleWidth && ballY > leftPaddleY && ballY < leftPaddleY + paddleHeight) { | ||||
|           ballSpeedX = -ballSpeedX; | ||||
|         } | ||||
| 
 | ||||
|         // Ball hits right paddle | ||||
|         if (ballX + ballSize > canvas.width - paddleWidth && ballY > rightPaddleY && ballY < rightPaddleY + paddleHeight) { | ||||
|           ballSpeedX = -ballSpeedX; | ||||
|         } | ||||
| 
 | ||||
|         // Ball goes out of bounds | ||||
|         if (ballX < 0) { | ||||
|           // Right player scores | ||||
|           rightScore++; | ||||
|           checkGameOver(); | ||||
|         } | ||||
| 
 | ||||
|         if (ballX > canvas.width) { | ||||
|           // Left player scores | ||||
|           leftScore++; | ||||
|           checkGameOver(); | ||||
|         } | ||||
|       } | ||||
|     } | ||||
| 
 | ||||
|     function checkGameOver() { | ||||
|       if (leftScore >= maxScore || rightScore >= maxScore) { | ||||
|         resetGame(); | ||||
|       } else { | ||||
|         resetBall(); | ||||
|       } | ||||
|     } | ||||
| 
 | ||||
|     function resetGame() { | ||||
|       leftScore = 0; | ||||
|       rightScore = 0; | ||||
|       resetBall(); | ||||
|     } | ||||
| 
 | ||||
|     function resetBall() { | ||||
|       ballX = canvas.width / 2; | ||||
|       ballY = canvas.height / 2; | ||||
|       ballSpeedX = 0; | ||||
|       ballSpeedY = 0; | ||||
|       gameActive = false; | ||||
|       setTimeout(() => { | ||||
|         ballSpeedX = Math.random() > 0.5 ? 5 : -5; | ||||
|         ballSpeedY = Math.random() > 0.5 ? 5 : -5; | ||||
|         gameActive = true; | ||||
|       }, 1000); | ||||
|     } | ||||
| 
 | ||||
|     function update() { | ||||
|       ctx.clearRect(0, 0, canvas.width, canvas.height); | ||||
|       drawPaddle(0, leftPaddleY); | ||||
|       drawPaddle(canvas.width - paddleWidth, rightPaddleY); | ||||
|       drawBall(); | ||||
|       movePaddle(); | ||||
|       moveBall(); | ||||
|       drawScores(); | ||||
|       requestAnimationFrame(update); | ||||
|     } | ||||
| 
 | ||||
|     function drawScores() { | ||||
|       ctx.fillStyle = "#fff"; | ||||
|       ctx.font = "20px Arial"; | ||||
|       ctx.fillText("Left Player: " + leftScore, 20, 30); | ||||
|       ctx.fillText("Right Player: " + rightScore, canvas.width - 160, 30); | ||||
|     } | ||||
| 
 | ||||
|     document.addEventListener("keydown", function(event) { | ||||
|       if (!gameActive && event.key === " ") { | ||||
|         resetGame(); | ||||
|         ballSpeedX = Math.random() > 0.5 ? 5 : -5; | ||||
|         ballSpeedY = Math.random() > 0.5 ? 5 : -5; | ||||
|         gameActive = true; | ||||
|       } | ||||
|     }); | ||||
| 
 | ||||
|     update(); | ||||
|   </script> | ||||
| </body> | ||||
| </html> | ||||
| 
 | ||||
| 
 | ||||
|                                              		 	               <% } %>    | ||||
| <% if (game === "sudoku") { %>  | ||||
|   <!DOCTYPE html> | ||||
| <html lang="en"> | ||||
| <head> | ||||
|   <meta charset="UTF-8"> | ||||
|   <link href="/css/yt-ukraine.svg?v=3" rel=icon> | ||||
|   <meta name="viewport" content="width=device-width, initial-scale=1.0"> | ||||
|   <style> | ||||
|     body { | ||||
|       display: flex; | ||||
|       align-items: center; | ||||
|       justify-content: center; | ||||
|       height: 100vh; | ||||
|       margin: 0; | ||||
|       background-color: #f0f0f0; | ||||
|       font-family: 'Arial', sans-serif; | ||||
|     } | ||||
| 
 | ||||
|     #sudoku-board { | ||||
|       display: grid; | ||||
|       grid-template-columns: repeat(9, 40px); | ||||
|       grid-template-rows: repeat(9, 40px); | ||||
|       grid-gap: 1px; | ||||
|     } | ||||
| 
 | ||||
|     .cell { | ||||
|       display: flex; | ||||
|       align-items: center; | ||||
|       justify-content: center; | ||||
|       width: 40px; | ||||
|       height: 40px; | ||||
|       font-size: 16px; | ||||
|       font-weight: bold; | ||||
|       cursor: pointer; | ||||
|       background-color: #ddd; | ||||
|       user-select: none; | ||||
|     } | ||||
| 
 | ||||
|     .given { | ||||
|       background-color: #ccc; | ||||
|     } | ||||
| 
 | ||||
|     .error { | ||||
|       background-color: #ffbaba; | ||||
|     } | ||||
|   </style> | ||||
|   <title>Sudoku</title> | ||||
| </head> | ||||
| <body> | ||||
|   <div id="sudoku-board"></div> | ||||
|  <script type="text/javascript"> | ||||
| <!--//--><![CDATA[//><!-- | ||||
| /** | ||||
|  * @licstart The following is the entire license notice for the JavaScript | ||||
|  * code in this page. | ||||
|  * | ||||
|  *  Copyright (C) 2021-2024 POKETUBE (https://codeberg.org/Ashley/poketube) | ||||
|  * | ||||
|  * The JavaScript code in this page is free software: you can redistribute | ||||
|  * it and/or modify it under the terms of the GNU General Public License | ||||
|  * (GNU GPL) as published by the Free Software Foundation, either version 3 | ||||
|  * of the License, or (at your option) any later version.  The code is | ||||
|  * distributed WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU GPL | ||||
|  * for more details. | ||||
|  * | ||||
|  * As additional permission under GNU GPL version 3 section 7, you may | ||||
|  * distribute non-source (e.g., minimized or compacted) forms of that code | ||||
|  * without the copy of the GNU GPL normally required by section 4, provided | ||||
|  * you include this license notice and a URL through which recipients can | ||||
|  * access the Corresponding Source. | ||||
|  * | ||||
|  * @licend The above is the entire license notice for the JavaScript code | ||||
|  * in this page. | ||||
|  */ | ||||
| 
 | ||||
| //--><!]]> | ||||
| </script> | ||||
|   <script> | ||||
|     const board = [ | ||||
|       [5, 3, 0, 0, 7, 0, 0, 0, 0], | ||||
|       [6, 0, 0, 1, 9, 5, 0, 0, 0], | ||||
|       [0, 9, 8, 0, 0, 0, 0, 6, 0], | ||||
|       [8, 0, 0, 0, 6, 0, 0, 0, 3], | ||||
|       [4, 0, 0, 8, 0, 3, 0, 0, 1], | ||||
|       [7, 0, 0, 0, 2, 0, 0, 0, 6], | ||||
|       [0, 6, 0, 0, 0, 0, 2, 8, 0], | ||||
|       [0, 0, 0, 4, 1, 9, 0, 0, 5], | ||||
|       [0, 0, 0, 0, 8, 0, 0, 7, 9] | ||||
|     ]; | ||||
| 
 | ||||
|     function initializeBoard() { | ||||
|       const sudokuBoard = document.getElementById('sudoku-board'); | ||||
| 
 | ||||
|       for (let i = 0; i < 9; i++) { | ||||
|         for (let j = 0; j < 9; j++) { | ||||
|           const cell = document.createElement('div'); | ||||
|           cell.className = 'cell'; | ||||
|           cell.textContent = board[i][j] !== 0 ? board[i][j] : ''; | ||||
|           cell.dataset.row = i; | ||||
|           cell.dataset.col = j; | ||||
| 
 | ||||
|           if (board[i][j] !== 0) { | ||||
|             cell.classList.add('given'); | ||||
|           } | ||||
| 
 | ||||
|           cell.addEventListener('click', () => handleClick(i, j)); | ||||
|           sudokuBoard.appendChild(cell); | ||||
|         } | ||||
|       } | ||||
|     } | ||||
| 
 | ||||
|     function handleClick(row, col) { | ||||
|       const cell = document.querySelector(`.cell[data-row="${row}"][data-col="${col}"]`); | ||||
| 
 | ||||
|       if (!cell.classList.contains('given')) { | ||||
|         const value = prompt('Enter a number (1-9):'); | ||||
|         const parsedValue = parseInt(value, 10); | ||||
| 
 | ||||
|         if (!isNaN(parsedValue) && parsedValue >= 1 && parsedValue <= 9) { | ||||
|           board[row][col] = parsedValue; | ||||
|           cell.textContent = parsedValue; | ||||
| 
 | ||||
|           if (isBoardValid()) { | ||||
|             cell.classList.remove('error'); | ||||
|           } else { | ||||
|             cell.classList.add('error'); | ||||
|           } | ||||
|         } else { | ||||
|           alert('Invalid input. Please enter a number between 1 and 9.'); | ||||
|         } | ||||
|       } | ||||
|     } | ||||
| 
 | ||||
|     function isBoardValid() { | ||||
|       // Check rows and columns | ||||
|       for (let i = 0; i < 9; i++) { | ||||
|         const rowSet = new Set(); | ||||
|         const colSet = new Set(); | ||||
| 
 | ||||
|         for (let j = 0; j < 9; j++) { | ||||
|           if (board[i][j] !== 0 && rowSet.has(board[i][j])) { | ||||
|             return false; | ||||
|           } | ||||
|           rowSet.add(board[i][j]); | ||||
| 
 | ||||
|           if (board[j][i] !== 0 && colSet.has(board[j][i])) { | ||||
|             return false; | ||||
|           } | ||||
|           colSet.add(board[j][i]); | ||||
|         } | ||||
|       } | ||||
| 
 | ||||
|       // Check 3x3 subgrids | ||||
|       for (let i = 0; i < 9; i += 3) { | ||||
|         for (let j = 0; j < 9; j += 3) { | ||||
|           const subgridSet = new Set(); | ||||
| 
 | ||||
|           for (let row = i; row < i + 3; row++) { | ||||
|             for (let col = j; col < j + 3; col++) { | ||||
|               if (board[row][col] !== 0 && subgridSet.has(board[row][col])) { | ||||
|                 return false; | ||||
|               } | ||||
|               subgridSet.add(board[row][col]); | ||||
|             } | ||||
|           } | ||||
|         } | ||||
|       } | ||||
| 
 | ||||
|       return true; | ||||
|     } | ||||
| 
 | ||||
|     initializeBoard(); | ||||
|   </script> | ||||
| </body> | ||||
| </html> | ||||
| 
 | ||||
|                                              		 	               <% } %>    | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Ashley
						Ashley