diff --git a/api/AIEngine.java b/api/AIEngine.java index 63a7641..b8cf37f 100644 --- a/api/AIEngine.java +++ b/api/AIEngine.java @@ -2,6 +2,10 @@ import boards.TicTacToeBoard; import game.*; +import stateManager.DefensivePlacement; +import stateManager.Placement; + +import java.util.Optional; public class AIEngine { private RuleEngine ruleEngine; @@ -62,32 +66,15 @@ public Cell getSmartMove(Player player, TicTacToeBoard board){ } public Cell getOptimalMove(Player player, TicTacToeBoard board){ - - // 1. Victorious Move = We found a winning move. - Cell best = defense(player,board); - if(best!=null) return best; - // 2. Defensive Move = We found a move where Player wins and we block the move. - best = offense(player,board); - if(best!=null) return best; - // 3. Fork Move = If I have a fork, then play it. - // 4. AntiFork Move = If opponent have a fork, then block it. - - GameInfo gameInfo = ruleEngine.getInfo(board); - if(gameInfo.hasAFork()){ - best = gameInfo.getForkCell(); - return best; - } - // 5. If the center is available, play it. - if(board.getSymbol(1,1)==null) return new Cell(1,1); - // 6. If the corner is available, play it. - int corners[][] = new int[][]{{0,0},{0,2},{2,0},{2,2}}; - for(int i=0;i<4;i++){ - if(board.getSymbol(corners[i][0],corners[i][1])==null) return new Cell(corners[i][0],corners[i][1]); + Placement placement = DefensivePlacement.get(); + while (placement.next()!=null){ + Optional place = placement.place(board,player); + if(place.isPresent()){ + return place.get(); + } + placement = placement.next(); } - return getBasicMove(player, board); - - //return new Cell(0,0); } public Move suggestMove(Player player, Board board){ diff --git a/stateManager/CenterPlacement.java b/stateManager/CenterPlacement.java new file mode 100644 index 0000000..e5020a4 --- /dev/null +++ b/stateManager/CenterPlacement.java @@ -0,0 +1,36 @@ +package stateManager; + +import boards.TicTacToeBoard; +import game.Board; +import game.Cell; +import game.Move; +import game.Player; + +import java.util.Optional; + +public class CenterPlacement implements Placement{ + + private static CenterPlacement centerPlacement; + + public synchronized static Placement get(){ + if(centerPlacement!= null) return centerPlacement; + return new CenterPlacement(); + } + + @Override + public Optional place(TicTacToeBoard board, Player player){ + Cell center = null; + if (board.getSymbol(1, 1) == null) { + center= new Cell (1,1); + } + return Optional.ofNullable(center); + + } + + @Override + public Placement next(){ + return CornerPlacement.get(); + } + + +} diff --git a/stateManager/CornerPlacement.java b/stateManager/CornerPlacement.java new file mode 100644 index 0000000..cfa83e5 --- /dev/null +++ b/stateManager/CornerPlacement.java @@ -0,0 +1,36 @@ +package stateManager; + +import boards.TicTacToeBoard; +import game.Board; +import game.Cell; +import game.Move; +import game.Player; + +import java.util.Optional; + +public class CornerPlacement implements Placement{ + + private static CornerPlacement cornerPlacement; + + public synchronized static Placement get(){ + if(cornerPlacement!= null) return cornerPlacement; + return new CornerPlacement(); + } + + @Override + public Optional place(TicTacToeBoard board, Player player){ + int corners[][] = new int[][]{{0,0},{0,2},{2,0},{2,2}}; + Cell cell = null; + for(int i=0;i<4;i++){ + if(board.getSymbol(corners[i][0],corners[i][1])==null) cell= new Cell(corners[i][0],corners[i][1]); + } + return Optional.ofNullable(cell); + } + + @Override + public Placement next(){ + return null; + } + + +} diff --git a/stateManager/DefensivePlacement.java b/stateManager/DefensivePlacement.java new file mode 100644 index 0000000..8729be6 --- /dev/null +++ b/stateManager/DefensivePlacement.java @@ -0,0 +1,47 @@ +package stateManager; + +import boards.TicTacToeBoard; +import game.Board; +import game.Cell; +import game.Move; +import game.Player; + +import java.util.Optional; + +public class DefensivePlacement implements Placement{ + + private static DefensivePlacement defensivePlacement; + + public synchronized static Placement get(){ + if(defensivePlacement!= null) return defensivePlacement; + return new DefensivePlacement(); + } + + @Override + public Optional place(TicTacToeBoard board, Player player){ + + return Optional.ofNullable(defense(player,board)); + } + + @Override + public Placement next(){ + return OffensivePlacement.get(); + } + + private Cell defense(Player player, TicTacToeBoard board) { + for (int i = 0; i < 3; i++) { + for (int j = 0; j < 3; j++) { + if (board.getSymbol(i, j) == null) { + Move move = new Move(player.flip(), new Cell(i,j)); + Board boardCopy = board.clone(); + boardCopy.move(move); + if (ruleEngine.getState(boardCopy).isOver()) { + return new Cell(i,j); + } + } + } + } + return null; + } + +} diff --git a/stateManager/ForkPlacement.java b/stateManager/ForkPlacement.java new file mode 100644 index 0000000..598472c --- /dev/null +++ b/stateManager/ForkPlacement.java @@ -0,0 +1,38 @@ +package stateManager; + +import boards.TicTacToeBoard; +import game.*; + +import java.util.Optional; + +public class ForkPlacement implements Placement{ + + private static ForkPlacement forkPlacement; + + public synchronized static Placement get(){ + if(forkPlacement!= null) return forkPlacement; + return new ForkPlacement(); + } + + @Override + public Optional place(TicTacToeBoard board, Player player){ + + return Optional.ofNullable(fork(player,board)); + } + + @Override + public Placement next(){ + return CenterPlacement.get(); + } + + private Cell fork(Player player, TicTacToeBoard board) { + GameInfo gameInfo = ruleEngine.getInfo(board); + Cell forkCell = null; + if(gameInfo.hasAFork()){ + forkCell = gameInfo.getForkCell(); + return forkCell; + } + return forkCell; + } + +} diff --git a/stateManager/OffensivePlacement.java b/stateManager/OffensivePlacement.java new file mode 100644 index 0000000..e7abf22 --- /dev/null +++ b/stateManager/OffensivePlacement.java @@ -0,0 +1,45 @@ +package stateManager; + +import boards.TicTacToeBoard; +import game.Board; +import game.Cell; +import game.Move; +import game.Player; + +import java.util.Optional; + +public class OffensivePlacement implements Placement{ + private static OffensivePlacement offensivePlacement; + + public synchronized static Placement get(){ + if(offensivePlacement!= null) return offensivePlacement; + return new OffensivePlacement(); + } + @Override + public Optional place(TicTacToeBoard board, Player player){ + return Optional.ofNullable(offense(player,board)); + } + + @Override + public Placement next(){ + return ForkPlacement.get() ; + } + + private Cell offense(Player player, TicTacToeBoard board) { + for (int i = 0; i < 3; i++) { + for (int j = 0; j < 3; j++) { + if (board.getSymbol(i,j)==null){ + Move move = new Move(player.flip(), new Cell(i,j)); + + Board boardCopy = board.clone(); + boardCopy.move(move); + if(ruleEngine.getState(boardCopy).isOver()){ + return new Cell(i,j); + } + } + } + } + return null; + } + +} diff --git a/stateManager/Placement.java b/stateManager/Placement.java new file mode 100644 index 0000000..2311a75 --- /dev/null +++ b/stateManager/Placement.java @@ -0,0 +1,14 @@ +package stateManager; + +import api.RuleEngine; +import boards.TicTacToeBoard; +import game.Cell; +import game.Player; + +import java.util.Optional; + +public interface Placement { + RuleEngine ruleEngine = new RuleEngine(); + Optional place(TicTacToeBoard board, Player player); + Placement next (); +}