package org.xwt.server;
import java.util.*;
/** a simple TicTacToe game implemented as an XML-RPC servlet */
public class TicTacToe {
private final static int empty = 0;
private final static int O = 1;
private final static int X = 2;
private final static int draw = -1;
/** board is a 3-element vector of 3-element vectors of strings */
public static Object move(Vector v) {
int[] board = new int[9];
for(int y=0; y<3; y++)
for(int x=0; x<3; x++)
board[y * 3 + x] = stringToInt(((Vector)v.elementAt(y)).elementAt(x).toString());
// where we should move to trigger a stalemate; -1 if no such move exists
int drawMove = -1;
// if we give up, this is where we move
int randomMove = -1;
for(int i=0; i<9; i++) {
if (board[i] != 0) continue;
randomMove = i;
board[i] = O;
int winner = whoWins(board, X);
if (winner == O) return finish("I move " + intToCompass(i) + " and expect to win", board);
else if (winner == draw) drawMove = i;
board[i] = 0;
}
if (drawMove != -1) {
board[drawMove] = O;
return finish("I move " + intToCompass(drawMove) + " and expect to draw", board);
} else if (randomMove != -1) {
board[randomMove] = O;
return finish("I move " + intToCompass(randomMove) + " and expect to lose", board);
} else {
return finish("the board is full; game over", board);
}
}
/** converts from int form to string form */
private static String intToCompass(int i) {
switch(i) {
case 0: return "northwest";
case 1: return "north";
case 2: return "northeast";
case 3: return "west";
case 4: return "center";
case 5: return "east";
case 6: return "southwest";
case 7: return "south";
case 8: return "southeast";
}
return "";
}
/** converts string form to int form */
private static int stringToInt(String s) {
if (s.toLowerCase().equals("x")) return X;
else if (s.toLowerCase().equals("o")) return O;
else return empty;
}
/** packs up the board and message into XML-RPC grokkable form */
private static Object finish(String message, int[] board) {
Hashtable h = new Hashtable();
Vector rows = new Vector();
h.put("message_text", message);
h.put("state", rows);
Vector r1 = new Vector(); rows.addElement(r1);
Vector r2 = new Vector(); rows.addElement(r2);
Vector r3 = new Vector(); rows.addElement(r3);
r1.addElement(board[0] == X ? "x" : (board[0] == O ? "o" : "empty"));
r1.addElement(board[1] == X ? "x" : (board[1] == O ? "o" : "empty"));
r1.addElement(board[2] == X ? "x" : (board[2] == O ? "o" : "empty"));
r2.addElement(board[3] == X ? "x" : (board[3] == O ? "o" : "empty"));
r2.addElement(board[4] == X ? "x" : (board[4] == O ? "o" : "empty"));
r2.addElement(board[5] == X ? "x" : (board[5] == O ? "o" : "empty"));
r3.addElement(board[6] == X ? "x" : (board[6] == O ? "o" : "empty"));
r3.addElement(board[7] == X ? "x" : (board[7] == O ? "o" : "empty"));
r3.addElement(board[8] == X ? "x" : (board[8] == O ? "o" : "empty"));
return h;
}
/** computs the winner if whoseTurn plays next on board and both opponents play optimally */
private static int whoWins(int[] board, int whoseTurn) {
// check for diagonal win
if (board[0] != 0 && board[0] == board[4] && board[4] == board[8]) return board[0];
if (board[2] != 0 && board[2] == board[4] && board[4] == board[6]) return board[2];
// check for column win
if (board[0] != 0 && board[0] == board[3] && board[3] == board[6]) return board[0];
if (board[1] != 0 && board[1] == board[4] && board[4] == board[7]) return board[1];
if (board[2] != 0 && board[2] == board[5] && board[5] == board[8]) return board[2];
// check for row win
if (board[0] != 0 && board[0] == board[1] && board[1] == board[2]) return board[0];
if (board[3] != 0 && board[3] == board[4] && board[4] == board[5]) return board[3];
if (board[6] != 0 && board[6] == board[7] && board[7] == board[8]) return board[6];
if (board[0] != empty && board[1] != empty && board[2] != empty &&
board[3] != empty && board[4] != empty && board[5] != empty &&
board[6] != empty && board[7] != empty && board[8] != empty) return draw;
// true iff there is a place we can move that leads to a stalemate
boolean foundStaleMate = false;
// try every possible move
for(int i=0; i<9; i++) {
if (board[i] != empty) continue;
board[i] = whoseTurn;
int whoWinsThere = whoWins(board, whoseTurn == X ? O : X);
board[i] = empty;
// take the winning move if we find it
if (whoWinsThere == whoseTurn) return whoseTurn;
if (whoWinsThere == draw) foundStaleMate = true;
}
// couldn't find a win, so we take the stalemate if we could find it
if (foundStaleMate) return draw;
// if we couldn't find either a stalemate or a win, the other guy wins
return whoseTurn == X ? O : X;
}
}