JavaScript中國象棋程序(1) - 界面設計


“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 - - 0 1

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位置。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM