You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用JavaScript遍历棋盘对角线实现棋子多步吃子检测?

跳棋多步吃子功能的JavaScript实现方案

问题描述

我已经用HTML、CSS和JavaScript实现了一个简单的跳棋棋盘,上方的金方棋子可以向下、向左或向右方向吃子。现在我想编写一个函数,检测被点击的棋子能否跳过对手棋子。单步吃子的逻辑很简单,只需检查棋子相邻单元格是否存在被空单元格包围的对手棋子;但多步吃子的实现比较复杂,需要循环检测吃子模式,并等待用户依次点击空方格完成移动。请问该如何用JavaScript实现这个功能?


现有代码

HTML

<!DOCTYPE html>
<html>
<head>
  <link rel="stylesheet" href="styles.css" />
  <script src="main.js"></script>
</head>
<body>
  <div id="playerA"></div>
  <table id="checkertable"></table>
  <div id="playerB"></div> <!-- 修正重复的id问题 -->
</body>
</html>

CSS

body {
  background: green;
}

/*style the table*/
.table {
  margin: auto;
  width: 800px;
  height: 800px;
}

.square {
  width: 100px;
  height: 100px;
}

.white {
  background-color: mintcream;
}

.brown {
  background-color: chocolate;
}

/*styles for the pieces*/
.gold-piece {
  box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.5);
  background-color: gold;
  width: 80%;
  height: 80%;
  border-radius: 50%;
  margin: 10%;
}

.red-piece {
  box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.5);
  background-color: orangered;
  width: 80%;
  height: 80%;
  border-radius: 50%;
  margin: 10%;
}

/*style for styling a selected piece*/
.selected-piece {
  border: 2px solid white;
}

原始JavaScript

let A = true;
let B = false;
//define views that we will use to send messages to both players
let messageForA = document.getElementById("playerA");
let messageForB = document.getElementById("playerB");

//this function checks if the tapped piece can make single or multiple jumps over opponent cells
function canJumpOverOpponent(table, row, col) {
  /*a piece can jump over opponent pieces if there is an opponent piece
  between that piece and an empty square
  we use a path finding algorithm to check for empty squares in the path of that piece
  */
  //the top pieces can either capture left or right downwards
}

//this function draws the chekerboard
function createCheckerboard() {
  const table = document.getElementById('checkertable');
  for (let row = 0; row < 8; row++) {
    const newRow = table.insertRow();
    for (let col = 0; col < 8; col++) {
      const newCell = newRow.insertCell();
      newCell.classList.add('square');
      if ((row + col) % 2 === 0) {
        //paint the white squares
        newCell.classList.add('white');
      } else {
        //paint the brow squares where we will draw pieces
        newCell.classList.add('brown');
        //we draw the old pieces in this section
        if (row < 3) {
          const goldpiece = document.createElement('div');
          goldpiece.classList.add('gold-piece');
          newCell.appendChild(goldpiece);
          goldpiece.addEventListener('click', function(event) {
            if (A) {
              if (event.target.classList.contains('gold-piece')) {
                //means the cell contains a piece
                console.log("This square contains a gold piece");
                //highlight this piece and remove highlights from any previous square
                const goldpieces = document.querySelectorAll('.gold-piece');
                console.log(goldpieces.length);
                goldpieces.forEach(function(element) {
                  if (element.classList.contains('selected-piece')) {
                    //remove the highlight from previous cells
                    element.classList.remove('selected-piece');
                  }
                });
                event.target.classList.add('selected-piece');
                //check if the piece can make a jump over opponent pieces
              } else {
                //this square is empty 
                console.log("this piece is empty, check if user had tapped a previous square or he is completing a capture");
              }
            } else {
              console.log("player one attempts to play while it is not his turn");
            }
          });
        }
        //we draw the red pieces in this section
        if (row >= 5) {
          const redpiece = document.createElement('div');
          redpiece.classList.add('red-piece');
          newCell.appendChild(redpiece);
        }
      }
    }
  }
}
window.onload = () => createCheckerboard();

实现方案

核心思路

  1. 状态跟踪:用全局变量管理当前选中棋子、玩家回合、是否处于连续吃子阶段,避免交互混乱。
  2. 单步吃子检测:判断棋子向某个方向移动时,中间是否有对手棋子,目标位置是否为空。
  3. 多步吃子逻辑:吃完一次后立即检测当前位置是否还能继续吃子,若可以则保持连续吃子状态,直到无法继续。
  4. 交互逻辑优化:区分用户点击的是己方棋子、空格子,在连续吃子阶段强制用户选择合法目标。

修改后的完整JavaScript代码

// 游戏状态管理
let currentPlayer = 'gold'; // 当前玩家:gold(金方)或red(红方)
let selectedPiece = null; // 当前选中的棋子元素
let selectedPos = { row: -1, col: -1 }; // 选中棋子的行列位置
let isInMultiJump = false; // 是否处于连续吃子阶段
// 玩家提示元素
let messageForA = document.getElementById("playerA");
let messageForB = document.getElementById("playerB");

// 获取单元格的行列位置
function getCellPos(cell) {
  const row = cell.parentElement.rowIndex;
  const col = cell.cellIndex;
  return { row, col };
}

// 判断指定位置是否存在指定类型的棋子
function hasPiece(row, col, pieceClass) {
  const table = document.getElementById('checkertable');
  // 超出棋盘范围直接返回false
  if (row < 0 || row >= 8 || col < 0 || col >= 8) return false;
  const cell = table.rows[row].cells[col];
  return cell.querySelector(`.${pieceClass}`) !== null;
}

// 判断指定位置是否为空(无任何棋子)
function isEmpty(row, col) {
  const table = document.getElementById('checkertable');
  if (row < 0 || row >= 8 || col < 0 || col >= 8) return false;
  const cell = table.rows[row].cells[col];
  return !cell.querySelector('.gold-piece') && !cell.querySelector('.red-piece');
}

// 检测单步吃子是否可行:从(startRow, startCol)向(dRow, dCol)方向
function canSingleJump(startRow, startCol, dRow, dCol) {
  const opponentClass = currentPlayer === 'gold' ? 'red-piece' : 'gold-piece';
  const jumpOverRow = startRow + dRow;
  const jumpOverCol = startCol + dCol;
  const targetRow = startRow + 2 * dRow;
  const targetCol = startCol + 2 * dCol;
  
  // 满足三个条件:中间有对手棋子、目标位置为空、所有位置在棋盘内
  return hasPiece(jumpOverRow, jumpOverCol, opponentClass) && isEmpty(targetRow, targetCol);
}

// 获取当前棋子所有可行的单步吃子方向
function getAllPossibleJumps(row, col) {
  // 根据玩家确定可移动方向:金方向下左右,红方向上左右
  const directions = currentPlayer === 'gold' ? 
    [{ dRow: 1, dCol: -1 }, { dRow: 1, dCol: 1 }] : 
    [{ dRow: -1, dCol: -1 }, { dRow: -1, dCol: 1 }];
  
  const possibleJumps = [];
  directions.forEach(dir => {
    if (canSingleJump(row, col, dir.dRow, dir.dCol)) {
      possibleJumps.push({
        targetRow: row + 2 * dir.dRow,
        targetCol: col + 2 * dir.dCol,
        jumpOverRow: row + dir.dRow,
        jumpOverCol: col + dir.dCol
      });
    }
  });
  return possibleJumps;
}

// 执行吃子操作:移动棋子、移除被吃棋子、更新状态
function performJump(jump) {
  const table = document.getElementById('checkertable');
  // 将选中棋子移动到目标单元格
  const targetCell = table.rows[jump.targetRow].cells[jump.targetCol];
  targetCell.appendChild(selectedPiece);
  // 移除被跳过的对手棋子
  const jumpedCell = table.rows[jump.jumpOverRow].cells[jump.jumpOverCol];
  jumpedCell.innerHTML = '';
  // 更新选中棋子的位置
  selectedPos = { row: jump.targetRow, col: jump.targetCol };
  
  // 检查吃完后是否还能继续吃子
  const nextPossibleJumps = getAllPossibleJumps(jump.targetRow, jump.targetCol);
  isInMultiJump = nextPossibleJumps.length > 0;
  
  if (!isInMultiJump) {
    // 结束连续吃子,切换玩家回合
    currentPlayer = currentPlayer === 'gold' ? 'red' : 'gold';
    selectedPiece.classList.remove('selected-piece');
    selectedPiece = null;
    selectedPos = { row: -1, col: -1 };
    // 更新玩家提示
    const messageEl = currentPlayer === 'gold' ? messageForA : messageForB;
    messageEl.textContent = `轮到${currentPlayer === 'gold' ? '金方' : '红方'}行动`;
    // 清空另一玩家的提示
    const otherMessageEl = currentPlayer === 'gold' ? messageForB : messageForA;
    otherMessageEl.textContent = '';
  } else {
    // 继续连续吃子,提示当前玩家继续操作
    const messageEl = currentPlayer === 'gold' ? messageForA : messageForB;
    messageEl.textContent = '请选择下一个吃子目标';
    const otherMessageEl = currentPlayer === 'gold' ? messageForB : messageForA;
    otherMessageEl.textContent = '';
  }
}

// 处理棋子点击事件
function handlePieceClick(event) {
  const piece = event.target;
  const cell = piece.parentElement;
  const pos = getCellPos(cell);
  
  // 不是当前玩家的棋子,直接忽略
  if ((currentPlayer === 'gold' && !piece.classList.contains('gold-piece')) ||
      (currentPlayer === 'red' && !piece.classList.contains('red-piece'))) {
    return;
  }
  
  // 处于连续吃子阶段时,只能选择当前正在吃子的棋子
  if (isInMultiJump && piece !== selectedPiece) {
    return;
  }
  
  // 移除之前的选中状态
  document.querySelectorAll('.selected-piece').forEach(p => p.classList.remove('selected-piece'));
  // 设置新的选中状态
  selectedPiece = piece;
  selectedPos = pos;
  piece.classList.add('selected-piece');
  
  // 检测该棋子的所有可行吃子路径
  const possibleJumps = getAllPossibleJumps(pos.row, pos.col);
  const messageEl = currentPlayer === 'gold' ? messageForA : messageForB;
  if (possibleJumps.length > 0) {
    messageEl.textContent = '请选择吃子目标';
  } else {
    messageEl.textContent = '该棋子无法吃子';
  }
  const otherMessageEl = currentPlayer === 'gold' ? messageForB : messageForA;
  otherMessageEl.textContent = '';
}

// 处理空单元格点击事件
function handleEmptyCellClick(event) {
  const cell = event.target;
  const pos = getCellPos(cell);
  
  // 没有选中棋子,或当前棋子无法吃子,直接忽略
  if (!selectedPiece || getAllPossibleJumps(selectedPos.row, selectedPos.col).length === 0) {
    return;
  }
  
  // 检查点击的位置是否是合法的吃子目标
  const possibleJumps = getAllPossibleJumps(selectedPos.row, selectedPos.col);
  const targetJump = possibleJumps.find(jump => jump.targetRow === pos.row && jump.targetCol === pos.col);
  
  if (targetJump) {
    // 执行吃子操作
    performJump(targetJump);
  }
}

// 创建棋盘
function createCheckerboard() {
  const table = document.getElementById('checkertable');
  table.classList.add('table'); // 绑定CSS中的table样式
  for (let row = 0; row < 8; row++) {
    const newRow = table.insertRow();
    for (let col = 0; col < 8; col++) {
      const newCell = newRow.insertCell();
      newCell.classList.add('square');
      if ((row + col) % 2 === 0) {
        newCell.classList.add('white');
      } else {
        newCell.classList.add('brown');
        // 为空单元格绑定点击事件
        newCell.addEventListener('click', handleEmptyCellClick);
        
        if (row < 3) {
          const goldpiece = document.createElement('div');
          goldpiece.classList.add('gold-piece');
          newCell.appendChild(goldpiece);
          goldpiece.addEventListener('click', handlePieceClick);
        }
        if (row >= 5) {
          const redpiece = document.createElement('div');
          redpiece.classList.add('red-piece');
          newCell.appendChild(redpiece);
          redpiece.addEventListener('click', handlePieceClick);
        }
      }
    }
  }
  // 初始化提示信息
  messageForA.textContent = '轮到金方行动';
}

window.onload = () => createCheckerboard();

内容的提问来源于stack exchange,提问作者Anthony Kinyua

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.23 22:10:54