📄 game.java
字号:
--nmoves;
}
while (currentMove != root
&& nmoves != 0
&& !(stopAtBranch && currentMove.isBranch()));
}
// This version goes back to the given move, or to the beginning if the
// given move isn't found.
public void goBackward (Move m) {
while (currentMove != root && currentMove != m) {
backup(true);
}
}
/*
* Go forward (locally only) to a later move.
* nmoves is the number of moves to go forward.
* If nmoves = -1 then go to end.
* variation is the child move to use. (This is useful in case
* the move we start at has variations and the user has just
* chosen one.)
* If variation is null then use the trunk, currentMove.child().
* If stopAtBranch is true then stop going forward if a move with
* variations is encountered, else use main branch.
* If stopAtMove is non-null then stop if that move is encountered.
* The move is compared with ==, not EQUALS.
*/
public void goForward (int nmoves, Move variation, boolean stopAtBranch,
Move stopAtMove, boolean stopAtKibitz) {
if (currentMove != finalMove()) {
if (variation != null && currentMove.isVariation(variation)) {
placeMove(variation, null, true, false);
nmoves--;
}
for (Move next = currentMove.child();
next != null && nmoves != 0;
nmoves--) {
placeMove(next, null, true, false);
if (next == stopAtMove
|| (stopAtBranch && next != null && next.isBranch())
|| (stopAtKibitz && next != null && next.hasKibitzes()))
break;
next = next.child();
}
}
}
/**
* Go to the end of the current branch.
**/
public void goToEnd () {
goForward(-1, null, false, null, false);
}
/**
* Go to the beginning of the game.
**/
public void goToBeginning () {
exitScoringMode();
for (int row = 0; row < size; row++)
for (int col = 0; col < size; col++) {
ss.writeStone(row, col, Move.EMPTY);
groupArray[row][col] = null;
}
clearKo();
capturedBlack = 0;
capturedWhite = 0;
setCurrentMove(root);
}
public void goBackToKibitz () {
do
backup(true);
while (currentMove != root
&& (currentMove.kibitzes() == null
|| currentMove.kibitzes().size() == 0));
}
/*
* Permanently undo the previous move. This only gets called
* to undo server moves.
*/
public void undo () {
Move m = finalServerMove(); // The move to undo
// Set the move being undone to be a variation. This will
// cause it to be moved from the trunk to being a variation
// the next time a server move is placed. See placeMove().
m.setIsVariation(true);
// m.addKibitz("--undone move--");
// If undoing the currently displayed move then do a local backup
// also so the display is updated correctly. Otherwise don't
// change the display.
if (m == currentMove) {
goBackward(1, false);
ss.emit();
}
}
/**
* Return a vector of all the positions (stones) abutting the given
* position.
*/
/*
* Personally, i find this much harder to read than the one below it. -sigue
*
private PositionVector positionsAbutting (Position pos) {
PositionVector pv = new PositionVector(0, 4);
int x[] = {-1, 0, 1, 0};
int y[] = { 0, 1, 0, -1};
int row = pos.row;
int col = pos.column;
for (int i = 0; i < 4; i++) {
int r = row + y[i];
int c = col + x[i];
if (!(r < 0 || r >= size || c < 0 || c >= size)
&& ss.readStone(r, c) != Move.EMPTY)
pv.addElement(new Position(r, c));
}
return (pv.size() == 0) ? null : pv;
}
*/
private PositionVector positionsAbutting (Position pos) {
PositionVector pv = new PositionVector(0, 4);
int r = pos.row;
int c = pos.column;
if (stoneAt(r + 1, c) != Move.EMPTY)
pv.addElement(new Position(r + 1, c));
if (stoneAt(r - 1, c) != Move.EMPTY)
pv.addElement(new Position(r - 1, c));
if (stoneAt(r, c + 1) != Move.EMPTY)
pv.addElement(new Position(r, c + 1));
if (stoneAt(r, c - 1) != Move.EMPTY)
pv.addElement(new Position(r, c - 1));
return (pv.size() == 0) ? null : pv;
}
public SimpleGroupVector groupsAbutting (Move m) {
SimpleGroupVector groups = null;
PositionVector placed = m.placedPositions(size);
if (placed != null) {
groups = new SimpleGroupVector(1, 2);
for (int i = 0; i < placed.size(); i++)
groupsAbutting(placed.elementAt(i), Move.nextColor(m.color()), groups);
}
return groups;
}
/**
* Return a vector of all the groups abutting the given position
* that are of the given color.
**/
public SimpleGroupVector groupsAbutting (Position pos, int color) {
return groupsAbutting(pos, color, null);
}
public SimpleGroupVector groupsAbutting (Position pos, int color,
SimpleGroupVector groups) {
if (groups == null)
groups = new SimpleGroupVector(1, 2);
int r = pos.row;
int c = pos.column;
SimpleGroup g;
g = groupAt(r - 1, c);
if (g != null && g.color() == color && groups.indexOf(g) == -1)
groups.addElement(g);
g = groupAt(r + 1, c);
if (g != null && g.color() == color && groups.indexOf(g) == -1)
groups.addElement(g);
g = groupAt(r, c - 1);
if (g != null && g.color() == color && groups.indexOf(g) == -1)
groups.addElement(g);
g = groupAt(r, c + 1);
if (g != null && g.color() == color && groups.indexOf(g) == -1)
groups.addElement(g);
if (groups.size() == 0)
return null;
else
return groups;
}
/**
* Update the stoneArray and groupArray to reflect the capture
* of the given group.
*
* For each stone in the group add a liberty to any groups
* abutting that stone. Update the number of stones captured
* for the other player.
*/
private void captureGroup (SimpleGroup group) {
int capturingColor = Move.nextColor(group.color());
synchronized (ss) {
for (int i = 0; i < group.size(); i++) {
Position pos = group.positionAt(i);
ss.writeStone(pos.row, pos.column, Move.EMPTY); // erase stone at pos
groupArray[pos.row][pos.column] = null; // erase group at pos
SimpleGroupVector oppGroups = groupsAbutting(pos, capturingColor);
if (oppGroups != null)
for (int j = 0; j < oppGroups.size(); j++) {
SimpleGroup oppGroup = oppGroups.elementAt(j);
// Note that addLiberty automatically removes duplicates.
oppGroup.addLiberty(pos);
}
}
// Update captured stones, which should always reflect the current
// state of the game as displayed on the screen.
if (group.color() == Move.BLACK)
capturedBlack += group.size();
else
capturedWhite += group.size();
}
}
/**
* The mirror image of captureGroup.
*/
private void uncaptureGroup (SimpleGroup group) {
if (Debug.debugGameLogicp)
Debug.println("uncaptureGroup(): " + group);
int mycolor = group.color();
int othercolor = Move.nextColor(mycolor);
synchronized (ss) {
// Update the stoneArray and the groupArray, removing liberties
// from abutting groups.
for (int i = 0; i < group.size(); i++) {
Position pos = group.positionAt(i);
ss.writeStone(pos.row, pos.column, mycolor);
groupArray[pos.row][pos.column] = group;
SimpleGroupVector oppGroups = groupsAbutting(pos, othercolor);
if (oppGroups != null)
for (int j = 0; j < oppGroups.size(); j++) {
SimpleGroup oppGroup = oppGroups.elementAt(j);
oppGroup.removeLiberty(pos);
}
}
SimpleGroup newGroup = recomputeGroupAt(group.positionAt(0));
if (Debug.debugGameLogicp && !group.equals(newGroup)) {
Debug.println("newGroup = " + newGroup);
}
// Update captured stones, which should always reflect the current
// state of the game as displayed on the screen.
if (mycolor == Move.BLACK)
capturedBlack -= group.size();
else
capturedWhite -= group.size();
}
}
/*
* This is called once a the move is known to be legal. newGroup
* is the group that was just created by this move. It may be a
* composition of several groups if it was a connecting move.
*/
// division of labour here between this and StoneMove.update is a bit unclear -
// since we are splitting update into legal() and commit(),
// suggest this function only fiddle with the Arrays, and be renamed
// updateArrays! Shift liberty-swizzling logic also into commit(),
// and remove third parameter.... AMB at 0.1
// Now mostly done.... AMB at 0.2
private void updateArrays (Move m, SimpleGroupVector newGroups,
SimpleGroupVector abuttingGroups) {
synchronized (ss) {
// Store the new groups in groupArray and stoneArray thus
// throwing out any groups that used to be at those positions.
if (newGroups != null)
for (int i = 0; i < newGroups.size(); i++) {
SimpleGroup group = newGroups.elementAt(i);
int color = group.color();
for (int j = 0; j < group.size(); j++) {
Position pos = group.positionAt(j);
groupArray[pos.row][pos.column] = group;
ss.writeStone(pos.row, pos.column, color);
}
}
// Remove any captured groups from both the group array and stone array.
if (m.capturedGroups() != null)
for (int j = 0; j < m.capturedGroups().size(); j++)
captureGroup(m.capturedGroups().elementAt(j));
// Remove liberties from the groups abutting the newly placed stone(s).
if (abuttingGroups != null) {
for (int k = 0; k < abuttingGroups.size(); k++) {
SimpleGroup group = abuttingGroups.elementAt(k);
for (int l = 0; l < m.placedPositions(size).size(); l++) {
Position lib = m.placedPositions(size).elementAt(l);
group.removeLiberty(lib);
}
}
}
}
}
/**
* Create a new group from a set of groups that are being connected
* by the placement of the given position. If newGroup is non-null
* then store the new group in it (as a kludge to get around lack
* of multiple value returns).
**/
public SimpleGroup composeGroups (SimpleGroupVector groups, int color,
Position pos) {
SimpleGroup newGroup = new SimpleGroup(color);
if (groups != null) {
// add the positions of each of the old groups to the new group.
for (int i = 0; i < groups.size(); i++) {
SimpleGroup group = groups.elementAt(i);
for (int j = 0; j < group.size(); j++)
newGroup.addPosition(group.positionAt(j));
}
// update the liberties of the new group. the new liberties
// are the union of the liberties of the groups and the new
// position. The union is automatically taken because addLiberty()
// will only add a liberty if it isn't already present.
for (int i = 0; i < groups.size(); i++) {
SimpleGroup group = groups.elementAt(i);
for (int j = 0; j < group.numberOfLiberties(); j++)
newGroup.addLiberty(group.libertyAt(j));
}
}
// Add the connecting position to the new group.
// This automatically removes pos as a liberty.
newGroup.addPosition(pos);
PositionVector poslibs = getLiberties(pos);
for (int i = 0; i < poslibs.size(); i++)
newGroup.addLiberty(poslibs.elementAt(i));
return newGroup;
}
public PositionVector getLiberties (Position pos) {
PositionVector positions = new PositionVector(2, 4);
int r = pos.row;
int c = pos.column;
int size = this.size - 1;
if (r > 0 && ss.readStone(r - 1, c) == Move.EMPTY)
positions.addElement(new Position(r - 1, c));
if (r < size && ss.readStone(r + 1, c) == Move.EMPTY)
positions.addElement(new Position(r + 1, c));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -