tictactoe——前世今生

类的协作 职责 以及 可修改性

simple tictactoe

完成的是就是根据输入打印每次的棋盘,并且进行判断输赢

Board类

成员变量是一个二维棋盘(把行列设为final同时也应用于下面,可以增加可修改性,防止后续全部改变)
职责: 构建一个棋盘,并且记录每一次的情况,判定当前游戏的结果

这里比较巧妙的代码实现点是:虽然是X O 但在进行中我们可以让数字去代表这两个字符,并且判定结果
Gmae: turn=turn✖-1;
可谓是节省很多麻烦的关键因素


class Board {
    final static int row = 3;
    final static int col = 3;
    private int[][] board = new int[row][col];

    public void setBoard(int turn, String pos) {
        int x = pos.charAt(1) - '1';
        int y = pos.charAt(0) - 'A';
        if (this.board[x][y] != 0)
            System.out.println("Error. This place has been placed before");
        else
            board[x][y] = turn;
    }

    public void print() {
        System.out.print(this.toString());
    }

    public String toString() {
        String lineSeparator = System.getProperty("line.separator");
        String ret = "  A B C" + lineSeparator;
        for (int i = 0; i < row; i++) {
            ret += i + 1;
            for (int j = 0; j < col; j++) {
                if (board[i][j] == 1)
                    ret += " X";
                else if (board[i][j] == -1)
                    ret += " O";
                else
                    ret += " _";
            }
            ret += lineSeparator;
        }
        return ret;
    }

    /**
     * 根据题目要求进行判断
     * @return
     */
    public Result getStatement() {
        for (int i = 0; i < row; i++) {
            int temp = 0;
            for (int j = 0; j < col; j++)
                temp += board[i][j];

            if (temp == 3)         return Result.X_WIN;
            else if (temp == -3)   return Result.O_WIN;
        }

        for (int i = 0; i < row; i++) {
            int temp = 0;
            for (int j = 0; j < col; j++)
                temp += board[j][i];

            if (temp == 3)        return Result.X_WIN;
            else if (temp == -3)  return Result.O_WIN;
        }

        //检查对角线
        if (row == col) {
            int sum = 0, sum_two = 0;
            for (int i = 0; i < row; i++) {
                sum += board[i][i];
                sum_two += board[i][row - i-1];
            }
            if(sum==3||sum_two==3)          return Result.X_WIN;
            else if(sum==-3||sum_two==-3)   return Result.O_WIN;

        } else {
            System.out.println("行列不相等 嘻嘻");
        }
        return Result.DRAW;
    }
}

Game类

职责:进行游戏的进行,控制游戏的开始和终止。


public class Game {
    //棋盘与游戏是组合关系 有生命周期的联系
    private Board checkBoard = new Board();
    private int turn = 1;  //步数 来以此在棋盘判断是放入哪个

    //游戏主方法playGame
    //输入为对弈双方轮番落子的位置,以英文逗号为间隔,X先走
    public Result playGame(String s) {

        String[] position = s.split(",");
        for (String pos : position) {
            checkBoard.setBoard(turn, pos);
            checkBoard.print();
            if (checkBoard.getStatement() != Result.DRAW)
                break;
            turn*=-1;
        }
        return checkBoard.getStatement();
    }
}

交互&协作

Board与game的分离,各自实现各自的功能,并且很好的进行了协作

注意,有的同学实现了Player类,但会发现,这个类总是不断去调用board的内容,没有很好的实现单一原则,所以为何不都在board中实现呢?

这两个类之间是什么关系?
这两个类是 组合 关系,因为两者之间交互性较强,并且又生命周期的关系,游戏开始,棋盘肯定要建立,成员变量就要new Board()

Tictactoe

tictactoe——前世今生_第1张图片

这是整体包的结构
六个主要类
两个枚举类
FIVE是继承上面类的,因为属于他的一种(其实那个类也可以实现为接口)

根据题意建立接口GameWinStrategy,里面的方法分别两种策略进行实现
并且HV与HVD为组合关系,因为就多了一个斜方判断,但仍然不能说是继承关系(仅仅为了代码复用)

Game 类

package cn.edu.nju.TicTacToe;
public class Game {
	private int size;

	/**
     * Game的接口方法,我们会通过该方法进行测试
     * @param gameMode 游戏模式,有四种可能,00,01,10,11
     * @param moveStr 落子序列
     * @param size 棋盘大小,size最小为3, 最大为9
     * @return 游戏结果
     * 
     * 根据需要改写方法,参数,返回结果类型不可修改
     */
    public Result playGame(String gameMode, String moveStr, int size){

    	Board board = new Board(size,gameMode);
    	String[] moves = moveStr.split(",");
    	Result res = Result.GAMING;

    	for(int counter=0;counter<moves.length;counter++)
		{
			res=board.nextMove(moves,counter);
			board.print();

    		// 游戏结束
    		if( !res.equals(Result.GAMING) )
    			break;
    	}
    	return res;
    }
}

Board类

package cn.edu.nju.TicTacToe;
public class Board {
	/**
	 * 成员变量的初始化代码请修改,请灵活选择初始化方式
	 * 必要时可添加成员变量
	 */
	protected char[][] cells;
	protected GameChessStrategy chessStrategy;  //五子方式
	protected GameWinStrategy winStrategy;  //输赢策略 横斜
	protected Player player = Player.X;

	/**
	 * 请修改构造方法,并添加合适的构造方法
	 */
	
	public Board(int boardSize, String gameMole){

		cells = new char[boardSize][boardSize];
		for(int i=0; i<boardSize; i++){
			for(int j=0; j<boardSize; j++){
				cells[i][j] = '_';
			}
		}

		//00 01 10 11 不同方式不同策略 多态
		char chess=gameMole.charAt(0);
		chessStrategy= (chess=='0')? (new GameChessStrategy()):(new GameChessStrategyFIVE());

		char win=gameMole.charAt(1);
		winStrategy= (win=='0') ? (new GameWinStrategyStrategy_HVD()):(new GameWinStrategyStrategy_HV());


	}

	/**
	 * @param moves 下棋的位置
	 * @return 落棋之后的结果
	 */
	public Result nextMove(String []moves,int counter) {
		chessStrategy.putChess(cells, nextPlay(), moves,counter);
		return winStrategy.check(cells,moves,counter);
	}
	
	/**
	 * @return 下一个落棋的玩家
	 */
	protected Player nextPlay(){
		Player res = player;
		player = player == Player.X ? Player.O : Player.X;   //进行player更替
		return res;
	}
	
	/**
	 * 棋盘的输出方法,根据需要进行修改
	 */
	public void print(){
		int length=cells.length;
		System.out.print(" ");
		for(int i=0;i<length;i++)
		{
			char temp=(char)('A'+i);
			System.out.print(" "+temp);
		}
		System.out.println();

		for(int i=0;i<length;i++)
		{
			System.out.print(i+1);
			for(int j=0;j<length;j++)
				System.out.print(" "+cells[i][j]);

			System.out.println();
		}
	}
}

体现了接口,抽象方法的思想,很nice的实现
主要传递的参数也很清晰: 游戏策略(体现了多态,动态时链接),下一步位置,当前步数。
各自类也有各自类的职责,清晰美丽

你可能感兴趣的:(软工一)