“JavaScript中国象棋程序” 这一系列教程将带你从头使用JavaScript编写一个中国象棋程序。这是教程的第1节。

程序的最终效果点击这里查看

这一系列共有9个部分:

0、JavaScript中国象棋程序(0)- 前言

这一节我们设计图形界面,显示初始化棋局。当点击某棋子时,弹窗提示所点击的具体棋子。效果如下:

1.1、棋盘表示

中国象棋有10行9列,很自然地想到可以用10×9矩阵表示棋盘。事实上,我们使用16×16矩阵来表示一个扩充了的虚拟棋盘。

如上图所示,灰色部分为真实棋盘,置于虚拟棋盘之中。这么做可以快速判断棋子是否走出边界。例如象沿田字走,如果走到真实棋盘之外的虚拟棋盘中,说明走法不合法。

容易想到使用二维数组表示16×16矩阵,这样棋盘上的一个位置需要两个变量表示。一个走法包括起点和终点,就需要四个变量。如果使用长度为256的一维数组表示,一个位置只需一个变量,这就可以减少计算量。因此用一维数组表示16×16矩阵。

一维矩阵和二维矩阵之间的转换也很简单:

// 将二维矩阵转换为一维矩阵
function COORD_XY(x, y) {
return x + (y << 4);
} // 根据一维矩阵,获取二维矩阵行数
function RANK_Y(sq) {
return sq >> 4;
} // 根据一维矩阵,获取二维矩阵列数
function FILE_X(sq) {
return sq & 15;
}

其中,sq & 15是通过位运算取余,与sq % 16结果相同(可参考篇文章)。

再使用一个辅助数组,标识虚拟棋盘中,哪些位置属于真实棋盘:

  var IN_BOARD_ = [
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0,
0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0,
0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0,
0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0,
0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0,
0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0,
0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0,
0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0,
0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0,
0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
];

要判断某位置是否在真实棋盘,可使用函数:

function IN_BOARD(sq) {
return IN_BOARD_[sq] != 0;
}

1.2、棋子表示

使用整数表示棋子:

红方

8

9

10

11

12

13

14

黑方

16

17

18

19

20

21

22

棋子这样表示,可以快速判断某棋子属于红方还是黑方,如下表所示:

红方棋子

黑方棋子

十进制

二进制

十进制

二进制

8

0000 1000

16

0001 0000

9

0000 1001

17

0001 0001

10

0000 1010

18

0001 0010

11

0000 1011

19

0001 0011

12

0000 1100

20

0001 0100

13

0000 1101

21

0001 0101

14

0000 1110

22

0001 0110

可以看出:

红方棋子 & 8 = 1

黑方棋子 & 16 = 1

1.3、字符串表示局面

使用数组表示局面,程序处理起来很方便,但是再网上传递棋局很不方便。我们可以用一行字符串表示一个局面,这就是FEN格式串,一种使用ASCII码字符描述国际象棋局面的标准,当然也可应用于中国象棋。中国象棋的初始局面可表示为:

rnbakabnr/9/1c5c1/p1p1p1p1p/9/9/P1P1P1P1P/1C5C1/9/RNBAKABNR w - -

(1)、红色区域,表示棋盘布局,小写表示黑方,大写表示红方。一个字母表示一个棋子,对应关系如下。

红方

字母

黑方

字母

对应单词

K

k

king

A

a

advisor

B

b

bishop

N

n

knight

R

r

rook

C

c

cannon

P

p

pawn

至于为什么马不用H(horse),象不用E(elephant),这是为了与国际象棋相对应。如果没有棋子,则用数字表示出相邻连续的空位数。中国象棋共有十行,每行都用一个字符串表示,行间使用正斜杠分割。例如:

rnbakabnr表示:

9表示:第二行都是空格。

1c5c1表示:

(2)、绿色区域,表示轮到哪一方走子,“w”表示红方,“b”表示黑方。(没有用r表示红方,我想也是为了与国际象棋对应吧,毕竟国际象棋是黑白两色。)

(3)、深紫色区域,在中国象棋中没有意义,始终用“-”表示。

(4)、紫红色区域,在中国象棋中没有意义,始终用“-”表示。

(5)、蓝色区域,表示双方没有吃子的走棋步数(半回合数),通常该值达到120就要判和(六十回合自然限着),一旦形成局面的上一步是吃子,这里就标记“0”。

(6)、棕色区域,表示当前的回合数。

我们的程序就是使用FEN串初始化棋局的,这就涉及到了将FEN串转化为一维棋局数组。暂时不考虑哪方走子,只解析红色部分,伪代码如下:

// 将FEN串转为一维数组
行变量 y = 3
列变量 x = 3
var c = FEN串第一个字符;
while (c != " ") {
if (c == "/") { // 换行
x = 3;
y ++;
if (y > 12) {
break;
}
} else if (c >= "1" && c <= "9") { // 出现空位
列向量x增加c
} else if (c >= "A" && c <= "Z") { // 红方棋子
将字符表示的棋子转换为整数,并放入数组x + (y << 4)的位置
} else if (c >= "a" && c <= "z") {
将字符表示的棋子转换为整数,并放入数组x + (y << 4)的位置
} c = FEN串的下一个字符;
}

1.4、棋盘前端设计思路

由于棋盘有90个交叉点,我们把棋盘划分为的90个小正方形区域,交叉点是小正方形的中心。每个区域都会定义一个img标签。

上图使用红色方框,标识出了4个小正方形区域。

这些img标签有两个作用:

(1)、显示棋子图片

如果某个区域存在棋子,就会显示相应的棋子图片;否则,显示一张透明图片(也就是oo.gif)。

(2)、响应点击事件

每个img标签都会绑定onmousedown事件。点击不同的img标签时,会传递不同的参数给响应函数,这样就知道点击的具体是哪个区域了。

1.5、核心代码说明

本节的代码可以在 Github 下载,也可以直接clone

git clone -b step-1 https://github.com/Royhoo/write-a-chinesechess-program

程序中定义了两个对象:Board和Position。Board表示一个棋盘,主要功能是初始化棋局,显示棋盘、棋子,响应棋盘上的点击事件。Position存储了一维棋局数组,并定义了很多对该数组进行操作的方法。

Board对象实例化的代码位于index.html中。

通过prototype属性,我们为这两个对象添加了很多的属性和方法。

Board的主要属性和方法:

(1)、pos

这是Position对象的一个实例。

(2)、flushBoard()

刷新棋盘,也就是重新显示棋盘上的棋子。

(3)、drawSquare(sq)

显示sq位置的棋子图片。如果该位置没棋子,则显示一张透明的图片。

(4)、clickSquare(sq_)

点击棋盘的响应函数。点击棋盘(棋子或者空位置),就会调用该函数。sq_是点击的位置。

Position的主要属性和方法:

(1)、squares

这就是一维棋局数组。

(2)、fromFen(fen)

通过FEN串初始化棋局,也就是将参数fen表示的棋局,转化为一维棋局数组squares表示的棋局。

(3)、addPiece(sq, pc)

将棋子pc添加进棋局中的sp位置。

JavaScript中国象棋程序(1) - 界面设计的更多相关文章

  1. JavaScript中国象棋程序(0) - 前言

    “JavaScript中国象棋程序” 这一系列教程将带你从头使用JavaScript编写一个中国象棋程序.希望通过这个系列,我们对博弈程序的算法有一定的了解.同时,我们也将构建出一个不错的中国象棋程序 ...

  2. JavaScript中国象棋程序(2) - 校验棋子走法

    "JavaScript中国象棋程序" 这一系列教程将带你从头使用JavaScript编写一个中国象棋程序.这是教程的第2节. 这一系列共有9个部分: 0.JavaScript中国象 ...

  3. JavaScript中国象棋程序(3) - 电脑自动走棋

    "JavaScript中国象棋程序" 这一系列教程将带你从头使用JavaScript编写一个中国象棋程序.这是教程的第3节. 这一系列共有9个部分: 0.JavaScript中国象 ...

  4. JavaScript中国象棋程序(4) - 极大极小搜索算法

    "JavaScript中国象棋程序" 这一系列教程将带你从头使用JavaScript编写一个中国象棋程序.这是教程的第4节. 这一系列共有9个部分: 0.JavaScript中国象 ...

  5. JavaScript中国象棋程序(5) - Alpha-Beta搜索

    "JavaScript中国象棋程序" 这一系列教程将带你从头使用JavaScript编写一个中国象棋程序.这是教程的第5节. 这一系列共有9个部分: 0.JavaScript中国象 ...

  6. JavaScript中国象棋程序(6) - 克服水平线效应、检查重复局面

    "JavaScript中国象棋程序" 这一系列教程将带你从头使用JavaScript编写一个中国象棋程序.这是教程的第6节. 这一系列共有9个部分: 0.JavaScript中国象 ...

  7. JavaScript中国象棋程序(7) - 置换表

    "JavaScript中国象棋程序" 这一系列教程将带你从头使用JavaScript编写一个中国象棋程序.这是教程的第2节. 这一系列共有9个部分: 0.JavaScript中国象 ...

  8. JavaScript中国象棋程序(8) - 进一步优化

    在这最后一节,我们的主要工作是使用开局库.对根节点的搜索分离出来.以及引入PVS(Principal Variation Search,)主要变例搜索. 8.1.开局库 这一节我们引入book.js文 ...

  9. 中国象棋程序的设计与实现(六)--N皇后问题的算法设计与实现(源码+注释+截图)

    八皇后问题,是一个古老而著名的问题,是回溯算法的典型例题. 该问题是十九世纪著名的数学家高斯1850年提出:在8X8格的国际象棋上摆放八个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行.同一列 ...

随机推荐

  1. 【转】15款Java程序员必备的开发工具

    如果你是一名Web开发人员,那么用膝盖想也知道你的职业生涯大部分将使用Java而度过.这是一款商业级的编程语言,我们没有办法不接触它. 对于Java,有两种截然不同的观点:一种认为Java是最简单功能 ...

  2. java实现——003二维数组中的查找

    import java.util.Scanner; public class T003 { public static void main(String[] args) { Scanner in = ...

  3. 【推荐】PHP中格式化时间函数date与gmdate的区别 | 修改PHP的默认时区

    PHP中的时间有2个格式化函数:date()和gmdate(),在官方的文档中的描述为: date -- 格式化一个本地时间/日期 gmdate -- 格式化一个 GMT/UTC 日期/时间,返回的是 ...

  4. Django中的许可(Permissions)和用户组(Group)

    Reference: http://www.cnblogs.com/esperyong/archive/2012/12/20/2826690.html 接着上面的3篇讨论文章,我们阐述了Django中 ...

  5. iOS 之 手势

    手势操作,有一个总的抽象类UIGestureRecognizer,用于检测设备的所有手势.其下有多个子类: 拍击UITapGestureRecognizer (任意次数的拍击) 向里或向外捏UIPin ...

  6. zepto animate

    // Zepto.js // (c) 2010-2013 Thomas Fuchs // Zepto.js may be freely distributed under the MIT licens ...

  7. 创建iwatch 程序选项

    include complication :包含自定义表盘事件 include glance scene:包含缩略图事件

  8. db2 将原表列notnull属性修改为null属性的方法 (查看主键约束,唯一约束去syscat.tabconst)

    好久没机会写点东西了,今天把自己遇到的一个小问题跟大家分享一下如何修改db2数据库表中列的属性--将列的非空属性改为允许空的属性,修改数据表的某一列属性其实很简单但是里面有需要细节需要dba注意,毕竟 ...

  9. Angular - - Angular数据类型判断

    angular.isArray 判断括号内的值是否为数组. 格式:angular.isArray(value); value: 被判断是否为数组的值. ------------------------ ...

  10. awakeFromNib与initWithCoder