Did commenting
This commit is contained in:
parent
2e9347cfb3
commit
1d87754f53
|
@ -7,18 +7,42 @@ import java.util.Arrays;
|
||||||
|
|
||||||
import player.Player;
|
import player.Player;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Maltes artificial intelligence for playing a game of Connect Four
|
||||||
|
*/
|
||||||
public class MalteAI implements Player{
|
public class MalteAI implements Player{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Name of the player.
|
||||||
|
*/
|
||||||
private String name;
|
private String name;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Random Object.
|
||||||
|
*/
|
||||||
private Random ran;
|
private Random ran;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The players ID.
|
||||||
|
*/
|
||||||
private int id;
|
private int id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The enemy's ID.
|
||||||
|
*/
|
||||||
private int enemyID;
|
private int enemyID;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor.
|
||||||
|
*
|
||||||
|
* @param name The name for the player.
|
||||||
|
*/
|
||||||
public MalteAI(String name){
|
public MalteAI(String name){
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.ran = new Random();
|
this.ran = new Random();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void setPlayerID(int id) {
|
public void setPlayerID(int id) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.enemyID = id == 1 ? 2: 1;
|
this.enemyID = id == 1 ? 2: 1;
|
||||||
|
@ -28,29 +52,40 @@ public class MalteAI implements Player{
|
||||||
this.enemyID = enemyID;
|
this.enemyID = enemyID;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public int move(int[][] board){
|
public int move(int[][] board){
|
||||||
|
// Create a set of all possible options.
|
||||||
Set<Integer> options = new HashSet<>(Arrays.asList(0,1,2,3,4,5,6));
|
Set<Integer> options = new HashSet<>(Arrays.asList(0,1,2,3,4,5,6));
|
||||||
|
// Remove impossible options.
|
||||||
for (Integer i: copySet(options)) {
|
for (Integer i: copySet(options)) {
|
||||||
if (board[i][0] != 0) {
|
if (board[i][0] != 0) {
|
||||||
options.remove(i);
|
options.remove(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Get options which would lead to instant win.
|
||||||
Set<Integer> winningOptions = getRowCompletionOptions(options, board, id);
|
Set<Integer> winningOptions = getRowCompletionOptions(options, board, id);
|
||||||
for (Integer i: winningOptions) {
|
for (Integer i: winningOptions) {
|
||||||
return i.intValue();
|
return i.intValue();
|
||||||
}
|
}
|
||||||
|
// Get options which would prevent an instant win of the enemy.
|
||||||
Set<Integer> preventionsOptions = getRowCompletionOptions(options, board, enemyID);
|
Set<Integer> preventionsOptions = getRowCompletionOptions(options, board, enemyID);
|
||||||
for (Integer i: preventionsOptions) {
|
for (Integer i: preventionsOptions) {
|
||||||
|
// Only accept options, that would not cause a winning opportunity for the enemy.
|
||||||
int[][] fakeBoard = makeMove(copyBoard(board), i, id);
|
int[][] fakeBoard = makeMove(copyBoard(board), i, id);
|
||||||
if (getRowCompletionOptions(options, fakeBoard, enemyID).size() == 0) {
|
if (getRowCompletionOptions(options, fakeBoard, enemyID).size() == 0) {
|
||||||
return i.intValue();
|
return i.intValue();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// If nothing applies, take a random valied one.
|
||||||
return takeRandom(options).intValue();
|
return takeRandom(options).intValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copies the given board.
|
||||||
|
*
|
||||||
|
* @param board The board to be copied.
|
||||||
|
* @return A deep copy of the board.
|
||||||
|
*/
|
||||||
private int[][] copyBoard(int[][] board) {
|
private int[][] copyBoard(int[][] board) {
|
||||||
int[][] copy = new int[board.length][board[0].length];
|
int[][] copy = new int[board.length][board[0].length];
|
||||||
for (int i = 0; i < board.length; i++) {
|
for (int i = 0; i < board.length; i++) {
|
||||||
|
@ -61,25 +96,56 @@ public class MalteAI implements Player{
|
||||||
return copy;
|
return copy;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Makes a move on the given board.
|
||||||
|
* Makes a move on the given board, no winning check or anything,
|
||||||
|
* just a fake move on the given board. Necessary for confirming that
|
||||||
|
* a chosen move will not give the enemy an instant win.
|
||||||
|
*
|
||||||
|
* @param board The board on which the move is made.
|
||||||
|
* @param choice The column to play in.
|
||||||
|
* @param id The player's id.
|
||||||
|
* @return The modified board.
|
||||||
|
*/
|
||||||
private int[][] makeMove(int[][] board, int choice, int id) {
|
private int[][] makeMove(int[][] board, int choice, int id) {
|
||||||
int column = 0;
|
int column = 0;
|
||||||
|
// If the column is full, do nothing.
|
||||||
if (board[choice][column] != 0) {
|
if (board[choice][column] != 0) {
|
||||||
return board;
|
return board;
|
||||||
}
|
}
|
||||||
|
// Find the last empty row.
|
||||||
while (board[choice][column + 1] == 0) {
|
while (board[choice][column + 1] == 0) {
|
||||||
column++;
|
column++;
|
||||||
}
|
}
|
||||||
|
// Add the players piece.
|
||||||
board[choice][column] = id;
|
board[choice][column] = id;
|
||||||
return board;
|
return board;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instant winning options.
|
||||||
|
* Returns a set of options for the player to choose from. If any one is choosen and
|
||||||
|
* played by the player with the given id, a win is certain.
|
||||||
|
*
|
||||||
|
* @param options The options, that are valid, a subset is returned.
|
||||||
|
* @param board The current game's board.
|
||||||
|
* @param id The players id.
|
||||||
|
* @return A subset of options which would lead to a win.
|
||||||
|
*/
|
||||||
private Set<Integer> getRowCompletionOptions(Set<Integer> options, int[][] board, int id) {
|
private Set<Integer> getRowCompletionOptions(Set<Integer> options, int[][] board, int id) {
|
||||||
|
// Get winning patterns from Generator.
|
||||||
Set<Pattern> pats = PatternGenerator.winningPatterns(id);
|
Set<Pattern> pats = PatternGenerator.winningPatterns(id);
|
||||||
|
// Get patterns, that match anywhere on the board.
|
||||||
Set<Pattern> matches = Pattern.matchingPatterns(pats, board);
|
Set<Pattern> matches = Pattern.matchingPatterns(pats, board);
|
||||||
|
// Create set to be returned.
|
||||||
Set<Integer> ret = new HashSet<>();
|
Set<Integer> ret = new HashSet<>();
|
||||||
|
// Iterate over all matches.
|
||||||
for (Pattern p: matches) {
|
for (Pattern p: matches) {
|
||||||
|
// Get all positions, this pattern matches.
|
||||||
Set<Position> positions = p.matches(board);
|
Set<Position> positions = p.matches(board);
|
||||||
|
// Get empty spaces in the pattern.
|
||||||
for (Item i: p.getZeros()) {
|
for (Item i: p.getZeros()) {
|
||||||
|
// Add all options to the set.
|
||||||
for(Position pos: positions) {
|
for(Position pos: positions) {
|
||||||
ret.add(new Integer(i.getPosX() + pos.getPosX()));
|
ret.add(new Integer(i.getPosX() + pos.getPosX()));
|
||||||
}
|
}
|
||||||
|
@ -88,10 +154,19 @@ public class MalteAI implements Player{
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copies a set of Integer.
|
||||||
|
*/
|
||||||
private Set<Integer> copySet(Set<Integer> s) {
|
private Set<Integer> copySet(Set<Integer> s) {
|
||||||
return new HashSet<Integer>(s);
|
return new HashSet<Integer>(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Takes a random Integer from a set of Integer.
|
||||||
|
*
|
||||||
|
* @param s The set to take from.
|
||||||
|
* @return A random element of s.
|
||||||
|
*/
|
||||||
private Integer takeRandom(Set<Integer> s) {
|
private Integer takeRandom(Set<Integer> s) {
|
||||||
int item = ran.nextInt(s.size());
|
int item = ran.nextInt(s.size());
|
||||||
int i = 0;
|
int i = 0;
|
||||||
|
@ -105,6 +180,9 @@ public class MalteAI implements Player{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the player's name.
|
||||||
|
*/
|
||||||
public String getName(){
|
public String getName(){
|
||||||
return this.name;
|
return this.name;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue