Implemented sequences

This commit is contained in:
Malte Tammena 2017-10-23 15:13:54 +02:00
parent 0c3623a45e
commit 8f984e653f
3 changed files with 96 additions and 61 deletions

View file

@ -74,11 +74,14 @@ public class MalteAI implements Player{
}
public double calculateWeight(int[][] board, int column) {
double W_START = 1.0;
double W_ILLEGAL = -1.0;
double W_INSTANT_WIN = 2;
double W_PREVENT_INSTANT_WIN = 1.9;
double weight = W_START;
double W_START = 1.0;
double W_ILLEGAL = -1.0;
double W_WIN = 1.5;
double W_INSTANT_WIN = 5.0;
double W_PREVENT_WIN = 1.4;
double W_PREVENT_INSTANT_WIN= 2.0;
double W_DONT = 0.01;
double weight = W_START;
// 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.
@ -92,65 +95,54 @@ public class MalteAI implements Player{
}
// Setup Sequences
Sequence[] sequences = new Sequence[8];
Sequence[] sequencesAbove = new Sequence[8];
for (int i = 0; i < sequences.length; i++) {
sequences[i] = Sequence.readSequenceFromBoard(board, thisPos, relAround[i]);
sequences[i] = Sequence.readSequenceFromBoard(board,
thisPos.add(relAround[i]),
relAround[i]);
sequences[i].setPlayerID(this.id);
sequences[i].setEnemyID(this.enemyID);
sequencesAbove[i] = Sequence.readSequenceFromBoard(board,
thisPos.add(relAround[0]).add(relAround[i]),
relAround[i]);
sequencesAbove[i].setPlayerID(this.id);
sequencesAbove[i].setEnemyID(this.enemyID);
}
// Collect information about our surroundings.
for (int i = 0; i < nrs.length; i++) {
// The postion around us we're collecting information from.
Position curPos = thisPos.add(relAround[i]);
// Check whether this position is on the board at all.
if (isPosOnBoard(curPos)) {
// Get the ID in this position.
ids[i] = getIDFromBoard(board, curPos);
// Get the number of IDs in this direction.
nrs[i] = countIDsInDir(board, ids[i], curPos, relAround[i]);
} else {
// If not on board, -1 is the way to go.
ids[i] = -1;
nrs[i] = -1;
}
}
// Look for problems/options in one direction at a time.
for (int i = 0; i < nrs.length; i++) {
if (nrs[i] == 3) {
if (ids[i] == this.id) {
// We can win like this!
for (int i = 0; i < sequences.length; i++) {
Sequence x = sequences[i];
if (x.matches("MMM")) {
weight *= W_INSTANT_WIN;
} else if (x.matches("EEE")) {
weight *= W_PREVENT_INSTANT_WIN;
} else if (x.matches("EE ")) {
weight *= W_PREVENT_WIN;
} else if (x.matches("MM ")) {
weight *= W_WIN;
} else if (i < 4) {
Sequence y = sequences[i + 4];
if ((x.matches("MM") &&
y.matches("M")) ||
(x.matches("M") &&
y.matches("MM"))) {
weight *= W_INSTANT_WIN;
} else if (ids[i] == this.enemyID) {
// We can at least prevent him from winning.
} else if ((x.matches("EE") &&
y.matches("E")) ||
(x.matches("E") &&
y.matches("EE"))) {
weight *= W_PREVENT_INSTANT_WIN;
} else if ((x.matches("MM ") &&
y.matches(" ")) ||
(x.matches(" ") &&
y.matches("MM "))) {
weight *= W_WIN;
}
}
}
// Look for problems/options in two directions at a time.
for (int i = 0; i < nrs.length / 2; i++) {
// Same ID on opposite sides.
if (ids[i] == ids[i + 4]) {
// Almost a finished row.
if (nrs[i] + nrs[i + 4] > 3) {
if (ids[i] == this.id) {
// Its our ID.
weight *= W_INSTANT_WIN;
} else if (ids[i] == this.enemyID) {
// Its the enemy's ID.
weight *= W_PREVENT_INSTANT_WIN;
}
}
// Prevent choosing a bad spot
Sequence xA = sequencesAbove[i];
if (sequencesAbove[i].matches("EEE")) {
weight *= W_DONT;
}
}
// Maybe we get lucky TODO: Expand this.
double extraWeight = 0.0;
for (int i = 0; i < ids.length; i++) {
if (ids[i] == this.id) {
extraWeight += Math.pow(nrs[i], 2) * 2;
} else if (ids[i] == this.enemyID) {
extraWeight += Math.pow(nrs[i], 2);
}
}
extraWeight /= 10 * 126;
weight *= extraWeight + 1.0;
return weight;
}

View file

@ -27,7 +27,7 @@ public class Position {
@Override
public String toString() {
return String.format("(%d, %d)", posX, posY);
return String.format("(%+d, %+d)", posX, posY);
}
public static Position[] getRelCirclePositions() {

View file

@ -10,19 +10,48 @@ public class Sequence {
private Position startingPos;
private Position direction;
private List<Integer> ids;
private int playerID;
private int enemyID;
public Sequence(List<Integer> ids) {
public Sequence(Position startingPos, Position direction, List<Integer> ids) {
this.ids = new ArrayList<Integer>(ids);
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) == ' ') {
return false;
} else if (s.charAt(i) != idStr.charAt(i)) {
return false;
}
}
return true;
}
public static Sequence readSequenceFromBoard(int[][] board, Position pos, Position dir) {
Position cur = pos;
List<Integer> ids = new ArrayList<Integer>();
while (isPosOnBoard(cur)) {
cur = cur.add(dir);
ids.add(getIDFromBoard(board, cur));
cur = cur.add(dir);
}
return new Sequence(ids);
return new Sequence(pos, dir, ids);
}
private static boolean isPosOnBoard(Position pos) {
@ -38,8 +67,22 @@ public class Sequence {
return new Integer(board[pos.getPosX()][pos.getPosY()]);
}
public String idString() {
String s = "";
for (Integer x: ids) {
if (x.intValue() == this.playerID) {
s += "M";
} else if (x.intValue() == this.enemyID) {
s += "E";
} else {
s += " ";
}
}
return s;
}
@Override
public String toString() {
return String.format("START: %s, DIR: %s, %s", startingPos, direction, ids);
return String.format("START: %s, DIR: %s, \"%s\"", startingPos, direction, idString());
}
}