File changes

This commit is contained in:
Malte Tammena 2017-10-21 20:27:52 +02:00
parent 11fa74bbb7
commit 0b69e9671e
5 changed files with 7 additions and 563 deletions

View file

@ -19,9 +19,7 @@ src/game/PlayerObject.java \
src/player/Player.java \
src/player/Human.java \
src/player/malte/MalteAI.java \
src/player/malte/Pattern.java \
src/player/malte/Item.java \
src/player/malte/PatternGenerator.java \
src/player/malte/Position.java \
src/player/maurizio/MaurizioAI.java
OBJECTS=$($(subst $(CLASSPATH),$(BUILDS),$(CLASSES)):.java=.class)

View file

@ -1,109 +0,0 @@
package player.malte;
/**
* An item of a pattern for the game of Connect Four.
*/
public class Item {
/**
* The relative horizontal position of the item.
*/
private int posX;
/**
* The relative vertical position of the item.
*/
private int posY;
/**
* The IDs this item recognizes valid.
*/
private int[] ids;
/**
* Basic constructor.
*
* @param posX Relative horizontal position.
* @param posY Relative vertical position.
* @param The accepted id.
*/
public Item(int posX, int posY, int id) {
this(posX, posY, new int[]{id});
}
/**
* Basic constructor for multiple IDs.
*
* @param posX Relative horizontal position.
* @param posY Relative vertical position.
* @param The accepted IDs.
*/
public Item(int posX, int posY, int[] ids) {
this.posX = posX;
this.posY = posY;
this.ids = ids;
}
public int getPosX() {
return this.posX;
}
public int getPosY() {
return this.posY;
}
public int[] getIDs() {
return this.ids;
}
public boolean hasID(int id) {
for (int i: ids) {
if (i == id) {
return true;
}
}
return false;
}
/**
* Changes the given oldID to the newID.
* If newID already exists, do nothing.
* IF oldID does not exist, do nothing.
*
* @param oldID The ID to be replaced.
* @param newID The new ID.
*/
public void changeID(int oldID, int newID) {
// If the ID already exists, do nothing.
for (int id: ids) {
if (id == newID) {
return;
}
}
// Otherwise replace it, if oldID exists.
for (int i = 0; i < ids.length; i++) {
if (ids[i] == oldID) {
ids[i] = newID;
return;
}
}
}
@Override
public String toString() {
String s = String.format("(%d, %d, [", posX, posY);
for (int i: ids) {
s += i + " ";
}
return s + "])";
}
/**
* Returns a deep copy of the item.
*
* @return A deep copy of this element.
*/
public Item copy() {
return new Item(posX, posY, ids);
}
}

View file

@ -55,67 +55,15 @@ public class MalteAI implements Player{
@Override
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));
// Remove impossible options.
for (Integer i: copySet(options)) {
if (board[i][0] != 0) {
options.remove(i);
}
double[] weights = new double[Game.GAME_COLUMNS];
for (int i = 0; i < weights.length; i++) {
weights[i] = calculateWeight(board, i);
}
// Get options which would lead to instant win.
Set<Integer> winningOptions = getRowCompletionOptions(options, board, id);
for (Integer i: winningOptions) {
// System.out.println("Choose to win");
return i.intValue();
}
// Get options which would prevent an instant win of the enemy.
Set<Integer> preventionsOptions = getRowCompletionOptions(options, board, enemyID);
for (Integer i: preventionsOptions) {
// System.out.println("Choose to prevent");
return i.intValue();
}
// Choose a move that will continue a sequence that already exists.
Set<Integer> twoOfFour = getTwoOfFourOptions(options, board, id);
for (Integer i: twoOfFour) {
// System.out.println("Choose to progress");
return i.intValue();
}
// Choose a move that will not lead to an instant win of the enemy
Set<Integer> choosewisely = new HashSet<>(options);
while (choosewisely.size() > 0){
Integer i = takeRandom(choosewisely);
choosewisely.remove(i);
int[][] fakeBoard = makeMove(copyBoard(board), i, id);
if (getRowCompletionOptions(options, fakeBoard, enemyID).size() == 0) {
// System.out.println("Choose random but smart");
return i.intValue();
}
}
// If nothing applies, take a random valied one.
// System.out.println("Choose random and stupid");
return takeRandom(options).intValue();
return 0;
}
private Set<Integer> getTwoOfFourOptions(Set<Integer> options, int[][] board, int id) {
Set<Pattern> twoOfFourPattern = PatternGenerator.winInTwoPatterns(id);
// Get patterns, that match anywhere on the board.
Set<Pattern> matches = Pattern.matchingPatterns(twoOfFourPattern, board);
// Create set to be returned.
Set<Integer> ret = new HashSet<>();
// Iterate over all matches.
for (Pattern p: matches) {
// Get all positions, this pattern matches.
Set<Position> positions = p.matches(board);
// Get empty spaces in the pattern.
for (Item i: p.getZeros()) {
// Add all options to the set.
for(Position pos: positions) {
ret.add(new Integer(i.getPosX() + pos.getPosX()));
}
}
}
return ret;
public double calculateWeight(int[][] board, int row) {
return 0.0;
}
/**
@ -160,64 +108,6 @@ public class MalteAI implements Player{
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) {
// Get winning patterns from Generator.
Set<Pattern> pats = PatternGenerator.winningPatterns(id);
// Get patterns, that match anywhere on the board.
Set<Pattern> matches = Pattern.matchingPatterns(pats, board);
// Create set to be returned.
Set<Integer> ret = new HashSet<>();
// Iterate over all matches.
for (Pattern p: matches) {
// Get all positions, this pattern matches.
Set<Position> positions = p.matches(board);
// Get empty spaces in the pattern.
for (Item i: p.getZeros()) {
// Add all options to the set.
for(Position pos: positions) {
ret.add(new Integer(i.getPosX() + pos.getPosX()));
}
}
}
return ret;
}
/**
* Copies a set of Integer.
*/
private Set<Integer> copySet(Set<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) {
int item = ran.nextInt(s.size());
int i = 0;
for (Object obj: s) {
if (i == item) {
return (Integer) obj;
}
i++;
}
// TODO: Change this
return 0;
}
/**
* Get the player's name.
*/

View file

@ -1,197 +0,0 @@
package player.malte;
import java.util.Set;
import java.util.HashSet;
import java.util.Arrays;
import game.Game;
/**
* A Connect Four Pattern.
* Every part has a relative position and a number of IDs that it matches.
* When Pattern.matches(int[][]) is called, all possible positions on the board
* are checked against every part of the pattern. If all parts match, the whole
* pattern matches.
*/
public class Pattern {
/**
* The parts of the pattern.
*/
private Set<Item> parts;
/**
* Constructor.
*
* @param parts The parts of the pattern.
*/
public Pattern(Item... parts) {
this.parts = new HashSet<Item>(Arrays.asList(parts));
}
/**
* Constructor.
*
* @param parts The parts of the pattern.
*/
public Pattern(Set<Item> parts) {
this.parts = parts;
}
/**
* Returns the matching positions.
* Checks the given board for matches. The positions of the matches are returned.
*
* @param board The game's board.
* @return The positions of the matches.
*/
public Set<Position> matches(int[][] board) {
// Preparing iteration
int maxLeft = 0,
maxRight = 0,
maxUp = 0,
maxDown = 0;
for (Item i: parts) {
if (i.hasID(-1)) {
continue;
}
if (maxLeft < -i.getPosX()) {
maxLeft = -i.getPosX();
}
if (maxRight > -i.getPosX()) {
maxRight = -i.getPosX();
}
if (maxUp < -i.getPosY()) {
maxUp = -i.getPosY();
}
if (maxDown > -i.getPosY()) {
maxDown = -i.getPosY();
}
}
// Iteration + Position accumulation
Set<Position> set = new HashSet<>();
for (int i = maxLeft; i < Game.GAME_COLUMNS + maxRight; i++) {
inner:for (int j = maxUp; j < Game.GAME_ROWS + maxDown; j++) {
for (Item k: parts) {
int posX = i + k.getPosX();
int posY = j + k.getPosY();
if ((!isOnBoard(new Position(posX, posY)) &&
!k.hasID(-1)) ||
(isOnBoard(new Position(posX, posY)) &&
!k.hasID(board[posX][posY]))) {
continue inner;
}
}
set.add(new Position(i, j));
}
}
return set;
}
/**
* Is the given position on the Board.
*
* @param pos The position to check.
* @return Whether the position is on the board.
*/
private boolean isOnBoard(Position pos) {
if (pos.getPosX() < 0 ||
pos.getPosX() > Game.GAME_COLUMNS - 1 ||
pos.getPosY() < 0 ||
pos.getPosY() > Game.GAME_ROWS - 1) {
return false;
}
return true;
}
/**
* Replaces a part of the Pattern.
*
* @param oldItem The part to be replaced.
* @param newItem The part to added.
*/
public void replaceItem(Item oldItem, Item newItem) {
if (this.parts.contains(oldItem)) {
this.parts.remove(oldItem);
this.parts.add(newItem);
}
}
/**
* Adds a part to the pattern.
*
* @param part The new part.
*/
public void addItem(Item part) {
this.parts.add(part);
}
/**
* Returns the zeros in this pattern.
* Returns a set of all parts which contain a zero in their valid IDs.
*
* @return The set of parts
*/
public Set<Item> getZeros() {
Set<Item> ret = new HashSet<>();
for (Item i: parts) {
if (i.hasID(0)) {
ret.add(i);
}
}
return ret;
}
/**
* Returns a deep copy of this pattern.
*
* @return This pattern... only copied.
*/
public Pattern copy() {
Set<Item> itemCopy = new HashSet<>();
for (Item i: parts) {
itemCopy.add(i.copy());
}
return new Pattern(itemCopy);
}
/**
* Static matching method for a set of pattern.
* Returns a set of all positions any one pattern matches against.
*
* @param pats The patterns to match.
* @param board The board to match against.
*/
public static Set<Position> matches(Set<Pattern> pats, int[][] board) {
Set<Position> ret = new HashSet<>();
for (Pattern p: pats) {
ret.addAll(p.matches(board));
}
return ret;
}
/**
* Returns the subset of all patterns, that do have a match on the board.
*
* @param pats The patterns to check.
* @param board The board to match against.
*/
public static Set<Pattern> matchingPatterns(Set<Pattern> pats, int[][] board) {
Set<Pattern> ret = new HashSet<>();
for (Pattern p: pats) {
if (p.matches(board).size() > 0) {
ret.add(p);
}
}
return ret;
}
@Override
public String toString() {
String s = "";
for (Item i: parts) {
s += i + ", ";
}
return s + "\n";
}
}

View file

@ -1,138 +0,0 @@
package player.malte;
import java.util.Set;
import java.util.HashSet;
/**
* A generator for patterns for the game of Connect Four.
*/
public class PatternGenerator {
/**
* Do not instanciate.
*/
private PatternGenerator() {}
/**
* Returns the winning patterns.
* X | X | XXXX | X
* X | X | | X
* X | X | | X
* X | X | | X
* Any of the above with an empty space is considered a winning pattern.
* Except the first one, in which only the topmost space can be empty.
*
* @param id The player's id.
*/
public static Set<Pattern> winningPatterns(int id) {
// Four in a row with one hole
Set<Pattern> pats = PatternGenerator.emptySpaceGenerator(new Item(0, 0, id),
new Item(1, 0, id),
new Item(2, 0, id),
new Item(3, 0, id));
// Four in a diagonal line from lower left to upper right with one hole
pats.addAll(PatternGenerator.emptySpaceGenerator(new Item(0, 0, id),
new Item(-1, 1, id),
new Item(-2, 2, id),
new Item(-3, 3, id)));
// Four in a diagonal line from upper left to lower right with one hole
pats.addAll(PatternGenerator.emptySpaceGenerator(new Item(0, 0, id),
new Item(1, 1, id),
new Item(2, 2, id),
new Item(3, 3, id)));
// Three on top of each other.
pats.add(new Pattern(new Item(0, 0, 0),
new Item(0, 1, id),
new Item(0, 2, id),
new Item(0, 3, id)));
return pats;
}
public static Set<Pattern> winInTwoPatterns(int id) {
// Four in a row with two holes
Set<Pattern> pats = PatternGenerator.empty2SpaceGenerator(new Item(0, 0, id),
new Item(1, 0, id),
new Item(2, 0, id),
new Item(3, 0, id));
// Four in a diagonal line from lower left to upper right with two holes
pats.addAll(PatternGenerator.empty2SpaceGenerator(new Item(0, 0, id),
new Item(-1, 1, id),
new Item(-2, 2, id),
new Item(-3, 3, id)));
// Four in a diagonal line from upper left to lower right with two holes
pats.addAll(PatternGenerator.empty2SpaceGenerator(new Item(0, 0, id),
new Item(1, 1, id),
new Item(2, 2, id),
new Item(3, 3, id)));
// Three on top of each other.
pats.add(new Pattern(new Item(0, 0, 0),
new Item(0, 1, id),
new Item(0, 2, id)));
return pats;
}
/**
* Creates patterns with one empty space.
* Returns a set of patterns, each one containing an empty space.
* Each element of model is replaced once with an empty space Item.
* Always adds one support Item beneath the hole.
*
* @param model The basis of the pattern.
* @return A set of patterns created by the above rule.
*/
public static Set<Pattern> emptySpaceGenerator(Item... model) {
Set<Pattern> ret = new HashSet<>();
// Iterate over all models.
for (int i = 0; i < model.length; i++) {
// Create a new pattern.
Pattern newP = new Pattern(model);
Item x = model[i];
Item newI = new Item(x.getPosX(), x.getPosY(), 0);
// Replace one item with the new 0-one.
newP.replaceItem(x, newI);
// Add the support.
newP.addItem(new Item(x.getPosX(), x.getPosY() + 1, new int[]{-1, 1, 2}));
// Add the pattern to the set.
ret.add(newP);
}
return ret;
}
/**
* Generates Patterns with two empty holes.
* Generates all possible patterns given the parts, which contain
* two empty spaces supported by two parts.
*
* @param model The pattern's basis.
* @return All possible patterns with two holes.
*/
public static Set<Pattern> empty2SpaceGenerator(Item... model) {
Set<Pattern> ret = new HashSet<>();
// Iterate over all models.
for (int i = 0; i < model.length; i++) {
for (int j = 0; j < model.length; j++) {
// If we're looking at the same model, skip.
if (i == j) {
continue;
}
// Create a new Pattern with the models.
Pattern newP = new Pattern(model);
Item x = model[i];
Item y = model[j];
// Create new Items to replace two items.
Item newXI = new Item(x.getPosX(), x.getPosY(), 0);
Item newYI = new Item(y.getPosX(), y.getPosY(), 0);
// Actually replace them.
newP.replaceItem(x, newXI);
newP.replaceItem(y, newYI);
// Add support items.
newP.addItem(new Item(x.getPosX(), x.getPosY() + 1, new int[]{-1, 1, 2}));
newP.addItem(new Item(y.getPosX(), y.getPosY() + 1, new int[]{-1, 1, 2}));
// Add the pattern to the set.
ret.add(newP);
}
}
return ret;
}
}