`
java--hhf
  • 浏览: 305447 次
  • 性别: Icon_minigender_1
社区版块
存档分类
最新评论

五子棋之人人五子棋

阅读更多

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

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

   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);

		//如果有了五个或五个以上的连续相同颜色就给出判断 true
		if(num >= 5)
			return true;
		else
			return 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);

		//如果有了五个或五个以上的连续相同颜色就给出判断 true
		if(num >= 5)
			return true;
		else
			return 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);

		//如果有了五个或五个以上的连续相同颜色就给出判断 true
		if(num >= 5)
			return true;
		else
			return 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);

		//如果有了五个或五个以上的连续相同颜色就给出判断 true
		if(num >= 5)
			return true;
		else
			return 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 stub
		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] == 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);
				}		
				
			}
		}

	}

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

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

 

 

      

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics