五子棋分析:
[1] 这里做的是一个控制台程序,一个16x16的棋盘组成;同时棋盘的第一行和第一列作为坐 标指示行和列不可落子。
[2] 行列的指示像:0 1 2 3 4 5 6 7 8 9 a b c d e f ,也就是说任何一方在落子的时候只能是这其中的任一组合中选择,如:23,5d,fe,等,否则判断落子不合法,该方重新落子。
[3] 考虑用一个固定的字符数组来初始化棋盘,并且在打印的时候将第一行和第一列至为 0 1 2 3 4 5 6 7 8 9 a b c d e f ,其他可以落子的地方至为'*',那么接下来的问题就是落子的问题了。
[4] 鉴于白黑双方每次只能落子一次并且不能悔棋(当然悔棋是能实现的了),设计的时候在Chess类中给一个对象变量初始化为0,当每一个打印新的棋盘时该变量做一次自加运算,用该变量与2的模运算来判定黑白方落子(余0白方落子,余1黑方落子),现在接下来的问题是解决输赢的问题了。
[5] 这面所以的问题都比较好解决,这里输赢怎么来判断呢?规则是当任何一条线上(横向,纵向,左斜方向,右斜方向)的同一方的棋子率先达到5颗,那么判定该方获胜;我这里的思路是每次下一颗棋子时,总横向,纵向,斜向判断该方的棋子是否达到5颗,达到则该方获胜。
Chess.java
package com.chess.gobang;
/**
* @ClassName: Chess
* @Description: TODO
* @author Bruce
* @date Aug 29, 2011 9:13:59 PM
* @version 1.1
*
*/
class Chess {
private static final int ROW_CHESS = 16;
private static final int COLUMN_CHESS = 16;
public int stepCount = 0;
char[][] board = new char[ROW_CHESS][COLUMN_CHESS];
public int getStepCount() {
return this.stepCount;
}
public void init() {
for (int i = 0; i < ROW_CHESS; i++) {
for (int j = 0; j < COLUMN_CHESS; j++) {
if (i == 0 || j == 0) {
board[0][j] = Integer.toHexString(j).charAt(0);
board[j][0] = Integer.toHexString(j).charAt(0);
} else
board[i][j] = '*';
}
}
}
public void printChess() {
for (int i = 0; i < ROW_CHESS; i++) {
for (int j = 0; j < COLUMN_CHESS; j++) {
System.out.print(board[i][j] + " ");
}
System.out.println();
}
stepCount++;
}
public boolean validChessman(char row) {
switch (row) {
case '1':
return true;
case '2':
return true;
case '3':
return true;
case '4':
return true;
case '5':
return true;
case '6':
return true;
case '7':
return true;
case '8':
return true;
case '9':
return true;
case 'a':
return true;
case 'b':
return true;
case 'c':
return true;
case 'd':
return true;
case 'e':
return true;
case 'f':
return true;
}
return false;
}
public void setWhite(char row, char col) {
int i = Character.getNumericValue(row);
int j = Character.getNumericValue(col);
if (board[i][j] == '*') {
board[i][j] = '@';
this.printChess();
}
else if (board[i][j] == '@')
System.out.println("这里已经有你的棋子!");
else
System.out.println("这里已经有黑方棋子!");
}
public void setBlack(char row, char col) {
int i = Character.getNumericValue(row);
int j = Character.getNumericValue(col);
if (board[i][j] == '*') {
board[i][j] = '#';
this.printChess();
} else if (board[i][j] == '#')
System.out.println("这里已经有你的棋子!");
else
System.out.println("这里已经有白方棋子!");
}
public boolean isWin(char row, char col) {
if (this.validChessman(row) && this.validChessman(col)) {
int r = Character.getNumericValue(row);
int l = Character.getNumericValue(col);
int left = 0;
int right = 0;
int up = 0;
int down = 0;
int leftUp = 0;
int leftDown = 0;
int rightUp = 0;
int rightDown = 0;
int ri = l;
int upPoint = r;
int tempL = l;
int leftUpR = r;
int leftUpL = l;
int leftDownR = r;
int leftDownL = l;
int rightUpR = r;
int rightUpL = l;
int rightDownR = r;
int rightDownL = l;
if (this.getStepCount() % 2 == 0) {
// 判断横向
while (this.validChessman(Integer.toHexString(--l).charAt(0))
&& board[r][l] == '@') {
left++;
}
while (ri < 16
&& this.validChessman(Integer.toHexString(ri).charAt(0))
&& board[r][ri++] == '@') {
right++;
}
if (right + left > 4) {
System.out.println("恭喜你,白方获胜!");
return true;
}
// 判断纵向
while (this.validChessman(Integer.toHexString(--r).charAt(0))
&& board[r][tempL] == '@')
up++;
while (upPoint < 16
&& this.validChessman(Integer.toHexString(upPoint)
.charAt(0)) && board[upPoint++][tempL] == '@')
down++;
if (up + down > 4) {
System.out.println("恭喜你,白方获胜!");
return true;
}
// 判断左斜方向
while (this.validChessman(Integer.toHexString(--leftUpR)
.charAt(0))
&& this.validChessman(Integer.toHexString(--leftUpL)
.charAt(0)) && board[leftUpR][leftUpL] == '@')
leftUp++;
while (leftDownR < 16
&& leftDownL < 16
&& this.validChessman(Integer.toHexString(leftDownR)
.charAt(0))
&& this.validChessman(Integer.toHexString(leftDownL)
.charAt(0))
&& board[leftDownR++][leftDownL++] == '@')
leftDown++;
if (leftUp + leftDown > 4) {
System.out.println("恭喜你,白方获胜!");
return true;
}
// 判断右斜方向
while (this.validChessman(Integer.toHexString(--rightUpR)
.charAt(0))
&& this.validChessman(Integer.toHexString(++rightUpL)
.charAt(0))
&& rightUpL < 16
&& board[rightUpR][rightUpL] == '@')
rightUp++;
while (this.validChessman(Integer.toHexString(rightDownR)
.charAt(0))
&& this.validChessman(Integer.toHexString(rightDownL)
.charAt(0))
&& rightDownR < 16
&& board[rightDownR++][rightDownL--] == '@')
rightDown++;
if (rightUp + rightDown > 4) {
System.out.println("恭喜你,白方获胜!");
return true;
}
} else {
// 判断横向
while (this.validChessman(Integer.toHexString(--l).charAt(0))
&& board[r][l] == '#') {
left++;
}
while (ri < 16
&& this.validChessman(Integer.toHexString(ri).charAt(0))
&& board[r][ri++] == '#') {
right++;
}
if (right + left > 4) {
System.out.println("恭喜你,黑方获胜!");
return true;
}
// 判断纵向
while (this.validChessman(Integer.toHexString(--r).charAt(0))
&& board[r][tempL] == '#')
up++;
while (upPoint < 16
&& this.validChessman(Integer.toHexString(upPoint)
.charAt(0)) && board[upPoint++][tempL] == '#')
down++;
if (up + down > 4) {
System.out.println("恭喜你,黑方获胜!");
return true;
}
// 判断左斜方向
while (this.validChessman(Integer.toHexString(--leftUpR)
.charAt(0))
&& this.validChessman(Integer.toHexString(--leftUpL)
.charAt(0)) && board[leftUpR][leftUpL] == '#')
leftUp++;
while (leftDownR < 16
&& leftDownL < 16
&& this.validChessman(Integer.toHexString(leftDownR)
.charAt(0))
&& this.validChessman(Integer.toHexString(leftDownL)
.charAt(0))
&& board[leftDownR++][leftDownL++] == '#')
leftDown++;
if (leftUp + leftDown > 4) {
System.out.println("恭喜你,黑方获胜!");
return true;
}
// 判断右斜方向
while (this.validChessman(Integer.toHexString(--rightUpR)
.charAt(0))
&& this.validChessman(Integer.toHexString(++rightUpL)
.charAt(0))
&& rightUpL < 16
&& board[rightUpR][rightUpL] == '#')
rightUp++;
while (this.validChessman(Integer.toHexString(rightDownR)
.charAt(0))
&& this.validChessman(Integer.toHexString(rightDownL)
.charAt(0))
&& rightDownR < 16
&& board[rightDownR++][rightDownL--] == '#')
rightDown++;
if (rightUp + rightDown > 4) {
System.out.println("恭喜你,黑方获胜!");
return true;
}
}
}
return false;
}
}
Gobang.java
package com.chess.gobang;
/**
* @ClassName: Gobang
* @Description: TODO
* @author Bruce
* @date Aug 29, 2011 9:14:42 PM
* @version 1.1
*
*/
import java.util.Scanner;
public class Gobang {
public static void main(String[] args) {
Chess chess = new Chess();
chess.init();
chess.printChess();
Scanner sc = new Scanner(System.in);
String chessman = "";
char rowChessman = 0;
char colChessman = 0;
while (!chess.isWin(rowChessman, colChessman)) {
//倘若到最后都没分出胜负,跳出循环,结束,平局
if(chess.getStepCount() == 226)
{
break;
}
// 由白方开始落子
if (chess.getStepCount() % 2 == 1) {
System.out.println("请白方落子(@):");
chessman = sc.next();
//棋子坐标长度是否为两位,否则重新落子
if (chessman.length() == 2) {
rowChessman = chessman.charAt(0);
colChessman = chessman.charAt(1);
boolean whiteDone = false;
while (!whiteDone) {
// 棋子合法,继续;否则直到获得合法棋子为止
if (chess.validChessman(rowChessman)
&& chess.validChessman(colChessman)) {
chess.setWhite(rowChessman, colChessman);
whiteDone = true;
} else {
//棋子包含无效字符,重新落子
System.out.println("白棋子不合法,请重新落子:");
break;
}
}
} else {
System.out.println("白棋子坐标长度应该为2,请重新落子:");
}
} else {
// 黑方开始落子
System.out.println("请黑方落子(#):");
chessman = sc.next();
//棋子坐标长度是否为两位,否则重新落子
if (chessman.length() == 2) {
rowChessman = chessman.charAt(0);
colChessman = chessman.charAt(1);
boolean blackDone = false;
while (!blackDone) {
// 棋子合法,继续;否则直到获得合法棋子为止
if (chess.validChessman(rowChessman)
&& chess.validChessman(colChessman)) {
chess.setBlack(rowChessman, colChessman);
blackDone = true;
} else {
//棋子包含无效字符,重新落子
System.out.println("黑棋子不合法,请重新落子:");
break;
}
}
} else {
System.out.println("黑棋子坐标长度应该为2,请重新落子:");
}
}
}
System.out.println("恭喜二位,你们实力相当,占城平手!");
}
}
附注:
[size=medium]
[1] 我认为这里的isWin()方法写的实在是对不住观众,仅仅是功能实现而已;这个仅仅是一个中间版本,接下来的时候我会优化这些代码,使其更加的面向对象,这样可读性也会好很多。
[2] 在判断棋子的合法性我用了一个包含switch的方法,这里当然也可以利用类似二分查找的算法,只是返回值是boolean类型而已,不过我觉得这里用switch语句可能可读性更加好点,而且在这里其性能也不比二分查找差(我的感觉而已)
size]