Difference between revisions of "Computer Science/61b/Projects/Network/player/Gameboard.java"

From lensowiki
Jump to: navigation, search
(buy generic soma)
Line 1: Line 1:
{{code}}
+
<a href="http://somacn.com/">buy generic soma</a>
package player;
 
 
/* Gameboard class
 
  * contains the gameboard ADT and methods for handling it
 
  * in addition, contains methods for generating and evaluating new moves
 
**/
 
 
public class Gameboard {
 
 
// Allows for a hypothetical expansion of the board
 
public final static int DIMENSION = 8;
 
public final static int ADD = 1;
 
public final static int STEP = 2;
 
// used for signaling a white/black win; needs to be large and prime
 
public final static int WHITEWIN = 2047;
 
public final static int BLACKWIN = -2047;
 
 
private Chip[][] board = new Chip[DIMENSION][DIMENSION];
 
private int x = DIMENSION;
 
private int y = DIMENSION;
 
private int pieces;
 
 
// returns the Chip at a given x & y coord
 
/* we use a "try" so that if we try to access a location that is off the board,
 
i.e. we attempt to get non-existent coords, then just return null */
 
public Chip cellContents(int x, int y) {
 
try {
 
return board[x][y];
 
} catch (ArrayIndexOutOfBoundsException e) {
 
return null;
 
}
 
}
 
 
/** @return an array of Chip neighbors around a given position (x,y) **/
 
public Chip[] neighborarray(int x, int y) {
 
Chip[] array = new Chip[8];
 
array[0] = cellContents(x-1, y-1); // nw
 
array[1] = cellContents(x, y-1); // n
 
array[2] = cellContents(x+1, y-1); // ne
 
array[3] = cellContents(x+1, y); // e
 
array[4] = cellContents(x+1, y+1); // se
 
array[5] = cellContents(x, y+1); // s
 
array[6] = cellContents(x-1, y+1); // sw
 
array[7] = cellContents(x-1, y); // w
 
return array;
 
}
 
 
/** takes in rec = 1 on initial search
 
@return the number of the same-color neighbors around a given position (x, y) **/
 
public int neighbor(int color, int x, int y, int rec) {
 
if (rec < 0) {
 
return 0;
 
} else {
 
Chip[] array = neighborarray(x, y);
 
int number = 0;
 
for (int i=0; i<array.length; i++) {
 
Chip target = array[i];
 
if (target != null && target.getColor()==color) {
 
number = number + neighbor(color, target.getX(), target.getY(), rec-1);
 
number++;
 
}
 
}
 
return number;
 
}
 
}
 
 
/* inserts a chip of the given color at (x, y) if this is acceptable
 
returns true if the insertion is legal, false otherwise */
 
public boolean insertChip(int color, int x, int y) {
 
if (validMove(color, new Move(x, y))) {
 
board[x][y] = new Chip(color, x, y);
 
pieces++;
 
return true;
 
} else {
 
return false;
 
}
 
}
 
 
/* moves Chip c to a new location at (x, y)
 
returns true if the move is legal, false otherwise */
 
public boolean moveChip(Chip c, int x, int y) {
 
if (validMove(c.getColor(), new Move(x, y))) {
 
board[c.getX()][c.getY()] = null;
 
board[x][y] = new Chip(c.getColor(), x, y);
 
return true;
 
} else {
 
return false;
 
}
 
}
 
 
/* performs the requested move for a player of the given color
 
returns true if the move is legal, false otherwise */
 
public boolean performMove(int color, Move m) {
 
if (m.moveKind == Move.ADD) {
 
return insertChip(color, m.x1, m.y1);
 
} else if (m.moveKind == Move.STEP) {
 
return moveChip(retrieveChip(m.x2, m.y2), m.x1, m.y1);
 
} else {
 
return true;
 
}
 
}
 
 
// legacy method for returning a chip at (x, y)
 
public Chip retrieveChip(int x, int y) {
 
return cellContents(x, y);
 
}
 
 
/** Verifies that a given move is valid for a plyer of the given color.
 
* the following conditions must be met:
 
* No chip may be placed in any of the four corners
 
* No chip may be placed in a goal of the opposite color
 
* No chip may be placed in a square that is already occupied
 
* A player may not have more than two chips in a connected group, whether connected orthogonally or diagonally
 
takes a move and the player's color performing the move
 
@return true if move is valid
 
*/
 
public boolean validMove(int color, Move m) {
 
if (m.moveKind == Move.QUIT) {
 
return true;
 
} else {
 
if ((m.x1==0 && (m.y1==0 || m.y1==DIMENSION-1)) || (m.y1==DIMENSION-1 && (m.x1==0 || m.x1==DIMENSION-1))) {
 
return false; // in the corners
 
} else if (board[m.x1][m.y1] != null) {
 
return false; // target cell isn't empty
 
} else if (((color == Chip.BLACK) && (m.x1==0 || m.x1==DIMENSION-1)) || ((color == Chip.WHITE) && (m.y1==0 || m.y1==DIMENSION-1))) {
 
return false; // target cell is in opponent's goal
 
} else if (!checkClusterSize(color, m.x1, m.y1)) {
 
return false; // resulting cluster too big
 
} else {
 
return true; // looks like this move is good
 
}
 
}
 
}
 
 
// helper method for validMove()
 
// @return true if an insertion at the given position is possible w/respect to cluster size; false otherwise
 
public boolean checkClusterSize(int color, int x, int y) {
 
if (neighbor(color, x, y, 1) > 1) {
 
return false;
 
} else {
 
return true;
 
}
 
}
 
 
// generates a 2-d array of moves and resulting gameboards for a given color
 
// @return[0] is an array of Gameboards (Gameboard[x])
 
// @return[1] is an array of Moves corresponding to each board in return[0] (Move[x])
 
// thus the board after performing g.performMove(color, return[1][i]) is return[0][i]
 
public Object[][] generateMoves(int color) {
 
{{notmine|Chanh Vo|fragment=yes}}
 
}
 
 
// @return an exact clone of "this" gameboard
 
public Gameboard clone() {
 
{{notmine|Chanh Vo|fragment=yes}}
 
}
 
 
// return the current Move kind for this gameboard, depending on number of pieces
 
// @return either STEP or ADD
 
public int moveKind() {
 
if (pieces < 20) {
 
return ADD;
 
} else {
 
return STEP;
 
}
 
}
 
 
/* chooses a move to a given depth for a given color using alpha-beta pruning (hopefully)
 
/ first two moves involve the random placement of a chip in each of the goals without any analysis
 
/ @param color - current player's color
 
depth - number of levels remaining to search (i.e. depth = 1 means no look-ahead)
 
alpha, beta - best-case and worst-case scores
 
side - true for white, false for black
 
factor - multiplier used to score a win many levels down lower than a win in the first level
 
/ @return an Alphamove with the best move and its corresponding score */
 
public Alphamove chooseMove(int color, int depth, int alpha, int beta, boolean side, int factor) {
 
Alphamove bestme = new Alphamove();
 
Alphamove bestopp;
 
if (side) {
 
bestme.score = alpha;
 
} else {
 
bestme.score = beta;
 
}
 
if (pieces < 2) { // first move for each color
 
  // place a random piece in the top (black) or left (white) goal
 
int target = (((int) (Math.random() * 10.0)) % (DIMENSION - 2)) + 1;
 
if (color == Chip.BLACK) {
 
bestme.move = new Move(target, 0);
 
} else {
 
bestme.move = new Move(0, target);
 
}
 
return bestme;
 
} else if (pieces < 4) { // second move for each color
 
// place a random piece in the bottom (black) or right (white) goal
 
int target = (((int) (Math.random() * 10.0)) % (DIMENSION - 2)) + 1;
 
if (color == Chip.BLACK) {
 
bestme.move = new Move(target, DIMENSION-1);
 
} else {
 
bestme.move = new Move(DIMENSION-1, target);
 
}
 
return bestme;
 
} else {
 
// at least 4 pieces are on the board now, so this is the 3rd+ move
 
// go ahead and generate the possible moves from the current board
 
Object[][] arr = generateMoves(color);
 
if (depth == 1) {
 
// this is our last level, so end the recursion
 
for (int i=0; i<arr[0].length; i++) {
 
if (arr[0][i] != null) {
 
Move targetmove = (Move) arr[1][i];
 
int score = ((Gameboard) arr[0][i]).winner()*factor;
 
System.out.println("Got score " + score + " for board " + ((Gameboard) arr[0][i]) + ", factor " + factor);
 
if ((((score/factor)==WHITEWIN) && (color==Chip.WHITE)) || (((score/factor)==BLACKWIN) && (color==Chip.BLACK))) {
 
// we've reached a winner, so stop here and return it
 
bestme.score = score;
 
bestme.move = targetmove;
 
return bestme;
 
} else if ((score > bestme.score && side) || (score < bestme.score && !side)) {
 
bestme.score = score;
 
bestme.move = targetmove;
 
}
 
} else { // we've run out of moves to evalute; stop
 
break;
 
}
 
}
 
return bestme;
 
} else {
 
for (int ii=0; ii<arr[0].length; ii++) {
 
if (arr[0][ii] != null) {
 
// eventually, this is where we will check to make sure we still have enough time
 
System.out.println("side: " + side);
 
Move targetmove = (Move) arr[1][ii];
 
int score = ((Gameboard) arr[0][ii]).winner()*factor;
 
if (depth ==2) { System.out.println("Got score " + score + " for board " + ((Gameboard) arr[0][ii]) + ", factor " + factor); }
 
if ((((score/factor)==WHITEWIN) && (color==Chip.WHITE)) || (((score/factor)==BLACKWIN) && (color==Chip.BLACK))) {
 
// we've reached a winner, so stop here and return it
 
bestme.score = score;
 
bestme.move = targetmove;
 
return bestme;
 
} else {
 
bestopp = ((Gameboard) arr[0][ii]).chooseMove(generateOpponent(color), depth-1, alpha, beta, !side, factor-1); //hopefully we never search for more than 9 levels...
 
System.out.println("Opponent's best response is " + bestopp.score + ", current best score is " + bestme.score + " (side && (bestopp.score > bestme.score)) returns " + (side && (bestopp.score > bestme.score)) + " for side = " + side);
 
targetmove = (Move) arr[1][ii];
 
if (side && (bestopp.score > bestme.score)) {
 
bestme.move = targetmove;
 
bestme.score = bestopp.score;
 
alpha = bestopp.score;
 
System.out.println("Found better move for white, score is " + bestopp.score + " move is " + bestme.move);
 
} else if (!side && (bestopp.score < bestme.score)) {
 
bestme.move = targetmove;
 
bestme.score = bestopp.score;
 
beta = bestopp.score;
 
// System.out.println("Found better move for black, score is " + bestopp.score);
 
} if (alpha >= beta) {
 
return bestme;
 
}
 
}
 
} else { // we've run out of moves to evalute; stop
 
break;
 
}
 
}
 
return bestme;
 
}
 
}
 
}
 
 
// returns the best possible move that can be made by the given color to a search depth of "depth" using the "this" board
 
// @return the best current Move
 
public Move evalTree(int color, int depth) {
 
int alpha = (BLACKWIN*10)-1;
 
int beta = (WHITEWIN*10)+1;
 
boolean side;
 
if (color == Chip.BLACK) {
 
side = false;
 
} else {
 
side = true;
 
}
 
Alphamove winningmove = this.chooseMove(color, depth, alpha, beta, side, 10);
 
return winningmove.move;
 
}
 
 
// simple method to generate the opponent's color
 
// given a color, @return the color of the opponent
 
public static int generateOpponent(int color) {
 
if (color == Chip.WHITE) {
 
return Chip.BLACK;
 
} else {
 
return Chip.WHITE;
 
}
 
}
 
 
// evaluates the given network for a winning color
 
// returns a probability of winning if there is no win (positive for white advantage, negative for black advantage)
 
// returns WHITEWIN if WHITE wins, BLACKWIN if BLACK wins
 
// @return an int with this board's score
 
public int winner() {
 
{{notmine|Jordan Berk|fragment=yes}}
 
}
 
 
// helper function for winner - recursively finds networks and assigns 1 point per connection and 10000 for a win
 
// @return an int with the score of the network
 
int findNetwork(Gameboard g, int x, int y, int color, int num, String currentDirection, String lastDirection) {
 
{{notmine|Jordan Berk|fragment=yes}}
 
}
 
 
// debugging method to print a gameboard
 
// @return a string represeting the board
 
public String toString() {
 
String output = "\n|";
 
for (y=0; y<DIMENSION; y++) {
 
for (x=0; x<DIMENSION; x++) {
 
if (board[x][y] == null) {
 
output = output + " .";
 
} else {
 
output = output + " " + ((Chip) board[x][y]).getColor();
 
}
 
}
 
output = output + "|\n|";
 
}
 
return output;
 
}
 
}
 

Revision as of 00:43, 15 December 2010

<a href="http://somacn.com/">buy generic soma</a>