javaでCUIオセロの制作　その２

#これまで
[前回](https://qiita.com/ymt8781/private/e11a4a70a1cbbbebb55b)でオセロを完成させました。そこにさらにプラスで機能を付けます。今回は対戦相手（CPU）の追加をしていこうと思います。

#やり方
CPUのターンで置ける場所を探してから、そこに置くようにします。端からマスに置けるか（裏返せる駒があるか）をチェックしていき、該当したらその場所に置きます。前回は裏返しと可否のチェックが一つのメソッドになっていたので、それを分けようと思います。

##変更前
上方向のマスをチェックするメソッドです。これと同じようなものが９方向分あります。裏返せる駒があるかチェックし、裏返せた分だけの数字を返します。

```java:前回
public int turnUp(int y, int x) {
    
    int targetY = y - 1;
    
    if(targetY < 0) {
        return 0;
    }
    
    while(bored[targetY][x] != 0 && bored[targetY][x] != colour) {

        targetY--;

        if(targetY < 0) {
            break;
        }

        if (bored[targetY][x] == colour) {

                int count = 0;
                for (; targetY < y; y--) {
                    bored[y][x] = colour;
                    count++;
                }
                
                return count - 1;
        }

    }
    
    return 0;
}
```

##変更後
ArrayList<int[]>を返り値に指定し裏返すことができる駒の座標を返すようにして、裏返しまでは行わないようにします。

```java:今回
public ArrayList<int[]> turnUp(int y, int x) {
    
    //座標をArrayListに入れて返す
    ArrayList<int[]> reverseKoma = new ArrayList<int[]>();
    
    int targetY = y - 1;
    
    if(targetY < 0) {
        return reverseKoma;
    }
    
    while(bored[targetY][x] != 0 && bored[targetY][x] != colour) {
        
        targetY--;
        
        if(targetY < 0) {
            break;
        }
        
        if (bored[targetY][x] == colour) {
            
            //その座標を配列に入れて、reverseKomaに追加していく
            for (; targetY < y; y--) {
                
                int[] komaList = {y, x};
                reverseKoma.add(komaList);
                
            }
            
            return reverseKoma;
        }
        
    }
    
    return reverseKoma;
}

```
#コード
##gameクラス
前回からの変更部分を載せます。上記のメソッドの９方向部分は省きます。
ターンメソッド(裏返し処理)に加えてチェックメソッド(そこのマスが有効か)も定義します。その両方に共通する処理である９方向分の裏返せる座標の取得のメソッドも定義して、それぞれで呼び出すようにします。

###９方向分の実行メソッド
９方向分呼び出して、一つのListにまとめます。その中には置いた駒のマスも含まれているので、それを抜くようにして裏返せる相手の駒のマスのみを返します。

```java:game.java
public ArrayList<int[]> sumTurnOver(int y, int x) {
    
    ArrayList<int[]> sumKoma = new ArrayList<int[]>();
    
    //9方向実行でマスを追加していく
    sumKoma.addAll(turnUp(y,x));
    sumKoma.addAll(turnDown(y,x));
    sumKoma.addAll(turnRight(y,x));
    sumKoma.addAll(turnLeft(y,x));
    sumKoma.addAll(turnRightUp(y,x));
    sumKoma.addAll(turnRightDown(y,x));
    sumKoma.addAll(turnLeftUp(y,x));
    sumKoma.addAll(turnLeftDown(y,x));
    
    //置いた位置も含まれているので抜いて、裏返せるマスのみにする
    int[] put = {y, x};
    for (int i = 0; i < sumKoma.size(); i++) {
        if (Arrays.equals(sumKoma.get(i), put)) {
            sumKoma.remove(i);
        }
    }
    
    return sumKoma;
}
```

###チェックメソッド
上記のメソッドを呼び出して、sizeで個数を計算して返します。1以上ならば有効となります。

```java:game.java
//個数チェック
public int checkReverse(int y, int x, int num) {
    
    
    ArrayList<int[]> sumKoma = new ArrayList<int[]>();
    
    //自分の色をセット
    colour = num;
    
    //裏返した駒の合計
    int sumReverse = 0;
    
    //置く場所が空なら
    if (bored[y][x] == 0) {
        
        sumKoma = sumTurnOver(y, x);
        //個数を数える
        sumReverse = sumKoma.size();
        
    };
    return sumReverse;
}
```
###ターンメソッド（裏返しメソッド）
前回から変更しました。sumTurnOverで取得した座標＋置いた駒の座標を裏返します。これを交互に呼び出すことでゲームを進めていきます。

```java:game.java
public int turnOver(int y, int x, int num) {
		
    //裏返した駒の合計
    int sumReverse = 0;
    //自分の色（数字）のセット
    colour = num;
    
    ArrayList<int[]> sumKoma = new ArrayList<int[]>();
    
    //裏返すマスの座標
    sumKoma = sumTurnOver(y, x);
    
    //駒を置いたマスを追加
    int[] put = {y, x};
    sumKoma.add(put);
    
    //裏返し
    for (int[] k: sumKoma) {
        bored[k[0]][k[1]] = colour;
    }
    
    showBoard();
    
    //どちらか一色になったら
    if (white == 0 || black == 0) {
        return -1;
    }
    
    return sumReverse;
}
```

##実行クラス
数字（色）がどちらかで、パターンを分けます。１なら自分のターンになり、こちらは前回とあまりかわりません。チェックメソッドを実行し置いた位置が有効か確かめます。２ならCPUのターンになり、yとx座標が１のはじからチェックメソッドを実行し、１以上が返ればそこでループを辞めます。位置が決まれば裏返しメソッドを実行しターンを前回同様進め、終了するまで行っていきます。

```java:Othello.java
public class Othello {

	public static void main(String[] args) {
		// TODO 自動生成されたメソッド・スタブ
		
		game game = new game();
		
		int x = 0;
		int y = 0;
		
		//１なら黒、２なら白
		int num = 1;
		
		//ボードの駒の数
		int komaTotal = 4;
		
		//裏返せる駒
		int sumReverse = 0;
		
		Scanner sc = new Scanner(System.in);
		
		//ここで終了判定
		while(komaTotal < 64) {
			
			//1（黒）は自分のターン
			if (num == 1) {
				
				//整数入力、それ以外の場合の例外
				try{
					
					System.out.println("行を入力してください。");
					y = sc.nextInt();
					System.out.println("列を入力してください。");
					x = sc.nextInt();
					
				}catch (InputMismatchException e){
					
					System.out.println("整数を入力してください");
					sc.next();
					continue;
					
				}
				
				//盤上か(1～8)
				if (x <= 0 || x > 8) {
					System.out.println("盤上に置いてください");
					continue;
				} else if (y <= 0 || y > 8) {
					System.out.println("盤上に置いてください");
					continue;
				}
				
				//指定した位置が置けるかのチェック
				sumReverse = game.checkReverse(y - 1, x - 1, num);
				
				//0なら不可
				if (sumReverse == 0) {
					System.out.println("有効な場所に置いてください");
					continue;
				}
				
			//2（白）はCPUのターン
			} else if (num ==2) {
				
				//はじからループして該当する（１以上が返る）まで
				LABEL1:{
					
					for (x = 1; x < 9; x++) {
						
						for (y = 1; y < 9; y++) {
							
							sumReverse = game.checkReverse(y - 1, x - 1, num);
							
							//１マス以上で
							if (sumReverse > 0) {
								
								//ラベルで２重ループを抜ける
								break LABEL1;
								
							}
						}
						
					}
				}
				
			}
			
			
			//裏返し
			int gameOver = game.turnOver(y - 1, x - 1, num);
			
			
			// 全部一色になった時
			if (gameOver == -1) {
				break;
			}
			
			//交代
			if (num == 1) {
				num = 2;
			} else if (num == 2) {
				num = 1;
			}
			
			komaTotal++;
			
		}
		
		sc.close();
		System.out.println("終了");
		
		game.showResult();
	}
	
}
```

#感想
少し複雑になってしまいましたが、実装できたので良かったです。もう少しきれいに書けるような気がしますが、今はこれが精いっぱいですかね・・・。実はまだ完璧とは言えなくて、前回書いたように自分の駒を置くことができな場合のパスが実装されてないので、機会があったらまた手を加えます。