物件導向課練習題 — 簡易暗棋遊戲

類別

棋子

屬性 — 隊伍、位階、國字、蓋&翻狀態。
方法 — 初始化、可否翻棋。

棋盤

屬性 — 4x8 的棋盤陣列、輪到誰。
方法 — 放棋子&初始化、打亂、顯示(刷新)棋局、移動、可否移動。

棋子類別

其中初始化以建構子完成、可否翻為布林函數(亦可為屬性)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class chiz {
String team; // 紅:r , 黑:b
int level; // 將帥:0 , 士仕:1...
String wd; // 將士象 , 帥仕相
int status; // 蓋:0 , 翻:1
chiz(String steam, int slevel, String sface, int sstatus) {
team = steam;
level = slevel;
wd = sface;
status = sstatus;
}
boolean flipable() {
return status == 0 ? true : false;
}
void flip() {
status = 1;
}
}

棋盤類別

chiz[][] grd 為存放 4x8 個棋子的陣列。
int turn 為回合輪到 玩家1 / 玩家2。

1
2
3
class board {
chiz[][] grd;
int turn; // 1:玩家1 , -1:玩家2

init() 的初始化方法

建立陣列、設定 turn=1 表第一回合為 玩家1。
依 chiz 建構子逐一建立棋子物件於陣列中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
void init() {
grd = new chiz[4][8];
turn = 1;
grd[0][0] = new chiz("r", 0, "帥", 0);
grd[0][1] = new chiz("r", 1, "仕", 0);
grd[0][2] = new chiz("r", 1, "仕", 0);
grd[0][3] = new chiz("r", 2, "相", 0);
grd[0][4] = new chiz("r", 2, "相", 0);
grd[0][5] = new chiz("r", 3, "俥", 0);
grd[0][6] = new chiz("r", 3, "俥", 0);
grd[0][7] = new chiz("r", 4, "傌", 0);
grd[1][0] = new chiz("r", 4, "傌", 0);
grd[1][1] = new chiz("r", 5, "炮", 0);
grd[1][2] = new chiz("r", 5, "炮", 0);
grd[1][3] = new chiz("r", 6, "兵", 0);
grd[1][4] = new chiz("r", 6, "兵", 0);
grd[1][5] = new chiz("r", 6, "兵", 0);
grd[1][6] = new chiz("r", 6, "兵", 0);
grd[1][7] = new chiz("r", 6, "兵", 0);
grd[2][0] = new chiz("b", 0, "將", 0);
grd[2][1] = new chiz("b", 1, "士", 0);
grd[2][2] = new chiz("b", 1, "士", 0);
grd[2][3] = new chiz("b", 0, "象", 0);
grd[2][4] = new chiz("b", 0, "象", 0);
grd[2][5] = new chiz("b", 0, "車", 0);
grd[2][6] = new chiz("b", 0, "車", 0);
grd[2][7] = new chiz("b", 0, "馬", 0);
grd[3][0] = new chiz("b", 0, "馬", 0);
grd[3][1] = new chiz("b", 0, "包", 0);
grd[3][2] = new chiz("b", 0, "包", 0);
grd[3][3] = new chiz("b", 0, "卒", 0);
grd[3][4] = new chiz("b", 0, "卒", 0);
grd[3][5] = new chiz("b", 0, "卒", 0);
grd[3][6] = new chiz("b", 0, "卒", 0);
grd[3][7] = new chiz("b", 0, "卒", 0);
}

打亂的 rnd() 方法

隨機抓取兩組座標進行交換。

1
2
3
4
5
6
7
8
9
10
11
12
13
void rnd() {
for(int i=0 ; i<200 ; i++) {
int x1 = (int) (Math.random() * 8);
int y1 = (int) (Math.random() * 4);
int x2 = (int) (Math.random() * 8);
int y2 = (int) (Math.random() * 4);
chiz tmp;
tmp = grd[y1][x1];
grd[y1][x1] = grd[y2][x2];
grd[y2][x2] = tmp;

}
}

顯示棋盤的 show() 方法

show() — 兩層迴圈搭配判斷應顯示為空白(3個空白字元) / 棋字 / 口(未翻狀態)。

1
2
3
4
5
6
7
8
9
10
11
12
void show() {
for(int i=0 ; i<4 ; i++) {
for(int j=0 ; j<8 ; j++)
if(grd[i][j] == null)
System.out.print(" ");
else if(grd[i][j].status == 1)
System.out.print(grd[i][j].wd + " ");
else if(grd[i][j].status == 0)
System.out.print("口 ");
System.out.println();
}
}

移動棋子的 move()

將第 2 組座標的陣列位置設定為第 1 組座標,並將第 1 組座標的物件變數設為 null。
若棋子不止有 0:未翻、1:已翻 的狀態,亦可先將第 2 組座標上的棋子設定狀態為 2:死亡,可當作列出已有哪些棋子被吃掉的判斷。
由於 move() 其實是 “吃” 或 “移動”, 所以第 2 組座標要將狀態設為 2,應先判斷第 2 組座標為 !=null

1
2
3
4
5
6
void move(int y1, int x1, int y2, int x2) {
if(grd[y2][x2] != null)
grd[y2][x2].status = 2;
grd[y2][x2] = grd[y1][x1];
grd[y1][x1] = null;
}

給定兩組座標,判斷可否移動

回傳布林的 movable()

初始值 movable = false,最後 return 回傳。
“炮” 的部份需要注意 — 上到下或下到上、左到右或右到左。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
boolean movable(int y1, int x1, int y2, int x2) {
boolean movable = false;
if(grd[y1][x1] != null && grd[y1][x1].status == 1)
if(grd[y2][x2] == null)
movable = true;
else if(grd[y2][x2].status == 1 && !grd[y1][x1].team.equals(grd[y2][x2].team))
if(grd[y1][x1].level == 5) {
int cnt = 0, f = 0, t = 0;
if(x1 == x2) {
if(y1 > y2) {
f = y2;
t = y1;
} else {
f = y1;
t = y2;
}
for(int i=f+1 ; i<t ; i++)
if(grd[i][x1] != null)
cnt++;
} else if (y1 == y2) {
if(x1 > x2) {
f = x2;
t = x1;
} else {
f = x1;
t = x2;
}
for(int i=f+1 ; i<t ; i++)
if(grd[y1][i] != null)
cnt++;
}
if(cnt == 1)
movable = true;
} else if(!(grd[y1][x1].level == 0 && grd[y2][x2].level == 0) && grd[y1][x1].level <= grd[y2][x2].level)
movable = true;
else if(grd[y1][x1].level == 6 && grd[y2][x2].level == 0)
movable = true;

return movable;
}


程式成果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
import java.util.Scanner;

class chiz {
String team; // 紅:r , 黑:b
int level; // 將帥:0 , 士仕:1...
String wd; // 將士象 , 帥仕相
int status; // 蓋:0 , 翻:1
chiz(String steam, int slevel, String sface, int sstatus) {
team = steam;
level = slevel;
wd = sface;
status = sstatus;
}
boolean flipable() {
return status == 0 ? true : false;
}
void flip() {
status = 1;
}
}

class board {
chiz[][] grd;
int turn; // 1:玩家1 , -1:玩家2

void init() {
grd = new chiz[4][8];
turn = 1;
grd[0][0] = new chiz("r", 0, "帥", 0);
grd[0][1] = new chiz("r", 1, "仕", 0);
grd[0][2] = new chiz("r", 1, "仕", 0);
grd[0][3] = new chiz("r", 2, "相", 0);
grd[0][4] = new chiz("r", 2, "相", 0);
grd[0][5] = new chiz("r", 3, "俥", 0);
grd[0][6] = new chiz("r", 3, "俥", 0);
grd[0][7] = new chiz("r", 4, "傌", 0);
grd[1][0] = new chiz("r", 4, "傌", 0);
grd[1][1] = new chiz("r", 5, "炮", 0);
grd[1][2] = new chiz("r", 5, "炮", 0);
grd[1][3] = new chiz("r", 6, "兵", 0);
grd[1][4] = new chiz("r", 6, "兵", 0);
grd[1][5] = new chiz("r", 6, "兵", 0);
grd[1][6] = new chiz("r", 6, "兵", 0);
grd[1][7] = new chiz("r", 6, "兵", 0);
grd[2][0] = new chiz("b", 0, "將", 0);
grd[2][1] = new chiz("b", 1, "士", 0);
grd[2][2] = new chiz("b", 1, "士", 0);
grd[2][3] = new chiz("b", 0, "象", 0);
grd[2][4] = new chiz("b", 0, "象", 0);
grd[2][5] = new chiz("b", 0, "車", 0);
grd[2][6] = new chiz("b", 0, "車", 0);
grd[2][7] = new chiz("b", 0, "馬", 0);
grd[3][0] = new chiz("b", 0, "馬", 0);
grd[3][1] = new chiz("b", 0, "包", 0);
grd[3][2] = new chiz("b", 0, "包", 0);
grd[3][3] = new chiz("b", 0, "卒", 0);
grd[3][4] = new chiz("b", 0, "卒", 0);
grd[3][5] = new chiz("b", 0, "卒", 0);
grd[3][6] = new chiz("b", 0, "卒", 0);
grd[3][7] = new chiz("b", 0, "卒", 0);
}
void rnd() {
for(int i=0 ; i<200 ; i++) {
int x1 = (int) (Math.random() * 8);
int y1 = (int) (Math.random() * 4);
int x2 = (int) (Math.random() * 8);
int y2 = (int) (Math.random() * 4);
chiz tmp;
tmp = grd[y1][x1];
grd[y1][x1] = grd[y2][x2];
grd[y2][x2] = tmp;

}
}
void show() {
for(int i=0 ; i<4 ; i++) {
for(int j=0 ; j<8 ; j++)
if(grd[i][j] == null)
System.out.print(" ");
else if(grd[i][j].status == 1)
System.out.print(grd[i][j].wd + " ");
else if(grd[i][j].status == 0)
System.out.print("口 ");
System.out.println();
}
}
void move(int y1, int x1, int y2, int x2) {
if(grd[y2][x2] != null)
grd[y2][x2].status = 2;
grd[y2][x2] = grd[y1][x1];
grd[y1][x1] = null;
}
boolean movable(int y1, int x1, int y2, int x2) {
boolean movable = false;
if(grd[y1][x1] != null && grd[y1][x1].status == 1)
if(grd[y2][x2] == null)
movable = true;
else if(grd[y2][x2].status == 1 && !grd[y1][x1].team.equals(grd[y2][x2].team))
if(grd[y1][x1].level == 5) {
int cnt = 0, f = 0, t = 0;
if(x1 == x2) {
if(y1 > y2) {
f = y2;
t = y1;
} else {
f = y1;
t = y2;
}
for(int i=f+1 ; i<t ; i++)
if(grd[i][x1] != null)
cnt++;
} else if (y1 == y2) {
if(x1 > x2) {
f = x2;
t = x1;
} else {
f = x1;
t = x2;
}
for(int i=f+1 ; i<t ; i++)
if(grd[y1][i] != null)
cnt++;
}
if(cnt == 1)
movable = true;
} else if(!(grd[y1][x1].level == 0 && grd[y2][x2].level == 0) && grd[y1][x1].level <= grd[y2][x2].level)
movable = true;
else if(grd[y1][x1].level == 6 && grd[y2][x2].level == 0)
movable = true;

return movable;
}
}
public class game {
public static void main(String[] args) {
board br = new board(); // 建立棋盤物件
br.init(); // 初始化
br.rnd(); // 打亂
br.show();
Scanner sc = new Scanner(System.in);
String cmd = "";
do {
System.out.println(br.turn == 1 ? "P1:" : "P2:"); // 棋盤回傳(turn)紀錄為1顯示P1:,否則顯示為P2:
cmd = sc.nextLine();
String token[] = cmd.split(",");
if(token.length == 2) { // 拆解後若有兩個數字,則表示欲翻棋
int y1 = Integer.parseInt(token[0]);
int x1 = Integer.parseInt(token[1]);
if(br.grd[y1][x1].flipable()) { // 若y1,x1位置可翻棋
br.grd[y1][x1].flip(); // 翻開
br.turn *= -1; // 回傳(turn)換手
}
} else if(token.length == 4) {
int y1 = Integer.parseInt(token[0]);
int x1 = Integer.parseInt(token[1]);
int y2 = Integer.parseInt(token[2]);
int x2 = Integer.parseInt(token[3]);
if(br.movable(y1, x1, y2, x2)) { // 如果可以的話就移動、換手
br.move(y1, x1, y2, x2);
br.turn *= -1;
}
}
br.show(); // 重新顯示(刷新棋盤)
} while (!cmd.equals("end"));
sc.close();
}
}

可修改處

1. 可將 init()rnd() 加上 private

1
private void init() {
1
private void rnd() {

2. 增加 board 建構子,並叫用 init()rnd()

1
2
3
4
board() {
init();
rnd();
}

主程式變動:

1
2
3
4
5
6
7
8
9
public static void main(String[] args) {
board br = new board();
// br.init();
// br.rnd();
// br.show();
Scanner sc = new Scanner(System.in);
String cmd = "";
do {
br.show();