fixed many bugs + implemented negamax(not tested)
This commit is contained in:
parent
ca65348b1f
commit
a81709ef84
1
.gitignore
vendored
1
.gitignore
vendored
@ -5,3 +5,4 @@
|
|||||||
.settings
|
.settings
|
||||||
.idea
|
.idea
|
||||||
*.iml
|
*.iml
|
||||||
|
out/
|
@ -1,7 +1,5 @@
|
|||||||
package othello;
|
package othello;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
|
|
||||||
import othello.players.Player;
|
import othello.players.Player;
|
||||||
import othello.players.RandomPlayer;
|
import othello.players.RandomPlayer;
|
||||||
|
|
||||||
@ -9,19 +7,21 @@ public class Main {
|
|||||||
|
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
Player p1 = new RandomPlayer();
|
Player p1 = new RandomPlayer(1);
|
||||||
Player p2 = new RandomPlayer();
|
Player p2 = new RandomPlayer(-1);
|
||||||
Player[][] board = initialize(p1, p2);
|
Player[][] board = initialize(p1, p2);
|
||||||
State game = new State(board, p1, p2);
|
State game = new State(board, p1, p2);
|
||||||
System.out.println("joueur 1: " + p1);
|
System.out.println("joueur 1: " + p1);
|
||||||
System.out.println("joueur 2: " + p2);
|
System.out.println("joueur 2: " + p2);
|
||||||
while(!game.isOver()) {
|
while(!game.isOver()) {
|
||||||
Player player = game.getCurrentPlayer();
|
Player player = game.getCurrentPlayer();
|
||||||
ArrayList<Pair<Point, Point>> moves = game.getMove(player);
|
|
||||||
System.out.println(game.toString());
|
System.out.println(game.toString());
|
||||||
game = game.play(player.play(moves, game, player));
|
game = game.play(player.play(game));
|
||||||
}
|
}
|
||||||
System.out.println("C'est " + game.getWinner() + " qui a gagné");
|
System.out.println(game.toString());
|
||||||
|
System.out.println(game.getWinner() + " a gagné la partie");
|
||||||
|
System.out.println(game.getScore(p1));
|
||||||
|
System.out.println(game.getScore(p2));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Player[][] initialize(Player p1, Player p2){
|
public static Player[][] initialize(Player p1, Player p2){
|
||||||
|
@ -2,16 +2,17 @@ package othello;
|
|||||||
|
|
||||||
public class Point {
|
public class Point {
|
||||||
|
|
||||||
public int x;
|
private int x;
|
||||||
public int y;
|
private int y;
|
||||||
|
|
||||||
public Point(int x, int y) {
|
public Point(int y, int x) {
|
||||||
this.x = x;
|
this.x = x;
|
||||||
this.y = y;
|
this.y = y;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isJump(Point other) {
|
public boolean isJump(Point other) {
|
||||||
return Math.pow(other.x - this.x, 2) + Math.pow(other.y - this.y, 2) == 4;
|
double value = Math.pow(other.x - this.x, 2) + Math.pow(other.y - this.y, 2);
|
||||||
|
return value == 4 || value == 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getX(){
|
public int getX(){
|
||||||
@ -24,7 +25,7 @@ public class Point {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString () {
|
public String toString () {
|
||||||
return "(" + x + ", " + y + ")";
|
return "(" + y + ", " + x + ")";
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,40 +1,45 @@
|
|||||||
package othello;
|
package othello;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
|
|
||||||
import othello.players.Player;
|
import othello.players.Player;
|
||||||
|
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
public class State {
|
public class State {
|
||||||
|
|
||||||
private Player[][] board;
|
public static List<State> previousSituations = new LinkedList<>();
|
||||||
private Player player1;
|
|
||||||
private Player player2;
|
private final Player[][] board;
|
||||||
|
private final Player player1;
|
||||||
|
private final Player player2;
|
||||||
private Player currentPlayer;
|
private Player currentPlayer;
|
||||||
private int n1;
|
private int n1;
|
||||||
private int n2;
|
private int n2;
|
||||||
|
|
||||||
public State(Player[][] board, Player p1, Player p2, int n1, int n2) {
|
public State(Player[][] board, Player p1, Player p2) {
|
||||||
this.board = board;
|
this.board = board;
|
||||||
this.player1 = p1;
|
this.player1 = p1;
|
||||||
this.player2 = p2;
|
this.player2 = p2;
|
||||||
currentPlayer = p1;
|
currentPlayer = p1;
|
||||||
this.n1 = n1;
|
this.n1 = 2;
|
||||||
this.n2 = n2;
|
this.n2 = 2;
|
||||||
}
|
|
||||||
|
|
||||||
public State(Player[][] board, Player p1, Player p2) {
|
|
||||||
this(board, p1, p2, 2, 2);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isOver() {
|
public boolean isOver() {
|
||||||
if(n1 == 0 || n2 == 0)
|
return n1 == 0 || n2 == 0 || (getMove(player1).isEmpty() && getMove(player2).isEmpty());
|
||||||
return true;
|
|
||||||
return getMove(player1).isEmpty() && getMove(player2).isEmpty();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public ArrayList<Pair<Point, Point>> getMove(Player player) {
|
public Player getPlayerById(int id) {
|
||||||
|
if(id == 1)
|
||||||
|
return player1;
|
||||||
|
else if(id == -1)
|
||||||
|
return player2;
|
||||||
|
throw new IllegalArgumentException("Invalid player id: " + id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public LinkedList<Pair<Point, Point>> getMove(Player player) {
|
||||||
// Pair<Depart, Arrivee>
|
// Pair<Depart, Arrivee>
|
||||||
ArrayList<Pair<Point, Point>> moves = new ArrayList<>();
|
LinkedList<Pair<Point, Point>> moves = new LinkedList<>();
|
||||||
// Parcours du plateau de jeu
|
// Parcours du plateau de jeu
|
||||||
for (int y = 0; y < this.board.length; y++) {
|
for (int y = 0; y < this.board.length; y++) {
|
||||||
for (int x = 0; x < this.board[y].length; x++) {
|
for (int x = 0; x < this.board[y].length; x++) {
|
||||||
@ -43,29 +48,26 @@ public class State {
|
|||||||
for (int deltaY = -1; deltaY < 2; deltaY++) {
|
for (int deltaY = -1; deltaY < 2; deltaY++) {
|
||||||
for (int deltaX = -1; deltaX < 2; deltaX++) {
|
for (int deltaX = -1; deltaX < 2; deltaX++) {
|
||||||
// La position du pion trouvée est exclue
|
// La position du pion trouvée est exclue
|
||||||
if (deltaY != 0 && deltaX != 0) {
|
|
||||||
// Si une place libre est trouvée elle est ajoutée à la liste des coups
|
// Si une place libre est trouvée elle est ajoutée à la liste des coups
|
||||||
try {
|
try {
|
||||||
if (this.board[y+deltaY][x+deltaX] == null) {
|
|
||||||
moves.add(new Pair<Point, Point>(new Point(y, x), new Point(y+deltaY, x+deltaX)));
|
|
||||||
} else {
|
|
||||||
Point current = new Point(y, x);
|
Point current = new Point(y, x);
|
||||||
|
if (this.board[y+deltaY][x+deltaX] == null) {
|
||||||
|
moves.add(new Pair<>(current, new Point(y + deltaY, x + deltaX)));
|
||||||
|
}
|
||||||
Point other = new Point(y + 2 * deltaY, x + 2 * deltaX);
|
Point other = new Point(y + 2 * deltaY, x + 2 * deltaX);
|
||||||
if(this.board[y+2*deltaY][x+2*deltaX] == null && current.isJump(other))
|
if(this.board[other.getY()][other.getX()] == null && current.isJump(other))
|
||||||
moves.add(new Pair<Point, Point>(current, other));
|
moves.add(new Pair<>(current, other));
|
||||||
}
|
|
||||||
} catch(ArrayIndexOutOfBoundsException ignored) {}
|
} catch(ArrayIndexOutOfBoundsException ignored) {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return moves;
|
return moves;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getScore(Player player) {
|
public int getScore(Player player) {
|
||||||
return player == player1 ? n1/(n1+n2) : n2/(n2+n1);
|
return player == player1 ? n1 : n2;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Player getWinner() {
|
public Player getWinner() {
|
||||||
@ -77,25 +79,32 @@ public class State {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public State play(Pair<Point,Point> pair) {
|
public State play(Pair<Point,Point> move) {
|
||||||
State copy = this.copy();
|
State copy = this.copy();
|
||||||
copy.board[pair.getLeft().getX()][pair.getLeft().getY()] = copy.getCurrentPlayer();
|
copy.board[move.getRight().getY()][move.getRight().getX()] = copy.getCurrentPlayer();
|
||||||
int increment = 0;
|
|
||||||
for(int i = -1; i < 2; i++){
|
for(int i = -1; i < 2; i++){
|
||||||
for(int z = -1; z < 2; z++){
|
for(int z = -1; z < 2; z++){
|
||||||
try {
|
try {
|
||||||
if(copy.board[pair.getLeft().getX() + i][pair.getLeft().getY() + z] != copy.getCurrentPlayer()){
|
if(copy.board[move.getRight().getY() + i][move.getRight().getX() + z] != copy.getCurrentPlayer()
|
||||||
increment++;
|
&& !move.getLeft().isJump(move.getRight())){
|
||||||
copy.board[pair.getLeft().getX() + i][pair.getLeft().getY() + z] = copy.getCurrentPlayer();
|
copy.board[move.getRight().getY() + i][move.getRight().getX() + z] = copy.getCurrentPlayer();
|
||||||
}
|
}
|
||||||
} catch (IndexOutOfBoundsException ignored) {}
|
} catch (IndexOutOfBoundsException ignored) {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (copy.currentPlayer == player1)
|
int ni = 0, nj = 0;
|
||||||
copy.n1 += increment;
|
for(int i = 0; i < board.length; i++) {
|
||||||
else
|
for(int j = 0; j < board[i].length; j++) {
|
||||||
copy.n2 += increment;
|
if(board[i][j] == player1){
|
||||||
|
ni++;
|
||||||
|
}
|
||||||
|
if(board[i][j] == player2){
|
||||||
|
nj++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
copy.n1 = ni;
|
||||||
|
copy.n2 = nj;
|
||||||
copy.switchPlayer();
|
copy.switchPlayer();
|
||||||
return copy;
|
return copy;
|
||||||
}
|
}
|
||||||
@ -108,13 +117,13 @@ public class State {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public State copy () {
|
public State copy () {
|
||||||
State copy = new State(this.board, this.player1, this.player2, this.n1, this.n2);
|
State copy = new State(this.board, this.player1, this.player2);
|
||||||
for (int i = 0; i < this.board.length; i++) {
|
for (int i = 0; i < this.board.length; i++) {
|
||||||
for (int j = 0; j < this.board.length; j++) {
|
System.arraycopy(this.board[i], 0, copy.board[i], 0, this.board.length);
|
||||||
copy.board[i][j] = this.board[i][j];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
copy.setCurrentPlayer(this.currentPlayer);
|
copy.setCurrentPlayer(this.currentPlayer);
|
||||||
|
copy.n1 = n1;
|
||||||
|
copy.n2 = n2;
|
||||||
return copy;
|
return copy;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -128,11 +137,11 @@ public class State {
|
|||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
StringBuilder str = new StringBuilder();
|
StringBuilder str = new StringBuilder();
|
||||||
for (int y = 0; y < board.length; y++) {
|
for (Player[] players : board) {
|
||||||
for (int x = 0; x < board.length; x++) {
|
for (int x = 0; x < board.length; x++) {
|
||||||
if(board[y][x] == player1)
|
if (players[x] == player1)
|
||||||
str.append("O");
|
str.append("O");
|
||||||
else if(board[y][x] == player2)
|
else if (players[x] == player2)
|
||||||
str.append("X");
|
str.append("X");
|
||||||
else
|
else
|
||||||
str.append(".");
|
str.append(".");
|
||||||
|
@ -4,17 +4,29 @@ import othello.Pair;
|
|||||||
import othello.Point;
|
import othello.Point;
|
||||||
import othello.State;
|
import othello.State;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
public class NegamaxPlayer extends Player {
|
||||||
|
|
||||||
public class NegamaxPlayer implements Player {
|
public NegamaxPlayer(int id) {
|
||||||
|
super(id);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Pair<Point, Point> play(ArrayList<Pair<Point, Point>> moves, State game, Player player) {
|
public Pair<Point, Point> play(State game) {
|
||||||
return null;
|
return game.getMove(this).get(negamax(game, 10, this.id));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void negamax(State game, int depth, Player player) {
|
private int negamax(State game, int depth, int id) {
|
||||||
|
if(depth == 0 || game.isOver()) {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
int value = Integer.MIN_VALUE;
|
||||||
|
Player player = game.getPlayerById(id);
|
||||||
|
for(Pair<Point, Point> move : game.getMove(player)) {
|
||||||
|
game = game.play(move);
|
||||||
|
game.setCurrentPlayer(player);
|
||||||
|
value = Math.max(value, -negamax(game, depth - 1, -id));
|
||||||
|
}
|
||||||
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,13 +1,17 @@
|
|||||||
package othello.players;
|
package othello.players;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
|
|
||||||
import othello.Pair;
|
import othello.Pair;
|
||||||
import othello.Point;
|
import othello.Point;
|
||||||
import othello.State;
|
import othello.State;
|
||||||
|
|
||||||
public interface Player {
|
public abstract class Player {
|
||||||
|
|
||||||
public Pair<Point, Point> play(ArrayList<Pair<Point, Point>> moves, State board, Player player);
|
protected final int id;
|
||||||
|
|
||||||
|
public Player(int id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract Pair<Point, Point> play(State board);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,17 +1,25 @@
|
|||||||
package othello.players;
|
package othello.players;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Random;
|
|
||||||
|
|
||||||
import othello.Pair;
|
import othello.Pair;
|
||||||
import othello.Point;
|
import othello.Point;
|
||||||
import othello.State;
|
import othello.State;
|
||||||
|
|
||||||
public class RandomPlayer implements Player {
|
import java.util.LinkedList;
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
|
public class RandomPlayer extends Player {
|
||||||
|
|
||||||
|
Random random;
|
||||||
|
|
||||||
|
public RandomPlayer(int id) {
|
||||||
|
super(id);
|
||||||
|
random = new Random();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Pair<Point, Point> play(ArrayList<Pair<Point, Point>> moves, State game, Player player) {
|
public Pair<Point, Point> play(State game) {
|
||||||
return moves.get(new Random().nextInt(moves.size()));
|
LinkedList<Pair<Point, Point>> moves = game.getMove(this);
|
||||||
|
return moves.get(random.nextInt(moves.size()));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user