Compare commits
3 Commits
classe_tui
...
kara-mosr-
| Author | SHA1 | Date | |
|---|---|---|---|
| 0c0e065103 | |||
| d8ea5cd958 | |||
| d2a1cb0d65 |
58
README.md
58
README.md
@@ -112,4 +112,60 @@ Voici un récapitulatif des commandes Git que vous utiliserez fréquemment :
|
|||||||
|
|
||||||
## 5. Supprimer une branche
|
## 5. Supprimer une branche
|
||||||
|
|
||||||
git branch -d <nom_de_la_branche>
|
git branch -d <nom_de_la_branche>
|
||||||
|
|
||||||
|
|
||||||
|
## Comment fonctionne l’algorithme de victoire (idée générale)
|
||||||
|
|
||||||
|
Dans Hex, un joueur gagne s’il existe un chemin continu de ses pions connectant ses deux bords :
|
||||||
|
|
||||||
|
PLAYER1 : relier gauche → droite
|
||||||
|
|
||||||
|
PLAYER2 : relier haut → bas
|
||||||
|
|
||||||
|
Un “chemin” = une suite de cases adjacentes sur la grille hexagonale (6 voisins possibles) appartenant au joueur.
|
||||||
|
|
||||||
|
Ce que fait l’algo (principe)
|
||||||
|
|
||||||
|
L’algo fait un parcours de graphe (DFS avec une pile, ou BFS avec une file c’est pareil pour le résultat) :
|
||||||
|
|
||||||
|
On prend toutes les cases du bord de départ du joueur (ex: bord gauche pour PLAYER1).
|
||||||
|
|
||||||
|
On ne garde que celles qui contiennent un pion du joueur.
|
||||||
|
|
||||||
|
À partir de ces cases, on explore toutes les cases voisines contenant aussi un pion du joueur, et ainsi de suite.
|
||||||
|
|
||||||
|
Si pendant l’exploration on atteint l’autre bord, alors il existe un chemin → victoire.
|
||||||
|
|
||||||
|
Pourquoi ça marche ?
|
||||||
|
|
||||||
|
Parce que ça revient à demander :
|
||||||
|
|
||||||
|
“Est-ce qu’il existe une composante connexe de pions du joueur qui touche les deux bords ?”
|
||||||
|
|
||||||
|
Le DFS/BFS explore exactement la composante connexe.
|
||||||
|
|
||||||
|
Les 6 voisins en Hex (grille hexagonale)
|
||||||
|
|
||||||
|
Dans ton code, tu as :
|
||||||
|
|
||||||
|
private static final int[][] NEIGHBORS = {
|
||||||
|
{-1, 0}, {+1, 0},
|
||||||
|
{ 0, -1}, { 0, +1},
|
||||||
|
{-1, +1}, {+1, -1}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
Ça signifie qu’une case (r,c) a jusqu’à 6 voisins :
|
||||||
|
'''
|
||||||
|
(r-1,c), (r+1,c) : “haut/bas”
|
||||||
|
|
||||||
|
(r,c-1), (r,c+1) : “gauche/droite”
|
||||||
|
|
||||||
|
(r-1,c+1) et (r+1,c-1) : les 2 diagonales propres au pavage hexagonal
|
||||||
|
'''
|
||||||
|
Complexité
|
||||||
|
|
||||||
|
Au pire, on visite chaque case une seule fois → O(N²) pour un plateau N×N.
|
||||||
|
|
||||||
|
Très correct pour Hex.
|
||||||
187
javaAPI/fr/iut_fbleau/HexGame/HexBoard.java
Normal file
187
javaAPI/fr/iut_fbleau/HexGame/HexBoard.java
Normal file
@@ -0,0 +1,187 @@
|
|||||||
|
package fr.iut_fbleau.HexGame;
|
||||||
|
|
||||||
|
import fr.iut_fbleau.GameAPI.*;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Plateau du jeu de Hex.
|
||||||
|
*
|
||||||
|
* Joueur 1 relie la gauche et la droite.
|
||||||
|
* Joueur 2 relie le haut et le bas.
|
||||||
|
*/
|
||||||
|
public class HexBoard extends AbstractBoard {
|
||||||
|
|
||||||
|
private final int size;
|
||||||
|
private Player[][] cells;
|
||||||
|
private Deque<AbstractPly> historyLocal;
|
||||||
|
|
||||||
|
private static final int[][] NEIGHBORS = {
|
||||||
|
{-1, 0}, {+1, 0},
|
||||||
|
{ 0, -1}, { 0, +1},
|
||||||
|
{-1, +1}, {+1, -1}
|
||||||
|
};
|
||||||
|
|
||||||
|
public HexBoard(int size) {
|
||||||
|
super();
|
||||||
|
this.size = size;
|
||||||
|
this.cells = new Player[size][size];
|
||||||
|
this.historyLocal = new ArrayDeque<>();
|
||||||
|
this.currentPlayer = Player.PLAYER1;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean inBounds(int r, int c) {
|
||||||
|
return r >= 0 && r < size && c >= 0 && c < size;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Player getCell(int r, int c) {
|
||||||
|
return cells[r][c];
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setCell(int r, int c, Player p) {
|
||||||
|
cells[r][c] = p;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean hasPlayer1Won() {
|
||||||
|
boolean[][] visited = new boolean[size][size];
|
||||||
|
Deque<int[]> stack = new ArrayDeque<>();
|
||||||
|
for (int r = 0; r < size; r++) {
|
||||||
|
if (getCell(r, 0) == Player.PLAYER1) {
|
||||||
|
visited[r][0] = true;
|
||||||
|
stack.push(new int[]{r, 0});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while (!stack.isEmpty()) {
|
||||||
|
int[] cur = stack.pop();
|
||||||
|
int cr = cur[0];
|
||||||
|
int cc = cur[1];
|
||||||
|
if (cc == size - 1) return true;
|
||||||
|
for (int[] d : NEIGHBORS) {
|
||||||
|
int nr = cr + d[0], nc = cc + d[1];
|
||||||
|
if (inBounds(nr, nc) && !visited[nr][nc] && getCell(nr, nc) == Player.PLAYER1) {
|
||||||
|
visited[nr][nc] = true;
|
||||||
|
stack.push(new int[]{nr, nc});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean hasPlayer2Won() {
|
||||||
|
boolean[][] visited = new boolean[size][size];
|
||||||
|
Deque<int[]> stack = new ArrayDeque<>();
|
||||||
|
for (int c = 0; c < size; c++) {
|
||||||
|
if (getCell(0, c) == Player.PLAYER2) {
|
||||||
|
visited[0][c] = true;
|
||||||
|
stack.push(new int[]{0, c});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while (!stack.isEmpty()) {
|
||||||
|
int[] cur = stack.pop();
|
||||||
|
int cr = cur[0];
|
||||||
|
int cc = cur[1];
|
||||||
|
if (cr == size - 1) return true;
|
||||||
|
for (int[] d : NEIGHBORS) {
|
||||||
|
int nr = cr + d[0], nc = cc + d[1];
|
||||||
|
if (inBounds(nr, nc) && !visited[nr][nc] && getCell(nr, nc) == Player.PLAYER2) {
|
||||||
|
visited[nr][nc] = true;
|
||||||
|
stack.push(new int[]{nr, nc});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isLegal(AbstractPly move) {
|
||||||
|
if (!(move instanceof HexPly)) return false;
|
||||||
|
HexPly hp = (HexPly) move;
|
||||||
|
int r = hp.getRow(), c = hp.getCol();
|
||||||
|
return inBounds(r, c)
|
||||||
|
&& getCell(r, c) == null
|
||||||
|
&& hp.getPlayer() == this.getCurrentPlayer();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void doPly(AbstractPly move) {
|
||||||
|
if (!(move instanceof HexPly))
|
||||||
|
throw new IllegalArgumentException("Coup invalide: " + move);
|
||||||
|
HexPly hp = (HexPly) move;
|
||||||
|
if (!isLegal(hp))
|
||||||
|
throw new IllegalStateException("Coup illégal: " + hp);
|
||||||
|
setCell(hp.getRow(), hp.getCol(), hp.getPlayer());
|
||||||
|
historyLocal.push(hp);
|
||||||
|
setNextPlayer();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isGameOver() {
|
||||||
|
return hasPlayer1Won() || hasPlayer2Won();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Result getResult() {
|
||||||
|
if (hasPlayer1Won()) return Result.WIN;
|
||||||
|
if (hasPlayer2Won()) return Result.LOSS;
|
||||||
|
return Result.DRAW;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Iterator<AbstractPly> getPlies() {
|
||||||
|
Player me = this.getCurrentPlayer();
|
||||||
|
List<AbstractPly> moves = new ArrayList<>();
|
||||||
|
for (int r = 0; r < size; r++) {
|
||||||
|
for (int c = 0; c < size; c++) {
|
||||||
|
if (getCell(r, c) == null) moves.add(new HexPly(me, r, c));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return moves.iterator();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Iterator<AbstractPly> getHistory() {
|
||||||
|
return historyLocal.iterator();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void undoLastPly() {
|
||||||
|
if (historyLocal.isEmpty()) return;
|
||||||
|
HexPly last = (HexPly) historyLocal.pop();
|
||||||
|
setCell(last.getRow(), last.getCol(), null);
|
||||||
|
this.currentPlayer = last.getPlayer();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IBoard safeCopy() {
|
||||||
|
HexBoard copy = new HexBoard(this.size);
|
||||||
|
copy.currentPlayer = this.currentPlayer;
|
||||||
|
for (int r = 0; r < size; r++) {
|
||||||
|
for (int c = 0; c < size; c++) {
|
||||||
|
copy.cells[r][c] = this.cells[r][c];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
copy.historyLocal = new ArrayDeque<>(this.historyLocal);
|
||||||
|
return copy;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
for (int r = 0; r < size; r++) {
|
||||||
|
for (int k = 0; k < r; k++) sb.append(" ");
|
||||||
|
for (int c = 0; c < size; c++) {
|
||||||
|
Player p = getCell(r, c);
|
||||||
|
char ch = '.';
|
||||||
|
if (p == Player.PLAYER1) ch = '1';
|
||||||
|
else if (p == Player.PLAYER2) ch = '2';
|
||||||
|
sb.append(ch).append(" ");
|
||||||
|
}
|
||||||
|
sb.append("\n");
|
||||||
|
}
|
||||||
|
sb.append("Current player: ").append(getCurrentPlayer()).append("\n");
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getSize() {
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
}
|
||||||
31
javaAPI/fr/iut_fbleau/HexGame/HexPly.java
Normal file
31
javaAPI/fr/iut_fbleau/HexGame/HexPly.java
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
package fr.iut_fbleau.HexGame;
|
||||||
|
|
||||||
|
import fr.iut_fbleau.GameAPI.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Représente un coup dans le jeu de Hex.
|
||||||
|
*/
|
||||||
|
public class HexPly extends AbstractPly {
|
||||||
|
|
||||||
|
private final int row;
|
||||||
|
private final int col;
|
||||||
|
|
||||||
|
public HexPly(Player j, int row, int col) {
|
||||||
|
super(j);
|
||||||
|
this.row = row;
|
||||||
|
this.col = col;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getRow() {
|
||||||
|
return this.row;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getCol() {
|
||||||
|
return this.col;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "HexPly{player=" + getPlayer() + ", row=" + row + ", col=" + col + "}";
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user