Java初心者によるオセロ開発日記

#はじめに
　Java初心者のlotokaです。何を思い立ったかJavaでオセロのボードを作ることになりました。そうすればモチベが上がるのではないか、という魂胆です。更新は日常生活の方とバランスを取りながら滅茶苦茶不定期にやっていく予定です。もしおかしな点などがありましたら教えていただけると幸いです。

　今回、次のような要素を実装していこうと思います。

- 勝敗の判断
- 置けない場合の自動スキップ
- 指定されたマスに置けない場合の忠告

　では、早速始めていきましょう。

#開発日記
######第一日目(2021.7.3)
　まず、変数の下準備をします。今回使いたい変数は次の通りです。（回数を重ねるごとに変更される可能性があります）

- オセロのボードを再現する二次元配列(`bord`)
- ユーザーが入力した座標を保管する変数(`orderx`,`odery`)
- 次が黒の番か白の番かを入れる変数(`turn`)

　今回は黒を`1`、白を`2`、何もないことを`0`と表記することにして、ひとまずボードの二次元配列の中全てに`0`をぶち込み、中央の4マスだけに黒と白を後から修正します。（二次元配列が`10*10`である理由は後述）

```Java:Othello.java
package othello;
import java.util.Scanner;

public class Othello {
    /*
	* non:0
	 * black:1
	 * white:2
	 */
	public static void main(String[] args) {
        //後々文字の入力を受け付ける必要が出てくるため先に宣言する
		Scanner scanner = new Scanner(System.in);
		
		int[][] bord = new int[10][10];
		
		int orderx;
		int ordery;
		
		int turn;

        //全てのマスを空にする		
		for (int i = 0; i < 10; i++) {
			for (int j = 0; j < 10; j++) {
				bord[i][j] = 0;
			}
		}
        //中央の4マスに置く
		bord[4][4] = 1;
		bord[4][5] = 2;
		bord[5][4] = 2;
		bord[5][5] = 1;
		
		System.out.println("例に従って座標を入力してください。\n例）a 1");
		
	}
}
```

　コード内にあるように、座標の入力は`a 1`のような「アルファベット␣数字」という形式で入力されます。リストと対応させるのがめんどくさいため、その変換用の関数を作っておきます。

```Java:char_to_int
private static int cToI(char ch) {
		if (ch == 'a') {
			return 1;
		}else if (ch == 'b') {
			return 2;
		}else if (ch == 'c') {
			return 3;
		}else if (ch == 'd') {
			return 4;
		}else if (ch == 'e') {
			return 5;
		}else if (ch == 'f') {
			return 6;
		}else if (ch == 'g') {
			return 7;
		}else if (ch == 'h') {
			return 8;
		}else {
			return -1;
		}
	}
```

　今回はユーザーが想定外のアルファベットを入力した場合を想定し、戻り値として`-1`を返せるようにしました。

　さて、次にユーザーの要求した座標に本当に置けるのかどうか判断する関数を作成します。考え方としては、

1. その場所にまだ何も置かれていないか
1. 今が黒の番なのか白の番なのか
1. ある方向に進んだときに隣にその番ではない色が連続しているか
1. その端はその番の色か

　1、2に関しては簡単なif文で条件分けができますが、3、4は少し複雑な処理が必要になってきます。そこで、次のようなfor文を用いて判断していきます。

```Java:can-1
for("置きたい場所からある方向へ確認していく" & "現在の確認場所がボードからはみ出していないか") {
    if ("現在の確認場所の一つ先に現在の番のコマがある") {
        //置けると判断する
    }
}
```

　ここで注意したいのがif文の中です。もし現在確認しているマスが端のマスであった場合、その一つ先のマスは存在しないため、配列の存在しない部分から数値を取り出そうとしてエラーが発生します。そこで、一つだけ余分な外枠を作ることでそのエラーを回避しているのです。これが配列を`10*10`とした理由です。
 そしてそれを実際に表記してみるとこうなります。

```Java:can
private static boolean can(int orderx, int ordery,int turn, int bord[][]) {
		boolean can = false;
		int nonturn;
		
		if (bord[orderx][ordery] == 0) {
			
			if (turn == 1) {
				nonturn = 2;
			}else {
				nonturn = 1;
			}
			
			for(int i = 1; bord[orderx + i][ordery] == nonturn & orderx + i < 9; i++) {
				if (bord[orderx + i + 1][ordery] == turn) {
					can |= true;
				}
			}
			
			for(int i = 1; bord[orderx + i][ordery] == nonturn & orderx - i > 0; i++) {
				if (bord[orderx - i - 1][ordery] == turn) {
					can |= true;
				}
			}
			
			for(int i = 1; bord[orderx][ordery + i] == nonturn & ordery + i < 9; i++) {
				if (bord[orderx][ordery+ i + 1] == turn) {
					can |= true;
				}
			}
			
			for(int i = 1; bord[orderx + i][ordery] == nonturn & ordery - i > 0; i++) {
				if (bord[orderx - i - 1][ordery] == turn) {
					can |= true;
				}
			}
			
			for(int i = 1; bord[orderx + i][ordery + i] == nonturn & orderx + i < 9 & ordery + i < 9; i++) {
				if (bord[orderx + i + 1][ordery + i + 1] == turn) {
					can |= true;
				}
			}
			
			for(int i = 1; bord[orderx - i][ordery + i] == nonturn & orderx - i > 0 & ordery + i < 9; i++) {
				if (bord[orderx - i - 1][ordery + i + 1] == turn) {
					can |= true;
				}
			}
			
			for(int i = 1; bord[orderx + i][ordery - i] == nonturn & orderx + i < 9 & ordery - i > 0; i++) {
				if (bord[orderx + i + 1][ordery - i - 1] == turn) {
					can |= true;
				}
			}
			
			for(int i = 1; bord[orderx - i][ordery - i] == nonturn & orderx - i > 0 & ordery - i > 0; i++) {
				if (bord[orderx - i - 1][ordery - i - 1] == turn) {
					can |= true;
				}
			}
		}
		
		return can;
	}
```

　本日の開発は以上です。

#開発環境
Windows10
Eclipse Version: 2019-09 R (4.13.0)
microsoft_dist_openjdk_1.8.0.25