五子棋游戏

五子棋 - deveco

html 复制代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>五子棋 - deveco</title>
  <style>
    body {
      font-family: Arial, sans-serif;
      display: flex;
      flex-direction: column;
      align-items: center;
      background-color: #f5f5f5;
    }
    
    h1 {
      color: #333;
    }
    
    #board {
      display: flex;
      flex-direction: column;
      background-color: #dcb35c;
      padding: 10px;
      border-radius: 5px;
      box-shadow: 0 0 10px rgba(0, 0, 0, 0.3);
      margin: 20px 0;
    }
    
    .row {
      display: flex;
    }
    
    .cell {
      width: 30px;
      height: 30px;
      border: 1px solid #000;
      display: flex;
      justify-content: center;
      align-items: center;
      position: relative;
      cursor: pointer;
    }
    
    .piece {
      width: 24px;
      height: 24px;
      border-radius: 50%;
    }
    
    .black {
      background-color: #000;
      box-shadow: 0 0 5px rgba(0, 0, 0, 0.5);
    }
    
    .white {
      background-color: #fff;
      box-shadow: 0 0 5px rgba(0, 0, 0, 0.5);
    }
    
    #status {
      font-size: 18px;
      font-weight: bold;
      margin: 10px 0;
    }
    
    button {
      padding: 10px 20px;
      background-color: #4CAF50;
      color: white;
      border: none;
      border-radius: 5px;
      cursor: pointer;
      font-size: 16px;
      margin: 0 5px;
    }
    
    #controls {
      display: flex;
      margin-bottom: 15px;
    }
    
    .difficulty {
      margin-top: 15px;
    }
    
    select {
      padding: 5px;
      margin-left: 10px;
    }
  </style>
</head>
<body>
  <h1>五子棋</h1>
  <div id="status">当前玩家:黑棋</div>
  <div id="controls">
    <button id="restart">重新开始</button>
    <button id="toggle-ai">切换AI模式</button>
  </div>
  <div class="difficulty">
    难度: 
    <select id="ai-level">
      <option value="easy">简单</option>
      <option value="medium" selected>中等</option>
      <option value="hard">困难</option>
    </select>
  </div>
  <div id="board"></div>

  <script>
    // 游戏状态
    const gameState = {
      board: [],
      currentPlayer: 1, // 1=黑棋, 2=白棋
      gameOver: false,
      size: 15,
      aiEnabled: true,
      aiPlayer: 2, // AI默认使用白棋
      aiLevel: 'medium'
    };

    // 初始化棋盘
    function initGame() {
      gameState.board = Array(gameState.size).fill().map(() => Array(gameState.size).fill(0));
      gameState.currentPlayer = 1;
      gameState.gameOver = false;
      renderBoard();
      
      // 更新AI状态按钮
      document.getElementById('toggle-ai').textContent = 
        gameState.aiEnabled ? "关闭AI模式" : "开启AI模式";
    }

    // 渲染棋盘
    function renderBoard() {
      const board = document.getElementById('board');
      board.innerHTML = '';
      
      for (let i = 0; i < gameState.size; i++) {
        const row = document.createElement('div');
        row.className = 'row';
        
        for (let j = 0; j < gameState.size; j++) {
          const cell = document.createElement('div');
          cell.className = 'cell';
          
          if (gameState.board[i][j] === 1) {
            const piece = document.createElement('div');
            piece.className = 'piece black';
            cell.appendChild(piece);
          } else if (gameState.board[i][j] === 2) {
            const piece = document.createElement('div');
            piece.className = 'piece white';
            cell.appendChild(piece);
          }
          
          cell.addEventListener('click', () => makeMove(i, j));
          row.appendChild(cell);
        }
        
        board.appendChild(row);
      }
      
      // 更新状态
      const status = document.getElementById('status');
      if (gameState.gameOver) {
        const winner = gameState.currentPlayer === 1 ? '黑棋' : '白棋';
        const isAI = gameState.aiEnabled && gameState.currentPlayer === gameState.aiPlayer;
        status.textContent = `游戏结束,${winner}${isAI ? '(AI)' : ''}胜利!`;
      } else {
        const currentPlayerText = gameState.currentPlayer === 1 ? '黑棋' : '白棋';
        const isAI = gameState.aiEnabled && gameState.currentPlayer === gameState.aiPlayer;
        status.textContent = `当前玩家:${currentPlayerText}${isAI ? '(AI思考中...)' : ''}`;
      }
    }

    // 落子
    function makeMove(row, col) {
      // 如果游戏结束或该位置已有棋子,则不允许落子
      if (gameState.gameOver || gameState.board[row][col] !== 0) {
        return;
      }
      
      // 如果当前是AI回合且AI启用,则忽略玩家点击
      if (gameState.aiEnabled && gameState.currentPlayer === gameState.aiPlayer) {
        return;
      }
      
      // 玩家落子
      gameState.board[row][col] = gameState.currentPlayer;
      
      // 检查是否获胜
      if (checkWin(row, col)) {
        gameState.gameOver = true;
        renderBoard();
        return;
      }
      
      // 切换玩家
      gameState.currentPlayer = gameState.currentPlayer === 1 ? 2 : 1;
      renderBoard();
      
      // 如果AI启用且现在是AI回合,则AI落子
      if (gameState.aiEnabled && gameState.currentPlayer === gameState.aiPlayer && !gameState.gameOver) {
        setTimeout(makeAIMove, 500); // 延迟500ms,让玩家能看到自己的落子
      }
    }

    // AI落子
    function makeAIMove() {
      if (gameState.gameOver) return;
      
      const move = findBestMove();
      if (move) {
        gameState.board[move.row][move.col] = gameState.aiPlayer;
        
        if (checkWin(move.row, move.col)) {
          gameState.gameOver = true;
          renderBoard();
          return;
        }
        
        gameState.currentPlayer = gameState.currentPlayer === 1 ? 2 : 1;
        renderBoard();
      }
    }

    // AI寻找最佳落子位置
    function findBestMove() {
      const aiLevel = gameState.aiLevel;
      const emptyPositions = [];
      
      // 找出所有空位置
      for (let i = 0; i < gameState.size; i++) {
        for (let j = 0; j < gameState.size; j++) {
          if (gameState.board[i][j] === 0) {
            emptyPositions.push({row: i, col: j});
          }
        }
      }
      
      // 如果是第一步,随机选择靠近中心的位置
      if (emptyPositions.length === gameState.size * gameState.size) {
        const center = Math.floor(gameState.size / 2);
        const offset = Math.floor(Math.random() * 3) - 1; // -1, 0, 或 1
        return {
          row: center + offset,
          col: center + Math.floor(Math.random() * 3) - 1
        };
      }
      
      // 评估每个位置的分数
      const movesWithScores = emptyPositions.map(pos => {
        return {
          ...pos,
          score: evaluatePosition(pos.row, pos.col, aiLevel)
        };
      });
      
      // 根据难度增加随机性
      if (aiLevel === 'easy') {
        // 简单模式有50%概率随机落子
        if (Math.random() < 0.5) {
          return emptyPositions[Math.floor(Math.random() * emptyPositions.length)];
        }
      } else if (aiLevel === 'medium') {
        // 中等模式有20%概率不选最佳位置
        if (Math.random() < 0.2) {
          movesWithScores.sort((a, b) => b.score - a.score);
          const topMoves = movesWithScores.slice(0, Math.min(5, movesWithScores.length));
          return topMoves[Math.floor(Math.random() * topMoves.length)];
        }
      }
      
      // 选择分数最高的位置
      movesWithScores.sort((a, b) => b.score - a.score);
      return movesWithScores[0];
    }

    // 评估位置分数
    function evaluatePosition(row, col, aiLevel) {
      const humanPlayer = gameState.aiPlayer === 1 ? 2 : 1;
      let score = 0;
      
      // 优先考虑靠近中心的位置
      const center = Math.floor(gameState.size / 2);
      const distanceFromCenter = Math.abs(row - center) + Math.abs(col - center);
      score -= distanceFromCenter;
      
      // 检查周围是否有棋子
      let hasNeighbor = false;
      for (let i = Math.max(0, row - 2); i <= Math.min(gameState.size - 1, row + 2); i++) {
        for (let j = Math.max(0, col - 2); j <= Math.min(gameState.size - 1, col + 2); j++) {
          if (gameState.board[i][j] !== 0) {
            hasNeighbor = true;
            break;
          }
        }
        if (hasNeighbor) break;
      }
      
      if (!hasNeighbor) {
        return score - 50; // 远离所有棋子的位置不太好
      }
      
      // 检查各个方向的得分
      const directions = [
        [0, 1],   // 水平
        [1, 0],   // 垂直
        [1, 1],   // 右下对角线
        [1, -1]   // 右上对角线
      ];
      
      for (const [dr, dc] of directions) {
        // 检查AI自己的得分
        score += evaluateDirection(row, col, dr, dc, gameState.aiPlayer) * 2;
        
        // 检查阻止对手的得分
        const humanScore = evaluateDirection(row, col, dr, dc, humanPlayer);
        
        // 如果对手即将获胜,优先阻止
        if (humanScore >= 100) {
          score += humanScore * 1.5;
        } else {
          score += humanScore;
        }
      }
      
      // 根据难度调整
      if (aiLevel === 'hard') {
        // 困难模式增加攻击性,更注重自己的连子
        score *= 1.2;
      } else if (aiLevel === 'easy') {
        // 简单模式减弱AI能力
        score *= 0.7;
      }
      
      return score;
    }

    // 评估某个方向上的得分
    function evaluateDirection(row, col, dr, dc, player) {
      const opponent = player === 1 ? 2 : 1;
      let score = 0;
      
      // 模拟在该位置放置棋子
      const tempBoard = JSON.parse(JSON.stringify(gameState.board));
      tempBoard[row][col] = player;
      
      // 检查连续棋子
      let count = 1; // 包括当前位置
      let open = [true, true]; // 两端是否开放
      
      // 正向检查
      for (let i = 1; i < 5; i++) {
        const r = row + i * dr;
        const c = col + i * dc;
        
        if (r >= 0 && r < gameState.size && c >= 0 && c < gameState.size) {
          if (tempBoard[r][c] === player) {
            count++;
          } else if (tempBoard[r][c] === opponent) {
            open[0] = false;
            break;
          } else {
            break;
          }
        } else {
          open[0] = false;
          break;
        }
      }
      
      // 反向检查
      for (let i = 1; i < 5; i++) {
        const r = row - i * dr;
        const c = col - i * dc;
        
        if (r >= 0 && r < gameState.size && c >= 0 && c < gameState.size) {
          if (tempBoard[r][c] === player) {
            count++;
          } else if (tempBoard[r][c] === opponent) {
            open[1] = false;
            break;
          } else {
            break;
          }
        } else {
          open[1] = false;
          break;
        }
      }
      
      // 根据连续棋子数和开放端计算得分
      const openEnds = (open[0] ? 1 : 0) + (open[1] ? 1 : 0);
      
      if (count >= 5) return 10000; // 五连珠,必胜
      
      if (count === 4) {
        if (openEnds === 2) return 5000; // 活四
        if (openEnds === 1) return 1000; // 冲四
      }
      
      if (count === 3) {
        if (openEnds === 2) return 500; // 活三
        if (openEnds === 1) return 100; // 冲三
      }
      
      if (count === 2) {
        if (openEnds === 2) return 50; // 活二
        if (openEnds === 1) return 10; // 冲二
      }
      
      if (count === 1) {
        if (openEnds === 2) return 5; // 活一
        if (openEnds === 1) return 1; // 冲一
      }
      
      return 0;
    }

    // 检查是否获胜
    function checkWin(row, col) {
      const directions = [
        [0, 1],   // 水平
        [1, 0],   // 垂直
        [1, 1],   // 右下对角线
        [1, -1]   // 右上对角线
      ];
      
      const player = gameState.board[row][col];
      
      for (const [dr, dc] of directions) {
        let count = 1;
        
        // 正向检查
        for (let i = 1; i < 5; i++) {
          const r = row + i * dr;
          const c = col + i * dc;
          
          if (r >= 0 && r < gameState.size && c >= 0 && c < gameState.size && 
              gameState.board[r][c] === player) {
            count++;
          } else {
            break;
          }
        }
        
        // 反向检查
        for (let i = 1; i < 5; i++) {
          const r = row - i * dr;
          const c = col - i * dc;
          
          if (r >= 0 && r < gameState.size && c >= 0 && c < gameState.size && 
              gameState.board[r][c] === player) {
            count++;
          } else {
            break;
          }
        }
        
        if (count >= 5) {
          return true;
        }
      }
      
      return false;
    }

    // 启动游戏
    document.addEventListener('DOMContentLoaded', () => {
      initGame();
      
      // 重新开始按钮
      document.getElementById('restart').addEventListener('click', initGame);
      
      // 切换AI模式按钮
      document.getElementById('toggle-ai').addEventListener('click', () => {
        gameState.aiEnabled = !gameState.aiEnabled;
        document.getElementById('toggle-ai').textContent = 
          gameState.aiEnabled ? "关闭AI模式" : "开启AI模式";
        
        // 如果切换到AI模式且当前是AI回合,则AI立即落子
        if (gameState.aiEnabled && gameState.currentPlayer === gameState.aiPlayer && !gameState.gameOver) {
          setTimeout(makeAIMove, 500);
        }
      });
      
      // 难度选择
      document.getElementById('ai-level').addEventListener('change', (e) => {
        gameState.aiLevel = e.target.value;
      });
    });
  </script>
</body>
</html>
相关推荐
剪刀石头布啊7 分钟前
使用 husky 配置git hooks 提交前校验
javascript
剪刀石头布啊11 分钟前
ECMAScript、html头、dom、bom、a空链、选择器、css样式继承等、css通用属性值、文档流等
css·html
剪刀石头布啊13 分钟前
浏览器进程与事件循环
前端·浏览器
剪刀石头布啊14 分钟前
浏览器渲染原理
前端·浏览器
日记成书40 分钟前
【HTML 基础教程】HTML 表格
前端·html
木木黄木木44 分钟前
HTML5贪吃蛇游戏开发经验分享
前端·html·html5
无名之逆1 小时前
hyperlane:Rust HTTP 服务器开发的不二之选
服务器·开发语言·前端·后端·安全·http·rust
李鸿耀1 小时前
前端包管理工具演进史:从 npm 到 pnpm 的技术革新
前端·面试
麓殇⊙1 小时前
前端基础知识汇总
前端
MariaH1 小时前
邂逅jQuery库
前端