mirror of
https://codeberg.org/ashley/poke
synced 2025-05-30 02:59:43 +00:00
Update html/gamehub.ejs
This commit is contained in:
parent
38094732ba
commit
efe0f7d758
329
html/gamehub.ejs
329
html/gamehub.ejs
@ -59,60 +59,142 @@
|
|||||||
--bg-start: #2c3e50;
|
--bg-start: #2c3e50;
|
||||||
--bg-end: #34495e;
|
--bg-end: #34495e;
|
||||||
--accent: #ffabcc;
|
--accent: #ffabcc;
|
||||||
--card-bg: rgba(255,255,255,0.1);
|
|
||||||
--card-hover: rgba(255,255,255,0.2);
|
|
||||||
--font-main: 'PokeTube Flex', sans-serif;
|
--font-main: 'PokeTube Flex', sans-serif;
|
||||||
|
--card-bg: rgba(255,255,255,0.1);
|
||||||
|
--card-border: rgba(255,255,255,0.6);
|
||||||
|
--card-hover: rgba(255,255,255,0.3);
|
||||||
}
|
}
|
||||||
* { box-sizing: border-box; margin:0; padding:0; }
|
* { box-sizing: border-box; margin:0; padding:0; }
|
||||||
body {
|
body {
|
||||||
font-family: var(--font-main);
|
font-family: var(--font-main);
|
||||||
background: linear-gradient(135deg, var(--bg-start), var(--bg-end));
|
background: linear-gradient(135deg, var(--bg-start), var(--bg-end));
|
||||||
color: #fff;
|
color: #fff;
|
||||||
display:flex; align-items:center; justify-content:center;
|
overflow: hidden;
|
||||||
min-height:100vh;
|
|
||||||
}
|
}
|
||||||
h1 {
|
|
||||||
font-weight:900; font-stretch:ultra-expanded; font-style:italic;
|
|
||||||
color: var(--accent); text-align:center; margin-bottom:1rem;
|
|
||||||
}
|
|
||||||
.game-container {
|
|
||||||
display:grid; grid-template-columns:repeat(auto-fit,minmax(240px,1fr));
|
|
||||||
gap:1rem; width:90%; max-width:1000px;
|
|
||||||
}
|
|
||||||
.game {
|
|
||||||
background: var(--card-bg);
|
|
||||||
border:2px solid #fff; border-radius:10px;
|
|
||||||
text-decoration:none; color:#fff; padding:1rem;
|
|
||||||
text-align:center; transition:background .3s;
|
|
||||||
}
|
|
||||||
.game:hover { background: var(--card-hover); }
|
|
||||||
.game h2 { margin-bottom: .5rem; }
|
|
||||||
canvas, .board { display:none; }
|
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: var(--font-main);
|
font-family: var(--font-main);
|
||||||
src: url("https://p.poketube.fun/.../robotoflex.ttf");
|
src: url("https://p.poketube.fun/.../robotoflex.ttf");
|
||||||
font-display: swap;
|
font-display: swap;
|
||||||
}
|
}
|
||||||
|
/* Animated emoji background */
|
||||||
|
.emoji-bg {
|
||||||
|
position: fixed;
|
||||||
|
top: 0; left: 0;
|
||||||
|
width: 100%; height: 100%;
|
||||||
|
pointer-events: none;
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
align-content: start;
|
||||||
|
font-size: 2rem;
|
||||||
|
}
|
||||||
|
.emoji-bg span {
|
||||||
|
margin: 0.5rem;
|
||||||
|
opacity: 0.15;
|
||||||
|
animation: float 8s ease-in-out infinite alternate;
|
||||||
|
}
|
||||||
|
@keyframes float {
|
||||||
|
to { transform: translateY(-20px) rotate(10deg); }
|
||||||
|
}
|
||||||
|
/* Main content wrapper */
|
||||||
|
.wrapper {
|
||||||
|
position: relative;
|
||||||
|
z-index: 1;
|
||||||
|
max-width: 1000px;
|
||||||
|
margin: 2rem auto;
|
||||||
|
padding: 2rem;
|
||||||
|
background: var(--card-bg);
|
||||||
|
border-radius: 15px;
|
||||||
|
border: 2px solid var(--card-border);
|
||||||
|
box-shadow: 0 8px 32px rgba(0,0,0,0.4);
|
||||||
|
backdrop-filter: blur(10px);
|
||||||
|
}
|
||||||
|
h1 {
|
||||||
|
font-weight: 900;
|
||||||
|
font-stretch: ultra-expanded;
|
||||||
|
font-style: italic;
|
||||||
|
color: var(--accent);
|
||||||
|
text-align: center;
|
||||||
|
font-size: 3rem;
|
||||||
|
margin-bottom: 1.5rem;
|
||||||
|
text-shadow: 2px 2px 8px rgba(0,0,0,0.7);
|
||||||
|
}
|
||||||
|
.game-container {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
|
||||||
|
gap: 1rem;
|
||||||
|
}
|
||||||
|
.game {
|
||||||
|
background: rgba(255,255,255,0.2);
|
||||||
|
border: 2px solid var(--card-border);
|
||||||
|
border-radius: 12px;
|
||||||
|
text-decoration: none;
|
||||||
|
color: #fff;
|
||||||
|
padding: 1.5rem 1rem;
|
||||||
|
text-align: center;
|
||||||
|
transition: transform 0.2s, background 0.3s;
|
||||||
|
}
|
||||||
|
.game:hover {
|
||||||
|
background: var(--card-hover);
|
||||||
|
transform: scale(1.05);
|
||||||
|
}
|
||||||
|
.game h2 {
|
||||||
|
margin-bottom: 0.75rem;
|
||||||
|
font-size: 1.5rem;
|
||||||
|
text-shadow: 1px 1px 4px rgba(0,0,0,0.7);
|
||||||
|
}
|
||||||
|
/* Hide canvas and boards until active */
|
||||||
|
canvas, .board { display: none; }
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div>
|
<div class="emoji-bg">
|
||||||
|
<span>🎮</span><span>🕹️</span><span>👾</span><span>🎧</span><span>🖥️</span>
|
||||||
|
<span>🎲</span><span>🏆</span><span>🎯</span><span>🔥</span><span>💥</span>
|
||||||
|
<span>🧩</span><span>🎮</span><span>🕹️</span><span>👾</span><span>🎧</span>
|
||||||
|
<span>🖥️</span><span>🎲</span><span>🏆</span><span>🎯</span><span>🔥</span>
|
||||||
|
<span>💥</span><span>🧩</span><span>🎮</span><span>🕹️</span><span>👾</span>
|
||||||
|
<span>🎧</span><span>🖥️</span><span>🎲</span><span>🏆</span><span>🎯</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- main hub -->
|
||||||
|
<div class="wrapper">
|
||||||
<h1>Poke! Games Hub</h1>
|
<h1>Poke! Games Hub</h1>
|
||||||
<div class="game-container">
|
<div class="game-container">
|
||||||
<a href="?game=snake" class="game"><h2>Snake</h2><canvas id="snakeCanvas"></canvas></a>
|
<a href="?game=snake" class="game">
|
||||||
<a href="?game=tic-tac-toe" class="game"><h2>Tic-Tac-Toe</h2><div id="message"></div><div class="board" id="board"></div></a>
|
<h2>Snake</h2>
|
||||||
<a href="?game=sudoku" class="game"><h2>Sudoku</h2><div class="board" id="sudokuBoard"></div></a>
|
<canvas id="snakeCanvas"></canvas>
|
||||||
<a href="?game=pong" class="game"><h2>Ping-Pong</h2><canvas id="pongCanvas"></canvas></a>
|
</a>
|
||||||
<a href="?game=minesweeper" class="game"><h2>Minesweeper</h2><div class="board" id="minesweeperBoard"></div></a>
|
<a href="?game=tic-tac-toe" class="game">
|
||||||
<a href="?game=breakout" class="game"><h2>Breakout</h2><canvas id="breakoutCanvas"></canvas></a>
|
<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 class="board" id="sudokuBoard"></div>
|
||||||
|
</a>
|
||||||
|
<a href="?game=pong" class="game">
|
||||||
|
<h2>Ping-Pong</h2>
|
||||||
|
<canvas id="pongCanvas"></canvas>
|
||||||
|
</a>
|
||||||
|
<a href="?game=minesweeper" class="game">
|
||||||
|
<h2>Minesweeper</h2>
|
||||||
|
<div class="board" id="minesweeperBoard"></div>
|
||||||
|
</a>
|
||||||
|
<a href="?game=breakout" class="game">
|
||||||
|
<h2>Breakout</h2>
|
||||||
|
<canvas id="breakoutCanvas"></canvas>
|
||||||
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script src="/static/data-mobile.js?v=6000"></script>
|
<script src="/static/data-mobile.js?v=6000"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
<% } %>
|
<% } %>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<% if (game === "snake") { %>
|
<% if (game === "snake") { %>
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
@ -213,93 +295,144 @@
|
|||||||
<div id="board"></div>
|
<div id="board"></div>
|
||||||
</div>
|
</div>
|
||||||
<script>
|
<script>
|
||||||
// GPL header omitted—see top of file
|
const boardElement = document.getElementById("board");
|
||||||
const boardEl = document.getElementById('board');
|
const messageElement = document.getElementById("message");
|
||||||
const msgEl = document.getElementById('message');
|
let currentPlayer = "X";
|
||||||
|
let board = ["", "", "", "", "", "", "", "", ""];
|
||||||
|
|
||||||
let board = Array(9).fill('');
|
function checkWinner() {
|
||||||
let currentPlayer = 'X';
|
const winningCombinations = [
|
||||||
|
[0, 1, 2], [3, 4, 5], [6, 7, 8], // Rows
|
||||||
function checkWin() {
|
[0, 3, 6], [1, 4, 7], [2, 5, 8], // Columns
|
||||||
const lines = [
|
[0, 4, 8], [2, 4, 6] // Diagonals
|
||||||
[0,1,2],[3,4,5],[6,7,8],
|
|
||||||
[0,3,6],[1,4,7],[2,5,8],
|
|
||||||
[0,4,8],[2,4,6]
|
|
||||||
];
|
];
|
||||||
return lines.some(l => l.every(i => board[i] && board[i] === board[l[0]]));
|
|
||||||
|
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() {
|
function checkDraw() {
|
||||||
return board.every(cell => cell);
|
return !board.includes("");
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleClick(index) {
|
||||||
|
if (board[index] === "" && !checkWinner() && !checkDraw()) {
|
||||||
|
board[index] = currentPlayer;
|
||||||
|
renderBoard();
|
||||||
|
const winner = checkWinner();
|
||||||
|
if (winner) {
|
||||||
|
messageElement.textContent = `Player ${winner} won!!!!!! woaah`;
|
||||||
|
} else if (checkDraw()) {
|
||||||
|
messageElement.textContent = "It's a draw! oh welp >~<";
|
||||||
|
} else {
|
||||||
|
currentPlayer = currentPlayer === "X" ? "O" : "X";
|
||||||
|
messageElement.textContent = `Player ${currentPlayer}'s turn :3`;
|
||||||
|
if (currentPlayer === "O") {
|
||||||
|
setTimeout(makeComputerMove, 500); // AI waits for 0.5 second
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function makeComputerMove() {
|
||||||
|
// Look for a winning move, then look to block player, otherwise, choose a random move
|
||||||
|
const winningMove = findWinningMove();
|
||||||
|
const blockingMove = findBlockingMove();
|
||||||
|
|
||||||
|
if (winningMove !== null) {
|
||||||
|
board[winningMove] = currentPlayer;
|
||||||
|
} else if (blockingMove !== null) {
|
||||||
|
board[blockingMove] = currentPlayer;
|
||||||
|
} else {
|
||||||
|
// 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} won!!!!!! woaah`;
|
||||||
|
} else if (checkDraw()) {
|
||||||
|
messageElement.textContent = "It's a draw! oh welp >~<";
|
||||||
|
} else {
|
||||||
|
currentPlayer = currentPlayer === "X" ? "O" : "X";
|
||||||
|
messageElement.textContent = `Player ${currentPlayer}'s turn :3`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function findWinningMove() {
|
||||||
|
for (let i = 0; i < board.length; i++) {
|
||||||
|
if (board[i] === "") {
|
||||||
|
board[i] = currentPlayer;
|
||||||
|
if (checkWinner() === currentPlayer) {
|
||||||
|
board[i] = ""; // Reset the move
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
board[i] = ""; // Reset the move
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function findBlockingMove() {
|
||||||
|
const opponent = currentPlayer === "X" ? "O" : "X";
|
||||||
|
for (let i = 0; i < board.length; i++) {
|
||||||
|
if (board[i] === "") {
|
||||||
|
board[i] = opponent;
|
||||||
|
if (checkWinner() === opponent) {
|
||||||
|
board[i] = ""; // Reset the move
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
board[i] = ""; // Reset the move
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderBoard() {
|
function renderBoard() {
|
||||||
boardEl.innerHTML = '';
|
boardElement.innerHTML = "";
|
||||||
board.forEach((val, idx) => {
|
board.forEach((value, index) => {
|
||||||
const cell = document.createElement('div');
|
const cell = document.createElement("div");
|
||||||
cell.className = 'cell';
|
cell.classList.add("cell");
|
||||||
cell.textContent = val;
|
cell.textContent = value;
|
||||||
cell.onclick = () => handleMove(idx);
|
cell.addEventListener("click", () => handleClick(index));
|
||||||
boardEl.append(cell);
|
boardElement.appendChild(cell);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleMove(idx) {
|
function resetGame() {
|
||||||
if (board[idx] || checkWin() || checkDraw()) return;
|
currentPlayer = "X";
|
||||||
|
board = ["", "", "", "", "", "", "", "", ""];
|
||||||
board[idx] = currentPlayer;
|
messageElement.textContent = `Player ${currentPlayer}'s turn :3`;
|
||||||
renderBoard();
|
renderBoard();
|
||||||
|
|
||||||
if (checkWin()) {
|
// If AI is the starting player, make the first move
|
||||||
msgEl.textContent = `Player ${currentPlayer} won!!!!!! woaah`;
|
if (currentPlayer === "O") {
|
||||||
} else if (checkDraw()) {
|
setTimeout(makeComputerMove, 500); // AI waits for 0.5 second
|
||||||
msgEl.textContent = "It's a draw! oh welp >~<";
|
|
||||||
} else {
|
|
||||||
currentPlayer = currentPlayer === 'X' ? 'O' : 'X';
|
|
||||||
msgEl.textContent = `Player ${currentPlayer}’s turn :3`;
|
|
||||||
|
|
||||||
if (currentPlayer === 'O') {
|
|
||||||
setTimeout(aiMove, 300);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function aiMove() {
|
// Initial setup
|
||||||
// 1) Try to win
|
resetGame();
|
||||||
for (let i = 0; i < 9; i++) {
|
|
||||||
if (!board[i]) {
|
|
||||||
board[i] = 'O';
|
|
||||||
if (checkWin()) {
|
|
||||||
handleMove(i);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
board[i] = '';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 2) Block X
|
|
||||||
for (let i = 0; i < 9; i++) {
|
|
||||||
if (!board[i]) {
|
|
||||||
board[i] = 'X';
|
|
||||||
if (checkWin()) {
|
|
||||||
board[i] = 'O';
|
|
||||||
handleMove(i);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
board[i] = '';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 3) Random
|
|
||||||
const empties = board
|
|
||||||
.map((v,i) => v === '' ? i : null)
|
|
||||||
.filter(i => i !== null);
|
|
||||||
const choice = empties[Math.floor(Math.random() * empties.length)];
|
|
||||||
handleMove(choice);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Initial render
|
|
||||||
renderBoard();
|
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
<% } %>
|
<% } %>
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user