JavaScript中国象棋程序(1)-界⾯设计
“JavaScript中国象棋程序” 这⼀系列教程将带你从头使⽤JavaScript编写⼀个中国象棋程序。这是教程的第1节。
程序的最终效果。
这⼀系列共有9个部分:
0、
1、
2、
3、
4、
5、
6、
7、
8、
这⼀节我们设计图形界⾯,显⽰初始化棋局。当点击某棋⼦时,弹窗提⽰所点击的具体棋⼦。效果如下:
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、棋⼦表⽰
使⽤整数表⽰棋⼦:
将⼠象马车炮卒
红⽅891011121314
⿊⽅16171819202122
棋⼦这样表⽰,可以快速判断某棋⼦属于红⽅还是⿊⽅,如下表所⽰:
红⽅棋⼦⿊⽅棋⼦
⼗进制⼆进制⼗进制⼆进制
80000 1000160001 0000
90000 1001170001 0001
100000 1010180001 0010
110000 1011190001 0011
120000 1100200001 0100
130000 1101210001 0101
140000 1110220001 0110
可以看出:
红⽅棋⼦ & 8 = 1
⿊⽅棋⼦ & 16 = 1
1.3、字符串表⽰局⾯
使⽤数组表⽰局⾯,程序处理起来很⽅便,但是再⽹上传递棋局很不⽅便。我们可以⽤⼀⾏字符串表⽰⼀个局⾯,这就是FEN格式串,⼀种使⽤ASCII码字符描述国际象棋局⾯的标准,当然也可应⽤于中国象棋。中国象棋的初始局⾯可表⽰为:
rnbakabnr/9/1c5c1/p1p1p1p1p/9/9/P1P1P1P1P/1C5C1/9/RNBAKABNR w--01
(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、核⼼代码说明
本节的代码可以在下载,也可以直接clone
git clone -b step-1 github/Royhoo/write-a-chinesechess-program
程序中定义了两个对象:Board和Position。Board表⽰⼀个棋盘,主要功能是初始化棋局,显⽰棋盘、棋⼦,响应棋盘上的点击事件。Position存储了⼀维棋局数组,并定义了很多对该数组进⾏操作的
⽅法。
Board对象实例化的代码位于index.html中。
通过prototype属性,我们为这两个对象添加了很多的属性和⽅法。
Board的主要属性和⽅法:
(1)、pos
javascript登录注册界面这是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位置。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。