“JavaScript中国象棋程序” 这一系列教程将带你从头使用JavaScript编写一个中国象棋程序。这是教程的第1节。
这一节我们设计图形界面,显示初始化棋局。当点击某棋子时,弹窗提示所点击的具体棋子。效果如下:
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) - 界面设计的更多相关文章
-
JavaScript中国象棋程序(0) - 前言
“JavaScript中国象棋程序” 这一系列教程将带你从头使用JavaScript编写一个中国象棋程序.希望通过这个系列,我们对博弈程序的算法有一定的了解.同时,我们也将构建出一个不错的中国象棋程序 ...
-
JavaScript中国象棋程序(2) - 校验棋子走法
"JavaScript中国象棋程序" 这一系列教程将带你从头使用JavaScript编写一个中国象棋程序.这是教程的第2节. 这一系列共有9个部分: 0.JavaScript中国象 ...
-
JavaScript中国象棋程序(3) - 电脑自动走棋
"JavaScript中国象棋程序" 这一系列教程将带你从头使用JavaScript编写一个中国象棋程序.这是教程的第3节. 这一系列共有9个部分: 0.JavaScript中国象 ...
-
JavaScript中国象棋程序(4) - 极大极小搜索算法
"JavaScript中国象棋程序" 这一系列教程将带你从头使用JavaScript编写一个中国象棋程序.这是教程的第4节. 这一系列共有9个部分: 0.JavaScript中国象 ...
-
JavaScript中国象棋程序(5) - Alpha-Beta搜索
"JavaScript中国象棋程序" 这一系列教程将带你从头使用JavaScript编写一个中国象棋程序.这是教程的第5节. 这一系列共有9个部分: 0.JavaScript中国象 ...
-
JavaScript中国象棋程序(6) - 克服水平线效应、检查重复局面
"JavaScript中国象棋程序" 这一系列教程将带你从头使用JavaScript编写一个中国象棋程序.这是教程的第6节. 这一系列共有9个部分: 0.JavaScript中国象 ...
-
JavaScript中国象棋程序(7) - 置换表
"JavaScript中国象棋程序" 这一系列教程将带你从头使用JavaScript编写一个中国象棋程序.这是教程的第2节. 这一系列共有9个部分: 0.JavaScript中国象 ...
-
JavaScript中国象棋程序(8) - 进一步优化
在这最后一节,我们的主要工作是使用开局库.对根节点的搜索分离出来.以及引入PVS(Principal Variation Search,)主要变例搜索. 8.1.开局库 这一节我们引入book.js文 ...
-
中国象棋程序的设计与实现(六)--N皇后问题的算法设计与实现(源码+注释+截图)
八皇后问题,是一个古老而著名的问题,是回溯算法的典型例题. 该问题是十九世纪著名的数学家高斯1850年提出:在8X8格的国际象棋上摆放八个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行.同一列 ...
随机推荐
-
linux x64下编译libjpeg,libpng,zlib
libJpeg编译: 下载libjpeg源码:http://www.ijg.org/,下载jpegsrc.v9a.tar.gz 解压源码,命令:tar -zxvf jpegsrc.v9a,源码文件夹为 ...
-
LPC1114
时钟配置: 3个时钟源:系统振荡源(system),IRC振荡源,(IRC,内部RC振荡器)看门狗振荡源(WatchDog) MAINCLKSEL:主时钟源选择寄存器(复位值:0) 只用了前两位: 0 ...
-
C#实现发送邮件
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.T ...
-
MysqlHelp
using System.Configuration;using MySql.Data: public class MySqlHelp { //链接字符串 private static string ...
-
有道云笔记Markdown上传本地图片的方法
有道云笔记截图&保存 方法有多种,例如:开通有道云笔记VIP会员.先将图片文件上传到有道云笔记后使用图片的分享链接.说到底还是使用的 Markdown 的图片功能 ![图片名称](图片链接 ...
-
python学习笔记(9)--函数
函数定义: def <函数名>(<参数(0个或多个)>): 函数体 return <返回值> 参数有非可选参数,和可选参数,可选参数放在参数列表的最后,可以为可选参 ...
-
倒计时实现两种方法-NSTimer/GCD
#import "ViewController.h" @interface ViewController () @property (nonatomic ,strong)UIBut ...
-
使用virtualbox 配置 linux host-only虚拟主机连接外网(转载)
host-only 下的虚拟机之间可以互相访问,虚拟机和宿主机可以互相访问,但是虚拟机不能访问外网. 需要设置: 1.宿主机设置 先对宿主机(windows机器,我这里是win7系统)进行相关配置. ...
-
spring cloud 之 Eureka 知识点
Eureka原理 当服务消费者想要调用服务提供者的API时,首先会在注册中心中查询当前可用的实例的网络地址(也可能是定时查询可用实例,本地缓存好可用服务列表),然后再使用客户端负载均衡,命中到其中一个 ...
-
java官网门户源码 SSM框架 自适应-响应式 freemarker 静态模版引擎
来源:http://www.fhadmin.org/webnewsdetail3.html 前台:支持(5+1[时尚单页风格])六套模版,可以在后台切换 官网:www.fhadmin.org 系统介绍 ...