博主闲得无聊,自己摸鱼做了一个游戏
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>三人四子棋</title> <style> * { margin: 0; padding: 0; box-sizing: border-box; } body { font-family: 'Microsoft YaHei', sans-serif; background: linear-gradient(135deg, #84fab0 0%, #8fd3f4 100%); min-height: 100vh; display: flex; flex-direction: column; align-items: center; padding: 10px; } header { text-align: center; margin-bottom: 15px; width: 100%; max-width: 500px; } .stats { background: rgba(255,255,255,0.9); padding: 10px 20px; border-radius: 20px; display: inline-block; margin-bottom: 10px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); } .stats span { margin: 0 10px; font-weight: bold; color: #2c3e50; } h1 { color: white; font-size: 2em; text-shadow: 2px 2px 4px rgba(0,0,0,0.2); } .players-info { display: flex; gap: 20px; margin-bottom: 15px; background: rgba(255,255,255,0.9); padding: 10px 20px; border-radius: 10px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); } .player { display: flex; align-items: center; gap: 8px; font-size: 0.9em; font-weight: bold; } .player-indicator { width: 25px; height: 25px; border-radius: 50%; transition: all 0.3s; } .player1 { background: linear-gradient(135deg, #667eea, #764ba2); } .player2 { background: linear-gradient(135deg, #f093fb, #f5576c); } .player3 { background: linear-gradient(135deg, #4facfe, #00f2fe); } .current-turn { transform: scale(1.3); box-shadow: 0 0 15px rgba(255,215,0,0.8); } main { background: rgba(255,255,255,0.95); padding: 15px; border-radius: 15px; box-shadow: 0 5px 20px rgba(0,0,0,0.1); max-width: 500px; width: 100%; } #board { display: grid; grid-template-columns: repeat(10, 1fr); gap: 2px; background: #34495e; padding: 8px; border-radius: 10px; aspect-ratio: 1; } .cell { background: #ecf0f1; cursor: pointer; position: relative; border-radius: 3px; aspect-ratio: 1; } .cell:hover:not(.occupied) { background: #bdc3c7; transform: scale(1.05); } .piece { width: 80%; height: 80%; border-radius: 50%; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); animation: dropIn 0.3s ease; box-shadow: 0 2px 4px rgba(0,0,0,0.3); } @keyframes dropIn { from { transform: translate(-50%, -50%) scale(0); opacity: 0; } to { transform: translate(-50%, -50%) scale(1); opacity: 1; } } .winning-piece { animation: pulse 1s infinite; } @keyframes pulse { 0%, 100% { transform: translate(-50%, -50%) scale(1); } 50% { transform: translate(-50%, -50%) scale(1.2); } } .controls { margin-top: 15px; text-align: center; } button { padding: 10px 20px; font-size: 14px; font-weight: bold; border: none; border-radius: 8px; cursor: pointer; background: linear-gradient(135deg, #667eea, #764ba2); color: white; transition: all 0.3s; } button:hover { transform: translateY(-2px); box-shadow: 0 4px 8px rgba(0,0,0,0.2); } .status { margin-top: 15px; text-align: center; font-size: 1.1em; font-weight: bold; color: #2c3e50; min-height: 25px; } .winner { color: #27ae60; animation: celebrate 0.5s ease; } @keyframes celebrate { 0%, 100% { transform: scale(1); } 50% { transform: scale(1.1); } } @media (max-width: 500px) { #board { max-width: 90vw; } } </style> </head> <body> <header> <div class="stats"> <span>胜: <span id="wins">0</span></span> <span>负: <span id="losses">0</span></span> <span>平: <span id="draws">0</span></span> </div> <h1>三人四子棋</h1> </header> <div class="players-info"> <div class="player"> <div class="player-indicator player1" id="indicator1"></div> <span>你</span> </div> <div class="player"> <div class="player-indicator player2" id="indicator2"></div> <span>凤九歌</span> </div> <div class="player"> <div class="player-indicator player3" id="indicator3"></div> <span>凉安</span> </div> </div> <main> <div id="board"></div> <div class="controls"> <button onclick="resetGame()">重新开始</button> </div> <div class="status" id="status"></div> </main> <script> const BOARD_SIZE = 10; const WIN_COUNT = 4; let board, currentPlayer, gameOver; const players = { 1: { name: '你', class: 'player1' }, 2: { name: '凤九歌', class: 'player2' }, 3: { name: '凉安', class: 'player3' } }; function initGame() { board = Array(BOARD_SIZE).fill(null).map(() => Array(BOARD_SIZE).fill(null)); currentPlayer = 1; gameOver = false; createBoard(); updateStatus(''); updateTurnIndicator(); } function createBoard() { const boardEl = document.getElementById('board'); boardEl.innerHTML = ''; for (let row = 0; row < BOARD_SIZE; row++) { for (let col = 0; col < BOARD_SIZE; col++) { const cell = document.createElement('div'); cell.className = 'cell'; cell.dataset.row = row; cell.dataset.col = col; cell.onclick = () => handleCellClick(row, col); boardEl.appendChild(cell); } } } function handleCellClick(row, col) { if (gameOver || currentPlayer !== 1 || board[row][col]) return; makeMove(row, col, 1); if (!gameOver) setTimeout(aiTurn, 500); } function makeMove(row, col, player) { board[row][col] = player; const cell = document.querySelector(`[data-row="${row}"][data-col="${col}"]`); cell.classList.add('occupied'); cell.innerHTML = `<div class="piece ${players[player].class}"></div>`; if (checkWin(row, col, player)) { gameOver = true; highlightWinning(row, col, player); updateStatus(`${players[player].name} 获胜!`, true); updateStats(player); } else if (isBoardFull()) { gameOver = true; updateStatus('平局!', true); updateStats(0); } else { currentPlayer = currentPlayer % 3 + 1; updateTurnIndicator(); } } function checkWin(row, col, player) { const dirs = [[[0,1],[0,-1]], [[1,0],[-1,0]], [[1,1],[-1,-1]], [[1,-1],[-1,1]]]; for (const dir of dirs) { let count = 1; for (const [dr, dc] of dir) { let r = row + dr, c = col + dc; while (r >= 0 && r < BOARD_SIZE && c >= 0 && c < BOARD_SIZE && board[r][c] === player) { count++; r += dr; c += dc; } } if (count >= WIN_COUNT) return true; } return false; } function highlightWinning(row, col, player) { const dirs = [[[0,1],[0,-1]], [[1,0],[-1,0]], [[1,1],[-1,-1]], [[1,-1],[-1,1]]]; for (const dir of dirs) { let pieces = [{row, col}]; let count = 1; for (const [dr, dc] of dir) { let r = row + dr, c = col + dc; while (r >= 0 && r < BOARD_SIZE && c >= 0 && c < BOARD_SIZE && board[r][c] === player) { pieces.push({row: r, col: c}); count++; r += dr; c += dc; } } if (count >= WIN_COUNT) { pieces.forEach(pos => { const piece = document.querySelector(`[data-row="${pos.row}"][data-col="${pos.col}"] .piece`); if (piece) piece.classList.add('winning-piece'); }); return; } } } function isBoardFull() { return board.every(row => row.every(cell => cell !== null)); } function aiTurn() { if (gameOver) return; const move = currentPlayer === 2 ? findBestMove(2, true) : findBestMove(3, false); if (move) { makeMove(move.row, move.col, currentPlayer); if (!gameOver && currentPlayer !== 1) setTimeout(aiTurn, 500); } } function findBestMove(player, aggressive) { let move = findWinningMove(player); if (move) return move; if (aggressive) { for (let p of [1, 3]) { move = findWinningMove(p); if (move) return move; } } else { for (let p of [1, 2]) { move = findWinningMove(p); if (move) return move; } } let bestScore = -1, bestMove = null; for (let row = 0; row < BOARD_SIZE; row++) { for (let col = 0; col < BOARD_SIZE; col++) { if (!board[row][col]) { const score = evaluatePosition(row, col, player); if (score > bestScore) { bestScore = score; bestMove = {row, col}; } } } } return bestMove; } function findWinningMove(player) { for (let row = 0; row < BOARD_SIZE; row++) { for (let col = 0; col < BOARD_SIZE; col++) { if (!board[row][col]) { board[row][col] = player; if (checkWin(row, col, player)) { board[row][col] = null; return {row, col}; } board[row][col] = null; } } } return null; } function evaluatePosition(row, col, player) { let score = 0; const dirs = [[0,1], [1,0], [1,1], [1,-1]]; for (const [dr, dc] of dirs) { let count = 0, open = 0; for (const [rDir, cDir] of [[dr, dc], [-dr, -dc]]) { let r = row + rDir, c = col + cDir; while (r >= 0 && r < BOARD_SIZE && c >= 0 && c < BOARD_SIZE) { if (board[r][c] === player) count++; else if (!board[r][c]) { open++; break; } else break; r += rDir; c += cDir; } } if (count >= 3) score += 100; else if (count === 2 && open >= 1) score += 10; else if (count === 1 && open >= 2) score += 1; } const center = BOARD_SIZE / 2; score += Math.max(0, 5 - (Math.abs(row - center) + Math.abs(col - center))); return score; } function updateTurnIndicator() { document.querySelectorAll('.player-indicator').forEach(el => el.classList.remove('current-turn')); document.getElementById(`indicator${currentPlayer}`).classList.add('current-turn'); } function updateStatus(msg, isWinner = false) { const status = document.getElementById('status'); status.textContent = msg; status.className = isWinner ? 'status winner' : 'status'; } function updateStats(winner) { const stats = JSON.parse(localStorage.getItem('gameStats') || '{"wins":0,"losses":0,"draws":0}'); if (winner === 1) stats.wins++; else if (winner === 0) stats.draws++; else stats.losses++; localStorage.setItem('gameStats', JSON.stringify(stats)); document.getElementById('wins').textContent = stats.wins; document.getElementById('losses').textContent = stats.losses; document.getElementById('draws').textContent = stats.draws; } function loadStats() { const stats = JSON.parse(localStorage.getItem('gameStats') || '{"wins":0,"losses":0,"draws":0}'); document.getElementById('wins').textContent = stats.wins; document.getElementById('losses').textContent = stats.losses; document.getElementById('draws').textContent = stats.draws; } function resetGame() { initGame(); } loadStats(); initGame(); </script> </body> </html>