001    /*
002     * Created on Feb 15, 2005
003     *
004     */
005    package aima.games;
006    
007    import java.util.ArrayList;
008    
009    import aima.basic.XYLocation;
010    
011    /**
012     * @author Ravi Mohan
013     * 
014     */
015    public class TicTacToe extends Game {
016            public TicTacToe() {
017                    ArrayList<XYLocation> moves = new ArrayList<XYLocation>();
018                    for (int i = 0; i < 3; i++) {
019                            for (int j = 0; j < 3; j++) {
020                                    XYLocation loc = new XYLocation(i, j);
021                                    moves.add(loc);
022                            }
023                    }
024                    initialState.put("moves", moves);
025                    initialState.put("player", "X");
026                    initialState.put("utility", new Integer(0));
027                    initialState.put("board", new TicTacToeBoard());
028                    initialState.put("level", new Integer(0));
029                    presentState = initialState;
030            }
031    
032            public TicTacToeBoard getBoard(GameState state) {
033    
034                    return (TicTacToeBoard) state.get("board");
035            }
036    
037            @Override
038            public ArrayList getSuccessorStates(GameState state) {
039                    GameState temp = presentState;
040                    ArrayList<Object> retVal = new ArrayList<Object>();
041                    int parentLevel = getLevel(state);
042                    for (int i = 0; i < getMoves(state).size(); i++) {
043                            XYLocation loc = (XYLocation) getMoves(state).get(i);
044    
045                            GameState aState = makeMove(state, loc);
046                            aState.put("moveMade", loc);
047                            aState.put("level", new Integer(parentLevel + 1));
048                            retVal.add(aState);
049    
050                    }
051                    presentState = temp;
052                    return retVal;
053            }
054    
055            @Override
056            public GameState makeMove(GameState state, Object o) {
057                    XYLocation loc = (XYLocation) o;
058                    return makeMove(state, loc.getXCoOrdinate(), loc.getYCoOrdinate());
059            }
060    
061            public GameState makeMove(GameState state, int x, int y) {
062                    GameState temp = getMove(state, x, y);
063                    if (temp != null) {
064                            presentState = temp;
065                    }
066                    return presentState;
067            }
068    
069            public GameState makeMove(int x, int y) {
070                    GameState state = presentState;
071                    GameState temp = getMove(state, x, y);
072                    if (temp != null) {
073                            presentState = temp;
074                    }
075                    return presentState;
076            }
077    
078            public GameState getMove(GameState state, int x, int y) {
079                    GameState retVal = null;
080                    XYLocation loc = new XYLocation(x, y);
081                    ArrayList moves = getMoves(state);
082                    ArrayList newMoves = (ArrayList) moves.clone();
083                    if (moves.contains(loc)) {
084                            int index = newMoves.indexOf(loc);
085                            newMoves.remove(index);
086    
087                            retVal = new GameState();
088    
089                            retVal.put("moves", newMoves);
090                            TicTacToeBoard newBoard = getBoard(state).cloneBoard();
091                            if (getPlayerToMove(state) == "X") {
092                                    newBoard.markX(x, y);
093                                    retVal.put("player", "O");
094    
095                            } else {
096                                    newBoard.markO(x, y);
097                                    retVal.put("player", "X");
098    
099                            }
100                            retVal.put("board", newBoard);
101                            retVal.put("utility", new Integer(computeUtility(newBoard,
102                                            getPlayerToMove(getState()))));
103                            retVal.put("level", new Integer(getLevel(state) + 1));
104                            // presentState = retVal;
105                    }
106                    return retVal;
107            }
108    
109            @Override
110            public int computeUtility(GameState state) {
111                    int utility = computeUtility((TicTacToeBoard) state.get("board"),
112                                    (getPlayerToMove(state)));
113                    return utility;
114            }
115    
116            private int computeUtility(TicTacToeBoard aBoard, String playerToMove) {
117                    int retVal = 0;
118                    if (aBoard.lineThroughBoard()) {
119                            if (playerToMove.equals("X")) {
120                                    retVal = -1;
121                            } else {
122                                    retVal = 1;
123                            }
124    
125                    }
126                    return retVal;
127            }
128    
129            @Override
130            public boolean terminalTest(GameState state) {
131                    TicTacToeBoard board = (TicTacToeBoard) state.get("board");
132                    boolean line = board.lineThroughBoard();
133                    boolean filled = board.getNumberOfMarkedPositions() == 9;
134                    return (line || filled);
135            }
136    
137            public void printPossibleMoves() {
138                    System.out.println("Possible moves");
139    
140                    ArrayList moves = getMoves(presentState);
141                    for (int i = 0; i < moves.size(); i++) {
142                            XYLocation moveLoc = (XYLocation) moves.get(i);
143                            GameState newState = getMove(presentState,
144                                            moveLoc.getXCoOrdinate(), moveLoc.getYCoOrdinate());
145                            TicTacToeBoard board = (TicTacToeBoard) newState.get("board");
146                            System.out.println("utility = " + computeUtility(newState));
147                            System.out.println("");
148                    }
149    
150            }
151    
152            @Override
153            public int getMiniMaxValue(GameState state) {
154                    // statesSeen = new ArrayList();
155                    // System.out.println("In get Minimax Value");
156                    // System.out.println("Received state ");
157                    // ((TicTacToeBoard)state.get("board")).print();
158                    if (getPlayerToMove(state).equalsIgnoreCase("X")) {
159                            return maxValue(state);
160    
161                    } else {
162                            return minValue(state);
163                    }
164            }
165    
166            @Override
167            public int getAlphaBetaValue(GameState state) {
168    
169                    if (getPlayerToMove(state).equalsIgnoreCase("X")) {
170                            AlphaBeta initial = new AlphaBeta(Integer.MIN_VALUE,
171                                            Integer.MAX_VALUE);
172                            int max = maxValue(state, initial);
173                            return max;
174    
175                    } else {
176                            // invert?
177                            AlphaBeta initial = new AlphaBeta(Integer.MIN_VALUE,
178                                            Integer.MAX_VALUE);
179                            return minValue(state, initial);
180                    }
181            }
182    }