My thoughts on the future [Preparation]

1. 1. Introduction (self-speaking named)

When I was a high school student, I was a little enrolled in the Go Shogi club at school. I wasn't playing Go or Shogi for a long time, but I was interested in being influenced by manga. As a result, I wasn't really good at it, and I wanted the weakest position in the club. So, for some reason, there was also an Othello board in the club room of the Go Shogi club, and after being smashed by other members in shogi, I was also doing Othello for a change. Othello has simpler rules than Go and Shogi, and of course there are difficulties, but I do not know where to use the pieces taken in Shogi, and I do not know when Go will be considered to be the end. For me, it was a really easy event for me. Well, it was still bumpy. By the way, it seems that there are fierce people in the world who can do Othello coding within the range of 7 lines $ × $ 79 characters, but I can not do it even with 700 lines, let alone 70 lines, which is 10 times as much. Since it works like a body, I decided to challenge the implementation of Othello this time without limiting the number of characters. Actually, I was aiming for the strongest Othello program as the title suggests by devising an algorithm to determine where it is best to put the stone, but as I expected, I will make it a situation where Othello can be done normally in the first place. It was all I could do. So, this time, as [Preparation], I will write the process until Othello became able to play for the time being.

2. Problem setting (excuse named)

This time, it would be nice if Othello could be made! I will say. However, I can't make something that works on the browser right now, so I'll make something that works on the familiar console every time. So, please forgive __not __ for something that you can do and play.

3. 3. Implementation ① Display of Othello board

Basically, all the Othello processing that we will implement will be written in a class called OthelloBoard. OthelloBoard has the following variables and arrays as members:

class OthelloBoard {
	private int size;				//One side of the Othello board(8, 10, 12, 14, 16)
	private char[][] squares;		//State of each square(B:black, W:White, N:No stone)
	private char playerColor;		//Player stone color
	private char otherColor;		//The color of the opponent's stone
	private int turnCounter;		//Count the number of turns
	private final String alphabets = "abcdefghijklmnop";
}

The int variable size represents the number of stones that can be placed on one side of the Othello board. In the constructor described later, the general 8 is assigned, but if you play with it, you can play with the size of madness of 16 squares $ × $ 16 squares. I tried it, but I was frustrated early. ~~ I'm crazy ~~ othello2.png Hmmm, this feeling of despair.

……Return the story. The char-type two-dimensional array squares is an array that represents the state of each cell. You can see if there is a stone in the square, and if so, whether it is Kuroishi or Shiraishi, or update it. The following char type variables playerColor and otherColor will contain either'B'or'W' when the player selects either Kuroishi or Shiraishi at the start of the game. The final string, alphabets, contains alphabets that represent the horizontal coordinates used to display the Othello board. This.alphabets.charAt (x) when you want to refer to the $ x $ th alphabet, and conversely, this when you want to know what number the alphabet y is (you want to know the horizontal coordinates as a numerical value). You can do something like .alphabets.indexOf ("y"). Also, since this string is not planned to be changed in the future, the final modifier is added. For this area, I referred to the comments I received in the previous articles. Thank you to everyone who made comments.

Now, from here, I will explain the part that displays the Othello board.

//Display the Othello board on the console
private void printBoard() {
	this.printBoardAlphabetLine();				//Alphabet line
	this.printBoardOtherLine("┏", "┳", "┓");		//Top edge
	for (int y = 0; y < this.size - 1; y ++) {
		this.printBoardDiscLine(y);			//Line to display stones
		this.printBoardOtherLine("┣", "╋", "┫");	//Line spacing
	}
	this.printBoardDiscLine(this.size - 1);			//Line to display stones
	this.printBoardOtherLine("┗", "┻", "┛");		//lower end
}

//Display the alphabet indicating the row of Othello board
private void printBoardAlphabetLine() {
	String buf = "  ";
	for (int x = 0; x < this.size; x ++) {
		buf += "   " + this.alphabets.charAt(x);
	}
	System.out.println(buf);
}

//Display one line with stones on the Othello board
private void printBoardDiscLine(int y) {
	String buf = String.format("%2d┃", y+1);
	for (int x = 0; x < this.size; x ++) {
		if (this.squares[y][x] == 'B') {
			buf += "●┃";
		} else if (this.squares[y][x] == 'W') {
			buf += "○┃";
		} else {
			buf += " ┃";
		}
	}
	System.out.println(buf);
}

//Display one line of ruled lines representing the frame of the Othello board
private void printBoardOtherLine(String left, String middle, String right) {
	String buf = "  " + left;
	for (int x = 0; x < this.size - 1; x ++) {
		buf += "━" + middle;
	}
	System.out.println(buf + "━" + right);
}

If you want to display the Othello board on the console, call the first printBoard method. In order to display the Othello board, it is necessary to display black circles and white circles that represent stones, ruled lines that represent the frame of the board, etc., but since there are many similar processes, only the parts are different. The parts with the same flow are put together in different methods printBoardAlphabetLine, printBoardDiscLine, and printBoardOtherLine, and they are called. By the way, when you execute the above method, you will see something like this (size is 8 squares $ x $ 8 squares). othello.png

Alphabets or numbers representing coordinates are output on the top and left of the Othello board. When the player inputs the place to put the stone, for example, enter alphabet + half-width space + number such as "a 1".

4. Implementation ② Player input

Next, we'll show you how to handle player input. As I wrote earlier, the place to put the stone is to enter "alphabet + half-width space + number", but you must make sure that the input is correct. The contents that need to be confirmed are as follows for the time being.

  1. Does the location of the entered coordinates actually exist? For example, an impossible place such as "z 15" or an unreadable coordinate such as "syoukou 1234" will not be accepted as input.
  2. Are there any other stones in the square at the entered coordinates?
  3. Isn't there any other stone in the square with the entered coordinates, but isn't it possible to turn over any stone on the other side?

The following code implements the process to check these.

//Accept input until you decide where to put the stone
private void askNewCoordinates(char myColor, char enemyColor) {
	while (true) {
		//input
		System.out.println("\n Decide where to put the stone.");
		System.out.println("[x coordinate y coordinate](Examplea1):");
		Scanner sc = new Scanner(System.in);
		//Determine if it is within the range of the Othello board
		Coordinates newDisc = this.checkCoordinatesRange(sc.nextLine());
		if (newDisc.equals(-1, -1)) {
			//If the coordinates are incorrect, re-enter
			System.out.println("The input is incorrect.");
			continue;
		}
		if (this.squares[newDisc.y][newDisc.x] != 'N') {
			//If a stone has already been placed, have it entered again
			System.out.println("There are already stones.");
			continue;
		}
		//Determine if the opponent's stone can be turned over
		ArrayList<Coordinates> discs = this.checkDiscsTurnedOverAllLine(
			myColor, enemyColor, newDisc, this.size*this.size);
		if (! discs.isEmpty()) {
			//If there is a stone that can be turned over, actually turn it over
			this.putDisc(myColor, newDisc);
			this.turnOverDiscs(discs);
			this.printDiscsTurnedOver(discs);
			return;
		}
		System.out.println("I can't turn over the opponent's stone.");
	}
}

//Determine if the coordinates entered by the player are within the range of the Othello board
//If the judgment succeeds, the coordinates are used, and if the judgment fails, the coordinates are used.(-1, -1)return it
private Coordinates checkCoordinatesRange(String line) {
	String[] tokens = line.split(" ");
	//Read the horizontal coordinates from the first letter of the alphabet
	int x = this.alphabets.indexOf(tokens[0]);
	if (tokens[0].length() != 1 || x < 0 || this.size <= x) {
		return new Coordinates(-1, -1);
	}
	//Read the vertical coordinates from the remaining characters
	int y;
	try {
		y = Integer.parseInt(tokens[1]);
		if (y <= 0 || this.size < y) {
			return new Coordinates(-1, -1);
		}
	} catch (NumberFormatException e) {
		return new Coordinates(-1, -1);
	}
	return new Coordinates(x, y - 1);
}

If you want the player to enter the location of the stone you want to place, call the first askNewCoordinates method. By using the while statement, the player keeps typing over and over again until it can be processed as correct input (it's a bit scary to say). The first item in the above bullet point is judged by the checkCoordinatesRange method. Since the player connects the alphabet of the horizontal coordinates and the number of the vertical coordinates with a half-width space, first split it with the split method. For vertical coordinates, the parseInt method is used to convert the character string to a numerical value, but in fact, if this method, __ conversion fails, an exception called NumberFormatException will be thrown and the entire program will be forcibly terminated __ It is. Therefore, I will use ~~ __ Exception Handling __ which I just studied recently so that it will not be forcibly terminated even if such an exception occurs. As in the above code, enclose the part where the exception may occur in __try block __, and write the processing after catching the exception in the __catch block __ after the try block. The try block is like putting a net in a place where exception handling can occur, and it feels like the processing to be applied to the exception caught in the net is written in the catch block (If you make a mistake, it would be helpful if you could comment). ). The second bullet point can be easily determined by referring to the char array squares. The third bullet point, which is annoying. Whether or not the opponent's stone can be turned over is exactly the process that can be said to be the basis of Othello. The checkDiscsTurnedOverAllLine method called in the above code is described in detail in the next section.

5. Implementation ③ Judgment of whether the opponent's stone can be turned over

First, let's talk about the Coordinates class, which will often appear in future processing. This Coordinates class is simply a class that stores the x-coordinate and y-coordinate of the Othello board as numerical values. The member variables x and y are made public to save the trouble of writing code. Strictly speaking, it should be private and a dedicated public method should be prepared for reference and assignment, but this time I gave priority to having fun. I'm sorry. There is also a copy method that copies other coordinates and an equals method that determines whether the coordinates are equal to the given coordinates.

class Coordinates {
	public int x;
	public int y;

	Coordinates(int x, int y)  {
		this.x = x;
		this.y = y;
	}

	Coordinates(Coordinates c)  {
		this.x = c.x;
		this.y = c.y;
	}

	public void copy(Coordinates c) {
		this.x = c.x;
		this.y = c.y;
	}

	public boolean equals(int x, int y) {
		if (this.x == x && this.y == y) {
			return true;
		} else {
			return false;
		}
	}
}

Now, let's talk about the most nasty part of this program, the judgment of whether or not the opponent's stone can be turned over. First, let's sort out how we determine if we can turn the opponent's stone over when we are actually playing with Othello.

  1. Focus on the squares that have no stones and have not been noticed yet.
  2. Look at the __8 directions __ of right, upper right, upper, upper left, left, lower left, lower, lower right from the square of interest. In each direction, when there is one or more opponent's stones next to the square you are paying attention to, and then one of your own stones, proceed to 3. If this is not the case in any direction, go back to 1.
  3. In all 8 directions, turn over the stone of the opponent sandwiched between the square of interest and your own stone found in 2. to make it your own stone.

I'm sorry it's hard to understand, but in words it looks like this. So, the following code is the one that implemented such a process.

//Determine if the stone at the entered coordinates can turn over the opponent's stone
//Returns the coordinates of the stone that can be turned over as an Arraylist
//Since the maximum value of the number that can be turned over can be determined by the argument countMax,
//If you just want to judge whether you can put a stone at that coordinate, 1 is enough
//Size to return all the coordinates of a stone that can be flipped*to size
private ArrayList<Coordinates> checkDiscsTurnedOverAllLine(
	char myColor, char enemyColor, Coordinates myCoordinates, int countMax)
{
	ArrayList<Coordinates> discs = new ArrayList<Coordinates>();
	//Scan in each direction
	for (int d = 0; d < 8; d ++) {
		discs.addAll(this.checkDiscsTurnedOverOneLine(myColor, enemyColor, myCoordinates, d));
		//If the maximum value of the stone that can be turned over is exceeded, the processing will be stopped.
		if (discs.size() > countMax) {
			break;
		}
	}
	return discs;
}

//Determine if the stone at the entered coordinates can turn over the opponent's stone
//The scanning direction changes depending on the argument direction.
// 0:0 degrees, 1:45 degrees, 2:90 degrees, 3:135 degrees, 4:180 degrees, 5:225 degrees, 6:270 degrees, 7:315 degrees
private ArrayList<Coordinates> checkDiscsTurnedOverOneLine(
	char myColor, char enemyColor, Coordinates myCoordinates, int direction)
{
	//Scan a stone that can be turned over
	Coordinates currentCoordinates = new Coordinates(myCoordinates);
	ArrayList<Coordinates> discs = new ArrayList<Coordinates>();
	//Keep scanning next to you while your opponent's stones continue
	while (true) {
		//Find the coordinates of the next stone
		Coordinates nextDisc = this.getNextDiscCoordinates(currentCoordinates, direction);
		if (nextDisc.equals(-1, -1)) {
			//Returns an empty list if there are no stones to flip
			discs.clear();
			break;
		}
		if (this.squares[nextDisc.y][nextDisc.x] == enemyColor) {
			//If there is an opponent's stone next to you, temporarily register it in the flip list
			discs.add(nextDisc);
		} else if (this.squares[nextDisc.y][nextDisc.x] == myColor) {
			//If you have your own stone next to it, return the list
			break;
		} else {
			//Returns an empty list if there are no stones next to it
			discs.clear();
			break;
		}
		//Proceed to the next stone
		currentCoordinates.copy(nextDisc);
	}
	return discs;
}

//next to(Depends on the direction)Returns the coordinates of the stone in
//If the coordinates are out of range(-1, -1)return it
private Coordinates getNextDiscCoordinates(Coordinates myDisc, int direction) {
	//x coordinate
	int x = myDisc.x;
	if (direction == 0 || direction == 1 || direction == 7) {
		x ++; //0 degrees,45 degrees,315 degrees
	} else if (direction == 3 || direction == 4 || direction == 5) {
		x --;  //135 degrees,180 degrees,225 degrees
	}
	//y coordinate
	int y = myDisc.y;
	if (direction == 1 || direction == 2 || direction == 3) {
		y --; //45 degrees,90 degree,135 degrees
	} else if (direction == 5 || direction == 6 || direction == 7) {
		y ++;  //225 degrees,270 degrees,315 degrees
	}
	if (x < 0 || this.size <= x || y < 0 || this.size <= y) {
		//When the coordinates are out of range
		return new Coordinates(-1, -1);
	}
	return new Coordinates(x, y);
}

If you want to find out if you can flip your opponent's stone, first call the checkDiscsTurnedOverAllLine method. I'm going to look at all 8 directions like AllLine, but I wanted to summarize the processing of similar parts, so I decided to call the checkDiscsTurnedOverOneLine method for each direction. This checkDiscsTurnedOverOneLine method processes only one direction specified by the argument direction, as in OneLine. For a certain direction, the coordinates of the adjacent stone are continuously obtained from the getNextDiscCoordinates method (the x and y coordinates are incremented, decremented, or unchanged by 1 by specifying the direction). In the while statement, if the opponent's stones are continuous next to the square of interest, __temporarily register __ in the list discs of stones that can turn them over. If you don't have your own stone after the opponent's stone that you might be able to turn over, or if you get out of the range of the Othello board, delete all the temporarily registered lists. Ultimately, the coordinates contained in the list returned by the checkDiscsTurnedOverAllLine method introduced at the beginning are the list of stones that can really be turned over.

6. Implementation ④ Overall flow of Othello

Finally, I will briefly introduce the part that describes the flow of the Othello game.

//Start Othello
public void start() {
	//Decide the player's stone
	this.askPlayerColor();
	//Put the Othello board in the state immediately after the start
	this.initializeBoard();
	this.printBoard();
	this.turnCounter = 1;
	int turnCounterMax = this.size*this.size - 4;
	int skipCounter = 0;
	//The first move decides which one
	boolean isPlayerTurn = true;
	if (this.playerColor == 'W') {
		isPlayerTurn = false;
	}
	//Processing of each turn
	System.out.println("Start Othello.");
	int playerDiscNum;
	int otherDiscNum;
	while (this.turnCounter <= turnCounterMax) {
		//Show the number of stones at the moment
		playerDiscNum = this.countDisc(this.playerColor);
		otherDiscNum = this.countDisc(this.otherColor);
		System.out.print("you= " + playerDiscNum + "  ");
		System.out.println("Opponent= " + otherDiscNum);
		if (isPlayerTurn) {
			//Player turn
			//Determine if the player can put a stone
			if (! this.checkSquaresForNewDisc(this.playerColor, this.otherColor)) {
				//Player turns are skipped
				System.out.println("Your turn has been skipped.");
				if (skipCounter == 1) {
					//If the opponent's turn has already been skipped, the game ends
					break;
				}
				isPlayerTurn = !isPlayerTurn;
				skipCounter ++;
				continue;
			}
			System.out.println("Turn " + turnCounter + ":It's your turn.");
			skipCounter = 0;
			this.askNewCoordinates(this.playerColor, this.otherColor);
		} else {
			//Opponent's turn
			//Determine if the opponent can put a stone
			if (! this.checkSquaresForNewDisc(this.otherColor, this.playerColor)) {
				//Player turns are skipped
				System.out.println("The opponent's turn was skipped.");
				if (skipCounter == 1) {
					//If the player's turn has already been skipped, the game ends
					break;
				}
				isPlayerTurn = !isPlayerTurn;
				skipCounter ++;
				continue;
			}
			//Opponent's turn
			System.out.println("Turn " + turnCounter + ":It's your opponent's turn.");
			skipCounter = 0;
			this.askNewCoordinates(this.otherColor, this.playerColor);
		}
		this.printBoard();
		//Processing for the next turn
		this.turnCounter ++;
		isPlayerTurn = !isPlayerTurn;
	}
	//Judgment of victory or defeat
	playerDiscNum = this.countDisc(this.playerColor);
	otherDiscNum = this.countDisc(this.otherColor);
	System.out.print("you= " + playerDiscNum + "  ");
	System.out.println("Opponent= " + otherDiscNum);
	if (playerDiscNum > otherDiscNum) {
		System.out.println("You win.");
	} else if (playerDiscNum == otherDiscNum) {
		System.out.println("It's a draw.");
	} else {
		System.out.println("You lose.");
	}
}

As an aside, it is not good to write 80 lines in one method like the start method above. You have to write code that is readable, such as grouping similar processes into different methods or separating some parts into different methods. __ is __, I didn't have enough time this time. Please forgive me as I will improve it the next time I show you.

Now, in controlling the flow of the game, there is one important thing: __ If you can't put your own stone at all, it will be a pass and it will be your opponent's turn __. In addition, it should be remembered that if neither you nor your opponent can place stones, the game will end __. Therefore, in the above code, an int type variable skipCounter is created, and 1 is added if either one of the player or the other party is in the pass situation, and the process is reset to 0 if the stone can be placed. Then, the game ends when you and your opponent pass in succession (skipCounter == 2).

7. Implementation summary

The rest of the process is simpler than the contents so far, so I will omit the explanation. The entire program implemented this time is described below.

Othello program (click to open)
import java.util.ArrayList;
import java.util.Scanner;

class OthelloBoardTest {
	public static void main(String args[]) {
		OthelloBoard ob = new OthelloBoard();
		ob.start();
	}
}

class OthelloBoard {
	private int size;				//One side of the Othello board(8, 10, 12, 14, 16)
	private char[][] squares;		//State of each square(B:black, W:White, N:No stone)
	private char playerColor;		//Player stone color
	private char otherColor;		//The color of the opponent's stone
	private int turnCounter;		//Count the number of turns
	private final String alphabets = "abcdefghijklmnop";
									//Alphabet showing horizontal coordinates

	//constructor
	public OthelloBoard() {
		this.size = 8;
//		this.size = askBoardSize();
		this.squares = new char[this.size][this.size];
	}

	//Start Othello
	public void start() {
		//Decide the player's stone
		this.askPlayerColor();
		//Put the Othello board in the state immediately after the start
		this.initializeBoard();
		this.printBoard();
		this.turnCounter = 1;
		int turnCounterMax = this.size*this.size - 4;
		int skipCounter = 0;
		//The first move decides which one
		boolean isPlayerTurn = true;
		if (this.playerColor == 'W') {
			isPlayerTurn = false;
		}
		//Processing of each turn
		System.out.println("Start Othello.");
		int playerDiscNum;
		int otherDiscNum;
		while (this.turnCounter <= turnCounterMax) {
			//Show the number of stones at the moment
			playerDiscNum = this.countDisc(this.playerColor);
			otherDiscNum = this.countDisc(this.otherColor);
			System.out.print("you= " + playerDiscNum + "  ");
			System.out.println("Opponent= " + otherDiscNum);
			if (isPlayerTurn) {
				//Player turn
				//Determine if the player can put a stone
				if (! this.checkSquaresForNewDisc(this.playerColor, this.otherColor)) {
					//Player turns are skipped
					System.out.println("Your turn has been skipped.");
					if (skipCounter == 1) {
						//If the opponent's turn has already been skipped, the game ends
						break;
					}
					isPlayerTurn = !isPlayerTurn;
					skipCounter ++;
					continue;
				}
				System.out.println("Turn " + turnCounter + ":It's your turn.");
				skipCounter = 0;
				this.askNewCoordinates(this.playerColor, this.otherColor);
			} else {
				//Opponent's turn
				//Determine if the opponent can put a stone
				if (! this.checkSquaresForNewDisc(this.otherColor, this.playerColor)) {
					//Player turns are skipped
					System.out.println("The opponent's turn was skipped.");
					if (skipCounter == 1) {
						//If the player's turn has already been skipped, the game ends
						break;
					}
					isPlayerTurn = !isPlayerTurn;
					skipCounter ++;
					continue;
				}
				//Opponent's turn
				System.out.println("Turn " + turnCounter + ":It's your opponent's turn.");
				skipCounter = 0;
				this.askNewCoordinates(this.otherColor, this.playerColor);
			}
			this.printBoard();
			//Processing for the next turn
			this.turnCounter ++;
			isPlayerTurn = !isPlayerTurn;
		}
		//Judgment of victory or defeat
		playerDiscNum = this.countDisc(this.playerColor);
		otherDiscNum = this.countDisc(this.otherColor);
		System.out.print("you= " + playerDiscNum + "  ");
		System.out.println("Opponent= " + otherDiscNum);
		if (playerDiscNum > otherDiscNum) {
			System.out.println("You win.");
		} else if (playerDiscNum == otherDiscNum) {
			System.out.println("It's a draw.");
		} else {
			System.out.println("You lose.");
		}
	}

	//Turn the stone over
	public void turnOverDiscs(ArrayList<Coordinates> discs) {
		for (int i = 0; i < discs.size(); i ++) {
			int x = discs.get(i).x;
			int y = discs.get(i).y;
			if (this.squares[y][x] == 'B') {
				this.squares[y][x] = 'W';
			} else if (this.squares[y][x] == 'W') {
				this.squares[y][x] = 'B';
			}
		}
	}

	//Place to put stones(A place where you can turn over other stones)Determine if there is
	private boolean checkSquaresForNewDisc(char myColor, char enemyColor) {
		for (int y = 0; y < this.size; y ++) {
			for (int x = 0; x < this.size; x ++) {
				if (this.squares[y][x] != 'N') {
					continue;
				}
				ArrayList<Coordinates> discs = this.checkDiscsTurnedOverAllLine(
						myColor, enemyColor, new Coordinates(x, y), 1);
				if (discs.size() >= 1) {
					return true;
				}
			}
		}
		return false;
	}

	//Accept input until you decide where to put the stone
	private void askNewCoordinates(char myColor, char enemyColor) {
		while (true) {
			//input
			System.out.println("\n Decide where to put the stone.");
			System.out.println("[x coordinate y coordinate](Examplea1):");
			Scanner sc = new Scanner(System.in);
			//Determine if it is within the range of the Othello board
			Coordinates newDisc = this.checkCoordinatesRange(sc.nextLine());
			if (newDisc.equals(-1, -1)) {
				//If the coordinates are incorrect, re-enter
				System.out.println("The input is incorrect.");
				continue;
			}
			if (this.squares[newDisc.y][newDisc.x] != 'N') {
				//If a stone has already been placed, have it entered again
				System.out.println("There are already stones.");
				continue;
			}
			//Determine if the opponent's stone can be turned over
			ArrayList<Coordinates> discs = this.checkDiscsTurnedOverAllLine(
				myColor, enemyColor, newDisc, this.size*this.size);
			if (! discs.isEmpty()) {
				//If there is a stone that can be turned over, actually turn it over
				this.putDisc(myColor, newDisc);
				this.turnOverDiscs(discs);
				this.printDiscsTurnedOver(discs);
				return;
			}
			System.out.println("I can't turn over the opponent's stone.");
		}
	}

	//Determine if the coordinates entered by the player are within the range of the Othello board
	//If the judgment succeeds, the coordinates are used, and if the judgment fails, the coordinates are used.(-1, -1)return it
	private Coordinates checkCoordinatesRange(String line) {
		String[] tokens = line.split(" ");
		//Read the horizontal coordinates from the first letter of the alphabet
		int x = this.alphabets.indexOf(tokens[0]);
		if (tokens[0].length() != 1 || x < 0 || this.size <= x) {
			return new Coordinates(-1, -1);
		}
		//Read the vertical coordinates from the remaining characters
		int y;
		try {
			y = Integer.parseInt(tokens[1]);
			if (y <= 0 || this.size < y) {
				return new Coordinates(-1, -1);
			}
		} catch (NumberFormatException e) {
			return new Coordinates(-1, -1);
		}
		return new Coordinates(x, y - 1);
	}

	//Determine if the stone at the entered coordinates can turn over the opponent's stone
	//Returns the coordinates of the stone that can be turned over as an Arraylist
	//Since the maximum value of the number that can be turned over can be determined by the argument countMax,
	//If you just want to judge whether you can put a stone at that coordinate, 1 is enough
	//Size to return all the coordinates of a stone that can be flipped*to size
	private ArrayList<Coordinates> checkDiscsTurnedOverAllLine(
		char myColor, char enemyColor, Coordinates myCoordinates, int countMax)
	{
		ArrayList<Coordinates> discs = new ArrayList<Coordinates>();
		//Scan in each direction
		for (int d = 0; d < 8; d ++) {
			discs.addAll(this.checkDiscsTurnedOverOneLine(myColor, enemyColor, myCoordinates, d));
			//If the maximum value of the stone that can be turned over is exceeded, the processing will be stopped.
			if (discs.size() > countMax) {
				break;
			}
		}
		return discs;
	}
	
	//Determine if the stone at the entered coordinates can turn over the opponent's stone
	//The scanning direction changes depending on the argument direction.
	// 0:0 degrees, 1:45 degrees, 2:90 degrees, 3:135 degrees, 4:180 degrees, 5:225 degrees, 6:270 degrees, 7:315 degrees
	private ArrayList<Coordinates> checkDiscsTurnedOverOneLine(
		char myColor, char enemyColor, Coordinates myCoordinates, int direction)
	{
		//Scan a stone that can be turned over
		Coordinates currentCoordinates = new Coordinates(myCoordinates);
		ArrayList<Coordinates> discs = new ArrayList<Coordinates>();
		//Keep scanning next to you while your opponent's stones continue
		while (true) {
			//Find the coordinates of the next stone
			Coordinates nextDisc = this.getNextDiscCoordinates(currentCoordinates, direction);
			if (nextDisc.equals(-1, -1)) {
				//Returns an empty list if there are no stones to flip
				discs.clear();
				break;
			}
			if (this.squares[nextDisc.y][nextDisc.x] == enemyColor) {
				//If there is an opponent's stone next to you, temporarily register it in the flip list
				discs.add(nextDisc);
			} else if (this.squares[nextDisc.y][nextDisc.x] == myColor) {
				//If you have your own stone next to it, return the list
				break;
			} else {
				//Returns an empty list if there are no stones next to it
				discs.clear();
				break;
			}
			//Proceed to the next stone
			currentCoordinates.copy(nextDisc);
		}
		return discs;
	}
	
	//next to(Depends on the direction)Returns the coordinates of the stone in
	//If the coordinates are out of range(-1, -1)return it
	private Coordinates getNextDiscCoordinates(Coordinates myDisc, int direction) {
		//x coordinate
		int x = myDisc.x;
		if (direction == 0 || direction == 1 || direction == 7) {
			x ++; //0 degrees,45 degrees,315 degrees
		} else if (direction == 3 || direction == 4 || direction == 5) {
			x --;  //135 degrees,180 degrees,225 degrees
		}
		//y coordinate
		int y = myDisc.y;
		if (direction == 1 || direction == 2 || direction == 3) {
			y --; //45 degrees,90 degree,135 degrees
		} else if (direction == 5 || direction == 6 || direction == 7) {
			y ++;  //225 degrees,270 degrees,315 degrees
		}
		if (x < 0 || this.size <= x || y < 0 || this.size <= y) {
			//When the coordinates are out of range
			return new Coordinates(-1, -1);
		}
		return new Coordinates(x, y);
	}

	//Accepts input until the size of the Othello board is decided
	//This method is the constructor of this.If you paste it on the right side of size,
	//You can add a process to enter the size of the Othello board
	private int askBoardSize() {
		while (true) {
			System.out.println("");
			System.out.println("Please decide the length of one side of the Othello board.");
			System.out.print("[8, 10, 12, 14,Any of 16]:");
			Scanner sc = new Scanner(System.in);
			String line = sc.nextLine();
			if ("8".equals(line) || "10".equals(line) || "12".equals(line) ||
				"14".equals(line) || "16".equals(line)) {
				System.out.println("The length of one side of the Othello board is" + line + "is.");
				return Integer.parseInt(line);
			}
			System.out.println("The input is incorrect.");
		}
	}

	//Accept input until the color of the player's stone is decided
	private void askPlayerColor() {
		while (true) {
			System.out.println("\n Decide on your stone.");
			System.out.println("[b (black), w (White)Any of]:");
			Scanner sc = new Scanner(System.in);
			String line = sc.nextLine();
			if ("b".equals(line)) {
				System.out.println("Your stone is black.");
				this.playerColor = 'B';
				this.otherColor = 'W';
				return;
			} else if ("w".equals(line)) {
				System.out.println("Your stone is white.");
				this.playerColor = 'W';
				this.otherColor = 'B';
				return;
			}
			System.out.println("The input is incorrect.");
		}
	}

	//Count stones of the specified color
	private int countDisc(char myColor) {
		int count = 0;
		for (int y = 0; y < this.size; y ++) {
			for (int x = 0; x < this.size; x ++) {
				if (this.squares[y][x] == myColor) {
					count ++;
				}
			}
		}
		return count;
	}

	//Put the Othello board in the state immediately after the start
	private void initializeBoard() {
		for (int y = 0; y < this.size; y ++) {
			for (int x = 0; x < this.size; x ++) {
				squares[y][x] = 'N';
			}
		}
		//Place stones only in the central 4 squares
		this.putDisc('B', this.size/2 - 1, this.size/2 - 1);
		this.putDisc('B', this.size/2, this.size/2);
		this.putDisc('W', this.size/2, this.size/2 - 1);
		this.putDisc('W', this.size/2 - 1, this.size/2);
	}

	//Place a stone at the specified coordinates on the Othello board
	private void putDisc(char discColor, int x, int y) {
		this.squares[y][x] = discColor;
	}
	private void putDisc(char discColor, Coordinates c) {
		this.putDisc(discColor, c.x, c.y);
	}

	//Show all coordinates of flipped stones
	private void printDiscsTurnedOver(ArrayList<Coordinates> discs) {
		System.out.println("I flipped the next stone.");
		int count = 0;
		for (int i = 0; i < discs.size(); i ++) {
			System.out.print(this.alphabets.substring(discs.get(i).x, discs.get(i).x + 1) +
				(discs.get(i).y + 1) + " ");
			count ++;
			if (count == 8) {
				System.out.println("");
				count = 0;
			}
		}
		System.out.println("");
	}

	//Display the Othello board on the console
	private void printBoard() {
		this.printBoardAlphabetLine();					//Alphabet line
		this.printBoardOtherLine("┏", "┳", "┓");		//Top edge
		for (int y = 0; y < this.size - 1; y ++) {
			this.printBoardDiscLine(y);					//Line to display stones
			this.printBoardOtherLine("┣", "╋", "┫");	//Line spacing
		}
		this.printBoardDiscLine(this.size - 1);			//Line to display stones
		this.printBoardOtherLine("┗", "┻", "┛");		//lower end
	}

	//Display the alphabet indicating the row of Othello board
	private void printBoardAlphabetLine() {
		String buf = "  ";
		for (int x = 0; x < this.size; x ++) {
			buf += "   " + this.alphabets.charAt(x);
		}
		System.out.println(buf);
	}

	//Display one line with stones on the Othello board
	private void printBoardDiscLine(int y) {
		String buf = String.format("%2d┃", y+1);
		for (int x = 0; x < this.size; x ++) {
			if (this.squares[y][x] == 'B') {
				buf += "●┃";
			} else if (this.squares[y][x] == 'W') {
				buf += "○┃";
			} else {
				buf += " ┃";
			}
		}
		System.out.println(buf);
	}

	//Display one line of ruled lines representing the frame of the Othello board
	private void printBoardOtherLine(String left, String middle, String right) {
		String buf = "  " + left;
		for (int x = 0; x < this.size - 1; x ++) {
			buf += "━" + middle;
		}
		System.out.println(buf + "━" + right);
	}
}

class Coordinates {
	public int x;
	public int y;

	Coordinates(int x, int y)  {
		this.x = x;
		this.y = y;
	}

	Coordinates(Coordinates c)  {
		this.x = c.x;
		this.y = c.y;
	}

	public void copy(Coordinates c) {
		this.x = c.x;
		this.y = c.y;
	}

	public boolean equals(int x, int y) {
		if (this.x == x && this.y == y) {
			return true;
		} else {
			return false;
		}
	}
}

8. Try to run

Since the Othello board is displayed each time you enter one coordinate, we will introduce only one screen instead of showing the whole game lazily.  othello3.png

At the very end, both you and your opponent passed, so the game is over. What's so painful is that we haven't implemented the processing of the other party (PC) yet, so at present we have to enter the coordinates up to the stone of the other party __. This sad __ self-made self-performing feeling __. What have I been doing since Sunday daytime ………

9. Future tasks

For the time being, I am now in a state where I can play Othello at a minimum, so I will implement the thinking routine of the other party in the future. At the beginning, it feels like you randomly choose from the places where you can put stones, but for example, in the early stages of the game, do not take too many stones, aim for a sticky corner in the middle stage, and let the calculation speed talk to you in the final stage. I would like to create a __ algorithm that has no gaps in the early, middle, and late stages, such as pre-reading.

I'm sorry that the explanation became redundant due to the long source code this time. Still, thank you to everyone who has read this far.

Recommended Posts

My thoughts on the future [Preparation]
My thoughts on the equals method (Java)
My thoughts on Othello [Thinking Routine 2]
My thoughts on Othello [Thinking Routine 1]
Scala runs on the JVM