patternjavaMinor
Evaluation function for Connect Four
Viewed 0 times
evaluationconnectfourfunctionfor
Problem
Here is some code I have written as a connect four negamax evaluation function. The state of the board is stored inside a class
```
private int[][] bS = {{3, 4, 5, 7, 5, 4, 3}, // coefficients for board values
{4, 6, 8, 10, 8, 6, 4},
{5, 8, 11, 13, 11, 8, 5},
{5, 8, 11, 13, 11, 8, 5},
{4, 6, 8, 10, 8, 6, 4},
{3, 4, 5, 7, 5, 4, 3}};
private int[] cS = {0, 10, 100}; // coefficients for x in a row
public int evaluate() {
int winner = state.getWinnerColor();
if (winner == 1) {
return Integer.MAX_VALUE;
}
else if (winner == -1) {
return -Integer.MAX_VALUE;
}
else if (state.isDraw()) {
return 0;
}
int total = 0;
total += boardStrength();
total += connectedStrength();
return total;
}
private int boardStrength() {
int total = 0;
for (int row = 0; row = 3) { // if possible to create a four with this chain
total += color * cS[a.first() + b.first()]; // add to heuristic
}
}
}
visited[row][col] = true;
}
}
}
return total;
}
private IntegerPair check(IntegerPair last, int d1, int d2, boolean[][] visited) { // returns the # in a row
//in row direction d1 and col direction d2 and also if the next one is free
int len = 1, player = state.get(last.first(), last.second());
while (last.first() + len * d1 >= 0
&& last.second() + l
state. state.get() is \$O(1)\$, state.getBoard() is \$O(1)\$, and state.getWinnerColor() and state.getDraw() are also constant (although they have a higher constant coefficient). The real meat of the problem is the connectedStrength() function, which is the most accurate component of the heuristic I have. With it commented out of evaluate(), it runs in around 2500 nanoseconds, uncommented, it jumps 430% to around 10800!```
private int[][] bS = {{3, 4, 5, 7, 5, 4, 3}, // coefficients for board values
{4, 6, 8, 10, 8, 6, 4},
{5, 8, 11, 13, 11, 8, 5},
{5, 8, 11, 13, 11, 8, 5},
{4, 6, 8, 10, 8, 6, 4},
{3, 4, 5, 7, 5, 4, 3}};
private int[] cS = {0, 10, 100}; // coefficients for x in a row
public int evaluate() {
int winner = state.getWinnerColor();
if (winner == 1) {
return Integer.MAX_VALUE;
}
else if (winner == -1) {
return -Integer.MAX_VALUE;
}
else if (state.isDraw()) {
return 0;
}
int total = 0;
total += boardStrength();
total += connectedStrength();
return total;
}
private int boardStrength() {
int total = 0;
for (int row = 0; row = 3) { // if possible to create a four with this chain
total += color * cS[a.first() + b.first()]; // add to heuristic
}
}
}
visited[row][col] = true;
}
}
}
return total;
}
private IntegerPair check(IntegerPair last, int d1, int d2, boolean[][] visited) { // returns the # in a row
//in row direction d1 and col direction d2 and also if the next one is free
int len = 1, player = state.get(last.first(), last.second());
while (last.first() + len * d1 >= 0
&& last.second() + l
Solution
Code duplication and magic numbers
You have some code duplication in
Let us first add a
great, we also removed the magic numbers.
Now we use this method in the extracted
which is called by the former
and again one magic number is gone.
This method will be called by the new
which is called by the
Comments should be used only to describe why something is done in the way it is done. The code itself should describe what is done by using meaningful names for classes, methods and variables.
By using guard clauses you can prevent to code by using the Arrow Anti Pattern.
You have some code duplication in
check() method which can be extracted to a separate method and be simplified to do less claculations. Let us first add a
isValidColorPosition() method to get this ugly while condition extracted private final int LEFT_BOTTOM_BORDER= 0;
private final int RIGHT_BORDER = 6;
private final int TOP_BORDER = 5;
private boolean isValidColorPosition(int row, int col, int color) {
return row >= LEFT_BOTTOM_BORDER
&& col >= LEFT_BOTTOM_BORDER
&& row <= TOP_BORDER
&& col <= RIGHT_BORDER
&& state.get(row, col) == color;
}great, we also removed the magic numbers.
Now we use this method in the extracted
getLength() method private int getLength(IntegerPair position, IntegerPair directions, int currentColor, boolean[][] visited, int count) {
int row = position.first() + count * directions.first();
int col = position.second() + count * directions.second();
while (isValidColorPosition(row, col, currentColor)) {
visited[row][col] = true;
count += 1;
row += directions.first();
col += directions.second();
}
return count;
}which is called by the former
check() method now renamed to getLengthPair() private final int EMPTY_COLOR = 0;
private IntegerPair getLengthPair(IntegerPair last, IntegerPair direction, int playerColor, boolean[][] visited) {
IntegerPair position = new IntegerPair(last.first() + direction.first(),
last.second() + direction.second());
int playerLength = getLength(position, direction, playerColor, visited, 0);
int possibleLength = getLength(position, direction, EMPTY_COLOR, visited, playerLength);
return new IntegerPair(playerLength, possibleLength);
}and again one magic number is gone.
This method will be called by the new
getStrength() method private int getStrength(IntegerPair last, int color, boolean[][] visited, int[][] directions) {
int strength = 0;
for (int i = 0; i = 3) {
strength += color * cS[a.first() + b.first()];
}
}
return strength;
}which is called by the
connectedStrength() method public int connectedStrength() {
int total = 0;
int[][] s = {{1, 1, 0, -1}, {0, 1, 1, 1}};
boolean[][] visited = new boolean[6][7];
for (int row = 0; row < 6; ++row) {
for (int col = 0; col < 7; ++col) {
if (visited[row][col]) {
continue;
}
int color = state.get(row, col);
if (color != 0) {
total += getStrength(new IntegerPair(row, col), color, visited, s);
}
visited[row][col] = true;
}
}
return total;
}Comments should be used only to describe why something is done in the way it is done. The code itself should describe what is done by using meaningful names for classes, methods and variables.
By using guard clauses you can prevent to code by using the Arrow Anti Pattern.
Code Snippets
private final int LEFT_BOTTOM_BORDER= 0;
private final int RIGHT_BORDER = 6;
private final int TOP_BORDER = 5;
private boolean isValidColorPosition(int row, int col, int color) {
return row >= LEFT_BOTTOM_BORDER
&& col >= LEFT_BOTTOM_BORDER
&& row <= TOP_BORDER
&& col <= RIGHT_BORDER
&& state.get(row, col) == color;
}private int getLength(IntegerPair position, IntegerPair directions, int currentColor, boolean[][] visited, int count) {
int row = position.first() + count * directions.first();
int col = position.second() + count * directions.second();
while (isValidColorPosition(row, col, currentColor)) {
visited[row][col] = true;
count += 1;
row += directions.first();
col += directions.second();
}
return count;
}private final int EMPTY_COLOR = 0;
private IntegerPair getLengthPair(IntegerPair last, IntegerPair direction, int playerColor, boolean[][] visited) {
IntegerPair position = new IntegerPair(last.first() + direction.first(),
last.second() + direction.second());
int playerLength = getLength(position, direction, playerColor, visited, 0);
int possibleLength = getLength(position, direction, EMPTY_COLOR, visited, playerLength);
return new IntegerPair(playerLength, possibleLength);
}private int getStrength(IntegerPair last, int color, boolean[][] visited, int[][] directions) {
int strength = 0;
for (int i = 0; i < 4; ++i) {
IntegerPair direction = new IntegerPair(directions[0][i], directions[1][i]);
IntegerPair a = getLengthPair(last, direction, color, visited);
direction = new IntegerPair(-directions[0][i], -directions[1][i]);
IntegerPair b = getLengthPair(last, direction, color, visited);
if (a.second() + b.second() >= 3) {
strength += color * cS[a.first() + b.first()];
}
}
return strength;
}public int connectedStrength() {
int total = 0;
int[][] s = {{1, 1, 0, -1}, {0, 1, 1, 1}};
boolean[][] visited = new boolean[6][7];
for (int row = 0; row < 6; ++row) {
for (int col = 0; col < 7; ++col) {
if (visited[row][col]) {
continue;
}
int color = state.get(row, col);
if (color != 0) {
total += getStrength(new IntegerPair(row, col), color, visited, s);
}
visited[row][col] = true;
}
}
return total;
}Context
StackExchange Code Review Q#82647, answer score: 5
Revisions (0)
No revisions yet.