国际象棋 PGN 查看器(JavaScript)






4.85/5 (38投票s)
使用 JavaScript 进行 Web 应用程序开发的面向对象方法
警告
如果您在1月4日之前已经下载了该版本,请下载(已修正)的ChessViewer
版本。抱歉,那是一个过时且有bug的版本。
引言
有人可能会争辩这个说法,但我相信任何软件开发者都应该喜欢国际象棋。便携式棋局记谱法(PGN)用于记录棋局的走法和注释(例如:1. e4 e5 2. Nf3 ...)。有许多用不同语言编写的国际象棋PGN查看器,JavaScript也是其中之一。但我遇到的示例都是使用document.write
("一些HTML")这样的操作符编写的。这种编程风格看起来很笨拙,也激发不了灵感。
背景
他们说JavaScript支持面向对象风格。要检验这个说法,可以尝试开发一些“有用”的应用程序。当我意识到JavaScript的强大以及在现代Web应用程序中使用它的必要性时,我选择了PGN查看器的问题作为起点。我为此问题思索了几年,直到现在(圣诞假期),我才抽出时间实现了从**上一个**FEN字符串和**当前**走法记法计算出FEN(描述当前走法后棋盘局面的字符串)的算法。
FEN -- Forsyth–Edwards Notation(FEN)。例如,假设上一个FEN字符串是
"rnb...nrpp.k.Bpp..pp................PB....bP.Q..P.PKN.PPq......R"
它描述了第11步之后棋盘上的所有64个格子(见上图)。下一步是:12. Nxc3(马吃掉了占据c3格的黑象)。问题是在走完Nc3后推导出下一个FEN字符串。这个字符串看起来是
"rnb...nrpp.k.Bpp..pp................PB....NP.Q..P.PK..PPq......R"
这个问题似乎并不难,但考虑到一个走法可能因当前情况而有不同的格式(Nc3
, Nec3
, N2c3
, Nxc3
, Nexc3
, N2xc3
, Nc3+
, Nec3+
, N2c3+
, Nxc3+
, Nexc3+
, N2xc3+
),您就会意识到这里有些工作要做。最大的麻烦在于兵的走法。您必须考虑:不规则性(e2上的兵可以走到e3或e4,但之后它只能前进一格),吃过路兵以及在最后一行可以升变成任何棋子(兵种)的可能性。最后这个特性称为兵升变。
我知道的最好的PGN查看器(redhotpawn.com)使用预定义的FEN字符串来记录所有走法。我冒着犯错的风险说,似乎所有这些字符串都是手工创建的(付出了巨大的努力!)。
Using the Code
您可以使用此项目的脚本开发一个Web应用程序,该应用程序可以接收用户的PGN文本,并让他们有机会观看任何棋局的动画,浏览走法,分析棋局,并学习下棋(这是锻炼思维的最佳游戏)。您也可以将您喜欢的棋局文本添加到现有列表中,并使用此应用程序度过愉快的时光。
我计划将此代码用于一个允许通过网络与朋友下棋的应用程序。是的,我知道这个问题已经解决了,现在任何人都可以通过网络下棋,但使用*您自己的*代码(为了流畅地动画棋子)会有所不同。这是一个完全不同的故事,一个可以激发灵感的故事。
解决方案结构
此项目中一个最有趣的部分是MoverTimer
——一个JavaScript对象(原型函数),它允许您同时动画许多图像(棋盘上的棋子)。当您从右侧的走法列表中选择任意走法时,就会发生这种情况。如果,比如说,10个棋子必须同时移动到10个不同的棋盘位置,那么就必须创建10个MoverTimer
对象。每个对象都必须单独工作,不得相互干扰。我在https://developer. mozilla.org上找到了一个很棒的Timer示例,并对其进行了微调以满足我的需求。
第二个重要细节是AnimateTransition
——PgnCtrl
对象的(JSON格式)方法。该方法的算法包含4个阶段:
- 收集棋盘上的所有棋子。
- 遍历所有格子,标记空单元格、已就位的棋子以及需要移动(动画)的棋子。
- 找到要移动到的方格,并标记需要移动到这些方格的棋子。如有需要,创建新棋子。
- 遍历棋盘上的所有棋子,计算它们的新位置并开始动画。删除当前FEN字符串中不存在的棋子。
MoverTimer
的一个非常方便的功能是能够指定回调函数(带有参数),该函数将在计时器完成任务后被调用。我使用此功能来调用Highlight
方法,该方法用于标记走法,控制显示注释的面板,并处理兵的升变。
当您分析走法为Qa8的走法时,您可以轻松找到目标方格(它是a8),但您还必须找出(计算)源方格(皇后将要移动的方格)。此任务由MoveAnalyzer
对象的SearchXXX
方法完成,其中XXX可以是:North、West、South、East、NW、NE、SW或SE。在这里,您可以看到一个车子的源方格的搜索技术。
SearchNESW: function (c)
{
if (!this.SearchNorth(c))
if (!this.SearchEast(c))
if (!this.SearchSouth(c))
if (!this.SearchWest(c))
return false;
return true;
}
以下代码片段显示了如何将目标方格(例如‘e4
’)转换为应用程序中使用的代数方格坐标。
ToX: function (c) { return c.charCodeAt(0) - 97; },
ToY: function (c) { return 8 - Number(c); },
有趣的是,国王和马的起始位置可以使用相同的算法找到。这是因为这两种棋子都有8个可能的选择。找到兵的上一步位置也是一个问题。所有这些任务都由MoveAnalyzer
的SearchEight
、SearchPawn
和SearchEnPassant
方法处理。处理易位(王和车交换位置,O-O和O-O-O走法)比看起来要容易得多。
关注点
尝试从文件Andersson.pgn(您可以在项目文件夹中找到它)加载超过2500个新棋局。所有新加载的棋局记法都将被添加到由FileManager
对象支持的表中。在这里,我们使用了JavaScript对象FileReader
的功能。它比以前使用的MS COM对象要方便得多。
PgnCtrl
对象创建UI元素。当然,这里可以使用一些库(JQuery或更好)。我的一个学生向我展示了他们公司使用的一个库,它看起来非常强大。是的,我们的一些学生现在一边工作一边学习(1991年以前这是不可能的——我想知道,这是好还是坏?)。我深信,在学习一门语言时,您不应该使用任何库。所有的魔术都应该由您自己动手完成。这就是为什么我使用几个全局函数(您可以在Kit.js中找到它们)。这组小函数有助于创建所有UI。
我想最后说,JavaScript非常棒!如果它早些被广泛认可,我们的发展可能会更快,当然也会有所不同。我认为在10多年的时间里,只有少数人真正看到了JavaScript的力量,而我们中的许多人只是忽视了这个精彩的动态语言。