JavaScript中国象棋程序(1) - 界面设计
“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格的国际象棋上摆放八个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行.同一列 ...
随机推荐
- NavigationView学习笔记
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/an ...
- RabbitMQ消息队列(四):分发到多Consumer(Publish/Subscribe)
上篇文章中,我们把每个Message都是deliver到某个Consumer.在这篇文章中,我们将会将同一个Message deliver到多个Consumer中.这个模式也被成为 "pub ...
- Badboy安装与使用
Badboy是一个录制web脚本的工具 1.下载Badboy:http://www.badboy.com.au/download/add 2.启动Badboy,认识主界面 3.使用Badboy录制we ...
- Android与JNI(一) ---- Java调用C 静态调用
第一.通过eclipse新建一个工程名为HelloJni的android工程,并编译. 第二.右键工程-->Android Tools --> Add Native Support,出现如 ...
- 洛谷 P1359 租用游艇
题目描述 长江游艇俱乐部在长江上设置了n 个游艇出租站1,2,-,n.游客可在这些游艇出租站租用游艇,并在下游的任何一个游艇出租站归还游艇.游艇出租站i 到游艇出租站j 之间的租金为r(i,j),1& ...
- GB和GBDT 算法流程及分析
1.优化模型的两种策略: 1)基于残差的方法 残差其实就是真实值和预测值之间的差值,在学习的过程中,首先学习一颗回归树,然后将“真实值-预测值”得到残差,再把残差作为一个学习目标,学习下一棵回归树,依 ...
- poi 导出excel 异常处理方式--曲线救国法
excel 导出不算什么新鲜的话题.目前各种生成excel的开源jar包,poi,jxtl等.但是下载过程中如果出现异常该如何处理呢. 翻了之前的几个项目中的excel导出,有的异常就直接抛了出去,有 ...
- iOS 框架 Nimbus
Nimbus好像是用来处理 视图控制器的 解耦 参考: http://www.oschina.net/p/nimbuskit
- iOS 错误之 NSObject 、CGFloat
需要添加 #import <Foundation/Foundation.h> #import <UIKit/UIKit.h>
- OC纯代码全手工打造ScroolView实现翻页
OC纯代码全手工打造ScroolView实现翻页 1. 概述 分为三部分: 上部标题ScrollView 下部内容ScrollView 上部当前页 标示线 2. 效果 上下两部分都随着手势的滑动一块滑 ...