《疯狂Java讲义(第4版)》-----第4章【控制台五子棋】

特此说明:本文参考《疯狂Java实战演义》

开发游戏:控制台五子棋
开发工具:记事本

五子棋流程分析

在这里插入图片描述

需求分析

这个游戏比较简单,我们要完成人机下棋,需要棋盘类、棋子类和游戏类。棋盘和棋子都可以看成是游戏的一部分,构成聚合关系。然后根据上面的游戏流程分析。重点还是自上而下地进行结构化设计程序。

  1. 开始游戏
  2. 强行退出或重玩游戏强行退出或重玩游戏
  3. 用户输入落子坐标
  4. 判断落子坐标是否合法
  5. 判断输赢和棋(如有赢方或和棋,判断是否重玩)
  6. 程序输入落子坐标

代码实现

经过约摸8小时左右的奋战。写着调试着,终于大功告成,不知是否还有bug!!笔者参考了原作者思路,并加以改进,完全使用记事本开发。具体代码如下!!
在这里插入图片描述
在这里插入图片描述
Chessman.java


//根据枚举类写法书写,棋子枚举类只需提供黑白棋两个实例即可
public enum Chessman{
	BLACK("●"),WHITE("○");//注意在黑框框命令行下●是灰色,估计是不够黑的缘故吧
	private String chessman;

	private Chessman(String chessman){
		this.chessman = chessman;
	}
	
	public String getChessman(){
		return this.chessman;
	}

	//测试
	/*
	public static void main(String[] args){
		System.out.println(Chessman.BLACK.getChessman());
		System.out.println(Chessman.WHITE.getChessman());
	}
	*/
	
}

Chessboard.java

public class Chessboard{
	//棋盘
	private String[][] chessboard;
	//棋盘长宽
	public static final int CHESSBOARD_SIZE = 15;

	//空参构造函数
	public Chessboard(){} 

	//初始化棋盘,用二维数组表示棋盘,每个数组元素都赋值为┼
	public void initChessboard(){
		this.chessboard = new String[CHESSBOARD_SIZE][CHESSBOARD_SIZE];
		
		//画出棋盘
		for(int i = 0; i< CHESSBOARD_SIZE; i++){
			for(int j = 0; j < CHESSBOARD_SIZE; j++){
				this.chessboard[i][j] = "┼";
			}
		}
		
	}

	
	//打印棋盘	
	public void printChessboard(){
		for(int i = 0; i<CHESSBOARD_SIZE; i++){
			for(int j = 0; j < CHESSBOARD_SIZE; j++){
				System.out.print(this.chessboard[i][j]);
			}
			System.out.println();
		}
	}

	//把棋盘上的位置(posX, posY)放上棋子chessman,单纯从这一点看,
	//棋盘类确实是依赖游戏类的,也就是说,不玩游戏的话,何谈要打印棋盘呢!
	public void setChessboard(int posX, int posY, String chessman){
		this.chessboard[posX][posY] = chessman;
	}
	
	//获得棋盘对象中的棋盘二维数组
	public String[][] getChessboard(){
		return this.chessboard;
	}

	//测试
	/*
	public static void main(String[] args){
		//准备一个棋盘
		Chessboard chessboard = new Chessboard();
		chessboard.initChessboard();
		//打印棋盘
		chessboard.printChessboard();
		//下一个黑子
		chessboard.setChessboard(5,5,"○");
		System.out.println();
		//打印棋盘
		chessboard.printChessboard();
		System.out.println();
		//获得棋盘对象中的棋盘数组并打印
		String[][] chessboard2 = chessboard.getChessboard();
		for(String[] x : chessboard2){
			for(String y : x){
				System.out.print(y);
			}
			System.out.println();
		}
	}
	*/
	
}

Gobang.java

import java.util.Scanner;

public class Gobang{

	//包含棋盘类Chessboard
	private Chessboard chessboard;
	private int posX;//落子横坐标
	private int posY;//落子纵坐标


	//空参构造函数
	public Gobang(){}


	//游戏入口
	public static void main(String[] args){
		Gobang gobang = new Gobang();
		gobang.run();
	}

	//运行游戏
	public void run(){
		//游戏开始提示
		System.out.println("**********游戏开始**********");
		System.out.println("exit----->强行退出**********");
		System.out.println("**********游戏开始**********");
		System.out.println();
		

		//准备棋盘
		this.chessboard = new Chessboard();
		this.chessboard.initChessboard();
		this.chessboard.printChessboard();
		
		System.out.println("请按照x,y格式输入棋子坐标");
		Scanner scan = new Scanner(System.in);

		while(scan.hasNextLine()){
				

			//存储用户输入的字符串到input
			String input = scan.nextLine();
			//如果输入exit,强制退出游戏
			if(input.equals("exit")){
				System.out.println("您已经退出游戏");
				break;
			}
			//输入不合法,重新输入
			if(!isLegal(input)){
				continue;
			}
			
			//输入合法,相应位置放上黑棋
			if(!isFull()){
				this.chessboard.setChessboard(this.posX,this.posY, Chessman.BLACK.getChessman());
					
			}else{
				
				//棋盘已经占满棋子,和棋
				System.out.println("和棋了!是否再玩一盘?输入y重玩,输入其他退出游戏");
				String isReplay = scan.nextLine();
				//如果重玩,输入的是y
				if(isReplay.equals("y")){
					chessboard.initChessboard();
					chessboard.printChessboard();
					continue;
				}else{
					//如果输入的是非y,结束游戏
					break;
				}
			}
			
			
			//判断用户是否赢了
			if(isWin(posX, posY, Chessman.BLACK.getChessman())){
				this.chessboard.printChessboard();
				System.out.println("恭喜您赢了!是否再玩一盘?输入y重玩,输入其他退出游戏");
				String isReplay = scan.nextLine();
				//如果重玩,输入的是y
				if(isReplay.equals("y")){
					chessboard.initChessboard();
					chessboard.printChessboard();
					continue;
				}else{
					//如果输入的是非y,结束游戏
					break;
				}
			}else{
				
				//用户没有赢,机器就继续下棋,随机找一个空着的位置落子
				int posMachineX = (int)(Math.random()*(this.chessboard.CHESSBOARD_SIZE-1));
				int posMachineY = (int)(Math.random()*(this.chessboard.CHESSBOARD_SIZE-1));
				//得到棋盘数组
				String[][] chessboardArr = this.chessboard.getChessboard();
				while(chessboardArr[posMachineX][posMachineY]!="┼"){
					posMachineX = (int)(Math.random()*(this.chessboard.CHESSBOARD_SIZE-1));
					posMachineY = (int)(Math.random()*(this.chessboard.CHESSBOARD_SIZE-1));
					
				}
				
				//如果棋盘还没有满的话
				if(!isFull()){
					this.chessboard.setChessboard(posMachineX ,posMachineY , Chessman.WHITE.getChessman());
					
				}else{
				
					//棋盘已经占满棋子,和棋
					System.out.println("和棋了!是否再玩一盘?输入y重玩,输入其他退出游戏");
					String isReplay = scan.nextLine();
					//如果重玩,输入的是y
					if(isReplay.equals("y")){
						chessboard.initChessboard();
						chessboard.printChessboard();
						continue;
					}else{
						//如果输入的是非y,结束游戏
						break;
					}
				}
				

				//判断机器是否赢了
				if(isWin(posX, posY, Chessman.WHITE.getChessman())){
					this.chessboard.printChessboard();
					System.out.println("您输了!是否再玩一盘?(y/n)");
					String isReplay = scan.nextLine();
					if(isReplay.equals("y")){
						chessboard.initChessboard();
						chessboard.printChessboard();
						continue;
					}else{
						//输入的是非y,退出游戏
						break;	
					}
				}
			}
			this.chessboard.printChessboard();
			System.out.println("请按照x,y格式输入棋子坐标");
			
		}		
	}

	//判断输入是否合法
	public boolean isLegal(String input){
		
		//要判断输入的格式是否是x,y格式
		String[] posStrArr = input.split(",");
		
		try{
			this.posX = Integer.parseInt(posStrArr[0]) - 1;
			this.posY = Integer.parseInt(posStrArr[1]) - 1;
		}catch(Exception e){
			//输入的数字格式不正确,导致用逗号劈开的字符串并不是数字
			chessboard.printChessboard();
			System.out.println("请按照x,y的格式(注意范围1-15)输入: ");
			return false;
		}
		
		
		//判断用户输入的坐标是否超过棋盘范围
		if(this.posX < 0 || this.posX >= this.chessboard.CHESSBOARD_SIZE || 
				this.posY < 0 || this.posY >= this.chessboard.CHESSBOARD_SIZE){
			chessboard.printChessboard();
			System.out.println("输入坐标不在棋盘范围(1-15)内,请重新输入: ");
			return false;
		}

		//判断输入的位置上是否已经有棋子
		String[][] chessboard_tmp = this.chessboard.getChessboard();
		if(!chessboard_tmp[this.posX][this.posY].equals("┼")){
			chessboard.printChessboard();
			System.out.println("这个位置上已经有棋子,请重新输入: ");
			return false;
		}
			
		return true;	
	}

	//判断输赢,传入的是当前落下的棋子,可根据颜色判断赢方
	//思路:每行、每列、每斜着的棋子,拼接成串,看是否包含五个黑子或五个白子连着的情况
	public boolean isWin(int posX, int posY, String chessman){
		//五个棋子拼接成一字符串subString
		String subString = "";
		for(int i = 0; i < 5; i++){
			subString += chessman;
		}

		//获得当前对象chessboard的棋盘的二维数组
		String[][] chessboard_tmp = this.chessboard.getChessboard();
		
		//判断每一行和每一列是否有五子相邻的情况
		for(int i = 0; i < this.chessboard.CHESSBOARD_SIZE; i++){
			//临时字符串,用于拼接每一行的串
			String tmp_row = "";
			//临时字符串,用于拼接每一列的串
			String tmp_col = "";
			for(int j = 0; j < this.chessboard.CHESSBOARD_SIZE; j++){
				tmp_row += chessboard_tmp[i][j];
				tmp_col += chessboard_tmp[j][i];
			}
			if(tmp_row.contains(subString) || tmp_col.contains(subString)){
				return true;
			}
		}
		
		//判断起点是第一行的斜着的两个方向串是否有五子相邻的情况
		for(int k = 0; k < this.chessboard.CHESSBOARD_SIZE; k++){
			//临时字符串,拼接起点是第一行的斜着的串
			String tmp_left = "";//斜着左下
			String tmp_right = "";//斜着右下
			//斜着右下
			for(int i = 0, j = k; i < this.chessboard.CHESSBOARD_SIZE && j < this.chessboard.CHESSBOARD_SIZE; i++,j++){
				tmp_left += chessboard_tmp[i][j];
			}
			//斜着左下
			for(int i = 0, j = k; i < this.chessboard.CHESSBOARD_SIZE && j >= 0; i++,j--){
				tmp_right += chessboard_tmp[i][j];
			}
			if(tmp_left.contains(subString) || tmp_right.contains(subString)){
				return true;
			}
		}

		//判断起点是最后一行的斜着的两个方向串是否有五子相邻的情况
		for(int k = 0; k < this.chessboard.CHESSBOARD_SIZE; k++){
			//临时字符串,拼接起点是最后一行的斜着的串
			String tmp_left = "";//斜着左上
			String tmp_right = "";//斜着右上
			//斜着右下
			for(int i = this.chessboard.CHESSBOARD_SIZE - 1, j = k; i >= 0 && j >= 0; i--,j--){
				tmp_left += chessboard_tmp[i][j];
			}
			//斜着左下
			for(int i = this.chessboard.CHESSBOARD_SIZE - 1, j=k; i >= 0 && j < this.chessboard.CHESSBOARD_SIZE; i--,j++){
				tmp_right += chessboard_tmp[i][j];
			}
			if(tmp_left.contains(subString) || tmp_right.contains(subString)){
				return true;
			}
		}
		
		return false;
	}

	//判断棋盘是否已经占满棋子
	public boolean isFull(){
		
		//得到棋盘数组
		String[][] chessboardArr = this.chessboard.getChessboard();
		//判断是否和棋
		for(int i = 0; i < this.chessboard.CHESSBOARD_SIZE; i++){
			for(int j = 0; j < this.chessboard.CHESSBOARD_SIZE; j++){
				if(chessboardArr[i][j].equals("┼")){
					return false;
				}
			}
		}
		return true;
	}


}
  • 4
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 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、付费专栏及课程。

余额充值