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.
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.
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 ~~ 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).
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".
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.
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.
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.
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.
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).
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.
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;
}
}
}
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.
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 ………
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.