5 Commits

Author SHA1 Message Date
vaisse
fe13b946b1 truc fonctionnel mais avec un retouchage dans l'API. dsl 2026-02-06 12:12:46 +01:00
vaisse
c278b18872 definable size for arena 2026-02-06 11:25:47 +01:00
vaisse
e0a2c2642a c'est 'bon' 2026-02-06 11:13:37 +01:00
vaisse
c9e559fe12 cette fois-ci ce sera la bonne 2026-02-06 11:01:27 +01:00
vaisse
98c6b4678e par pitié 2026-02-06 11:00:03 +01:00
22 changed files with 170 additions and 108 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1 @@
,vaisse,salle235-12,06.02.2026 11:29,file:///export/home/an23/vaisse/.config/libreoffice/4;

View File

@@ -0,0 +1,7 @@
Bot 1, Bot 2, Winner
RandomBot,MiniMaxBot,WIN
RandomBot,HeuristicBot,WIN
RandomBot,MonteCarloBot,WIN
MiniMaxBot,HeuristicBot,WIN
MiniMaxBot,MonteCarloBot,WIN
HeuristicBot,MonteCarloBot,WIN
1 Bot 1 Bot 2 Winner
2 RandomBot MiniMaxBot WIN
3 RandomBot HeuristicBot WIN
4 RandomBot MonteCarloBot WIN
5 MiniMaxBot HeuristicBot WIN
6 MiniMaxBot MonteCarloBot WIN
7 HeuristicBot MonteCarloBot WIN

View File

@@ -26,5 +26,6 @@ public abstract class AbstractGamePlayer {
* @throws IllegalStateException if the Situation is already in the bookmarks
*/
public abstract AbstractPly giveYourMove(IBoard p);
public abstract Boolean jesuisMinimax();
}

View File

@@ -12,11 +12,13 @@ public class Arena {
private List<AbstractGamePlayer> bots = new ArrayList<>();
private FileWriter csvWriter;
private int board_size;
public Arena() {
public Arena(int size) {
try {
csvWriter = new FileWriter("arena_results.csv");
csvWriter.append("Bot 1, Bot 2, Winner\n");
this.board_size = size;
} catch (IOException e) {
e.printStackTrace();
}
@@ -51,12 +53,12 @@ public class Arena {
}
private Result playMatch(AbstractGamePlayer bot1, AbstractGamePlayer bot2) {
IBoard board = new HexBoard(11);
IBoard board = new HexBoard(this.board_size);
EnumMap<Player, AbstractGamePlayer> players = new EnumMap<>(Player.class);
players.put(Player.PLAYER1, bot1);
players.put(Player.PLAYER2, bot2);
Simulation simulation = new Simulation(board, players);
return simulation.run();
return simulation.runForArena();
}
}

View File

@@ -4,8 +4,12 @@ import fr.iut_fbleau.GameAPI.Player;
public class ArenaMain {
public static void main(String[] args) {
Arena arena = new Arena();
arena.addBot(new RandomBot(Player.PLAYER1, 12345L)); // Correct constructor usage
int size = 7;
if (args.length >= 1) {
try { size = Integer.parseInt(args[0]); } catch (NumberFormatException ignored) {}
}
Arena arena = new Arena(size);
arena.addBot(new RandomBot(Player.PLAYER1, 24015L)); // Correct constructor usage
arena.addBot(new MiniMaxBot(Player.PLAYER2));
arena.addBot(new HeuristicBot(Player.PLAYER1));
arena.addBot(new MonteCarloBot(Player.PLAYER2)); // Correct constructor usage

View File

@@ -8,6 +8,10 @@ public class HeuristicBot extends AbstractGamePlayer {
super(me); // Correct constructor usage
}
public Boolean jesuisMinimax(){
return false;
}
@Override
public AbstractPly giveYourMove(IBoard board) {
HexBoard hb = (HexBoard) board;
@@ -35,10 +39,11 @@ public class HeuristicBot extends AbstractGamePlayer {
int size = board.getSize();
int center = size / 2;
float score = 0;
//HexBoard simBoard = (HexBoard) board.safeCopy();
for (int i = 0; i < size; i++) {
for (int j = 0; j < size; j++) {
if (board.getPlayerAt(i, j) == Player.PLAYER1) {
if (board.getCellPlayer(i, j) == Player.PLAYER1) {
score += Math.abs(i - center) + Math.abs(j - center); // Distance from center
}
}

View File

@@ -1,7 +1,6 @@
package fr.iut_fbleau.HexGame;
import fr.iut_fbleau.GameAPI.*;
import java.util.EnumMap;
import java.util.Scanner;
@@ -11,7 +10,7 @@ import java.util.Scanner;
public class HexMain {
public static void main(String[] args) {
int size = 11;
int size = 7;
if (args.length >= 1) {
try { size = Integer.parseInt(args[0]); } catch (NumberFormatException ignored) {}
}
@@ -19,12 +18,19 @@ public class HexMain {
HexBoard board = new HexBoard(size);
Scanner sc = new Scanner(System.in);
Result res;
EnumMap<Player, AbstractGamePlayer> players = new EnumMap<>(Player.class);
players.put(Player.PLAYER1, new HumanConsolePlayer(Player.PLAYER1, sc));
players.put(Player.PLAYER2, new HumanConsolePlayer(Player.PLAYER2, sc));
if (args.length>=2 && args[1].equals("autoplay")) {
Simulation sim = new Simulation(board, players);
res = sim.run();
} else {
AbstractGame game = new AbstractGame(board, players) {};
Result res = game.run();
res = game.run();
}
System.out.println(board);
System.out.println("Résultat (du point de vue de PLAYER1) : " + res);

View File

@@ -18,6 +18,10 @@ public class HumanConsolePlayer extends AbstractGamePlayer {
this.in = in;
}
public Boolean jesuisMinimax(){
return false;
}
@Override
public AbstractPly giveYourMove(IBoard board) {
if (!(board instanceof HexBoard)) {

View File

@@ -10,6 +10,10 @@ public class MiniMaxBot extends AbstractGamePlayer {
super(me); // Correct constructor usage
}
public Boolean jesuisMinimax(){
return true;
}
@Override
public AbstractPly giveYourMove(IBoard board) {
HexBoard hb = (HexBoard) board;
@@ -79,7 +83,7 @@ public class MiniMaxBot extends AbstractGamePlayer {
int score = 0;
for (int i = 0; i < size; i++) {
for (int j = 0; j < size; j++) {
if (board.getPlayerAt(i, j) == Player.PLAYER1) {
if (board.getCellPlayer(i, j) == Player.PLAYER1) {
score += Math.abs(i - center) + Math.abs(j - center); // Distance from center
}
}

View File

@@ -12,6 +12,10 @@ public class MonteCarloBot extends AbstractGamePlayer {
super(me); // Correct constructor usage
}
public Boolean jesuisMinimax(){
return false;
}
@Override
public AbstractPly giveYourMove(IBoard board) {
HexBoard hb = (HexBoard) board;
@@ -37,7 +41,7 @@ public class MonteCarloBot extends AbstractGamePlayer {
private float monteCarloSimulation(HexBoard board) {
RandomBot simBot = new RandomBot(Player.PLAYER1, new Random().nextLong());
HexBoard simBoard = board.safeCopy();
HexBoard simBoard = (HexBoard) board.safeCopy();
int wins = 0;
int simulations = 0;
@@ -51,7 +55,7 @@ public class MonteCarloBot extends AbstractGamePlayer {
wins++;
}
simulations++;
simBoard = board.safeCopy(); // Reset the board for the next simulation
simBoard = (HexBoard) board.safeCopy(); // Reset the board for the next simulation
}
return (float) wins / simulations;

View File

@@ -19,6 +19,10 @@ public class RandomBot extends AbstractGamePlayer {
this.rng = rng;
}
public Boolean jesuisMinimax(){
return false;
}
public RandomBot(Player me, long seed) {
this(me, new Random(seed));
}

View File

@@ -3,6 +3,7 @@ package fr.iut_fbleau.HexGame;
import fr.iut_fbleau.GameAPI.*;
import java.util.EnumMap;
import java.util.LinkedList;
import java.util.Random;
public class Simulation extends AbstractGame {
@@ -27,18 +28,19 @@ public class Simulation extends AbstractGame {
//METHODES
/*Le jeu de Hex ne peut jamais finir avec le résultat null. En utilisant cette propriété, on peut avoir cet algorithme simplifié du monte-carlo*/
private float MonteCarlo(HexBoard position){
RandomBot simplay = new RandomBot();
HexBoard simpos = position.safeCopy();
private float MonteCarlo(HexBoard position, Player current){
RandomBot simplay = new RandomBot(current, new Random().nextLong());
HexBoard simpos = position;
LinkedList<Integer[]> ctaken = taken;
HexPly testmove;
float wins = 0;
float losses = 0;
int count = 0;
for(int i=0; i<EVALDEPTH; i++){
while(!simpos.isGameOver()){
count++;
testmove = (HexPly) simplay.giveYourMove(simpos);
if(!ctaken.contains(t) && simpos.isLegal(testmove)){
if(!ctaken.contains(new Integer[]{testmove.getRow(), testmove.getCol()}) && simpos.isLegal(testmove)){
ctaken.add(new Integer[]{testmove.getRow(), testmove.getCol()});
simpos.doPly(testmove);
if(simpos.getResult()==Result.LOSS){
@@ -48,16 +50,16 @@ public class Simulation extends AbstractGame {
}
}
}
simpos = position.safeCopy();
//System.out.println("count:"+count);
for (int j=0; j<count; j++) {
simpos.undoPly();
}
ctaken = taken;
count = 0;
}
if(wins>=losses){
return losses/wins;
} else {
return -(wins/losses);
}
//System.out.println(" wins : "+wins+"/losses : "+losses);
//System.out.println(" eval : "+(wins-losses)/EVALDEPTH);
return (wins-losses)/EVALDEPTH;
}
private float explMAX(HexBoard position, int depth){
@@ -66,7 +68,7 @@ public class Simulation extends AbstractGame {
} else if (position.getResult()==Result.WIN){
return 1.0f;
} else if (depth==MAXDEPTH) {
return MonteCarlo(position);
return MonteCarlo(position, Player.PLAYER1);
} else {
float bestcase = -1.0f;
HexPly bestcasemove;
@@ -108,7 +110,7 @@ public class Simulation extends AbstractGame {
} else if (position.getResult()==Result.WIN){
return 1.0f;
} else if (depth==MAXDEPTH) {
return MonteCarlo(position);
return MonteCarlo(position, Player.PLAYER2);
} else {
float bestcase = 1.0f;
HexPly bestcasemove;
@@ -145,37 +147,37 @@ public class Simulation extends AbstractGame {
}
private float explMAXAB(HexBoard position, int depth, float A, float B){
if (position.getResult() == Result.LOSS) {
if (position.getResult()==Result.LOSS) {
return -1.0f;
} else if (position.getResult() == Result.WIN) {
} else if (position.getResult()==Result.WIN){
return 1.0f;
} else if (depth == MAXDEPTH) {
return MonteCarlo(position);
} else if (depth==MAXDEPTH) {
return MonteCarlo(position, Player.PLAYER1);
} else {
float bestcase = A;
HexPly bestcasemove;
HexPly testmove;
for (int i = 0; i < position.getSize(); i++) {
for (int j = 0; j < position.getSize(); j++) {
if (depth == 0) {
for (int i=0; i<position.getSize(); i++) {
for (int j=0; j<position.getSize(); j++) {
if(depth==0){
//System.out.println("MAX New Line :");
}
Integer[] t = new Integer[]{i, j};
testmove = new HexPly(Player.PLAYER1, i, j);
if (!taken.contains(t) && position.isLegal(testmove)) {
if(!taken.contains(t) && position.isLegal(testmove)){
//System.out.println(" MAX test move : "+Integer.toString(i)+","+Integer.toString(j));
taken.add(t);
position.doPly(testmove);
float val = explMINAB(position, depth + 1, bestcase, B);
float val = explMINAB(position, depth+1, bestcase, B);
if (val >= bestcase) {
//System.out.println(" MAX new best case");
bestcase = val;
bestcasemove = testmove;
if (depth == 0) {
if (depth==0) {
this.bestoutcome = bestcase;
this.bestmove = bestcasemove;
}
if (bestcase >= B) {
if(bestcase>=B){
return bestcase;
}
}
@@ -187,40 +189,38 @@ public class Simulation extends AbstractGame {
return bestcase;
}
}
private float explMINAB(HexBoard position, int depth, float A, float B){
if (position.getResult() == Result.LOSS) {
private float explMINAB(HexBoard position, int depth, float A, float B){
if (position.getResult()==Result.LOSS) {
return -1.0f;
} else if (position.getResult() == Result.WIN) {
} else if (position.getResult()==Result.WIN){
return 1.0f;
} else if (depth == MAXDEPTH) {
return MonteCarlo(position);
} else if (depth==MAXDEPTH) {
return MonteCarlo(position, Player.PLAYER2);
} else {
float bestcase = B;
HexPly bestcasemove;
HexPly testmove;
for (int i = 0; i < position.getSize(); i++) {
for (int j = 0; j < position.getSize(); j++) {
if (depth == 0) {
for (int i=0; i<position.getSize(); i++) {
for (int j=0; j<position.getSize(); j++) {
if(depth==0){
//System.out.println("MIN New Line :");
}
Integer[] t = new Integer[]{i, j};
testmove = new HexPly(Player.PLAYER2, i, j);
if (!taken.contains(t) && position.isLegal(testmove)) {
if(!taken.contains(t) && position.isLegal(testmove)){
//System.out.println(" MIN test move : "+Integer.toString(i)+","+Integer.toString(j));
taken.add(t);
position.doPly(testmove);
float val = explMAXAB(position, depth + 1, A, bestcase);
float val = explMAXAB(position, depth+1, A, bestcase);
if (val <= bestcase) {
//System.out.println(" MIN new best case");
bestcase = val;
bestcasemove = testmove;
if (depth == 0) {
if (depth==0) {
this.bestoutcome = bestcase;
this.bestmove = bestcasemove;
}
if (bestcase <= A) {
if(bestcase<=A){
return bestcase;
}
}
@@ -232,9 +232,7 @@ private float explMINAB(HexBoard position, int depth, float A, float B){
}
return bestcase;
}
}
}
private AbstractPly GiveBestMove(IBoard board) {
@@ -269,5 +267,27 @@ private float explMINAB(HexBoard position, int depth, float A, float B){
return simCurrentBoard.getResult();
}
public Result runForArena(){
while(!simCurrentBoard.isGameOver()){
AbstractGamePlayer player = simmapPlayers.get(simCurrentBoard.getCurrentPlayer());
IBoard board = simCurrentBoard.safeCopy();
AbstractPly ply;
if(player.jesuisMinimax()){
ply = GiveBestMove(board);
} else {
ply = player.giveYourMove(board);
}
HexPly concretePly = (HexPly) ply;
if (simCurrentBoard.isLegal(ply)) {
simCurrentBoard.doPly(ply);
taken.add(new Integer[]{concretePly.getRow(), concretePly.getCol()});
System.out.println("Player "+player+" goes ("+concretePly.getRow()+","+concretePly.getCol()+")");
}
else throw new IllegalStateException("Player "+ player + " is a bloody cheat. He tried playing : "+concretePly.getRow()+","+concretePly.getCol()+" I give up.");
}
return simCurrentBoard.getResult();
}
}