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; } }