Pour le moment, j'ai créé un programme qui met à jour et affiche le tableau Othello à chaque fois que j'entre dans un endroit pour poser une pierre sur la console. À partir de ce moment, nous développerons progressivement la routine de réflexion du côté ennemi. * Cette fois, le contenu est petit, mais pardonnez-moi s'il vous plaît.
Maintenant, avant d'entrer dans le sujet principal, nettoyons la méthode de démarrage, qui était un peu redondante dans le programme précédent. Quand j'étais à l'université il y a longtemps, un ami qui était bon en programmation disait souvent: «Le code à écrire dans une méthode est __ aussi peu que possible __, et il ne devrait pas faire plus de 30 lignes au plus. Si tel est le cas, divisez-le en différentes méthodes. " Maintenant, je comprends le sens du mot. Écrire beaucoup de code dans une seule méthode signifie souvent emballer une grande variété de processus ou copier le même processus. Cela rend la lecture difficile, difficile à réécrire plus tard et dans le pire des cas, même si un bogue est introduit, il ne sera pas remarqué. Pour éviter de tels risques, il est important de réduire le nombre de lignes par méthode.
//Démarrez Othello
public void start() {
//Traitement avant de commencer
this.askPlayerColor();
boolean isPlayerTurn = this.getFirstMove();
int skipCount = 0;
//Traitement de chaque tour
System.out.println("Démarrez Othello.");
this.printBoard();
while (this.turnCount <= turnCountMax) {
//Déterminez s'il faut sauter le virage
int skipFlag = this.checkSkipCount(isPlayerTurn, skipCount);
if (skipFlag == 2) {
break;
} else if (skipFlag == 1) {
isPlayerTurn = !isPlayerTurn;
skipCount ++;
continue;
}
//Lorsque vous ne sautez pas
skipCount = 0;
if (isPlayerTurn) {
//Tour du joueur
System.out.println("\nTurn " + turnCount + ":C'est ton tour.");
this.askNewCoordinates(this.playerColor, this.otherColor);
} else {
//Tour de l'adversaire
System.out.println("\nTurn " + turnCount + ":C'est au tour de votre adversaire.");
this.thinkNewCoordinates(this.otherColor, this.playerColor);
}
this.printBoard();
//Traitement pour le prochain tour
this.turnCount ++;
isPlayerTurn = !isPlayerTurn;
}
//Jugement de victoire ou de défaite
this.printDiscNumber();
this.printResult();
}
En séparant certains processus en différentes méthodes et en résumant le jugement sur l'opportunité de sauter le virage dans l'instruction while au début, nous avons pu réduire le programme de 80 lignes à 37 lignes. En fait, je devrais le couper un peu plus, mais je m'arrêterai ici une fois.
Puisque les spécifications de la routine de réflexion concrète n'ont pas encore été finalisées, cette fois, nous mettrons en œuvre un processus pour en sélectionner une au hasard à partir de l'endroit où la pierre peut être placée. C'est la méthode thinkNewCoordinates illustrée ci-dessous.
//Affinez automatiquement où placer la pierre suivante
private void thinkNewCoordinates(char myColor, char enemyColor) {
ArrayList<Candidate> candidates = new ArrayList<Candidate>();
//Stockez une liste d'endroits où vous pouvez placer les pierres en premier
for (int y = 0; y < this.size; y ++) {
for (int x = 0; x < this.size; x ++) {
//Ignorer le traitement ultérieur si d'autres pierres sont placées
if (this.squares[y][x] != 'N') {
continue;
}
//Si vous ne pouvez pas retourner la pierre de l'adversaire, ignorez le traitement suivant
Coordinates newDisc = new Coordinates(x, y);
ArrayList<Coordinates> discs = this.checkDiscsTurnedOverAllLine(
myColor, enemyColor, newDisc, this.size*this.size);
if (discs.isEmpty()) {
continue;
}
//Inscrivez-vous dans la liste des candidats
candidates.add(new Candidate(newDisc));
}
}
//Choisissez au hasard un de chaque candidat
Coordinates newDisc = candidates.get(new Random().nextInt(candidates.size()));
ArrayList<Coordinates> discs = this.checkDiscsTurnedOverAllLine(
myColor, enemyColor, newDisc, this.size*this.size);
this.putDisc(myColor, newDisc);
this.turnOverDiscs(discs);
this.printDiscsTurnedOver(discs);
}
Contrairement au moment où le joueur entre dans l'emplacement de la pierre, vous pouvez rechercher toutes les cases en utilisant simplement l'instruction for. Regardez les carrés un par un, et s'il y a un carré qui peut retourner la pierre de l'adversaire, enregistrez-le comme candidat pour le prochain endroit où poser la pierre. Cette fois, nous en sélectionnerons un parmi les candidats au hasard.
De plus, compte tenu de la mise en œuvre d'une routine de réflexion à l'avenir, les données possédées par chaque candidat ne sont pas seulement les coordonnées sur le plateau d'Othello, mais également des paramètres qui représentent une certaine importance (comme prendre une valeur élevée si le coin peut être pris, ou la pierre de l'adversaire). Je veux avoir une variable (par exemple, plus la valeur est élevée, plus vous la retournez). Par conséquent, en tant que candidat pour l'emplacement suivant, nous avons nouvellement défini la classe Candidate, qui est __ héritée de la classe Coordinates qui n'a que les coordonnées du tableau Othello. Un jour, ce cours montrera son vrai potentiel …………
class Candidate extends Coordinates {
public int priority;
public Candidate(Coordinates c) {
super(c);
}
}
J'ai omis l'explication, mais il y a quelques changements depuis la dernière fois (variables membres, etc.). Merci de votre compréhension.
import java.util.ArrayList;
import java.util.Random;
import java.util.Scanner;
class OthelloBoardTest {
public static void main(String args[]) {
OthelloBoard ob = new OthelloBoard();
ob.start();
}
}
class OthelloBoard {
private int size; //Un côté du plateau d'Othello(8, 10, 12, 14, 16)
private char[][] squares; //État de chaque masse(B:noir, W:blanc, N:Pas de pierre)
private int turnCount; //Comptez le nombre de tours
private int turnCountMax; //Nombre maximum de tours(1 côté*1 côté-4)
private char playerColor; //Couleur de la pierre du joueur
private char otherColor; //La couleur de la pierre de l'adversaire
private int playerDiscNum; //Nombre de pierres de joueur
private int otherDiscNum; //Nombre de pierres de l'adversaire
private final String alphabets = "abcdefghijklmnop";
//Alphabet montrant les coordonnées horizontales
//constructeur
public OthelloBoard() {
this.size = 8;
// this.size = askBoardSize();
this.squares = new char[this.size][this.size];
this.turnCount = 1;
this.turnCountMax = this.size*this.size - 4;
//Mettez la carte Othello en état immédiatement après le départ
this.initializeBoard();
}
//Démarrez Othello
public void start() {
//Traitement avant de commencer
this.askPlayerColor();
boolean isPlayerTurn = this.getFirstMove();
int skipCount = 0;
//Traitement de chaque tour
System.out.println("Démarrez Othello.");
this.printBoard();
while (this.turnCount <= turnCountMax) {
//Déterminez s'il faut sauter le virage
int skipFlag = this.checkSkipCount(isPlayerTurn, skipCount);
if (skipFlag == 2) {
break;
} else if (skipFlag == 1) {
isPlayerTurn = !isPlayerTurn;
skipCount ++;
continue;
}
//Lorsque vous ne sautez pas
skipCount = 0;
if (isPlayerTurn) {
//Tour du joueur
System.out.println("\nTurn " + turnCount + ":C'est ton tour.");
this.askNewCoordinates(this.playerColor, this.otherColor);
} else {
//Tour de l'adversaire
System.out.println("\nTurn " + turnCount + ":C'est au tour de votre adversaire.");
this.thinkNewCoordinates(this.otherColor, this.playerColor);
}
this.printBoard();
//Traitement pour le prochain tour
this.turnCount ++;
isPlayerTurn = !isPlayerTurn;
}
//Jugement de victoire ou de défaite
this.printDiscNumber();
this.printResult();
}
//Affinez automatiquement où placer la pierre suivante
private void thinkNewCoordinates(char myColor, char enemyColor) {
ArrayList<Candidate> candidates = new ArrayList<Candidate>();
//Stockez une liste d'endroits où vous pouvez placer les pierres en premier
for (int y = 0; y < this.size; y ++) {
for (int x = 0; x < this.size; x ++) {
//Ignorer le traitement ultérieur si d'autres pierres sont placées
if (this.squares[y][x] != 'N') {
continue;
}
//Si vous ne pouvez pas retourner la pierre de l'adversaire, ignorez le traitement suivant
Coordinates newDisc = new Coordinates(x, y);
ArrayList<Coordinates> discs = this.checkDiscsTurnedOverAllLine(
myColor, enemyColor, newDisc, this.size*this.size);
if (discs.isEmpty()) {
continue;
}
//Inscrivez-vous dans la liste des candidats
candidates.add(new Candidate(newDisc));
}
}
//Choisissez au hasard un de chaque candidat
Coordinates newDisc = candidates.get(new Random().nextInt(candidates.size()));
ArrayList<Coordinates> discs = this.checkDiscsTurnedOverAllLine(
myColor, enemyColor, newDisc, this.size*this.size);
this.putDisc(myColor, newDisc);
this.turnOverDiscs(discs);
this.printDiscsTurnedOver(discs);
}
//Déterminez s'il faut sauter le virage
//0 si le saut n'est pas requis, 1 si le saut est requis et que le tour précédent n'a pas été sauté
//Renvoie 2 si le saut est requis et que le tour précédent a également été ignoré
private int checkSkipCount(boolean isPlayerTurn, int skipCount) {
char myColor;
char enemyColor;
int result = 0;
if (isPlayerTurn) {
myColor = this.playerColor;
enemyColor = this.otherColor;
} else {
myColor = this.otherColor;
enemyColor = this.playerColor;
}
if (! this.checkSquaresForNewDisc(myColor, enemyColor)) {
//Passer le tour du joueur
System.out.println("Le virage a été sauté.");
result = 1;
if (skipCount == 1) {
//Si le tour de l'adversaire a déjà été sauté, la partie se termine
result = 2;
}
}
return result;
}
//Le premier mouvement décide lequel
//Si le joueur est Kuroishi, le joueur est le premier, et si Shiraishi, l'adversaire est le premier.
private boolean getFirstMove() {
if (this.playerColor == 'B') {
return true;
} else {
return false;
}
}
//Retourne la pierre
private 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';
}
}
}
//Endroit pour mettre des pierres(Un endroit où vous pouvez retourner d'autres pierres)Déterminez s'il y a
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;
}
//Acceptez l'entrée jusqu'à ce que l'endroit où placer la pierre soit décidé
private void askNewCoordinates(char myColor, char enemyColor) {
while (true) {
//contribution
System.out.println("\n Décidez où placer la pierre.");
System.out.println("[coordonnée x coordonnée y](Exemplea1):");
Scanner sc = new Scanner(System.in);
//Déterminez s'il est à portée de la planche Othello
Coordinates newDisc = this.checkCoordinatesRange(sc.nextLine());
if (newDisc.equals(-1, -1)) {
//Si les coordonnées sont incorrectes, ressaisissez
System.out.println("L'entrée est incorrecte.");
continue;
}
if (this.squares[newDisc.y][newDisc.x] != 'N') {
//Si une pierre a déjà été placée, faites-la entrer
System.out.println("J'ai déjà une pierre.");
continue;
}
//Déterminez si la pierre de l'adversaire peut être retournée
ArrayList<Coordinates> discs = this.checkDiscsTurnedOverAllLine(
myColor, enemyColor, newDisc, this.size*this.size);
if (! discs.isEmpty()) {
//S'il y a une pierre qui peut être retournée, retournez la pierre
this.putDisc(myColor, newDisc);
this.turnOverDiscs(discs);
this.printDiscsTurnedOver(discs);
return;
}
System.out.println("Je ne peux pas retourner la pierre de l'adversaire.");
}
}
//Déterminez si les coordonnées saisies par le joueur sont à portée du plateau Othello
//Si le jugement réussit, les coordonnées sont utilisées, et si le jugement échoue, les coordonnées sont utilisées.(-1, -1)rends le
private Coordinates checkCoordinatesRange(String line) {
String[] tokens = line.split(" ");
//Lire les coordonnées horizontales de la première lettre de l'alphabet
int x = this.alphabets.indexOf(tokens[0]);
if (tokens[0].length() != 1 || x < 0 || this.size <= x) {
return new Coordinates(-1, -1);
}
//Lire les coordonnées verticales des caractères restants
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);
}
//Déterminez si la pierre aux coordonnées saisies peut retourner la pierre de l'adversaire
//Renvoie les coordonnées de la pierre qui peut être retournée comme Arraylist
//Étant donné que la valeur maximale du nombre pouvant être retourné peut être déterminée par l'argument countMax
//1 suffit pour juger si une pierre peut être placée à cette coordonnée
//Taille pour renvoyer toutes les coordonnées d'une pierre qui peut être retournée*à la taille
private ArrayList<Coordinates> checkDiscsTurnedOverAllLine(
char myColor, char enemyColor, Coordinates myCoordinates, int countMax)
{
ArrayList<Coordinates> discs = new ArrayList<Coordinates>();
//Scannez dans chaque direction
for (int d = 0; d < 8; d ++) {
discs.addAll(this.checkDiscsTurnedOverOneLine(myColor, enemyColor, myCoordinates, d));
//Si la valeur maximale de la pierre qui peut être retournée est dépassée, le traitement sera arrêté.
if (discs.size() > countMax) {
break;
}
}
return discs;
}
//Déterminez si la pierre aux coordonnées saisies peut retourner la pierre de l'adversaire
//La direction de balayage change en fonction de la direction de l'argument
// 0:0 degrés, 1:45 degrés, 2:90 degrés, 3:135 degrés, 4:180 degrés, 5:225 degrés, 6:270 degrés, 7:315 degrés
private ArrayList<Coordinates> checkDiscsTurnedOverOneLine(
char myColor, char enemyColor, Coordinates myCoordinates, int direction)
{
//Scannez une pierre qui peut être retournée
Coordinates currentCoordinates = new Coordinates(myCoordinates);
ArrayList<Coordinates> discs = new ArrayList<Coordinates>();
//Continuez à scanner à côté de vous pendant que les pierres de votre adversaire continuent
while (true) {
//Trouvez les coordonnées de la prochaine pierre
Coordinates nextDisc = this.getNextDiscCoordinates(currentCoordinates, direction);
if (nextDisc.equals(-1, -1)) {
//Renvoie une liste vide s'il n'y a pas de pierres à retourner
discs.clear();
break;
}
if (this.squares[nextDisc.y][nextDisc.x] == enemyColor) {
//S'il y a une pierre adverse à côté de vous, enregistrez-la temporairement dans la flip list
discs.add(nextDisc);
} else if (this.squares[nextDisc.y][nextDisc.x] == myColor) {
//Si vous avez votre propre pierre à côté, renvoyez la liste
break;
} else {
//S'il n'y a pas de pierre à côté, retournez une liste vide
discs.clear();
break;
}
//Passez à la pierre suivante
currentCoordinates.copy(nextDisc);
}
return discs;
}
//à côté de(Dépend de la direction)Renvoie les coordonnées de la pierre en
//Si les coordonnées sont hors de portée(-1, -1)rends le
private Coordinates getNextDiscCoordinates(Coordinates myDisc, int direction) {
//coordonnée x
int x = myDisc.x;
if (direction == 0 || direction == 1 || direction == 7) {
x ++; //0 degrés,45 degrés,315 degrés
} else if (direction == 3 || direction == 4 || direction == 5) {
x --; //135 degrés,180 degrés,225 degrés
}
//coordonnée y
int y = myDisc.y;
if (direction == 1 || direction == 2 || direction == 3) {
y --; //45 degrés,90 degrés,135 degrés
} else if (direction == 5 || direction == 6 || direction == 7) {
y ++; //225 degrés,270 degrés,315 degrés
}
if (x < 0 || this.size <= x || y < 0 || this.size <= y) {
//Lorsque les coordonnées sont hors de portée
return new Coordinates(-1, -1);
}
return new Coordinates(x, y);
}
//Accepte les entrées jusqu'à ce que la taille de la carte Othello soit décidée
//Cette méthode est le constructeur de ce.Si vous le collez sur le côté droit de la taille,
//Vous pouvez ajouter un processus pour entrer la taille du tableau Othello
private int askBoardSize() {
while (true) {
System.out.println("");
System.out.println("Veuillez décider de la longueur d'un côté de la planche Othello.");
System.out.print("[8, 10, 12, 14,L'un des 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("La longueur d'un côté de la planche Othello est" + line + "est.");
return Integer.parseInt(line);
}
System.out.println("L'entrée est incorrecte.");
}
}
//Acceptez l'entrée jusqu'à ce que la couleur de la pierre du joueur soit décidée
private void askPlayerColor() {
while (true) {
System.out.println("\n Choisissez votre pierre.");
System.out.println("[b (noir), w (blanc)N'importe quel]:");
Scanner sc = new Scanner(System.in);
String line = sc.nextLine();
if ("b".equals(line)) {
System.out.println("Votre pierre est noire.");
this.playerColor = 'B';
this.otherColor = 'W';
return;
} else if ("w".equals(line)) {
System.out.println("Votre pierre est blanche.");
this.playerColor = 'W';
this.otherColor = 'B';
return;
}
System.out.println("L'entrée est incorrecte.");
}
}
//Montrez le résultat du jeu
private void printResult() {
if (playerDiscNum > otherDiscNum) {
System.out.println("Vous gagnez.");
} else if (playerDiscNum == otherDiscNum) {
System.out.println("C'est un tirage au sort.");
} else {
System.out.println("Tu as perdu.");
}
}
//Afficher le nombre de pierres du joueur et de l'adversaire
private void printDiscNumber() {
this.playerDiscNum = this.countDisc(this.playerColor);
this.otherDiscNum = this.countDisc(this.otherColor);
System.out.print("tu= " + playerDiscNum + " ");
System.out.println("Adversaire= " + otherDiscNum);
}
//Compter les pierres de la couleur spécifiée
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;
}
//Mettez la carte Othello en état immédiatement après le départ
private void initializeBoard() {
for (int y = 0; y < this.size; y ++) {
for (int x = 0; x < this.size; x ++) {
squares[y][x] = 'N';
}
}
//Placez les pierres uniquement dans les 4 cases centrales
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);
}
//Placez une pierre aux coordonnées spécifiées sur le plateau Othello
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);
}
//Afficher toutes les coordonnées des pierres retournées
private void printDiscsTurnedOver(ArrayList<Coordinates> discs) {
System.out.println("J'ai retourné la pierre suivante.");
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("");
}
//Affichez la carte Othello sur la console
private void printBoard() {
this.printBoardAlphabetLine(); //Ligne alphabet
this.printBoardOtherLine("┏", "┳", "┓"); //Bord supérieur
for (int y = 0; y < this.size - 1; y ++) {
this.printBoardDiscLine(y); //Ligne affichant des pierres
this.printBoardOtherLine("┣", "╋", "┫"); //Interligne
}
this.printBoardDiscLine(this.size - 1); //Ligne affichant des pierres
this.printBoardOtherLine("┗", "┻", "┛"); //Bas de gamme
}
//Afficher l'alphabet indiquant la ligne du plateau Othello
private void printBoardAlphabetLine() {
String buf = " ";
for (int x = 0; x < this.size; x ++) {
buf += " " + this.alphabets.charAt(x);
}
System.out.println(buf);
}
//Afficher une ligne avec des pierres sur le plateau Othello
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);
}
//Afficher une ligne de lignes réglées représentant le cadre du plateau d'Othello
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 Candidate extends Coordinates {
public int priority;
public Candidate(Coordinates c) {
super(c);
}
}
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;
}
}
}
À propos, si vous modifiez la partie qui traite le tour du joueur dans la méthode start pour appeler la méthode thinkNewCoordinates au lieu de la méthode askNewCoordinates, le traitement se déroulera automatiquement du côté du joueur et le jeu se terminera dans un instant. Cela facilite les tests!
Cette fois, c'est un peu petit, mais je vais m'arrêter ici. Merci pour la lecture!