您当前的位置:首页 > 计算机 > 编程开发 > Html+Div+Css(前端)

手把手教你用 HTML+CSS+JS 写一个能玩的简易象棋!(附完整源码)

时间:08-25来源:作者:点击数:
CDSY,CDSY.XYZ
有没有想过,不用框架、不靠第三方库,只用最基础的 HTML + CSS + JS,写出一个可以点、可以走、还能悔棋的中国象棋小游戏?

今天,带你一步步从 0 开始,搭建一个能玩的网页版象棋! <br/>最后还有完整源码,直接拿来练手、改造!


项目功能预览

  • • 绘制标准9×10象棋棋盘
  • • 棋子初始排布
  • • 支持点击选子、点击落子
  • • 支持吃子(不能吃自己人)
  • • 简单胜负判定(帅/将被吃掉)
  • • 支持悔棋重新开始
  • • 不依赖任何库,纯原生实现

页面结构 (index.html)

<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <title>简易象棋</title>
  <link rel="stylesheet" href="style.css">
</head>
<body>
  <h1>简易象棋</h1>

  <div id="controls">
    <button onclick="restartGame()">重新开始</button>
    <button onclick="undoMove()">悔棋</button>
  </div>

  <div id="chessboard"></div>

  <script src="script.js"></script>
</body>
</html>

结构非常简单,主体分为:标题、控制按钮区、棋盘区域。


样式美化 (style.css)

body {
  font-family: Arial, sans-serif;
  text-align: center;
  background: #f5f5dc;
}

h1 {
  margin-top: 20px;
}

#controls {
  margin-bottom: 10px;
}

#chessboard {
  width: 450px;
  height: 500px;
  margin: 0 auto;
  display: grid;
  grid-template-columns: repeat(9, 1fr);
  grid-template-rows: repeat(10, 1fr);
  border: 2px solid #333;
  background: #ffe4c4;
  position: relative;
}

.cell {
  border: 1px solid #333;
  position: relative;
}

.piece {
  width: 90%;
  height: 90%;
  margin: 5%;
  border-radius: 50%;
  background: #d9b382;
  display: flex;
  justify-content: center;
  align-items: center;
  font-size: 18px;
  cursor: pointer;
  user-select: none;
}

.red {
  color: red;
}

.black {
  color: black;
}

让棋盘有格子,有背景,棋子圆圆胖胖,看着更舒服。


核心逻辑 (script.js)

const board = document.getElementById('chessboard');
let selectedPiece = null;
let selectedCell = null;
let moveHistory = [];

const initialPieces = {
  "0,0": { text: "车", color: "black" },
  "1,0": { text: "马", color: "black" },
  "2,0": { text: "象", color: "black" },
  "3,0": { text: "士", color: "black" },
  "4,0": { text: "将", color: "black" },
  "5,0": { text: "士", color: "black" },
  "6,0": { text: "象", color: "black" },
  "7,0": { text: "马", color: "black" },
  "8,0": { text: "车", color: "black" },
  "1,2": { text: "炮", color: "black" },
  "7,2": { text: "炮", color: "black" },
  "0,3": { text: "兵", color: "black" },
  "2,3": { text: "兵", color: "black" },
  "4,3": { text: "兵", color: "black" },
  "6,3": { text: "兵", color: "black" },
  "8,3": { text: "兵", color: "black" },

  "0,9": { text: "车", color: "red" },
  "1,9": { text: "马", color: "red" },
  "2,9": { text: "相", color: "red" },
  "3,9": { text: "仕", color: "red" },
  "4,9": { text: "帅", color: "red" },
  "5,9": { text: "仕", color: "red" },
  "6,9": { text: "相", color: "red" },
  "7,9": { text: "马", color: "red" },
  "8,9": { text: "车", color: "red" },
  "1,7": { text: "炮", color: "red" },
  "7,7": { text: "炮", color: "red" },
  "0,6": { text: "兵", color: "red" },
  "2,6": { text: "兵", color: "red" },
  "4,6": { text: "兵", color: "red" },
  "6,6": { text: "兵", color: "red" },
  "8,6": { text: "兵", color: "red" },
};

function createBoard() {
  board.innerHTML = '';
  for (let y = 0; y < 10; y++) {
    for (let x = 0; x < 9; x++) {
      const cell = document.createElement('div');
      cell.className = 'cell';
      cell.dataset.x = x;
      cell.dataset.y = y;

      const key = `${x},${y}`;
      if (initialPieces[key]) {
        const piece = document.createElement('div');
        piece.className = `piece ${initialPieces[key].color}`;
        piece.innerText = initialPieces[key].text;
        cell.appendChild(piece);
      }

      cell.addEventListener('click', onCellClick);
      board.appendChild(cell);
    }
  }
}

function onCellClick(e) {
  const cell = e.currentTarget;
  const piece = cell.querySelector('.piece');

  if (selectedPiece) {
    if (!piece || selectedPiece.classList.contains('red') !== piece.classList.contains('red')) {
      moveHistory.push({
        fromX: selectedCell.dataset.x,
        fromY: selectedCell.dataset.y,
        toX: cell.dataset.x,
        toY: cell.dataset.y,
        movedPiece: selectedPiece,
        capturedPiece: piece
      });

      if (piece) {
        piece.remove();
      }

      cell.appendChild(selectedPiece);
      selectedPiece.style.border = "none";

      if (piece && (piece.innerText === "帅" || piece.innerText === "将")) {
        alert((piece.classList.contains('red') ? "黑方胜利!" : "红方胜利!"));
        restartGame();
        return;
      }
    } else {
      alert("不能吃自己人!");
    }
    selectedPiece = null;
    selectedCell = null;
  } else if (piece) {
    selectedPiece = piece;
    selectedCell = cell;
    piece.style.border = "2px solid blue";
  }
}

function restartGame() {
  selectedPiece = null;
  selectedCell = null;
  moveHistory = [];
  createBoard();
}

function undoMove() {
  if (moveHistory.length === 0) {
    alert("没有可以悔棋的步骤!");
    return;
  }

  const lastMove = moveHistory.pop();
  const fromCell = getCell(lastMove.fromX, lastMove.fromY);
  const toCell = getCell(lastMove.toX, lastMove.toY);

  fromCell.appendChild(lastMove.movedPiece);

  if (lastMove.capturedPiece) {
    toCell.appendChild(lastMove.capturedPiece);
  }
}

function getCell(x, y) {
  return document.querySelector(`.cell[data-x="${x}"][data-y="${y}"]`);
}

createBoard();

总结

虽然这个象棋项目比较基础:

  • • 还没加上复杂走法规则(比如马走日、炮隔子)
  • • 红黑轮流行棋目前也没有加
  • • 动画、提示、保存进度还没做

作为前端练习小项目完美够用

想要继续升级?可以考虑:

  • • 添加走法验证(每种棋子不同)
  • • 支持双人对战模式
  • • 支持手机触控
  • • 自动保存棋局进度
  • • 带AI简单对弈
CDSY,CDSY.XYZ
方便获取更多学习、工作、生活信息请关注本站微信公众号城东书院 微信服务号城东书院 微信订阅号
推荐内容
相关内容
栏目更新
栏目热门
本栏推荐