diff --git a/Makefile b/Makefile index 78c007f..6b5513d 100644 --- a/Makefile +++ b/Makefile @@ -20,9 +20,8 @@ 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/malte/Sequence.java \ src/player/maurizio/MaurizioAI.java OBJECTS=$($(subst $(CLASSPATH),$(BUILDS),$(CLASSES)):.java=.class) diff --git a/src/game/Game.java b/src/game/Game.java index dfc5412..37985ab 100644 --- a/src/game/Game.java +++ b/src/game/Game.java @@ -307,7 +307,11 @@ public class Game { } System.out.println("|"); } - System.out.println(); + System.out.println("+-+-+-+-+-+-+-+"); + for (int i = 0; i < board.length; i++) { + System.out.print("|" + i); + } + System.out.println("|"); } public static boolean checkWin(int[][] board, int player){ diff --git a/src/player/Human.java b/src/player/Human.java index 3d73f4f..b7869fa 100644 --- a/src/player/Human.java +++ b/src/player/Human.java @@ -27,14 +27,14 @@ public class Human implements Player { } } int choice = -1; - // make sure that the user chooses a legal move + // make sure that the user chooses a legal move while (!options.contains(new Integer(choice))) { System.out.print("Choose a move from " + options + ": "); - System.out.flush(); + System.out.flush(); choice = sc.nextInt(); - if(!options.contains(new Integer(choice))){ - System.out.println("This is not a legal move!"); - } + if(!options.contains(new Integer(choice))){ + System.out.println("This is not a legal move!"); + } } return choice; } diff --git a/src/player/malte/Item.java b/src/player/malte/Item.java index e28e1cb..46d68a0 100644 --- a/src/player/malte/Item.java +++ b/src/player/malte/Item.java @@ -1,109 +1,35 @@ 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; + public final Position pos; + public final int id; + public final boolean hasScaffold; + public final boolean onBoard; - /** - * 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}); + public Item(Position pos, + int id, + boolean hasScaffold, + boolean onBoard) { + this.pos = pos; + this.id = id; + this.hasScaffold = hasScaffold; + this.onBoard = onBoard; } - /** - * 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; - } + public String idString(int playerID, int enemyID) { + String s = ""; + if (!onBoard) { + s = "!"; + } else if (this.id == playerID) { + s = "M"; + } else if (this.id == enemyID) { + s = "E"; + } else if (hasScaffold) { + s = "O"; + } else { + s = " "; } - 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); + return s; } } diff --git a/src/player/malte/MalteAI.java b/src/player/malte/MalteAI.java index 2116dab..e5a7141 100644 --- a/src/player/malte/MalteAI.java +++ b/src/player/malte/MalteAI.java @@ -4,6 +4,7 @@ import java.util.Random; import java.util.Set; import java.util.HashSet; import java.util.Arrays; +import java.lang.Math; import player.Player; import game.Game; @@ -55,67 +56,178 @@ public class MalteAI implements Player{ @Override public int move(int[][] board){ - // Create a set of all possible options. - Set 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); + } + double max = -1; + for (double d: weights) { + max = max > d ? max: d; + } + for (int i = 0; i < weights.length; i++) { + if (Math.abs(max - weights[i]) < 0.000001) { + return i; } } - // Get options which would lead to instant win. - Set 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 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 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 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 getTwoOfFourOptions(Set options, int[][] board, int id) { - Set twoOfFourPattern = PatternGenerator.winInTwoPatterns(id); - // Get patterns, that match anywhere on the board. - Set matches = Pattern.matchingPatterns(twoOfFourPattern, board); - // Create set to be returned. - Set ret = new HashSet<>(); - // Iterate over all matches. - for (Pattern p: matches) { - // Get all positions, this pattern matches. - Set 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())); - } + public double calculateWeight(int[][] board, int column) { + double W_ILLEGAL = Double.MIN_VALUE; + double W_DONT = 0.01; + double weight = 1.0; + // Prever a place in the center; + weight *= 1.0 - Math.abs(3.0 - column) / (3.0 * 100.0); + // Relative positions like (-1, -1), (0, -1), etc. + Position[] relAround = Position.getRelCirclePositions(); + // The position we're looking at + Position thisPos = getLastEmpty(board, column); + // There is no space left in this row. + if (thisPos == null) { + weight *= W_ILLEGAL; + return weight; + } + // Setup Sequences + Sequence[] sequences = new Sequence[8]; + Sequence[] sequencesAbove = new Sequence[8]; + int[][] futureBoard = makeMove(copyBoard(board), column, this.id); + for (int i = 0; i < sequences.length; i++) { + sequences[i] = Sequence.readSequenceFromBoard(board, + thisPos.add(relAround[i]), + relAround[i], + this.id, + this.enemyID); + sequences[i].setPlayerID(this.id); + sequences[i].setEnemyID(this.enemyID); + sequencesAbove[i] = Sequence.readSequenceFromBoard(futureBoard, + thisPos.add(relAround[0]).add(relAround[i]), + relAround[i], + this.id, + this.enemyID); + sequencesAbove[i].setPlayerID(this.id); + sequencesAbove[i].setEnemyID(this.enemyID); + } + for (int i = 0; i < sequences.length / 2; i++) { + Sequence x = sequences[i]; + Sequence y = sequences[i + 4]; + weight *= getBaseWeightForSequences(x, y); + Sequence xA = sequencesAbove[i]; + Sequence yA = sequencesAbove[i + 4]; + // weight *= getBaseWeightForSequences(xA, yA); + if ((xA.matches("EEE") || + yA.matches("EEE")) || + ((xA.matches("E") && + yA.matches("EE")) || + (xA.matches("EE") && + yA.matches("E")))) { + // TODO: Do this right! + weight /= 2<<6; } } - return ret; + return weight; + } + + private double getBaseWeightForSequences(Sequence x, Sequence y) { + double W_PRIORITY_1 = 2 << 8; + double W_PRIORITY_2 = 2 << 6; + double W_PRIORITY_3 = 2 << 4; + double W_PRIORITY_4 = 2 << 2; + double W_PRIORITY_5 = 2 << 0; + double W_PRIORITY_6 = 1.0; + double W_START = 1.0; + double weight = W_START; + if (x.matches("MMM") || + y.matches("MMM")) { + weight *= W_PRIORITY_1; + } else if ((x.matches("M") && + y.matches("MM")) || + (x.matches("MM") && + y.matches("M"))) { + weight *= W_PRIORITY_1; + } else if (x.matches("EEE") || + y.matches("EEE")) { + weight *= W_PRIORITY_2; + } else if ((x.matches("E") && + y.matches("EE")) || + (x.matches("EE") && + y.matches("E"))) { + weight *= W_PRIORITY_2; + } else if ((x.matches("O") && + y.matches("MMO")) || + (x.matches("MMO") && + y.matches("O"))) { + weight *= W_PRIORITY_3; + } else if ((x.matches("O") && + y.matches("EEO")) || + (x.matches("EEO") && + y.matches("O"))) { + weight *= W_PRIORITY_4; + } else if (x.matches("EO") && + y.matches("EO")) { + weight *= W_PRIORITY_4; + } else if (x.matches("MMO") || + y.matches("MMO")) { + weight *= W_PRIORITY_5; + } else if ((x.matches("O") && + y.matches("MM")) || + (x.matches("MM") && + y.matches("O"))) { + weight *= W_PRIORITY_5; + } else if ((x.matches("M") && + y.matches("MO")) || + (x.matches("MO") && + y.matches("M"))) { + weight *= W_PRIORITY_5; + } else if (x.matches("EEO") || + y.matches("EEO")) { + weight *= W_PRIORITY_6; + } else if ((x.matches("O") && + y.matches("EE")) || + (x.matches("EE") && + y.matches("O"))) { + weight *= W_PRIORITY_6; + } else if ((x.matches("E") && + y.matches("EO")) || + (x.matches("EO") && + y.matches("E"))) { + weight *= W_PRIORITY_6; + } + return weight; + } + + /** + * + */ + private Position getLastEmpty(int[][] board, int column) { + if (board[column][0] != 0) { + return null; + } + int row = 0; + while (row < Game.GAME_ROWS - 1 && + board[column][row + 1] == 0) { + row++; + } + return new Position(column, row); + } + + /** + * + */ + private boolean isPosOnBoard(Position pos) { + if (pos.getPosX() <= Game.GAME_COLUMNS - 1 && + pos.getPosX() >= 0 && + pos.getPosY() <= Game.GAME_ROWS - 1 && + pos.getPosY() >= 0) { + return true; + } + return false; + } + + /** + * + */ + private int getIDFromBoard(int[][] board, Position pos) { + return board[pos.getPosX()][pos.getPosY()]; } /** @@ -160,64 +272,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 getRowCompletionOptions(Set options, int[][] board, int id) { - // Get winning patterns from Generator. - Set pats = PatternGenerator.winningPatterns(id); - // Get patterns, that match anywhere on the board. - Set matches = Pattern.matchingPatterns(pats, board); - // Create set to be returned. - Set ret = new HashSet<>(); - // Iterate over all matches. - for (Pattern p: matches) { - // Get all positions, this pattern matches. - Set 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 copySet(Set s) { - return new HashSet(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 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. */ diff --git a/src/player/malte/Pattern.java b/src/player/malte/Pattern.java deleted file mode 100644 index af3a129..0000000 --- a/src/player/malte/Pattern.java +++ /dev/null @@ -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 parts; - - /** - * Constructor. - * - * @param parts The parts of the pattern. - */ - public Pattern(Item... parts) { - this.parts = new HashSet(Arrays.asList(parts)); - } - - /** - * Constructor. - * - * @param parts The parts of the pattern. - */ - public Pattern(Set 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 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 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 getZeros() { - Set 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 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 matches(Set pats, int[][] board) { - Set 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 matchingPatterns(Set pats, int[][] board) { - Set 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"; - } -} diff --git a/src/player/malte/PatternGenerator.java b/src/player/malte/PatternGenerator.java deleted file mode 100644 index 5b34f2b..0000000 --- a/src/player/malte/PatternGenerator.java +++ /dev/null @@ -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 winningPatterns(int id) { - // Four in a row with one hole - Set 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 winInTwoPatterns(int id) { - // Four in a row with two holes - Set 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 emptySpaceGenerator(Item... model) { - Set 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 empty2SpaceGenerator(Item... model) { - Set 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; - } - -} diff --git a/src/player/malte/Position.java b/src/player/malte/Position.java index 3f28b12..7f85d6a 100644 --- a/src/player/malte/Position.java +++ b/src/player/malte/Position.java @@ -20,8 +20,26 @@ public class Position { return this.posY; } + public Position add(Position pos) { + return new Position(this.getPosX() + pos.getPosX(), + this.getPosY() + pos.getPosY()); + } + @Override public String toString() { - return String.format("(%d, %d)", posX, posY); + return String.format("(%+d, %+d)", posX, posY); + } + + public static Position[] getRelCirclePositions() { + return new Position[]{ + new Position(0, -1), + new Position(1, -1), + new Position(1, 0), + new Position(1, 1), + new Position(0, 1), + new Position(-1, 1), + new Position(-1, 0), + new Position(-1, -1) + }; } } diff --git a/src/player/malte/Sequence.java b/src/player/malte/Sequence.java new file mode 100644 index 0000000..f0347a8 --- /dev/null +++ b/src/player/malte/Sequence.java @@ -0,0 +1,98 @@ +package player.malte; + +import java.util.List; +import java.util.ArrayList; + +import game.Game; + +public class Sequence { + + private Position startingPos; + private Position direction; + private List items; + private int playerID; + private int enemyID; + + public Sequence(Position startingPos, Position direction, List items) { + this.items = new ArrayList(items); + this.startingPos = startingPos; + this.direction = direction; + } + + public void setPlayerID(int playerID) { + this.playerID = playerID; + } + + public void setEnemyID(int enemyID) { + this.enemyID = enemyID; + } + + public boolean matches(String s) { + String idStr = idString().toLowerCase(); + s = s.toLowerCase(); + for (int i = 0; i < s.length(); i++) { + if (i >= idStr.length()) { + return false; + } + if (s.charAt(i) == 'p' && + (idStr.charAt(i) != 'm' && + idStr.charAt(i) != 'e')) { + return false; + } else if (s.charAt(i) != idStr.charAt(i)) { + return false; + } + } + return true; + } + + public static Sequence readSequenceFromBoard(int[][] board, + Position pos, + Position dir, + int playerID, + int enemyID) { + Position cur = pos; + List items = new ArrayList(); + Position down = new Position(0, 1); + while (isPosOnBoard(cur)) { + boolean hasScaffold = (isPosOnBoard(cur.add(down)) && + getIDFromBoard(board, cur.add(down)) != 0) || cur.getPosY() == 5; + items.add(new Item(cur, + getIDFromBoard(board, cur), + hasScaffold, + true)); + cur = cur.add(dir); + } + items.add(new Item(cur, + -1, + false, + false)); + return new Sequence(pos, dir, items); + } + + private static boolean isPosOnBoard(Position pos) { + if (pos.getPosX() <= Game.GAME_COLUMNS - 1 && + pos.getPosX() >= 0 && + pos.getPosY() <= Game.GAME_ROWS - 1 && + pos.getPosY() >= 0) { + return true; + } + return false; + } + + private static Integer getIDFromBoard(int[][] board, Position pos) { + return new Integer(board[pos.getPosX()][pos.getPosY()]); + } + + public String idString() { + String s = ""; + for (Item x: items) { + s += x.idString(playerID, enemyID); + } + return s; + } + + @Override + public String toString() { + return String.format("START: %s, DIR: %s, \"%s\"", startingPos, direction, idString()); + } +} diff --git a/src/player/malte/SequencesOrdered b/src/player/malte/SequencesOrdered new file mode 100644 index 0000000..502e42b --- /dev/null +++ b/src/player/malte/SequencesOrdered @@ -0,0 +1,14 @@ +1 XMMM // Vierter in der Reihe +1 MXMM +2 XEEE // Vierter beim Gegner +2 EXEE +3 _XMM_ // Sicherer Sieg nächste Runde +3 _MXM_ +4 _XEE_ // Sicherer Sieg des Gegners nächste Runde +4 _EXE_ +5 XMM_ // Möglicher Sieg nächste Runde +5 _XMM +5 MXM_ +6 XEE_ // Möglicher Sieg des Gegners in der nächsten Runde +6 _XEE +6 EXE_ \ No newline at end of file