📄 backgammonboard.java
字号:
//package bkgm;
import java.util.*;
import java.io.*;
import java.math.*;
public class BackgammonBoard implements Cloneable {
// Each cell in our model is free, or has a checker from player 0 or
// has a checker from player 1
// (represented respectively by 0, negative, positive)
// Player 0 is negative counts and moves in negative direction of board index.
// Player 1 is opposite.
int[] board;
// Checkers on bar (that have been hit). on_bar[0] is first player, on_bar[1] is second player.
int[] on_bar;
// Checkers in home. in_home[0] is first player, in_home[1] is second player.
int[] in_home;
// The current dice rolls.
int dc1;
int dc2;
// Print lots 'o stuff or not.
boolean verbose;
// Where to print the output
PrintStream out_stream;
public static int CHECKERS_PER_PLAYER = 15;
public static int NUM_POINTS = 24;
public static int BAR_LOC0 = NUM_POINTS;
public static int BAR_LOC1 = -1;
// Set use_doubles to false if you would like to turn off the quadruple moves for testing.
public static boolean use_doubles = false;
protected Object clone() {
BackgammonBoard b = null;
try {
b = (BackgammonBoard) super.clone();
} catch (CloneNotSupportedException e) {
System.err.println("I caught the error of board cloning");
}
b.board = (int[])board.clone();
b.on_bar = (int[])on_bar.clone();
b.in_home = (int[])in_home.clone();
return b;
}
public BackgammonBoard(PrintStream ps) {
out_stream = ps;
initialize();
}
public BackgammonBoard() {
out_stream = System.out;
initialize();
}
private void initialize() {
// Allocating space for the array cells
board = new int[NUM_POINTS];
on_bar = new int[2];
in_home = new int[2];
verbose = true;
// Initializing the cells to the "free" state (i.e. ZERO)
for (int i = 0; i < NUM_POINTS; i = i + 1)
board[i] = 0;
/*
// Initilizing the checkers for player 0
board[5] = -5;
board[7] = -3;
board[12] = -5;
board[23] = -2;
// Initilizing the checkers for player 1
board[0] = 2;
board[11] = 5;
board[16] = 3;
board[18] = 5;
on_bar[0] = 0;
on_bar[1] = 0;
in_home[0] = 0;
in_home[1] = 0;
*/
// Initilizing the checkers for player
board[5] = 0;
board[7] = 0;
board[12] = 0;
board[23] = -2;
// Initilizing the checkers for player 1
board[0] = 2;
board[11] = 0;
board[16] = 0;
board[18] = 0;
on_bar[0] = 0;
on_bar[1] = 0;
in_home[0] = 0;
in_home[1] = 0;
}
// Apply Move m for player to the board.
public void applyMove(int player, Move m)
{
if (m != null) {
if (player==0)
m.sortDescend();
else
m.sortAscend();
Iterator iter = m.getAtomicMoves();
try {
while (iter.hasNext()) {
AtomicMove am = (AtomicMove) iter.next();
if (verbose) {
out_stream.println("Agent"+ player +" selects move: (" + am.source_column + "," + am.dest_column + ") (source, dest)");
}
applyAtomicMove(player,am);
}
} catch (NoSuchElementException e) {
System.err.println("Error in applying move for player " + player);
}
}
}
private void applyAtomicMove(int player, AtomicMove am) {
pickChecker(player, am.source_column);
putChecker(player, am.dest_column);
}
// Remove a checker from a location.
private void pickChecker(int player, int column) {
if ((column < -1) || (column > NUM_POINTS)) {
System.err.println("Error, out of range.");
} else {
// column -1 means the table!
// So if a checker is transfered from the column -1, it is simply put in the game.
if (column == BAR_LOC1 || column == BAR_LOC0) {
if (on_bar[player] < 1)
System.err.println("Error, no pieces on bar.");
else
on_bar[player]--;
} else {
int p_type = pType(player);
if (((p_type) * board[column]) >= p_type) {
board[column] -= p_type;
} else {
System.err.println("Error, no pieces at this location.");
}
}
}
}
// Wrapper to get count type (-1/+1) from player number (0/1)
public int pType(int player) {
return player==0 ? -1 : 1;
}
// Place one of player's checkers at location column.
// Handles hitting of blots, prints error if this is an invalid move (should never happen).
private void putChecker(int player, int column) {
if ((column < -1) || (column > NUM_POINTS)) {
System.err.println("Error, out of range.");
} else {
int p_type = pType(player);
if (column==-1 || column==NUM_POINTS) {
in_home[player]++;
} else if (p_type * board[column] >= 0) {
board[column] += p_type;
} else if (board[column] == -p_type) {
board[column] = p_type;
on_bar[((player+1) % 2)]++;
} else {
System.err.println("Error, too many opponent pieces at this locations.");
}
}
}
// Get a set of valid moves for a player, assuming it's his/her
// turn, given the current dice roll.
public MoveSet getValidMoves(int player) {
Move empty_move = new Move();
MoveSet rtn_mset = null;
int[] dice;
int dice_left;
if ((dc1==dc2)&&(use_doubles)) {
dice_left = 4;
dice = new int[4];
dice[0]=dc1;
dice[1]=dc1;
dice[2]=dc1;
dice[3]=dc1;
int s_pos = player==1 ? 0 : NUM_POINTS-1;
rtn_mset = getValidMovesDoublesRec(empty_move, player, dice_left, dice, s_pos);
// Doubles version does not guarrantee maximum number of dice is used.
if (rtn_mset != null)
rtn_mset.maxify();
} else {
dice_left = 2;
dice = new int[2];
// Make two calls to getValidMovesRec, one for each ordering of the dice.
// Remove duplicate moves later.
dice[0]=dc1;
dice[1]=dc2;
rtn_mset = getValidMovesRec(empty_move, player, dice_left, dice);
dice[0]=dc2;
dice[1]=dc1;
rtn_mset.addSet(getValidMovesRec(empty_move, player, dice_left, dice));
if (rtn_mset != null) {
// Must use as many dice as possible.
rtn_mset.maxify();
// If you can only move one die, the larger must be used.
rtn_mset.bigify(dc1,dc2);
}
}
// Remove duplicate moves from MoveSet.
if (rtn_mset != null) {
rtn_mset.uniquify();
// Moves must be in descending order for player 0, ascending order for player 1.
for (Iterator iter = rtn_mset.getIterator(); iter.hasNext(); ) {
if (player==0)
((Move) iter.next()).sortDescend();
else
((Move) iter.next()).sortAscend();
}
}
return rtn_mset;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -