[JAVA] Othello de mes pensées [Routine de réflexion 1]

1. 1. Synopsis de la dernière fois (préparation)

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.

2. Slim la méthode

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.

3. 3. Pour le moment, plaçons les pierres au hasard

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

4. Programme jusqu'à présent

J'ai omis l'explication, mais il y a quelques changements depuis la dernière fois (variables membres, etc.). Merci de votre compréhension.

Programme Othello (cliquez pour ouvrir)
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!

Recommended Posts

Othello de mes pensées [Routine de réflexion 2]
Othello de mes pensées [Routine de réflexion 1]
Mes pensées sur l'avenir [Préparation]
Mes réflexions sur la méthode d'égalité (Java)
Mes pensées sur l'avenir [Version de l'application Gradle ①]