读书人

五子棋之人们五子棋

发布时间: 2012-12-23 11:28:15 作者: rapoo

五子棋之人人五子棋

???? 编写一个五子棋代码量不会很大,但这好歹也算是个项目,所以还是需要花点时间的。看别人的代码需要耐心,要看懂别人的代码就更需要耐心了,作为一个程序员也就是需要这样的耐心。当然,在代码里我会尽量的多加一些注释来提高代码的可读性,唯一的要求就是要读者们一步一步的跟着我来,顺着我的思路一步一步的深入,这样才能最终达到我写这篇博客和你看这篇博客的目的。

????????那下面呢,我就具体介绍一下人人五子棋是如何实现的。

???1)首先我们要有一个五子棋界面,就是画出许多行横线和许多行竖线

?

private void DrawCheesTable(Graphics g) {// TODO Auto-generated method stub//画出指定的行数for( int i = 0; i < Config.ROWS; i++)g.drawLine(Config.X0, Config.Y0 + Config.SIZE * i,Config.X0 + Config.SIZE *( Config.COLUMNS - 1), Config.Y0 +Config.SIZE * i);//画出指定的列数for( int i = 0; i < Config.COLUMNS; i++)g.drawLine(Config.X0 + Config.SIZE * i,Config.Y0, Config.X0 + Config.SIZE * i,Config.Y0 +( Config.ROWS - 1) * Config.SIZE);}

?

???? 看到上面的代码里面有一些奇怪的符号吧,不急,那是我事先定义好的保存常量数据的类。另外,for语句中画线所用到的数据是如何给定的,留给读者自己分析了。

??? 2)创建一个保存常量的类,为了方便我们改变棋子大小,棋盘大小

????? 棋盘画好了,现在就来实现释放鼠标时画填充圆。鼠标释放,就用到?public void mouseReleased(MouseEvent e) {}函数,于是就要监听器类extends java.awt.event.MouseAdapter了。

public interface Config {//棋盘的初始点坐标public static final int X0 = 50;public static final int Y0 = 50;//多少列多少行public static final int ROWS = 11;public static final int COLUMNS = 14;//棋子的大小  //格子的大小public static final int CHESS_SIZE = 40;public static final int SIZE = 40;}

?

??? 3)鼠标释放方法

public void mouseReleased(MouseEvent e) {//得到鼠标释放时的点的坐标int x1 = e.getX();int y1 = e.getY();//按下点后我们就去找 它在拿个交点附近for(int i = 0; i < Config.ROWS; i++){for(int j = 0; j < Config.COLUMNS; j++){//得到每一个交点的值xx = Config.X0 + Config.SIZE * j;yy = Config.Y0 + Config.SIZE * i;//如果这个交点可以放棋子if(FiveChress_array[i][j] == 0)//判断离谁更近if(x1 > xx - Config.SIZE/3 && x1 < xx + Config.SIZE/ 3 && y1 > yy - Config.SIZE /3 && y1 < yy + Config.SIZE /3 )//花黑棋if(count){System.out.println("再黑棋中xx的值是 " +xx +"\t" + "在黑棋中yy的值是  " + yy);//画出来的是黑棋g.setColor(java.awt.Color.BLACK);g.fillOval(xx - Config.CHESS_SIZE/2, yy - Config.CHESS_SIZE/2, Config.CHESS_SIZE, Config.CHESS_SIZE);//下一次是画白棋count = false;//用数组记录每个交点的属性 1黑棋 0空白 -1白棋FiveChress_array[i][j] = 1;x = j;y = i;//画出了点酒结束 不再循环break;}else{//画白棋System.out.println("再白棋中xx的值是 " +xx +"\t" + "在白棋中yy的值是  " + yy);g.setColor(java.awt.Color.WHITE);g.fillOval(xx - Config.CHESS_SIZE/2, yy - Config.CHESS_SIZE/2, Config.CHESS_SIZE, Config.CHESS_SIZE);count = true;FiveChress_array[i][j] = -1 ;x = j;y = i;//画出了点酒结束 不再循环break;}}}//调用判断是否赢棋函数win_or_not(x,y);}

????? 这其中包含了一个判断鼠标按下点离哪个棋盘交点最近的算法,留给读者自己分析了。里面同时有使用很多的变量它们的声明如下

//定义画板对象 private java.awt.Graphics g;//每个棋子的基本属性    true表示要放黑棋  false表示要放白棋 private boolean count = true;//再创建两个数来表示交点坐标 使得画出来的圈圆心会在交点private int xx,yy;//创建(x,y)来表示按下的那个点所放在的焦点坐标  比如(1,3) 表示第一行第三个交点private int x,y;//创建一个数组记录每个可以放棋子的点的状态  0表示空  1表示黑棋 -1表示白棋private int [][] FiveChress_array = new int[Config.ROWS][Config.COLUMNS];

???? 4)鼠标监听器类的构造函数

//构造函数public ChessListener(java.awt.Graphics g1 , int [][] FiveChress_array){//地址传递this.g = g1;this.FiveChress_array = FiveChress_array;}

???? 现在我们的棋子可以下了,而且可以下在正确的位置上,下面要做的是实现win_or_not()函数了,该函数里我们要实现行列左倾斜,右倾斜的判断。

????? 5)实现win_or_not()函数

private void win_or_not(int x, int y) {//如果在行列左斜右斜的方向上有了五个连续的同色棋子 就可以判断出输赢了System.out.println("进入win_or_not函数");if(check_row(x,y) || check_columns(x,y) || check_left(x,y) || check_right(x,y) ){if(!count){//黑棋赢了JOptionPane.showMessageDialog(null,"我靠 黑棋赢了");System.out.println("我靠 黑棋赢了");}else{//白棋赢了JOptionPane.showMessageDialog(null,"我靠 白棋赢了");System.out.println("我靠 白棋赢了");}}}

???? 在if判断里调用了判断行、列、左斜、右斜的函数。其中JOptionPane.showMessageDialog(null,"");是用来弹出一个对话框突出显示输赢。

???? 6)check_row函数的实现

private boolean check_row(int x, int y) {int num = 0; //表示相同颜色的棋子个数//开始向右找相邻的相同颜色的for(int i = x ; i < Config.COLUMNS ; i++){if(FiveChress_array[y][x] == FiveChress_array[y][i]){//找到了 就加一num ++;}else{//找到了有一个不是 就跳出break;}}//开始向左找相邻的相同颜色的for(int i = x ; i > 0 ; i--){if(FiveChress_array[y][x] == FiveChress_array[y][i-1]){//找到了 就加一num ++;}else{//找到了有一个不是 就跳出break;}}System.out.println("在check_row函数里num = " + num);//如果有了五个或五个以上的连续相同颜色就给出判断 trueif(num >= 5)return true;elsereturn false;}

?

???? 7)check_columns函数的实现

private boolean check_columns(int x, int y) {int num = 0; //表示相同颜色的棋子个数//开始向右找相邻的相同颜色的for(int i = y ; i < Config.ROWS ; i++){if(FiveChress_array[y][x] == FiveChress_array[i][x]){//找到了 就加一num ++;}else{//找到了有一个不是 就跳出break;}}//开始向左找相邻的相同颜色的for(int i = y ; i > 0 ; i--){if(FiveChress_array[y][x] == FiveChress_array[i-1][x]){//找到了 就加一num ++;}else{//找到了有一个不是 就跳出break;}}System.out.println("在check_columns函数中num = " + num);//如果有了五个或五个以上的连续相同颜色就给出判断 trueif(num >= 5)return true;elsereturn false;}

?

???? 8)check_left函数的实现

private boolean check_left(int x, int y) {int num = 0; //表示相同颜色的棋子个数//定义ix,jy记录下(y,x);int ix = x;int jy = y;//开始向右上找相邻的相同颜色的for(int i = x, j = y;(Config.COLUMNS - i) < j ? (i < Config.COLUMNS) : j >= 0 ; i++,j--){if(FiveChress_array[y][x] == FiveChress_array[j][i]){//找到了 就加一num ++;}else{//找到了有一个不是 就跳出break;}}//开始向左下角找相邻的相同颜色的for(int i = ix, j = jy ; i <(Config.ROWS - j) ? i>=0 : (j < Config.ROWS) ; i--,j++){if(FiveChress_array[jy][ix] == FiveChress_array[j][i]){//找到了 就加一num ++;}else{//找到了有一个不是 就跳出break;}}//在两个for循环里有两次和自己比较颜色num--;System.out.println("在check_left函数里num = " + num);//如果有了五个或五个以上的连续相同颜色就给出判断 trueif(num >= 5)return true;elsereturn false;}

?

???? 9)check_right函数的实现

private boolean check_right(int x, int y) {int num = 0; //表示相同颜色的棋子个数//定义i,j记录下(y,x);int ix = x;int jy = y;//开始向右下角找相邻的相同颜色的for(int i = x, j = y;(Config.COLUMNS - i) < (Config.ROWS - j) ? (i < Config.COLUMNS) : (j < Config.ROWS) ; i++,j++){if(FiveChress_array[jy][ix] == FiveChress_array[j][i]){//找到了 就加一num ++;}else{//找到了有一个不是 就跳出break;}}//开始向左上角找相邻的相同颜色的for(int i = ix, j = jy ; i < j ? i >= 0 : j >= 0 ; i--,j--){if(FiveChress_array[y][x] == FiveChress_array[j][i]){//找到了 就加一num ++;}else{//找到了有一个不是 就跳出break;}}//在两个for循环里有两次和自己比较颜色num--;System.out.println("在check_right函数里num = " + num);//如果有了五个或五个以上的连续相同颜色就给出判断 trueif(num >= 5)return true;elsereturn false;}

????这些个方法都大同小异,主要注意它们的坐标,和递增递减关系,行和列一定不能表示错。x的改变就是列数的改变,y的改变就是行数的改变。

??? 写到这里基本上人人五子棋就完成了,下面要做的就是重绘,因为之前我们已经有用一个二维数组及路线每一个交点的属性,现在这个也就比较好实现了。

??? 10)paint函数的重写

public void paint(Graphics g1){//先绘出各个组件super.paint(g1);//绘出棋盘DrawCheesTable(g1);//重绘棋子DrawChees(g1);}

??? 11)重绘棋子函数的实现

private void DrawChees(Graphics g1) {// TODO Auto-generated method stubfor(int i = 0; i < Config.ROWS; i++){for(int j = 0; j < Config.COLUMNS; j++){//得到每一个交点的值xx = Config.X0 + Config.SIZE * j;yy = Config.Y0 + Config.SIZE * i;if(FiveChress_array[i][j] == 1){g.setColor(Color.BLACK);g.fillOval(xx - Config.CHESS_SIZE/2, yy - Config.CHESS_SIZE/2, Config.CHESS_SIZE, Config.CHESS_SIZE);}else if(FiveChress_array[i][j] == -1){g.setColor(Color.WHITE);g.fillOval(xx - Config.CHESS_SIZE/2, yy - Config.CHESS_SIZE/2, Config.CHESS_SIZE, Config.CHESS_SIZE);}}}}

???? 现在人人五子棋就完成了。

???? 但,这还是无比不够的。首先非常重要的界面不够美观,悔棋,重新开始,判断输赢后就不可以再下棋等等都还没有实现,留给读者们自己扩展了。

?

?

??????

读书人网 >编程

热点推荐