# TDD实战（四）“井字游戏” 需求三




### 需求3
---

现在考虑这个游戏的获胜规则，这部分工作会比较麻烦。我们必须检查所可能获胜的情况，只要满足其中一个，就宣布相应玩家获胜。

>  最先在水平、锤直或对角线上将自己的3个标记连起来的玩家获胜。


#### 测试用例1
---

首先定义`play()` 的默认返回值：

```Java

@Test
public void whenPlayThenNoWinner(){
    String actual = ticTacToe.play(1,1);
    assertEquals("No winner", actual);
}
```

如果不满足获胜条件，则无人获胜。

##### 实现代码1

这个用例很容易满足，修改 `play()` 方法如下：

```Java

public String play(int x, int y){
    checkAxis(x);
    checkAxis(y);
    setBox(x, y);
    lastPlayer = nextPlayer();
    return "No winner";
}
```

** __执行 测试用例1 检查它是否运行通过。__


#### 测试用例2
---

处理各种获胜条件。

```Java
@Test
public void whenPlayAndWholeHorizontalLineThenWinner(){
    ticTacToe.play(1,1);  //X
    ticTacToe.play(1,2);  //O
    ticTacToe.play(2,1);  //X
    ticTacToe.play(2,2);  //O
    String actual = ticTacToe.play(3, 1); //X
    assertEquals("X is the winner", actual);
}
```

X 玩家最新占满一条水平线，所以 X 玩家获胜。

##### 实现代码2

为了让这个测试通过，需要检查是否有水平线全被当前玩家的棋子占据。现在需要记录哪些棋盘格是空的，还需要记录各个棋盘格被哪个玩家占据。

```Java

public String play(int x, int y){
    checkAxis(x);
    checkAxis(y);
    lastPlayer = nextPlayer();
    setBox(x, y, lastPlayer);
    for(int index = 0; index < 3; index++){
        if(board[0][index] == lastPlayer &&
            board[1][index] == lastPlayer &&
            board[2][index] == lastPlayer){
            return lastPlayer + " is the winner";
        }
    }
    return "No winner";
}

private void setBox(int x, int y, char lastPlayer){
    if(board[x-1][y-1] != '\0'){
        throw new RuntimeException("Box is occupied");
    }else {
        board[x-1][y-1] = lastPlayer;
    }
}
```

** __执行 测试用例2 检查它是否运行通过。__

##### 重构
---
前面代码虽然可以让测试通过，但并非没有改进的空间，所以现在要对上面的代码进行重构。

```Java
private static final int SIZE = 3;

public String play(int x, int y){
    checkAxis(x);
    checkAxis(y);
    lastPlayer = nextPlayer();
    setBox(x, y, lastPlayer);
    if(isWin()){
        return lastPlayer + " is the winner";
    }
    return "No winner";
}

private boolean isWin(){
    for(int i = 0; i < SIZE; i++){
        if(board[0][i] == lastPlayer &&
                board[1][i] == lastPlayer &&
                board[2][i] == lastPlayer){
            return true;
        }
    }
    return false;
}
```
重构之后代码结构看起来更好了。`play()` 方法保持了简洁。

** __执行 所有测试用例，保证此次重构没有对功能造成影响。__

__需求3__ 有些复杂，先休息一下！！




原始封面

![课程图片](https://images.unsplash.com/uploads/141103282695035fa1380/95cdfeef?w=300)


