[JAVA] Mes pensées sur l'avenir [Préparation]

1. 1. Introduction (nommée autoproclamée)

Quand j'étais lycéen, j'étais un peu inscrit au club Go Shogi à l'école. Je ne jouais pas au Go ou au Shogi depuis longtemps, mais j'étais intéressé à être influencé par les mangas. En conséquence, je n'étais pas vraiment bon dans ce domaine et je voulais la position la plus faible du club. Donc, pour une raison quelconque, il y avait aussi un tableau d'Othello dans la salle du club du club Go Shogi, et après avoir été foiré par d'autres membres avec Shogi, je faisais aussi Othello pour changer. Othello a des règles plus simples que Go et Shogi, donc il y a bien sûr des difficultés, mais je ne sais pas où utiliser les morceaux pris avec Shogi, ou quand Go est considéré comme la fin. Pour moi, c'était un événement vraiment facile. Eh bien, c'était encore cahoteux. À propos, il semble qu'il y ait des gens féroces dans le monde qui peuvent tirer le codage d'Othello dans une plage de 7 lignes $ × 79 $ caractères, mais je ne peux pas le faire même avec 700 lignes, et encore moins 70 lignes, soit 10 fois plus. Comme il fonctionne comme un corps, j'ai décidé de contester l'implémentation d'Othello cette fois sans limiter le nombre de personnages. En fait, je visais le programme Othello le plus puissant comme le suggère le titre en concevant un algorithme pour déterminer où il est préférable de placer la pierre, mais comme je m'y attendais, je vais en faire une situation où Othello peut être fait normalement en premier lieu. C'était tout ce que je pouvais faire. Donc, cette fois, en tant que [Préparation], j'écrirai sur le processus jusqu'à ce qu'Othello devienne capable de jouer pour le moment.

2. Définition du problème (excuse nommée)

Cette fois, ce serait bien si Othello pouvait être fait! Je vais le dire. Cependant, je ne peux pas faire quelque chose qui fonctionne sur le navigateur pour le moment, donc je vais faire quelque chose qui fonctionne sur la console familière à chaque fois. Alors, veuillez pardonner __pas __ pour quelque chose que vous pouvez faire et jouer.

3. 3. Mise en œuvre ① Affichage de la carte Othello

En gros, tous les traitements d'Othello que nous allons implémenter seront écrits dans une classe appelée OthelloBoard. OthelloBoard a les variables et tableaux suivants comme membres:

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 char playerColor;		//Couleur de la pierre du joueur
	private char otherColor;		//La couleur de la pierre de l'adversaire
	private int turnCounter;		//Comptez le nombre de tours
	private final String alphabets = "abcdefghijklmnop";
}

La taille variable de type int représente le nombre de pierres qui peuvent être placées sur un côté de la planche Othello. Dans le constructeur décrit plus loin, le général 8 est attribué, mais si vous jouez avec, vous pouvez jouer avec la taille de madness de 16 carrés $ × 16 $ carrés. J'ai essayé, mais j'ai été frustré au début. ~~ Je suis fou ~~ othello2.png Hmmm, ce sentiment de désespoir.

…… Renvoyez l'histoire. Les carrés de tableau à deux dimensions de type char sont un tableau qui représente l'état de chaque cellule. Vous pouvez voir s'il y a une pierre dans le carré, et si c'est le cas, s'il s'agit d'une pierre noire ou blanche, ou la mettre à jour. Les variables de type char suivantes playerColor et otherColor contiendront soit "B" soit "W" lorsque le joueur sélectionne Kuroishi ou Shiraishi au début de la partie. La dernière chaîne, alphabets, contient des alphabets qui représentent les coordonnées horizontales utilisées pour afficher le tableau Othello. This.alphabets.charAt (x) lorsque vous voulez faire référence à l'alphabet $ x $ th, et inversement, cela lorsque vous voulez savoir quel est le nombre de la lettre y (vous voulez connaître les coordonnées horizontales sous forme de valeur numérique). Vous pouvez faire quelque chose comme .alphabets.indexOf ("y"). De plus, comme cette chaîne ne devrait pas être modifiée à l'avenir, le modificateur final est ajouté. Pour ce domaine, je me suis référé aux commentaires que j'ai reçus dans les articles précédents. Merci à tous ceux qui ont fait des commentaires.

Maintenant, d'ici, je vais vous expliquer la partie qui affiche le tableau d'Othello.

//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 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);
}

Si vous souhaitez afficher la carte Othello sur la console, appelez la première méthode printBoard. Afin d'afficher le plateau Othello, il est nécessaire d'afficher des cercles noirs et des cercles blancs qui représentent des pierres, des lignes de règle qui représentent le cadre du plateau, etc. Les pièces avec le même flux sont assemblées dans différentes méthodes printBoardAlphabetLine, printBoardDiscLine et printBoardOtherLine, et elles sont appelées. En passant, lorsque vous exécutez la méthode ci-dessus, vous verrez quelque chose comme ceci (la taille est de 8 carrés $ x 8 $ carrés). othello.png

Les alphabets ou les nombres représentant les coordonnées sont affichés en haut et à gauche du tableau Othello. Lorsque le joueur saisit l'endroit où placer la pierre, par exemple, saisissez alphabet + espace demi-largeur + nombre tel que "un 1".

4. Mise en œuvre ② Entrée du joueur

Ensuite, nous vous montrerons comment gérer les entrées des joueurs. Comme je l'ai écrit plus tôt, l'endroit où placer la pierre est de saisir "alphabet + espace demi-largeur + nombre", mais vous devez vous assurer que l'entrée est correcte. Les contenus qui doivent être confirmés sont les suivants pour le moment.

  1. L'emplacement des coordonnées saisies existe-t-il réellement? Par exemple, un endroit impossible tel que "z 15" ou un objet dont les coordonnées ne peuvent pas être lues tel que "syoukou 1234" ne sera pas accepté comme entrée.
  2. Y a-t-il d'autres pierres dans le carré aux coordonnées entrées?
  3. N'y a-t-il pas d'autre pierre dans la case avec les coordonnées entrées, mais n'est-il pas possible de retourner l'une des autres pierres?

Le code suivant implémente le processus pour les vérifier.

//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, la faire 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);
}

Si vous souhaitez que le joueur entre l'emplacement de la pierre que vous souhaitez placer, appelez la première méthode askNewCoordinates. En utilisant l'instruction while, le lecteur continue de taper encore et encore jusqu'à ce qu'il puisse être traité comme une entrée correcte (c'est un peu effrayant à dire). Le premier des bulletins ci-dessus est jugé par la méthode checkCoordinatesRange. Puisque le lecteur relie l'alphabet des coordonnées horizontales et le nombre de coordonnées verticales avec un espace demi-largeur, commencez par le diviser avec la méthode de fractionnement. Pour les coordonnées verticales, la méthode parseInt est utilisée pour convertir la chaîne de caractères en une valeur numérique, mais en fait, si cette méthode, la conversion __ échoue, une exception appelée NumberFormatException sera levée et l'ensemble du programme sera interrompu de force __ Il est. Par conséquent, utilisez ~~ __ Exception Handling __ que vous venez d'étudier afin qu'il ne soit pas interrompu de force même si une telle exception se produit. Comme dans le code ci-dessus, placez la partie où l'exception peut se produire dans le bloc __try __ et écrivez le traitement après avoir intercepté l'exception dans le bloc __catch __ après le bloc try. Le bloc try est comme placer un réseau dans un endroit où le traitement des exceptions peut se produire, et il semble que le traitement à appliquer à l'exception sur le net est écrit dans le bloc catch (si vous faites une erreur, il serait utile que vous puissiez commenter). ). La deuxième puce peut être facilement déterminée en se référant aux carrés du tableau de type char. La troisième balle, mais c'est ennuyeux. Que la pierre de l'adversaire puisse être retournée ou non, c'est exactement le processus qui peut être considéré comme la base d'Othello. La méthode checkDiscsTurnedOverAllLine appelée dans le code ci-dessus est décrite en détail dans la section suivante.

5. Mise en œuvre ③ Jugement sur la possibilité de retourner la pierre de l'adversaire

Tout d'abord, je vais expliquer la classe Coordinates qui apparaîtra souvent dans les traitements futurs. Cette classe Coordinates est simplement une classe qui stocke les coordonnées x et y de la carte Othello sous forme de valeurs numériques. Les variables membres x et y sont rendues publiques pour éviter les problèmes d'écriture de code. À proprement parler, il doit être privé et une méthode publique dédiée doit être préparée pour référence et affectation, mais cette fois j'ai donné la priorité au plaisir. Je suis désolé. Il existe également une méthode de copie qui copie d'autres coordonnées et une méthode d'égalité qui détermine si les coordonnées sont égales aux coordonnées données.

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;
		}
	}
}

Maintenant, parlons de la partie la plus désagréable de ce programme, le jugement de savoir si la pierre de l'adversaire peut être retournée ou non. Tout d'abord, voyons comment nous déterminons si nous pouvons retourner la pierre de l'adversaire lorsque nous jouons réellement avec Othello.

  1. Concentrez-vous sur les carrés qui n'ont pas de pierres et qui n'ont pas encore été remarqués.
  2. Regardez les __8 directions __ de droite, en haut à droite, en haut, en haut à gauche, à gauche, en bas à gauche, en bas, en bas à droite à partir du carré d'intérêt. Dans chaque direction, quand une ou plusieurs pierres de l'adversaire continuent de la prochaine à la case d'intérêt __1 puis l'une de vos propres pierres __, passez à 3. Si ce n'est le cas dans aucune direction, revenez à 1.
  3. Dans les huit directions, retournez le carré d'intérêt et la pierre de l'adversaire pris en sandwich entre vos pierres trouvées en 2. pour fabriquer votre propre pierre.

Je suis désolé, c'est difficile à comprendre, mais en mots, ça ressemble à ça. Ainsi, le code suivant est celui qui a essayé d'implémenter un tel processus.

//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ée 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 pouvant ê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);
}

Si vous voulez savoir si vous pouvez retourner la pierre de votre adversaire, appelez d'abord la méthode checkDiscsTurnedOverAllLine. Je vais examiner les huit directions comme AllLine, mais je voulais résumer le traitement de pièces similaires, j'ai donc décidé d'appeler la méthode checkDiscsTurnedOverOneLine pour chaque direction. Cette méthode checkDiscsTurnedOverOneLine ne traite qu'une seule direction spécifiée par la direction de l'argument, comme dans OneLine. Pour une certaine direction, les coordonnées de la pierre suivante sont obtenues en continu à partir de la méthode getNextDiscCoordinates (les coordonnées x et y sont incrémentées, décrémentées ou inchangées de 1 en spécifiant la direction). Dans la déclaration while, si les pierres de l'adversaire sont continues à côté du carré d'intérêt, __temporairement enregistrez __ dans la liste des disques de pierres qui peuvent les retourner. Si vous n'avez pas votre propre pierre après la pierre de l'adversaire que vous pourriez être en mesure de retourner, ou si vous sortez de la portée du plateau Othello, supprimez toutes les listes temporairement enregistrées. Au final, les coordonnées contenues dans la liste retournée par la méthode checkDiscsTurnedOverAllLine introduite au début sont la liste des pierres qui peuvent vraiment être retournées.

6. Mise en œuvre ④ Flux global d'Othello

Enfin, je présenterai brièvement la partie qui décrit le déroulement du jeu Othello.

//Démarrez Othello
public void start() {
	//Décidez de la pierre du joueur
	this.askPlayerColor();
	//Mettez la carte Othello en état immédiatement après le départ
	this.initializeBoard();
	this.printBoard();
	this.turnCounter = 1;
	int turnCounterMax = this.size*this.size - 4;
	int skipCounter = 0;
	//Le premier mouvement décide lequel
	boolean isPlayerTurn = true;
	if (this.playerColor == 'W') {
		isPlayerTurn = false;
	}
	//Traitement de chaque tour
	System.out.println("Démarrez Othello.");
	int playerDiscNum;
	int otherDiscNum;
	while (this.turnCounter <= turnCounterMax) {
		//Afficher le nombre de pierres pour le moment
		playerDiscNum = this.countDisc(this.playerColor);
		otherDiscNum = this.countDisc(this.otherColor);
		System.out.print("tu= " + playerDiscNum + "  ");
		System.out.println("Adversaire= " + otherDiscNum);
		if (isPlayerTurn) {
			//Tour du joueur
			//Déterminez si le joueur peut poser une pierre
			if (! this.checkSquaresForNewDisc(this.playerColor, this.otherColor)) {
				//Les tours des joueurs sont sautés
				System.out.println("Votre tour a été sauté.");
				if (skipCounter == 1) {
					//Si le tour de l'adversaire a déjà été sauté, la partie se termine
					break;
				}
				isPlayerTurn = !isPlayerTurn;
				skipCounter ++;
				continue;
			}
			System.out.println("Turn " + turnCounter + ":C'est ton tour.");
			skipCounter = 0;
			this.askNewCoordinates(this.playerColor, this.otherColor);
		} else {
			//Tour de l'adversaire
			//Déterminez si l'adversaire peut mettre une pierre
			if (! this.checkSquaresForNewDisc(this.otherColor, this.playerColor)) {
				//Les tours des joueurs sont sautés
				System.out.println("Le tour de l'adversaire a été sauté.");
				if (skipCounter == 1) {
					//Si le tour du joueur a déjà été sauté, le jeu se termine
					break;
				}
				isPlayerTurn = !isPlayerTurn;
				skipCounter ++;
				continue;
			}
			//Tour de l'adversaire
			System.out.println("Turn " + turnCounter + ":C'est au tour de votre adversaire.");
			skipCounter = 0;
			this.askNewCoordinates(this.otherColor, this.playerColor);
		}
		this.printBoard();
		//Traitement pour le prochain tour
		this.turnCounter ++;
		isPlayerTurn = !isPlayerTurn;
	}
	//Jugement de victoire ou de défaite
	playerDiscNum = this.countDisc(this.playerColor);
	otherDiscNum = this.countDisc(this.otherColor);
	System.out.print("tu= " + playerDiscNum + "  ");
	System.out.println("Adversaire= " + otherDiscNum);
	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.");
	}
}

En passant, il n'est pas bon d'écrire 80 lignes dans une méthode comme la méthode de démarrage ci-dessus. Vous devez écrire un code facile à lire en regroupant des processus similaires en différentes méthodes ou en séparant certaines parties en différentes méthodes. __ est __, je n'ai pas eu assez de temps cette fois. Veuillez me pardonner car je l'améliorerai la prochaine fois que je le montrerai.

Maintenant, pour contrôler le déroulement du jeu, il y a une chose importante: __ Si vous ne pouvez pas du tout poser votre propre pierre, ce sera une passe et ce sera le tour de votre adversaire __. De plus, il ne faut pas oublier que si ni vous ni votre adversaire ne pouvez placer une pierre, le jeu se terminera __. Par conséquent, dans le code ci-dessus, une variable de type int skipCounter est créée et 1 est ajouté si l'un de vous ou l'autre partie est en situation de réussite, et si une pierre peut être placée, elle est réinitialisée à 0. Ensuite, le jeu se termine lorsque vous et votre adversaire passez successivement (skipCounter == 2).

7. Résumé de la mise en œuvre

Le reste du processus est plus simple que le contenu jusqu'à présent, je vais donc omettre l'explication. L'ensemble du programme mis en œuvre cette fois est décrit ci-dessous.

<détails>

Programme Othello (cliquez pour ouvrir) </ summary>

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;				//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 char playerColor;		//Couleur de la pierre du joueur
	private char otherColor;		//La couleur de la pierre de l'adversaire
	private int turnCounter;		//Comptez le nombre de tours
	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];
	}

	//Démarrez Othello
	public void start() {
		//Décidez de la pierre du joueur
		this.askPlayerColor();
		//Mettez la carte Othello en état immédiatement après le départ
		this.initializeBoard();
		this.printBoard();
		this.turnCounter = 1;
		int turnCounterMax = this.size*this.size - 4;
		int skipCounter = 0;
		//Le premier mouvement décide lequel
		boolean isPlayerTurn = true;
		if (this.playerColor == 'W') {
			isPlayerTurn = false;
		}
		//Traitement de chaque tour
		System.out.println("Démarrez Othello.");
		int playerDiscNum;
		int otherDiscNum;
		while (this.turnCounter <= turnCounterMax) {
			//Afficher le nombre de pierres pour le moment
			playerDiscNum = this.countDisc(this.playerColor);
			otherDiscNum = this.countDisc(this.otherColor);
			System.out.print("tu= " + playerDiscNum + "  ");
			System.out.println("Adversaire= " + otherDiscNum);
			if (isPlayerTurn) {
				//Tour du joueur
				//Déterminez si le joueur peut poser une pierre
				if (! this.checkSquaresForNewDisc(this.playerColor, this.otherColor)) {
					//Les tours des joueurs sont sautés
					System.out.println("Votre tour a été sauté.");
					if (skipCounter == 1) {
						//Si le tour de l'adversaire a déjà été sauté, la partie se termine
						break;
					}
					isPlayerTurn = !isPlayerTurn;
					skipCounter ++;
					continue;
				}
				System.out.println("Turn " + turnCounter + ":C'est ton tour.");
				skipCounter = 0;
				this.askNewCoordinates(this.playerColor, this.otherColor);
			} else {
				//Tour de l'adversaire
				//Déterminez si l'adversaire peut mettre une pierre
				if (! this.checkSquaresForNewDisc(this.otherColor, this.playerColor)) {
					//Les tours des joueurs sont sautés
					System.out.println("Le tour de l'adversaire a été sauté.");
					if (skipCounter == 1) {
						//Si le tour du joueur a déjà été sauté, le jeu se termine
						break;
					}
					isPlayerTurn = !isPlayerTurn;
					skipCounter ++;
					continue;
				}
				//Tour de l'adversaire
				System.out.println("Turn " + turnCounter + ":C'est au tour de votre adversaire.");
				skipCounter = 0;
				this.askNewCoordinates(this.otherColor, this.playerColor);
			}
			this.printBoard();
			//Traitement pour le prochain tour
			this.turnCounter ++;
			isPlayerTurn = !isPlayerTurn;
		}
		//Jugement de victoire ou de défaite
		playerDiscNum = this.countDisc(this.playerColor);
		otherDiscNum = this.countDisc(this.otherColor);
		System.out.print("tu= " + playerDiscNum + "  ");
		System.out.println("Adversaire= " + otherDiscNum);
		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.");
		}
	}

	//Retourne la pierre
	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';
			}
		}
	}

	//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, la faire 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ée 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 pouvant ê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.");
		}
	}

	//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 d'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 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 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. Essayez de courir

Puisque le plateau d'Othello est affiché à chaque fois que vous entrez une coordonnée, nous n'introduirons qu'un seul écran au lieu d'afficher le jeu entier paresseusement.  othello3.png

À la toute fin, vous et votre adversaire avez réussi, le jeu s'est donc terminé. Ce qui est difficile, c'est que nous n'avons pas encore implémenté le traitement de l'autre partie (PC), donc pour le moment nous devons entrer les coordonnées jusqu'à la pierre de l'autre partie __. Ce sentiment triste __ auto-fait __. Que fais-je depuis dimanche jour ………

9. Tâches futures

Pour le moment, je suis maintenant dans un état où je peux au moins Othello, donc je vais mettre en œuvre la routine de réflexion de l'autre partie à l'avenir. Au début, on a l'impression de choisir au hasard à partir de l'endroit où vous pouvez poser la pierre, mais par exemple, au début du jeu, ne prenez pas trop de pierre, visez un coin collant dans la partie médiane, et laissez la vitesse de calcul vous parler dans la partie finale Je voudrais créer un algorithme __ qui n'a pas de lacunes dans les étapes précoces, intermédiaires et tardives, comme la pré-lecture.

Je suis désolé que l'explication soit devenue redondante en raison du code source long cette fois. Encore merci à tous ceux qui ont lu jusqu'ici.

Recommended Posts

Mes pensées sur l'avenir [Préparation]
Mes réflexions sur la méthode d'égalité (Java)
Othello de mes pensées [Routine de réflexion 2]
Othello de mes pensées [Routine de réflexion 1]
Scala s'exécute sur une JVM