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

如何修改Chessboard.js代码实现PGN加载与方向键复盘功能?

实现PGN加载与方向键浏览对局的代码修改方案

核心修改内容

  • 新增全局变量存储对局每一步的FEN序列、当前浏览位置
  • 新增PGN加载函数,传入PGN字符串即可自动解析生成步数序列
  • 绑定键盘方向键事件,实现对局步进退控制
  • 兼容原有状态更新逻辑,无需修改原有核心走棋代码

完整修改后JS代码

var board = null
var game = new Chess()
var $status = $('#status')
var $fen = $('#fen')
var $pgn = $('#pgn')
// 新增对局浏览相关变量
var fenHistory = []
var currentMoveIndex = 0

function onDragStart (source, piece, position, orientation) {
  // 对局结束后禁止拾取棋子
  if (game.game_over()) return false

  // 仅允许当前走棋方拾取己方棋子
  if ((game.turn() === 'w' && piece.search(/^b/) !== -1) ||
      (game.turn() === 'b' && piece.search(/^w/) !== -1)) {
    return false
  }
}

function onDrop (source, target) {
  // 校验走法合法性
  var move = game.move({
    from: source,
    to: target,
    promotion: 'q' // 示例默认升变为后,可根据需求调整
  })

  // 非法走法自动回弹棋子
  if (move === null) return 'snapback'

  updateStatus()
}

// 棋子落子后更新棋盘位置,兼容王车易位、吃过路兵、升变场景
function onSnapEnd () {
  board.position(game.fen())
}

function takeBack () {
  board.position(game.undo())
}

// 新增:加载PGN函数
function loadPgn(pgnStr) {
  // 重置所有状态
  game.reset()
  fenHistory = []
  currentMoveIndex = 0
  // 解析PGN
  const loadSuccess = game.load_pgn(pgnStr)
  if (!loadSuccess) {
    alert('PGN格式错误,加载失败')
    return
  }
  // 生成每一步对应的FEN序列
  const allMoves = game.history()
  game.reset()
  fenHistory.push(game.fen()) // 存储初始位置FEN
  allMoves.forEach(move => {
    game.move(move)
    fenHistory.push(game.fen())
  })
  // 初始化到对局起始位置
  currentMoveIndex = 0
  board.position(fenHistory[currentMoveIndex])
  updateStatus()
}

// 新增:绑定方向键事件
$(document).keydown(function(e) {
  if (fenHistory.length === 0) return
  // 左箭头:后退一步
  if (e.key === 'ArrowLeft' || e.keyCode === 37) {
    if (currentMoveIndex > 0) {
      currentMoveIndex--
      game.load(fenHistory[currentMoveIndex])
      board.position(fenHistory[currentMoveIndex])
      updateStatus()
    }
  }
  // 右箭头:前进一步
  if (e.key === 'ArrowRight' || e.keyCode === 39) {
    if (currentMoveIndex < fenHistory.length - 1) {
      currentMoveIndex++
      game.load(fenHistory[currentMoveIndex])
      board.position(fenHistory[currentMoveIndex])
      updateStatus()
    }
  }
})

function updateStatus () {
  var status = ''

  var moveColor = '白方'
  if (game.turn() === 'b') {
    moveColor = '黑方'
  }

  // 判定将死
  if (game.in_checkmate()) {
    status = '对局结束,' + moveColor + '被将死'
  }

  // 判定和棋
  else if (game.in_draw()) {
    status = '对局结束,和棋'
  }

  // 对局进行中
  else {
    status = moveColor + '行棋'

    // 判定将军
    if (game.in_check()) {
      status += ',' + moveColor + '被将军'
    }
  }
  // 新增:显示当前浏览进度
  if (fenHistory.length > 0) {
    status += ` | 第 ${currentMoveIndex} 步 / 共 ${fenHistory.length - 1} 步`
  }

  $status.html(status)
  $fen.html(game.fen())
  $pgn.html(game.pgn())
}

var config = {
  draggable: true, // 如果仅做对局浏览,可改为false禁用拖拽走棋
  position: 'start',
  onDragStart: onDragStart,
  onDrop: onDrop,
  onSnapEnd: onSnapEnd
}
board = Chessboard('legalBoard', config)

updateStatus()

// 对接sqlite使用示例:读取到PGN内容后直接调用loadPgn即可
/*
const pgnFromSqlite = '从sqlite中读取到的PGN文本内容'
loadPgn(pgnFromSqlite)
*/

HTML可选补充(测试用)

如果需要手动触发加载PGN,可以在原有HTML中新增加载按钮:

<button id="loadPgnBtn">加载PGN对局</button>
<div id="legalBoard" style="width: 400px"></div>
<span>对局状态</span>
<div id="status"></div>
<span>PGN</span>
<div id="pgn"></div>
<span>FEN</span>
<div id="fen"></div>

对接sqlite说明

你只需要从sqlite中读取到.pgn文件对应的文本内容后,调用loadPgn(pgn文本)函数即可完成对局加载,加载完成后直接按键盘左右方向键即可浏览对局进程。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.27 11:06:04