legitbugfix #19
BIN
build/fr/iut_fbleau/HexGame/Arena.class
Normal file
BIN
build/fr/iut_fbleau/HexGame/Arena.class
Normal file
Binary file not shown.
BIN
build/fr/iut_fbleau/HexGame/ArenaMain.class
Normal file
BIN
build/fr/iut_fbleau/HexGame/ArenaMain.class
Normal file
Binary file not shown.
Binary file not shown.
62
javaAPI/fr/iut_fbleau/HexGame/Arena.java
Normal file
62
javaAPI/fr/iut_fbleau/HexGame/Arena.java
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
package fr.iut_fbleau.HexGame;
|
||||||
|
|
||||||
|
import fr.iut_fbleau.GameAPI.*;
|
||||||
|
|
||||||
|
import java.io.FileWriter;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.EnumMap;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class Arena {
|
||||||
|
|
||||||
|
private List<AbstractGamePlayer> bots = new ArrayList<>();
|
||||||
|
private FileWriter csvWriter;
|
||||||
|
|
||||||
|
public Arena() {
|
||||||
|
try {
|
||||||
|
csvWriter = new FileWriter("arena_results.csv");
|
||||||
|
csvWriter.append("Bot 1, Bot 2, Winner\n");
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addBot(AbstractGamePlayer bot) {
|
||||||
|
bots.add(bot);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void run() {
|
||||||
|
for (int i = 0; i < bots.size(); i++) {
|
||||||
|
for (int j = i + 1; j < bots.size(); j++) {
|
||||||
|
AbstractGamePlayer bot1 = bots.get(i);
|
||||||
|
AbstractGamePlayer bot2 = bots.get(j);
|
||||||
|
|
||||||
|
System.out.println("Running match: " + bot1.getClass().getSimpleName() + " vs " + bot2.getClass().getSimpleName());
|
||||||
|
Result result = playMatch(bot1, bot2);
|
||||||
|
|
||||||
|
try {
|
||||||
|
csvWriter.append(bot1.getClass().getSimpleName() + "," + bot2.getClass().getSimpleName() + "," + result + "\n");
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
csvWriter.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Result playMatch(AbstractGamePlayer bot1, AbstractGamePlayer bot2) {
|
||||||
|
IBoard board = new HexBoard(11); // Standard 11x11 Hex board
|
||||||
|
EnumMap<Player, AbstractGamePlayer> players = new EnumMap<>(Player.class);
|
||||||
|
players.put(Player.PLAYER1, bot1);
|
||||||
|
players.put(Player.PLAYER2, bot2);
|
||||||
|
|
||||||
|
Simulation simulation = new Simulation(board, players); // Ensure Simulation is correctly imported
|
||||||
|
return simulation.run();
|
||||||
|
}
|
||||||
|
}
|
||||||
15
javaAPI/fr/iut_fbleau/HexGame/ArenaMain.java
Normal file
15
javaAPI/fr/iut_fbleau/HexGame/ArenaMain.java
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
package fr.iut_fbleau.HexGame;
|
||||||
|
|
||||||
|
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
|
||||||
|
arena.addBot(new MiniMaxBot(Player.PLAYER2));
|
||||||
|
arena.addBot(new HeuristicBot(Player.PLAYER1));
|
||||||
|
arena.addBot(new MonteCarloBot(Player.PLAYER2)); // Correct constructor usage
|
||||||
|
|
||||||
|
arena.run();
|
||||||
|
}
|
||||||
|
}
|
||||||
48
javaAPI/fr/iut_fbleau/HexGame/HeuristicBot.java
Normal file
48
javaAPI/fr/iut_fbleau/HexGame/HeuristicBot.java
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
package fr.iut_fbleau.HexGame;
|
||||||
|
|
||||||
|
import fr.iut_fbleau.GameAPI.*;
|
||||||
|
|
||||||
|
public class HeuristicBot extends AbstractGamePlayer {
|
||||||
|
|
||||||
|
public HeuristicBot(Player me) {
|
||||||
|
super(me); // Correct constructor usage
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AbstractPly giveYourMove(IBoard board) {
|
||||||
|
HexBoard hb = (HexBoard) board;
|
||||||
|
float bestScore = -Float.MAX_VALUE;
|
||||||
|
HexPly bestMove = null;
|
||||||
|
|
||||||
|
for (int i = 0; i < hb.getSize(); i++) {
|
||||||
|
for (int j = 0; j < hb.getSize(); j++) {
|
||||||
|
HexPly move = new HexPly(hb.getCurrentPlayer(), i, j);
|
||||||
|
if (hb.isLegal(move)) {
|
||||||
|
hb.doPly(move);
|
||||||
|
float score = evaluateBoard(hb);
|
||||||
|
if (score > bestScore) {
|
||||||
|
bestScore = score;
|
||||||
|
bestMove = move;
|
||||||
|
}
|
||||||
|
hb.undoPly();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return bestMove;
|
||||||
|
}
|
||||||
|
|
||||||
|
private float evaluateBoard(HexBoard board) {
|
||||||
|
int size = board.getSize();
|
||||||
|
int center = size / 2;
|
||||||
|
float score = 0;
|
||||||
|
|
||||||
|
for (int i = 0; i < size; i++) {
|
||||||
|
for (int j = 0; j < size; j++) {
|
||||||
|
if (board.getPlayerAt(i, j) == Player.PLAYER1) {
|
||||||
|
score += Math.abs(i - center) + Math.abs(j - center); // Distance from center
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return score;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -15,6 +15,19 @@ import java.util.Random;
|
|||||||
* java fr.iut_fbleau.HexGame.HexSimMain
|
* java fr.iut_fbleau.HexGame.HexSimMain
|
||||||
* java fr.iut_fbleau.HexGame.HexSimMain --games 10000 --size 7 --seed 123
|
* java fr.iut_fbleau.HexGame.HexSimMain --games 10000 --size 7 --seed 123
|
||||||
* java fr.iut_fbleau.HexGame.HexSimMain --games 5000 --size 11 --csv results.csv
|
* java fr.iut_fbleau.HexGame.HexSimMain --games 5000 --size 11 --csv results.csv
|
||||||
|
*
|
||||||
|
* À seed identique, la suite de nombres
|
||||||
|
* pseudo-aléatoires générée est identique, donc les bots "aléatoires" joueront les mêmes coups
|
||||||
|
* dans le même ordre (tant que le code et l'ordre des appels à Random ne changent pas).</p>
|
||||||
|
*
|
||||||
|
* Intérêt :
|
||||||
|
*
|
||||||
|
* Reproductibilité</b> : relancer exactement la même simulation pour déboguer / analyser.</li>
|
||||||
|
* Comparaison équitable</b> : comparer 2 bots sur les mêmes tirages aléatoires.</li>
|
||||||
|
* Si aucun seed n'est fourni, on utilise généralement l'heure courante, ce qui rend chaque exécution différente.</p>
|
||||||
|
*
|
||||||
|
* long seed;
|
||||||
|
*
|
||||||
*/
|
*/
|
||||||
public class HexSimMain {
|
public class HexSimMain {
|
||||||
|
|
||||||
@@ -170,7 +183,7 @@ public class HexSimMain {
|
|||||||
// ex: "7 10000"
|
// ex: "7 10000"
|
||||||
if (isInt(s)) {
|
if (isInt(s)) {
|
||||||
int v = Integer.parseInt(s);
|
int v = Integer.parseInt(s);
|
||||||
if (a.size == 7) a.size = v;
|
if (a.size == 11) a.size = v;
|
||||||
else a.games = v;
|
else a.games = v;
|
||||||
} else {
|
} else {
|
||||||
System.err.println("Unknown arg: " + s);
|
System.err.println("Unknown arg: " + s);
|
||||||
|
|||||||
89
javaAPI/fr/iut_fbleau/HexGame/MiniMaxBot.java
Normal file
89
javaAPI/fr/iut_fbleau/HexGame/MiniMaxBot.java
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
package fr.iut_fbleau.HexGame;
|
||||||
|
|
||||||
|
import fr.iut_fbleau.GameAPI.*;
|
||||||
|
|
||||||
|
public class MiniMaxBot extends AbstractGamePlayer {
|
||||||
|
|
||||||
|
private int MAXDEPTH = 5;
|
||||||
|
|
||||||
|
public MiniMaxBot(Player me) {
|
||||||
|
super(me); // Correct constructor usage
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AbstractPly giveYourMove(IBoard board) {
|
||||||
|
HexBoard hb = (HexBoard) board;
|
||||||
|
float bestScore = -Float.MAX_VALUE;
|
||||||
|
HexPly bestMove = null;
|
||||||
|
|
||||||
|
for (int i = 0; i < hb.getSize(); i++) {
|
||||||
|
for (int j = 0; j < hb.getSize(); j++) {
|
||||||
|
HexPly move = new HexPly(hb.getCurrentPlayer(), i, j);
|
||||||
|
if (hb.isLegal(move)) {
|
||||||
|
hb.doPly(move);
|
||||||
|
float score = minimax(hb, MAXDEPTH, -Float.MAX_VALUE, Float.MAX_VALUE, true);
|
||||||
|
if (score > bestScore) {
|
||||||
|
bestScore = score;
|
||||||
|
bestMove = move;
|
||||||
|
}
|
||||||
|
hb.undoPly();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return bestMove;
|
||||||
|
}
|
||||||
|
|
||||||
|
private float minimax(HexBoard board, int depth, float alpha, float beta, boolean isMaximizing) {
|
||||||
|
if (depth == 0 || board.isGameOver()) {
|
||||||
|
return evaluateBoard(board);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isMaximizing) {
|
||||||
|
float bestScore = -Float.MAX_VALUE;
|
||||||
|
for (int i = 0; i < board.getSize(); i++) {
|
||||||
|
for (int j = 0; j < board.getSize(); j++) {
|
||||||
|
HexPly move = new HexPly(board.getCurrentPlayer(), i, j);
|
||||||
|
if (board.isLegal(move)) {
|
||||||
|
board.doPly(move);
|
||||||
|
float score = minimax(board, depth - 1, alpha, beta, false);
|
||||||
|
bestScore = Math.max(bestScore, score);
|
||||||
|
alpha = Math.max(alpha, bestScore);
|
||||||
|
if (beta <= alpha) break; // Pruning
|
||||||
|
board.undoPly();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return bestScore;
|
||||||
|
} else {
|
||||||
|
float bestScore = Float.MAX_VALUE;
|
||||||
|
for (int i = 0; i < board.getSize(); i++) {
|
||||||
|
for (int j = 0; j < board.getSize(); j++) {
|
||||||
|
HexPly move = new HexPly(board.getCurrentPlayer(), i, j);
|
||||||
|
if (board.isLegal(move)) {
|
||||||
|
board.doPly(move);
|
||||||
|
float score = minimax(board, depth - 1, alpha, beta, true);
|
||||||
|
bestScore = Math.min(bestScore, score);
|
||||||
|
beta = Math.min(beta, bestScore);
|
||||||
|
if (beta <= alpha) break; // Pruning
|
||||||
|
board.undoPly();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return bestScore;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private float evaluateBoard(HexBoard board) {
|
||||||
|
int size = board.getSize();
|
||||||
|
int center = size / 2;
|
||||||
|
int score = 0;
|
||||||
|
for (int i = 0; i < size; i++) {
|
||||||
|
for (int j = 0; j < size; j++) {
|
||||||
|
if (board.getPlayerAt(i, j) == Player.PLAYER1) {
|
||||||
|
score += Math.abs(i - center) + Math.abs(j - center); // Distance from center
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return score;
|
||||||
|
}
|
||||||
|
}
|
||||||
59
javaAPI/fr/iut_fbleau/HexGame/MonteCarloBot.java
Normal file
59
javaAPI/fr/iut_fbleau/HexGame/MonteCarloBot.java
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
package fr.iut_fbleau.HexGame;
|
||||||
|
|
||||||
|
import fr.iut_fbleau.GameAPI.*;
|
||||||
|
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
|
public class MonteCarloBot extends AbstractGamePlayer {
|
||||||
|
|
||||||
|
private static final int SIMULATION_COUNT = 1000;
|
||||||
|
|
||||||
|
public MonteCarloBot(Player me) {
|
||||||
|
super(me); // Correct constructor usage
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AbstractPly giveYourMove(IBoard board) {
|
||||||
|
HexBoard hb = (HexBoard) board;
|
||||||
|
float bestScore = -Float.MAX_VALUE;
|
||||||
|
HexPly bestMove = null;
|
||||||
|
|
||||||
|
for (int i = 0; i < hb.getSize(); i++) {
|
||||||
|
for (int j = 0; j < hb.getSize(); j++) {
|
||||||
|
HexPly move = new HexPly(hb.getCurrentPlayer(), i, j);
|
||||||
|
if (hb.isLegal(move)) {
|
||||||
|
hb.doPly(move);
|
||||||
|
float score = monteCarloSimulation(hb);
|
||||||
|
if (score > bestScore) {
|
||||||
|
bestScore = score;
|
||||||
|
bestMove = move;
|
||||||
|
}
|
||||||
|
hb.undoPly();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return bestMove;
|
||||||
|
}
|
||||||
|
|
||||||
|
private float monteCarloSimulation(HexBoard board) {
|
||||||
|
RandomBot simBot = new RandomBot(Player.PLAYER1, new Random().nextLong());
|
||||||
|
HexBoard simBoard = board.safeCopy();
|
||||||
|
int wins = 0;
|
||||||
|
int simulations = 0;
|
||||||
|
|
||||||
|
for (int i = 0; i < SIMULATION_COUNT; i++) {
|
||||||
|
while (!simBoard.isGameOver()) {
|
||||||
|
AbstractPly move = simBot.giveYourMove(simBoard);
|
||||||
|
simBoard.doPly(move);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (simBoard.getResult() == Result.WIN) {
|
||||||
|
wins++;
|
||||||
|
}
|
||||||
|
simulations++;
|
||||||
|
simBoard = board.safeCopy(); // Reset the board for the next simulation
|
||||||
|
}
|
||||||
|
|
||||||
|
return (float) wins / simulations;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -10,9 +10,6 @@ import java.util.Iterator;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
|
|
||||||
/**
|
|
||||||
* Bot non intelligent : joue un coup légal au hasard.
|
|
||||||
*/
|
|
||||||
public class RandomBot extends AbstractGamePlayer {
|
public class RandomBot extends AbstractGamePlayer {
|
||||||
|
|
||||||
private final Random rng;
|
private final Random rng;
|
||||||
@@ -28,7 +25,6 @@ public class RandomBot extends AbstractGamePlayer {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public AbstractPly giveYourMove(IBoard board) {
|
public AbstractPly giveYourMove(IBoard board) {
|
||||||
// On récupère tous les coups légaux via l'itérateur fourni par le plateau.
|
|
||||||
List<AbstractPly> legal = new ArrayList<>();
|
List<AbstractPly> legal = new ArrayList<>();
|
||||||
Iterator<AbstractPly> it = board.iterator();
|
Iterator<AbstractPly> it = board.iterator();
|
||||||
while (it.hasNext()) {
|
while (it.hasNext()) {
|
||||||
|
|||||||
273
javaAPI/fr/iut_fbleau/HexGame/Simulation.java
Normal file
273
javaAPI/fr/iut_fbleau/HexGame/Simulation.java
Normal file
@@ -0,0 +1,273 @@
|
|||||||
|
package fr.iut_fbleau.HexGame;
|
||||||
|
|
||||||
|
import fr.iut_fbleau.GameAPI.*;
|
||||||
|
import java.util.EnumMap;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
|
||||||
|
|
||||||
|
public class Simulation extends AbstractGame {
|
||||||
|
|
||||||
|
//ATTRIBUTS
|
||||||
|
private HexPly bestmove;
|
||||||
|
private float bestoutcome;
|
||||||
|
private int MAXDEPTH = 9;
|
||||||
|
private int EVALDEPTH = 10;
|
||||||
|
private LinkedList<Integer[]> taken = new LinkedList<Integer[]>();
|
||||||
|
|
||||||
|
//ATTRIBUTS QUE JE NE VOUDRAIS PAS CRÉER IDÉALEMENT
|
||||||
|
private IBoard simCurrentBoard;
|
||||||
|
private EnumMap<Player, AbstractGamePlayer> simmapPlayers;
|
||||||
|
|
||||||
|
//CONSTRUCTEUR
|
||||||
|
public Simulation(IBoard b, EnumMap<Player,AbstractGamePlayer> m){
|
||||||
|
super(b, m);
|
||||||
|
simCurrentBoard = b;
|
||||||
|
simmapPlayers = m;
|
||||||
|
}
|
||||||
|
|
||||||
|
//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();
|
||||||
|
LinkedList<Integer[]> ctaken = taken;
|
||||||
|
HexPly testmove;
|
||||||
|
float wins = 0;
|
||||||
|
float losses = 0;
|
||||||
|
|
||||||
|
for(int i=0; i<EVALDEPTH; i++){
|
||||||
|
while(!simpos.isGameOver()){
|
||||||
|
testmove = (HexPly) simplay.giveYourMove(simpos);
|
||||||
|
if(!ctaken.contains(t) && simpos.isLegal(testmove)){
|
||||||
|
ctaken.add(new Integer[]{testmove.getRow(), testmove.getCol()});
|
||||||
|
simpos.doPly(testmove);
|
||||||
|
if(simpos.getResult()==Result.LOSS){
|
||||||
|
losses++;
|
||||||
|
} else if(simpos.getResult()==Result.WIN){
|
||||||
|
wins++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
simpos = position.safeCopy();
|
||||||
|
ctaken = taken;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(wins>=losses){
|
||||||
|
return losses/wins;
|
||||||
|
} else {
|
||||||
|
return -(wins/losses);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private float explMAX(HexBoard position, int depth){
|
||||||
|
if (position.getResult()==Result.LOSS) {
|
||||||
|
return -1.0f;
|
||||||
|
} else if (position.getResult()==Result.WIN){
|
||||||
|
return 1.0f;
|
||||||
|
} else if (depth==MAXDEPTH) {
|
||||||
|
return MonteCarlo(position);
|
||||||
|
} else {
|
||||||
|
float bestcase = -1.0f;
|
||||||
|
HexPly bestcasemove;
|
||||||
|
HexPly testmove;
|
||||||
|
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)){
|
||||||
|
//System.out.println(" MAX test move : "+Integer.toString(i)+","+Integer.toString(j));
|
||||||
|
taken.add(t);
|
||||||
|
position.doPly(testmove);
|
||||||
|
float val = explMIN(position, depth+1);
|
||||||
|
if (val >= bestcase) {
|
||||||
|
//System.out.println(" MAX new best case");
|
||||||
|
bestcase = val;
|
||||||
|
bestcasemove = testmove;
|
||||||
|
if (depth==0) {
|
||||||
|
this.bestoutcome = bestcase;
|
||||||
|
this.bestmove = bestcasemove;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
position.undoPly();
|
||||||
|
taken.remove(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return bestcase;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private float explMIN(HexBoard position, int depth){
|
||||||
|
if (position.getResult()==Result.LOSS) {
|
||||||
|
return -1.0f;
|
||||||
|
} else if (position.getResult()==Result.WIN){
|
||||||
|
return 1.0f;
|
||||||
|
} else if (depth==MAXDEPTH) {
|
||||||
|
return MonteCarlo(position);
|
||||||
|
} else {
|
||||||
|
float bestcase = 1.0f;
|
||||||
|
HexPly bestcasemove;
|
||||||
|
HexPly testmove;
|
||||||
|
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)){
|
||||||
|
//System.out.println(" MIN test move : "+Integer.toString(i)+","+Integer.toString(j));
|
||||||
|
taken.add(t);
|
||||||
|
position.doPly(testmove);
|
||||||
|
float val = explMAX(position, depth+1);
|
||||||
|
if (val <= bestcase) {
|
||||||
|
//System.out.println(" MIN new best case");
|
||||||
|
bestcase = val;
|
||||||
|
bestcasemove = testmove;
|
||||||
|
if (depth==0) {
|
||||||
|
this.bestoutcome = bestcase;
|
||||||
|
this.bestmove = bestcasemove;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
position.undoPly();
|
||||||
|
taken.remove(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return bestcase;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private float explMAXAB(HexBoard position, int depth, float A, float B){
|
||||||
|
if (position.getResult() == Result.LOSS) {
|
||||||
|
return -1.0f;
|
||||||
|
} else if (position.getResult() == Result.WIN) {
|
||||||
|
return 1.0f;
|
||||||
|
} else if (depth == MAXDEPTH) {
|
||||||
|
return MonteCarlo(position);
|
||||||
|
} 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) {
|
||||||
|
//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)) {
|
||||||
|
//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);
|
||||||
|
if (val >= bestcase) {
|
||||||
|
//System.out.println(" MAX new best case");
|
||||||
|
bestcase = val;
|
||||||
|
bestcasemove = testmove;
|
||||||
|
if (depth == 0) {
|
||||||
|
this.bestoutcome = bestcase;
|
||||||
|
this.bestmove = bestcasemove;
|
||||||
|
}
|
||||||
|
if (bestcase >= B) {
|
||||||
|
return bestcase;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
position.undoPly();
|
||||||
|
taken.remove(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return bestcase;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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) {
|
||||||
|
return 1.0f;
|
||||||
|
} else if (depth == MAXDEPTH) {
|
||||||
|
return MonteCarlo(position);
|
||||||
|
} 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) {
|
||||||
|
//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)) {
|
||||||
|
//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);
|
||||||
|
if (val <= bestcase) {
|
||||||
|
//System.out.println(" MIN new best case");
|
||||||
|
bestcase = val;
|
||||||
|
bestcasemove = testmove;
|
||||||
|
if (depth == 0) {
|
||||||
|
this.bestoutcome = bestcase;
|
||||||
|
this.bestmove = bestcasemove;
|
||||||
|
}
|
||||||
|
if (bestcase <= A) {
|
||||||
|
return bestcase;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
position.undoPly();
|
||||||
|
taken.remove(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return bestcase;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private AbstractPly GiveBestMove(IBoard board) {
|
||||||
|
if (!(board instanceof HexBoard)) {
|
||||||
|
throw new IllegalArgumentException("Ce joueur attend un HexBoard.");
|
||||||
|
}
|
||||||
|
HexBoard hb = (HexBoard) board;
|
||||||
|
float bestcase;
|
||||||
|
if(hb.getCurrentPlayer()==Player.PLAYER1){
|
||||||
|
bestcase = explMAXAB(hb, 0, -1.0f, 1.0f);
|
||||||
|
} else {
|
||||||
|
bestcase = explMINAB(hb, 0, -1.0f, 1.0f);
|
||||||
|
}
|
||||||
|
return this.bestmove;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Result run(){
|
||||||
|
while(!simCurrentBoard.isGameOver()) {
|
||||||
|
AbstractGamePlayer player = simmapPlayers.get(simCurrentBoard.getCurrentPlayer());
|
||||||
|
IBoard board = simCurrentBoard.safeCopy();
|
||||||
|
AbstractPly ply = GiveBestMove(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();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user