Java疯狂讲义第四章五子棋

import java.io.*;
import java.util.*;
public class Gobang{
	//定义棋盘的大小
	private static final int BOARD_SIZE = 15;
	//用二维数组充当棋盘
	private String[][] board;
	//用来画棋盘的符号("+"),此符号处代表无棋子
	private final String POINT = "+";
	//黑棋子
	private final String BLACK = "●";
	//白棋子
	private final String WHITE = "○";
	
	public static void main(String args[]) throws IOException{
		Gobang gb = new Gobang();
		gb.initBoard();
		gb.printBoard();
		gb.start();
	}
	
	public void initBoard(){
		//动态初始化棋盘数组
		board = new String[BOARD_SIZE][BOARD_SIZE];
		for(int i = 0; i < BOARD_SIZE; i ++){
			for(int j = 0; j < BOARD_SIZE; j ++){
					//每个位置赋值+,用于画出棋盘
					board[i][j] = POINT;
			}
		}
	}
	//在控制台输出棋盘
	public void printBoard(){
		for(int i = 0; i < BOARD_SIZE; i ++){
			for(int j = 0; j < BOARD_SIZE; j ++){
				System.out.print(board[i][j]);
			}
			System.out.print("\n");
		}
	}
	//游戏开始
	public void start() throws IOException{
		System.out.println("请输入您下棋的坐标,应以x,y的格式:");
		//获取从键盘输入的方法
		BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
		String inputStr = "";
		//键盘输入后按回车能被bufferedReader读取到
		while((inputStr = bufferedReader.readLine()) != null){
			String[] posStrArr = inputStr.split(",");
			int x = 0;
			int y = 0;
			try{					
				x = Integer.parseInt(posStrArr[0]);
				y = Integer.parseInt(posStrArr[1]);
			}catch(NumberFormatException e){
				//装换错误说明输入格式不对,重新输入
				System.out.println("输入的格式不正确!");
				continue;
			}
			if(!pointValid(x - 1,y - 1)){
				System.out.println("您输入的棋子坐标无效,请重输!");
				//无效直接跳过后面代码
				continue;
			}
			//对应位置用●赋值,代表一枚棋子
			board[x - 1][y - 1] = BLACK;
			if(scan()){
				System.out.println("玩家胜利!游戏结束");
				printBoard();
				break;
			}
				
			/*
				电脑随机生成两个整数,作为电脑下棋的坐标,赋值给board数组
				还涉及:
					1.坐标的有效性,只能是数字,不能超出棋盘的范围
					2.下棋的点,不能重复下棋
					3.每次下棋后需要扫描谁赢了
			*/
			
			computer();//需要完善的点:可以选择谁先下而不是默认的玩家先下
			if(scan()){
				System.out.println("电脑胜利!游戏结束");
				printBoard();
				break;
			}
			printBoard();
			System.out.println("请输入您下棋的坐标,应以x,y的格式(原点为左上角,x正方向向下,y正方向向右):");	
		}
	}
	//电脑下棋的方法
	private void computer(){
		//已满足生成点的坐标在棋盘内
		Random random = new Random();
		int x = random.nextInt(BOARD_SIZE);
		int y = random.nextInt(BOARD_SIZE);
		//有效性验证
		while(!pointValid(x,y)){
			//无效坐标重新生成
			x = random.nextInt(BOARD_SIZE);
			y = random.nextInt(BOARD_SIZE);
		}
		board[x][y] = WHITE;//需要完善的点:可以让玩家选择棋子,而不是默认玩家黑,电脑白
	}
	
	/**
	*
	*	验证下棋点的有效性
	*		1.验证下棋点是否超出棋盘范围(玩家下棋时需要验证,电脑这一步其实可以不验证)
	*		2.验证下棋的点是否已存在棋子
	*	@param x 横坐标(索引 0开始)
	*	@param y 纵坐标(索引 0开始)
	*	@return 坐标的有效性 有效:true,无效:false
	*
	*	java语法: javadoc只处理public protected修饰的类、接口、方法、成员变量、
	*			   构造函数、和内部类之前的文档注释(此处private,所以不会处理)
	*/
	private boolean pointValid(int x,int y){
		//验证下棋点是否超出棋盘范围(玩家下棋时需要验证,电脑这一步其实可以不验证,因为它生成的位置就在范围内)
		if(x >= BOARD_SIZE || y >= BOARD_SIZE || x < 0 || y < 0)
			return false;
		//验证下棋的点是否已存在棋子
		if(board[x][y] != POINT){
			//已存在棋子
			return false;
		}
		return true;
	} 
	/**
		难点:扫描算法(自己写的比较蠢的办法...智商不够用..哈哈)
		扫描是否有五个相同棋子连成一条线(—|\/)
		
		分析:
			一条线有四种情况—|\/:
			原点为左上角,x正方向向下,y正方向向右
			-: x相等  y从左到右依次加1
			|: y相等  x从上到下依次加1
			\:  从左上到右下,xy都依次加1
			/:  从右上到左下,x从上到下依次加1,y从右到左依次减1
			
			
		@return 有返回true,没有返回false
	*/
	private boolean scan(){
		for(int i = 0; i < BOARD_SIZE; i ++){
			for(int j = 0; j < BOARD_SIZE; j ++){
				if(board[i][j] != POINT){
					//有棋子
					if(board[i][j] == BLACK){
						if(getFive1(i,j,BLACK) || getFive2(i,j,BLACK) || getFive3(i,j,BLACK) || getFive4(i,j,BLACK))
							return true;
					}		
					//白棋子
					if(board[i][j] == WHITE){
						if(getFive1(i,j,WHITE) || getFive2(i,j,WHITE) || getFive3(i,j,WHITE) || getFive4(i,j,WHITE))
							return true;
					}
				}
			}
		}
		return false;
	}
	
	// "-"
	private boolean getFive1(int x,int y,String point){
		boolean flag = true;
		try{
			for(int m = 1; m <= 4 && flag; m ++){
				if(board[x][y+m]!=point){
					flag = false;
				}
			}
		}catch(ArrayIndexOutOfBoundsException e){
			flag = false;
		}
		return flag;
	}
	// "|"
	private boolean getFive2(int x,int y,String point){
		boolean flag = true;
		try{
			for(int m = 1; m <= 4 && flag; m ++){
				if(board[x+m][y]!=point){
					flag = false;
				}
			}
		}catch(ArrayIndexOutOfBoundsException e){
			flag = false;
		}
		return flag;
	}
	// "/"
	private boolean getFive3(int x,int y,String point){
		boolean flag = true;
		try{
			for(int m = 1; m <= 4 && flag; m ++){
				if(board[x+m][y-m]!=point){
					flag = false;
				}
			}
		}catch(ArrayIndexOutOfBoundsException e){
			flag = false;
		}
		return flag;
	}
	// "\"
	private boolean getFive4(int x,int y,String point){
		boolean flag = true;
		try{
			for(int m = 1; m <= 4 && flag; m ++){
				if(board[x+m][y+m]!=point){
					flag = false;
				}
			}
		}catch(ArrayIndexOutOfBoundsException e){
			flag = false;
		}
		return flag;
	}
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
疯狂Java讲义课后题 自己编写的 对于这个程序,最关键的在于判断是否连成5个棋子 一般的棋盘大小为15*15, 用大小为[15][15]的二维数组来盛放棋盘 要判断是否连成5个棋子,就要对棋子的周围进行遍历 这里规定遍历的方式为(左,右),(上,下),(左上,右下),(右上,左下) 4种最特殊的情况:  左上角:只进行右,下,右下  左下角:只进行右,上,右上  右上角:只进行左,下,左下  右下角:只进行左,上,左上 4种特殊情况(不含4个角):  上边界:不进行上遍历  下边界:不进行下遍历  左边界:不进行左遍历  右边界:不进行右遍历 对其他位置的遍历则为(左,右),(上,下),(左上,右下),(右上,左下) 每下一个棋子,都要判断它所处的位置来选择遍历的方式且每次遍历时都要判断是否到达边界,以防数组越界 这样的话,现实起来就会挺复杂 所以改进的方法是这样的: 用大小为[17][17]的二维数组来盛放棋盘 这样就可对每个位置的棋子用相同的遍历方式来遍历,即(左,右),(上,下),(左上,右下),(右上,左下)。并且不需要判断是否到达边界,大大降低了复杂性。 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 棋盘为如图所示的那么大。而实际上程序中规定的“棋盘”为中间的部分(即棋子只能摆在从1-15的位置上,否则会被程序告知摆放的位置不对),这样一来,不管棋子位于“棋盘”中的哪个位置,都可以采用(左,右),(上,下),(左上,右下),(右上,左下)的方式遍历而不会发生数组越界的错误,且无需判断是否到达边界。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值