?? controller.java
字號:
* When the output of the games command is received we check to see if
* the user is observing that game, and if so update the title of that game.
*
* this constructs Game Windows by use of handleMovesGame....
* it issues the "moves" command to acquire the game history. AMB
*/
protected void handleGames(ParsedMessage p) {
skipwhite(p);
String mess = p.rest();
if (mess.indexOf("white name") != -1 && handleMovesGame == -1) {
sgc.clear();
}
try {
p.continueParse("[ %i ] %s [ %w ] vs. %s [ %w ] ( %i %i %i %f %i %w ) ( %i )");
// fields -> 1 2 3 4 5 6 7 8 9 10 11 12
int n = p.intAt(1); // game number
String w = p.stringAt(2);
String b = p.stringAt(4);
String flags = p.stringAt(11); // e.g., "FI" = Free, IGS rules.
String acctName = client.getAccountName();
boolean teachingGame = flags.indexOf("T") != -1;
boolean freeGame = flags.indexOf("F") != -1;
boolean playing = w.equals(acctName) || b.equals(acctName);
int matchi = -1;
if ((w.equals(b) && w.equals(acctName))
|| (playing && teachingGame))
matchi = Move.BOTH;
else if (w.equals(acctName))
matchi = Move.WHITE;
else if (b.equals(acctName))
matchi = Move.BLACK;
// getGameWindowByName will invalidate any other window with
// game# = n, and will update its title if necessary.
GameWindow gwin = client.getGameWindowByName(w, b, n);
String wr = p.stringAt(3);
String br = p.stringAt(5);
int size = p.intAt(7);
int handi = p.intAt(8);
double komi = p.doubleAt(9);
int byotime = p.intAt(10);
sgc.apply(p.stringAt(1), w, wr, b, br, p.stringAt(6),
p.stringAt(7), p.stringAt(8), p.stringAt(9),
p.stringAt(10), flags, p.stringAt(12), true);
// problem here, no announcement of end of games.......!
if (handleMovesGame != -1) { // this means that this issue of
// the games command is by handleMoves().
countergames = true; // do not show the window after this.
// handleMoves has just seen the first move for a new game.
// The window is created here because the "games" command is
// the only (?) place to find out the size of the game. The
// other needed info has already been saved in handleMovesMessage.
// Issue a "moves" message for this game so the board will
// get refreshed.
gwin = client.addGameWindow(size, w, wr, b, br, komi, n, matchi, byotime, freeGame);
conn.send("moves " + n, false);
int waitingMove = p.intAt(6);
if (waitingMove > 0) {
waitingGameWindow = gwin;
waitingMoveNumber = waitingMove;
gwin.game.ss.setQuiet(true);
seenmoveone = false;
}
handleMovesGame = -1;
}
}
catch (ErgoException e) {}
} // end method handleGames
/*
* Handle a prompt. For reference, here is the list of prompt types from
* the protocol document.
*
* LOGON = 0, initial state
* PASSWORD = 1, getting password
* PASSWD_NEW = 2, verifiying password: not used, registration
* PASSWD_CONFIRM = 3, ditto
* REGISTER = 4, not used
* WAITING = 5, After login the basic state
* PLAYING = 6, Playing a game
* SCORING = 7, Scoring a game
* OBSERVING = 8, Observing (and playing?) a game
* TEACHING = 9, In teaching mode, can move for W and B
* COMPLETE = 10 game complete
*/
private int previousPrompt = 0;
protected void handlePrompt(ParsedMessage p) {
try {
p.continueParse(" %i");
int n = p.intAt(1);
switch (n) {
case 1:
// Getting password (only if client was toggled on initially)
client.displayString("Password: ", null, true);
if (client.loginDialogExists()
&& client.loginDialogDone()
&& !client.passwordSent()) {
client.sendPassword();
}
break;
case 7:
if (n != previousPrompt && conn.server.isNNGStype()) {
// We just entered scoring mode. On NNGS (as of 1998-01-17) there
// is a bug on NNGS such that the second Pass move in a row is not
// sent to both players in the game. Instead the game goes directly
// into scoring mode by sending prompt 7. This is not the case on
// IGS. Since I use 2 Pass moves to know when to enter scoring
// mode (so that it will work the same in server games as it does
// in local games), this poses a problem. Until the bug is fixed
// on NNGS (I reported it today) I will generate a Pass move here.
GameWindow gwin = client.getGameBeingPlayed();
Move parent = gwin.game.finalServerMove();
int movenum = parent.moveNumber() + 1;
int color = Move.nextColor(parent.color());
PassMove m = new PassMove(parent, 0, movenum, color, false);
// Why does this use handleMovesWindow rather than gwin?
handleMovesWindow.placeMove(m, true);
}
client.displayStringInActiveGame("Enter dead group:");
break;
default:
conn.stopScanningForLogin();
break;
}
previousPrompt = n;
}
catch (ErgoException e) { }
}
/*
* Undo has two formats:
* While playing: 28 sigue undid the last move (C7).
* While observing: 28 Undo in game 6: vhdl vs snapback: C9
* It is then followed immediately by the previous move:
* 15 Game 12 I: sigue (0 600 -1) vs sigue (0 600 -1)
* 15 0(B): G3
*/
protected void handleUndo(ParsedMessage p) {
// Need to find out what game the undo is for...
GameWindow gwin;
try {
// Is it the format of a game that's being observed?
p.continueParse(" Undo in game %i: %a vs %a: %a");
int gameNumber = p.intAt(1);
String white = p.stringAt(2);
String black = p.stringAt(3);
client.undoMove(white, black, gameNumber);
}
catch (ParseException e) {
// Not a game being observed, so must be playing a game.
client.undoMove();
}
}
/**
* Deal with "shouts", which are not just shouts.
*
* Examples:
* {Game 16: smount vs cht : W 67.5 B 120.0}
* {Game 15: fanzhen vs indigo : White resigns.}
* {Game 15: fanzhen vs indigo : White forfeits on time.} // NNGS & IGS
* {Game 15: fanzhen vs indigo : White lost by Time.} // IGS
* {Game 18: seanlarsen vs gremlin has adjourned.}
* {Game 47: Allegro vs a11 @ Move 71}
* {Match 15: kado [ 5k*] vs. anhui [ 6k*] }
* {sisi [ 6k*] has connected.}
* {cinnabar has disconnected.}
* !JeryGarcia!: anyone 9x9, or 13x13 with 30k?
*/
protected void handleShout (ParsedMessage p) {
skipwhite(p);
String message = p.rest();
switch (message.charAt(0)) {
case '{':
try {
// First case: end, resumption or adjournment of a game.
if (message.regionMatches(true, 0, "{Game ", 0, 6)) {
p.continueParse("{Game %i: %a vs %a "); // What happend to "Match"? AMB
int gnum = p.intAt(1);
String white = p.stringAt(2);
String black = p.stringAt(3);
String rest = p.rest();
if (rest.indexOf("adjourned.}") != -1) { // case 1: adjourn
client.adjournGame(white, black, gnum);
sgc.disapply(gnum, white, black);
break; // exit the switch
}
// Try to find out the SGF result of the game.
// Hold your nose...
String score = "";
String winner = "";
if (rest.indexOf(" B ") != -1) { // case 2: result
if (client.isDisplayingGame(white, black, gnum)) {
try {
// WING Note: A finished, scored game looks like this:
// {Game 1: foo vs bar : W 82.5 B 76.0 White wins by 6.5.}
// So this won't display the result correctly on WING.
// The first two %s's are to strip off "White resigns."
ParsedMessage ugh
= new ParsedMessage(rest, " : %s %s %s %f %s %f");
double whiteScore = ugh.doubleAt(3);
/*
ParseException: Illegal field access - asked for 5.
at ParsedMessage.matchAt(util.java:598)
at Controller.handleShout(Controller.java:1028)
at Controller.dispatchMessage(Controller.java:275)
at Controller.run(Controller.java:157)
at java.lang.Thread.run(Thread.java:474)
The following call to matchAt blew out with the above.
The score was successfully displayed, but there was
no SGF result displayed. I think the IGS messages
may have changed.
*/
double blackScore = ugh.doubleAt(5);
score = "" + Math.abs(whiteScore - blackScore);
winner = (whiteScore < blackScore) ? "B" : "W";
client.resignGame(white, black, gnum, winner + "+" + score);
}
catch (ParseException grunt) {
Debug.backtrace(grunt);
}
}
sgc.disapply(gnum, white, black);
break; // exit the switch
}
else if (rest.indexOf("resigns.}") != -1) { // case 3: resign
score = "Resign";
winner = (rest.indexOf("White") != -1) ? "B" : "W";
client.resignGame(white, black, gnum, winner + "+" + score);
sgc.disapply(gnum, white, black);
break; // exit the switch
}
// {Game 15: fanzhen vs indigo : White forfeits on time.} // NNGS & IGS
// {Game 15: fanzhen vs indigo : White lost by Time.} // IGS
// The latter is (I believe) only used on IGS for games that were
// replayed at the request of a user. Need to verify this.
else if (rest.indexOf("forfeit") != -1 // case 4: time
|| rest.indexOf("Time") != -1) { // IGS requested games.
score = "Time";
winner = (rest.indexOf("White") != -1) ? "B" : "W";
client.resignGame(white, black, gnum, winner + "+" + score);
sgc.disapply(gnum, white, black);
break; // exit the switch
}
else if (rest.indexOf("@ Move") != -1) { // case 5: resume
if (client.isDisplayingGame(white, black, gnum))
conn.send("observe " + gnum); // auto re-observe game.
p.continueParse("@ Move %i");
ServerPlayer spw = spc.byName(white);
ServerPlayer spb = spc.byName(black);
String wrank = (spw == null ? "??" : spw.rank.render());
String brank = (spb == null ? "??" : spb.rank.render());
sgc.apply(p.stringAt(1), white, wrank, black, brank, p.stringAt(4));
} // end if resume
} // end if it is a message beginning "{Game"
if (message.regionMatches(true, 0, "{Match ", 0, 7)) {
p.continueParse("{Match %i: %s [ %w ] vs. %s [ %w ]");
// Issue a "games n" command, to automatically update
// the "games" window when a new match starts.
// +++ The "games" window has to be modified for this to work.
// Currently it erases everything except game n if I
// issue a "games n" command.
//conn.send("games " + p.intAt(1));
sgc.apply(p.stringAt(1), p.stringAt(2), p.stringAt(3),
p.stringAt(4), p.stringAt(5));
// New games are important enough to display as terminal output.
client.displayString(message);
}
else if (message.indexOf(" has connected.}") != -1) {
p.continueParse("{%s [ %w ]");
spc.apply(p.stringAt(1), p.stringAt(2));
}
else if (message.indexOf(" has disconnected}") != -1) {
p.continueParse("{%s");
ServerPlayer sp = spc.byName(p.stringAt(1));
// System.out.println(sp.name+" is gone");
spc.removePlayer(sp, false);
}
} // end try block
catch (ParseException e) {
e.printStackTrace(System.out);
}
finally {
// Always display this junk in the noise string area.
client.displayNoiseString(message);
}
break;
default:
// If we get to here, I believe message is "!foo! blah blah blah"
client.displayShout(message);
break;
} // end switch on first character of message...
}
protected int[][] gameResult = null;
protected String gameResultWhite = null;
protected String gameResultBlack = null;
private String gameResultWR = null;
private String gameResultBR = null;
private double gameResultKomi = 5.5f;
/* Score looks like this: AMB
22 Bosmon 25k 0 1570 23 F 5.5 0
22 paulcc 25k 0 1781 24 F 5.5 0
22 0: 222222222
22 1: 222222222
22 2: 226262022
22 3: 220222222
22 4: 226262622
22 5: 222222222
22 6: 226262122
22 7: 222222222
22 8: 222222222
The first two lines are
22 whitename rank n timeleft n T/F komi n
20 ogre (W:O): 57.5 to ogre (B:#): 8.0
20 ogre (W:O): 57.5 to ogre (B:#): 8.0
*/
protected void handleScore (ParsedMessage pm) {
String message = pm.rest();
try {
pm.continueParse(" %i: %a");
int column = pm.intAt(1);
String data = pm.stringAt(2);
int size = data.length(); // assume square board
if (gameResult == null) {
gameResult = new int[size][size];
for (int i = 0; i < size; i++)
for (int j = 0; j < size; j++)
gameResult[i][j] = -1;
}
for (int i = 0; i < size; i++) {
char c = data.charAt(i);
if (Character.isDigit(c))
gameResult[size - i - 1][column] = Character.digit(c, 10);
else
break;
}
boolean done = (gameResultBlack != null && gameResultWhite != null);
outer:
for (int i = 0; i < size; i++)
for (int j = 0; j < size; j++)
if (gameResult[i][j] == -1) {
done = false;
break outer;
}
if (done) {
GameWindow gwin = client.getGameWindowByName(gameResultWhite, gameResultBlack, -1);
if (gwin == null) {
// If no game by this name, then this must be the "look" command.
// Create a local game with one move, the result.
gwin = client.createGame(size, gameResultWhite, gameResultWR,
gameResultBlack, gameResultBR, gameResultKomi);
}
// Place the move. The second argument (fromServer) is false
// because the server doesn't model the game result as a move
// so it would cause problems if we modelled it as a server move.
// (e.g., we might try to UNDO it on the server). I don't think
// it should cause a problem to treat it as a local move since at
// the point this move is received the game is over.
client.placeMove(gameResultWhite, gameResultBlack, -1,
new GameResultMove(gwin.game.finalServerMove(), gameResult),
false); // this is a lie, technically.
gameResult = null;
gameResultBlack = null;
gameResultWhite = null;
gameResultWR = null;
gameResultBR = null;
}
}
catch (ParseException e) {
try {
// 22 Bosmon 25k 0 1570 23 F 5.5 0
ParsedMessage pmess = new ParsedMessage(message, " %a %s %i %i %i %c %f %i");
if (gameResultWhite == null) {
gameResultWhite = pmess.stringAt(0);
gameResultWR = pmess.stringAt(1);
gameResultKomi = pmess.doubleAt(6);
}
else if (gameResultBlack == null) {
gameResultBlack = pmess.stringAt(0);
gameResultBR = pmess.stringAt(1);
}
}
catch (ParseException e1) { }
}
}
// Display a yell as "<##:username> text ..."
// Yell message format is "32 ##:username: text"
protected void handleYell(ParsedMessage pm) {
try {
pm.continueParse(" %s ");
String from = pm.stringAt(1);
String text = pm.rest();
from = from.substring(0, from.length() - 1);
// +++ from includes the channel number. should separate them.
client.displayYell(from, text);
}
catch (ParseException pe) {
client.displayString(pm.rest());
}
}
} // end class Controller
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -