📄 checkers.txt
字号:
//--------------------------------------------------------
// utilities to decode small, compactly-stored small ints.
/**
* Turns a byte into a pair of coordinates.
*/
public static int[] decodeCoords(byte coordByte) {
int[] retArray = new int[2];
// we perform a bitwise and with the value 15
// in order to just get the bits of the lower
// half of the byte:
retArray[1] = coordByte & 15;
// To get the bits of the upper half of the
// byte, we perform a shift to move them down:
retArray[0] = coordByte >> 4;
// bytes in Java are generally assumed to be
// signed, but in this coding algorithm we
// would like to treat them as unsigned:
if(retArray[0] < 0) {
retArray[0] += 16;
}
return(retArray);
}
/**
* Turns a byte into eight ints.
*/
public static int[] decode8(byte data) {
int[] retArray = new int[8];
// The flag allows us to look at each bit individually
// to determine if it is 1 or 0. The number 128
// corresponds to the highest bit of a byte, so we
// start with that one.
int flag = 128;
// We use a loop that checks
// the data bit by bit by performing a bitwise
// and (&) between the data byte and a flag:
for(int i = 0; i < 8; i++) {
if((flag & data) != 0) {
retArray[i] = 1;
} else {
retArray[i] = 0;
}
// move the flag down one bit so that we can
// check the next bit of data on the next pass
// through the loop:
flag = flag >> 1;
}
return(retArray);
}
//--------------------------------------------------------
// standard integer interpretation
/**
* Uses an input stream to convert an array of bytes to an int.
*/
public static int parseInt(byte[] data) throws IOException {
DataInputStream stream
= new DataInputStream(new ByteArrayInputStream(data));
int retVal = stream.readInt();
stream.close();
return(retVal);
}
/**
* Uses an output stream to convert an int to four bytes.
*/
public static byte[] intToFourBytes(int i) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream(4);
DataOutputStream dos = new DataOutputStream(baos);
dos.writeInt(i);
baos.close();
dos.close();
byte[] retArray = baos.toByteArray();
return(retArray);
}
//--------------------------------------------------------
// integer interpretation illustrated
/**
* Java appears to treat a byte as being signed when
* returning it as an int--this function converts from
* the signed value to the corresponding unsigned value.
* This method is used by nostreamParseInt.
*/
public static int unsign(int signed) {
int retVal = signed;
if(retVal < 0) {
retVal += 256;
}
return(retVal);
}
/**
* Takes an array of bytes and returns an int.
* This version will return the same value as the
* method parseInt above. This version is included
* in order to illustrate how Java encodes int values
* in terms of bytes.
* @param data an array of 1, 2, or 4 bytes.
*/
public static int nostreamParseInt(byte[] data) {
// byte 0 is the high byte which is assumed
// to be signed. As we add the lower bytes
// one by one, we unsign them because because
// a single byte alone is interpreted as signed,
// but in an int only the top byte should be signed.
// (note that the high byte is the first one in the array)
int retVal = data[0];
for(int i = 1; i < data.length; i++) {
retVal = retVal << 8;
retVal += unsign(data[i]);
}
return(retVal);
}
/**
* Takes an arbitrary int and returns
* an array of four bytes.
* This version will return the same byte array
* as the method intToFourBytes above. This version
* is included in order to illustrate how Java encodes
* int values in terms of bytes.
*/
public static byte[] nostreamIntToFourBytes(int i) {
byte[] fourBytes = new byte[4];
// when you take the byte value of an int, it
// only gives you the lowest byte. So we
// get all four bytes by taking the lowest
// byte four times and moving the whole int
// down by one byte between each one.
// (note that the high byte is the first one in the array)
fourBytes[3] = (new Integer(i)).byteValue();
i = i >> 8;
fourBytes[2] = (new Integer(i)).byteValue();
i = i >> 8;
fourBytes[1] = (new Integer(i)).byteValue();
i = i >> 8;
fourBytes[0] = (new Integer(i)).byteValue();
return(fourBytes);
}
/**
* Takes an int between -32768 and 32767 and returns
* an array of two bytes. This does not verify that
* the argument is of the right size. If the absolute
* value of i is too high, it will not be encoded
* correctly.
*/
public static byte[] nostreamIntToTwoBytes(int i) {
byte[] twoBytes = new byte[2];
// when you take the byte value of an int, it
// only gives you the lowest byte. So we
// get the lower two bytes by taking the lowest
// byte twice and moving the whole int
// down by one byte between each one.
twoBytes[1] = (new Integer(i)).byteValue();
i = i >> 8;
twoBytes[0] = (new Integer(i)).byteValue();
return(twoBytes);
}
}
/**
* This class takes care of the underlying logic and data of
* the checkers game being played. That includes where
* all of the pieces are on the board and where it is okay
* for them to move to.
*
* @author Carol Hamer
*/
class CheckersGame {
//-------------------------------------------------------
// static fields
/**
* The length of the checkerboard in the x-direction.
*/
public static final byte X_LENGTH = 4;
/**
* The length of the checkerboard in the y-direction.
*/
public static final byte Y_LENGTH = 8;
//-------------------------------------------------------
// instance fields
/**
* a handle to the communications class that exchanges
* data with the server.
*/
private Communicator myCommunicator;
/**
* This array represents the black squares of the
* checkerboard. The two dimensions of the array
* represent the two dimensions of the checkerboard.
* The value represents what type of piece is on
* the square.
* 0 = empty
* 1 = local player's piece
* 2 = local player's king
* -1 = remote player's piece
* -2 = remote player's king
*/
private byte[][] myGrid;
/**
* If the user has currently selected a piece to move,
* this is its X grid coordinate. (-1 if none selected)
*/
private byte mySelectedX = -1;
/**
* If the user has currently selected a piece to move,
* this is its Y grid coordinate.(-1 if none selected)
*/
private byte mySelectedY = -1;
/**
* If the user has currently selected a possible
* destination square for a move, this is its X coordinate..
* (-1 if none selected)
*/
private byte myDestinationX = -1;
/**
* If the user has currently selected a possible
* destination square for a move, this is its Y coordinate..
* (-1 if none selected)
*/
private byte myDestinationY = -1;
/**
* This Vector contains the coordinates of all of the
* squares that the player could currently move to.
*/
private Vector myPossibleMoves = new Vector(4);
/**
* Whether or not the currently displayed checkers has
* been completed.
*/
private boolean myGameOver = false;
/**
* Whether or not it is currently this player's turn.
*/
private boolean myTurn = false;
/**
* This is true if the player has just jumped and can
* jump again.
*/
private boolean myIsJumping = false;
//-------------------------------------------------------
// get/set data
/**
* get the piece on the given grid square.
*/
byte getPiece(byte x, byte y) {
return(myGrid[x][y]);
}
/**
* This is callsed by CheckersCanvas to determine if
* the square is currently selected (as containing
* a piece to move or a destination square).
*/
boolean isSelected(byte x, byte y) {
boolean retVal = false;
if((x == mySelectedX) && (y == mySelectedY)) {
retVal = true;
} else if((x == myDestinationX) && (y == myDestinationY)) {
retVal = true;
}
return(retVal);
}
/**
* This tells whether or not the keystrokes should currently
* be taken into account.
*/
boolean isMyTurn() {
boolean retVal = false;
if((!myGameOver) && ((myTurn) || (myIsJumping))) {
retVal = true;
}
return(retVal);
}
/**
* This tells whether or not the game has ended.
*/
boolean getGameOver() {
boolean retVal = false;
if(myGameOver) {
retVal = true;
}
return(retVal);
}
/**
* tell the CheckersGame that the other player has ended the game.
*/
void setGameOver() {
myGameOver = true;
}
/**
* set the communicator object.
*/
void setCommunicator(Communicator comm) {
myCommunicator = comm;
}
//-------------------------------------------------------
// initialization
/**
* Constructor puts the pieces in their initial positions:
*/
CheckersGame() {
myGrid = new byte[X_LENGTH][];
for(byte i = 0; i < myGrid.length; i++) {
myGrid[i] = new byte[Y_LENGTH];
for(byte j = 0; j < myGrid[i].length; j++) {
if(j < 3) {
// fill the top of the board with remote players
myGrid[i][j] = -1;
} else if(j > 4) {
// fill the bottom of the board with local players
myGrid[i][j] = 1;
}
}
}
}
/**
* This is called just before the player makes the
* first move.
*/
void start() {
mySelectedX = 0;
mySelectedY = 5;
myTurn = true;
getMoves(mySelectedX, mySelectedY, myPossibleMoves, false);
}
//-------------------------------------------------------
// move the opponent
// to be called by Communicator
/**
* This is called when the opponent wants to move
* its piece.
* @param moveData an array of four bytes:
* moveData[0] = opponent's initial X coordinate
* moveData[1] = opponent's initial Y coordinate
* moveData[2] = opponent's destination X coordinate
* moveData[3] = opponent's destination Y coordinate
*/
void moveOpponent(byte[] moveData) {
// since both players appear on their own screens
// as the red side (bottom of the screen), we need
// to invert the opponent's move:
moveData[0] = (new Integer(X_LENGTH - moveData[0] - 1)).byteValue();
moveData[2] = (new Integer(X_LENGTH - moveData[2] - 1)).byteValue();
moveData[1] = (new Integer(Y_LENGTH - moveData[1] - 1)).byteValue();
moveData[3] = (new Integer(Y_LENGTH - moveData[3] - 1)).byteValue();
myGrid[moveData[2]][moveData[3]]
= myGrid[moveData[0]][moveData[1]];
myGrid[moveData[0]][moveData[1]] = 0;
// deal with an opponent's jump:
if((moveData[1] - moveData[3] > 1) ||
(moveData[3] - moveData[1] > 1)) {
int jumpedY = (moveData[1] + moveData[3])/2;
int jumpedX = moveData[0];
int parity = moveData[1] % 2;
if((parity > 0) && (moveData[2] > moveData[0])) {
jumpedX++;
} else if((parity == 0) && (moveData[0] > moveData[2])) {
jumpedX--;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -