View Javadoc

1   /*------------------------------------------------------------------------------
2    * The contents of this file are subject to the Mozilla Public License Version
3    * 1.1 (the "License"); you may not use this file except in compliance with
4    * the License. You may obtain a copy of the License at
5    * http://www.mozilla.org/MPL/
6    * Software distributed under the License is distributed on an "AS IS" basis,
7    * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
8    * the specific language governing rights and limitations under the License.
9    *
10   * The Original Code is levelonelabs.com code.
11   * The Initial Developer of the Original Code is Level One Labs. Portions
12   * created by the Initial Developer are Copyright (C) 2001 the Initial
13   * Developer. All Rights Reserved.
14   *
15   *         Contributor(s):
16   *             Scott Oster      (ostersc@alum.rpi.edu)
17   *             Steve Zingelwicz (sez@po.cwru.edu)
18   *             William Gorman   (willgorman@hotmail.com)
19   *
20   * Alternatively, the contents of this file may be used under the terms of
21   * either the GNU General Public License Version 2 or later (the "GPL"), or
22   * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
23   * in which case the provisions of the GPL or the LGPL are applicable
24   * instead of those above. If you wish to allow use of your version of this
25   * file only under the terms of either the GPL or the LGPL, and not to allow
26   * others to use your version of this file under the terms of the NPL, indicate
27   * your decision by deleting the provisions above and replace them with the
28   * notice and other provisions required by the GPL or the LGPL. If you do not
29   * delete the provisions above, a recipient may use your version of this file
30   * under the terms of any one of the NPL, the GPL or the LGPL.
31   *----------------------------------------------------------------------------*/
32  
33  package com.levelonelabs.aimbot.modules;
34  
35  import java.util.ArrayList;
36  import java.util.Hashtable;
37  import java.util.Random;
38  import java.util.StringTokenizer;
39  import java.util.logging.Logger;
40  
41  import com.levelonelabs.aim.AIMBuddy;
42  import com.levelonelabs.aimbot.AIMBot;
43  import com.levelonelabs.aimbot.BotModule;
44  
45  
46  /***
47   * Allows someone to play Tic Tac Toe against the computer or competitior. This
48   * is to demonstrate how state can be saved for a game or other type of module.
49   * Thanks to Niel Eyde for the idea.
50   * 
51   * @author Will Gorman
52   * @created April 18, 2003
53   */
54  public class TicTacToeModule extends BotModule {
55      private static ArrayList services;
56      /*** This hashtable stores the states of all the games */
57      private static Hashtable games;
58      static Random rand = new Random();
59      static Logger logger = Logger.getLogger(TicTacToeModule.class.getName());
60  
61      /***
62       * Initialize the service commands.
63       */
64      static {
65          services = new ArrayList();
66          services.add("ttt");
67          services.add("tictactoe");
68          games = new Hashtable();
69      }
70  
71  
72      /***
73       * Constructor for the TicTacToeModule object
74       * 
75       * @param bot
76       */
77      public TicTacToeModule(AIMBot bot) {
78          super(bot);
79      }
80  
81  
82      /***
83       * Gets the services attribute of the PreferenceModule object
84       * 
85       * @return The services value
86       */
87      public ArrayList getServices() {
88          return services;
89      }
90  
91  
92      /***
93       * Gets the name attribute of the Tic Tack Toe Module object
94       * 
95       * @return The name value
96       */
97      public String getName() {
98          return "TicTacToe Module";
99      }
100 
101 
102     /***
103      * Describes the usage of the module
104      * 
105      * @return the usage of the module
106      */
107     public String help() {
108         StringBuffer sb = new StringBuffer();
109         sb.append("<B>ttt <i>BUDDY</i></B> (starts a game with a buddy, if buddy is left blank, bot will play)\n");
110         sb.append("<B>ttt <i>N</i></B> (tells tic tac toe what your move is, where N is the place to move)\n");
111         sb.append("<B>ttt end</B> (ends a current game)\n");
112         sb.append("<B>ttt show</B> (shows the current game)\n");
113         return sb.toString();
114     }
115 
116 
117     /***
118      * sends a message unless it is to the computer
119      * 
120      * @param buddy
121      *            buddy to send message to
122      * @param message
123      *            message to send
124      */
125     public void sendMessageUnlessRobot(AIMBuddy buddy, String message) {
126         if (!buddy.getName().equalsIgnoreCase(bot.getUsername())) {
127             sendMessage(buddy, message);
128         }
129     }
130 
131 
132     /***
133      * Handle a tic tac toe query
134      * 
135      * @param buddy
136      * @param query
137      */
138     public void performService(AIMBuddy buddy, String query) {
139         if (query.toLowerCase().startsWith("ttt") || query.toLowerCase().startsWith("tictactoe")) {
140             StringTokenizer st = new StringTokenizer(query, " ");
141             st.nextToken(); // command
142             String you = buddy.getName();
143             TicTacToeGame tttg = (TicTacToeGame) games.get(you);
144             if (tttg == null) {
145                 // starting a new game. either computer or player
146                 AIMBuddy competitor = null;
147                 String compname = null;
148                 if (st.hasMoreTokens()) {
149                     compname = st.nextToken();
150                     competitor = getBuddy(compname);
151                 }
152                 if ((compname == null) || compname.equalsIgnoreCase(bot.getUsername())) {
153                     // see if the person is already in a game? (i guess not..
154                     // see above).
155                     // play against the computer
156                     tttg = new TicTacToeGame(you, bot.getUsername());
157                     tttg.state = tttg.STARTED;
158                     tttg.computerMove();
159                     games.put(you, tttg);
160                     sendMessage(buddy, "\n" + tttg.displayMoves() + "\nSelect " + tttg.getCurrentXO()
161                         + " Move (ttt N):");
162                 } else if (compname != null) {
163                     if (competitor != null) {
164                         // check if competitor is online, if so, invite him to
165                         // the game.
166                         if (games.get(competitor.getName()) != null) {
167                             sendMessage(buddy, "Sorry, " + competitor.getName() + " is in another tic tac toe game.");
168                         } else {
169                             // let the user know competitor has been asked.
170                             if (competitor.getName().equalsIgnoreCase(buddy.getName())) {
171                                 sendMessage(buddy, "Sorry, no playing with yourself.");
172                             } else if (competitor.isOnline()) {
173                                 tttg = new TicTacToeGame(you, competitor.getName());
174                                 games.put(competitor.getName(), tttg);
175                                 games.put(you, tttg);
176                                 sendMessage(buddy, "Inviting " + compname + " to play.");
177                                 sendMessage(competitor, "Would you like to play Tic Tac Toe with " + you
178                                     + "? (ttt yes/ttt no)");
179                             } else {
180                                 sendMessage(buddy, "Sorry, " + competitor.getName() + " isn't online.");
181                             }
182                         }
183                     } else {
184                         sendMessage(buddy, "Sorry, can't find " + compname + " to play with.");
185                     }
186                 }
187             } else {
188                 if (st.hasMoreTokens()) {
189                     String command = st.nextToken();
190                     String comp = tttg.getCompetitor(you);
191                     if (command.equals("end")) {
192                         sendMessage(buddy, "the game has been terminated.");
193                         sendMessageUnlessRobot(getBuddy(comp), "\n" + tttg.displayMoves() + "\n" + you
194                             + " ended the game.");
195                         games.remove(comp);
196                         games.remove(you);
197                     } else if (command.equals("show")) {
198                         sendMessage(buddy, "\n" + tttg.displayMoves() + "\nwaiting for " + tttg.getCurrentPlayer()
199                             + " to make a move.");
200                     } else if (command.equals("yes")) {
201                         if ((tttg.state == tttg.REQUESTED) && (tttg.getPlayerNumber(you) == 1)) {
202                             tttg.state = tttg.STARTED;
203                             sendMessage(getBuddy(tttg.getCurrentPlayer()), "\n" + tttg.displayMoves() + "\nSelect "
204                                 + tttg.getCurrentXO() + " Move  (ttt N):");
205                         } else {
206                             sendMessage(buddy, "Not sure what you are saying yes to.");
207                         }
208                     } else if (command.equals("no")) {
209                         if ((tttg.state == tttg.REQUESTED) && (tttg.getPlayerNumber(you) == 1)) {
210                             sendMessage(getBuddy(comp), you + " said no to tic tac toe.");
211                             games.remove(comp);
212                             games.remove(you);
213                         } else {
214                             sendMessage(buddy, "Not sure what you are saying no to.");
215                         }
216                     } else {
217                         if (tttg.state == tttg.STARTED) {
218                             try {
219                                 int move = Integer.parseInt(command);
220 
221                                 // make sure move is valid
222                                 boolean valid = tttg.playerMove(you, move);
223                                 if (valid) {
224                                     if (comp.equals(bot.getUsername())) {
225                                         tttg.computerMove();
226                                     }
227                                     if (tttg.gameOver()) {
228                                         int w = tttg.winner();
229                                         if (w != -1) {
230                                             String winner = tttg.getPlayerName(w);
231                                             String loser = tttg.getCompetitor(winner);
232                                             sendMessageUnlessRobot(getBuddy(winner), "\n" + tttg.displayMoves()
233                                                 + "\nYou won!");
234                                             sendMessageUnlessRobot(getBuddy(loser), "\n" + tttg.displayMoves()
235                                                 + "\nYou lost!");
236                                         } else {
237                                             sendMessage(buddy, "\n" + tttg.displayMoves() + "\nIt was a tie!");
238                                             sendMessageUnlessRobot(getBuddy(comp), "\n" + tttg.displayMoves()
239                                                 + "\nIt was a tie!");
240                                         }
241                                         games.remove(comp);
242                                         games.remove(you);
243                                     } else {
244                                         sendMessage(getBuddy(tttg.getCurrentPlayer()), "\n" + tttg.displayMoves()
245                                             + "\nSelect " + tttg.getCurrentXO() + " Move (ttt N):");
246                                     }
247                                 } else {
248                                     sendMessage(buddy, "\n" + tttg.displayMoves()
249                                         + "\nInvalid move. Type \"ttt show\" to see the current state of the game.");
250                                 }
251                             } catch (Exception e) {
252                                 logger.severe("Error: " + command + ":" + e.getMessage());
253                                 sendMessage(buddy, "Unrecognized tic tac toe command: " + command);
254                             }
255                         } else {
256                             sendMessage(buddy, "state of game not started.  sorry.");
257                         }
258                     }
259                 } else {
260                     sendMessage(buddy, "no command given!");
261                 }
262             }
263         }
264     }
265 
266 
267     /***
268      * this internal class keeps track of a tic tac toe game.
269      */
270     static class TicTacToeGame {
271         int REQUESTED = 0;
272         int STARTED = 1;
273         String[] player = new String[2];
274         char[] xo = {'x', 'o'};
275         int state = 0;
276         int currentTurn = 0;
277         char[][] board = new char[3][3];
278 
279 
280         /***
281          * Standard constructor, inits game.
282          * 
283          * @param p0
284          *            player 0
285          * @param p1
286          *            player 1
287          */
288         public TicTacToeGame(String p0, String p1) {
289             state = REQUESTED;
290             player[0] = p0;
291             player[1] = p1;
292             for (int i = 0; i < 9; i++) {
293                 board[i / 3][i % 3] = ' ';
294             }
295             currentTurn = rand.nextInt(2);
296         }
297 
298 
299         /***
300          * get the current player
301          * 
302          * @return player name
303          */
304         public String getCurrentPlayer() {
305             return player[currentTurn];
306         }
307 
308 
309         /***
310          * get current x or o
311          * 
312          * @return x or o
313          */
314         public String getCurrentXO() {
315             return "" + xo[currentTurn];
316         }
317 
318 
319         /***
320          * get player name
321          * 
322          * @param p
323          *            id of player
324          * @return name of player
325          */
326         public String getPlayerName(int p) {
327             return player[p];
328         }
329 
330 
331         /***
332          * get player number
333          * 
334          * @param p
335          *            name of player
336          * @return player number
337          */
338         public int getPlayerNumber(String p) {
339             if (p.equals(player[0])) {
340                 return 0;
341             }
342             return 1;
343         }
344 
345 
346         /***
347          * get the competitor of the current player
348          * 
349          * @param p
350          *            name of player
351          * @return competitor
352          */
353         public String getCompetitor(String p) {
354             if (p.equals(player[0])) {
355                 return player[1];
356             }
357             return player[0];
358         }
359 
360 
361         /***
362          * Decide whether the game is over or not.
363          * 
364          * @return is the game over
365          */
366         public boolean gameOver() {
367             // Either all the spaces are full, or someone won
368             if (winner() != -1) {
369                 return true;
370             }
371             for (int i = 0; i < 9; i++) {
372                 if (board[i / 3][i % 3] == ' ') {
373                     return false;
374                 }
375             }
376             return true;
377         }
378 
379 
380         /***
381          * Return the winner number
382          * 
383          * @return the winner
384          */
385         public int winner() {
386             int d1 = -1;
387             int d2 = -1;
388 
389             for (int i = 0; i < 3; i++) {
390                 int v = -1;
391                 int h = -1;
392 
393                 if (i == 0) {
394                     d1 = board[i][i];
395                     d2 = board[2 - i][i];
396                 } else {
397                     if (board[i][i] != d1) {
398                         d1 = -1;
399                     }
400                     if (board[2 - i][i] != d2) {
401                         d2 = -1;
402                     }
403                 }
404                 for (int j = 0; j < 3; j++) {
405                     if (j == 0) {
406                         v = board[i][j];
407                         h = board[j][i];
408                     } else {
409                         if (board[i][j] != v) {
410                             v = -1;
411                         }
412                         if (board[j][i] != h) {
413                             h = -1;
414                         }
415                     }
416                 }
417                 if ((v != -1) && (v != ' ')) {
418                     return ((v == xo[0]) ? 0 : 1);
419                 }
420                 if ((h != -1) && (h != ' ')) {
421                     return ((h == xo[0]) ? 0 : 1);
422                 }
423             }
424             if ((d1 != -1) && (d1 != ' ')) {
425                 return ((d1 == xo[0]) ? 0 : 1);
426             }
427             if ((d2 != -1) && (d2 != ' ')) {
428                 return ((d2 == xo[0]) ? 0 : 1);
429             }
430 
431             return -1;
432         }
433 
434 
435         /***
436          * Computer's move. Randomly select a location.
437          */
438         public void computerMove() {
439             if ((currentTurn == 1) && !gameOver()) {
440                 int n = rand.nextInt(9);
441                 while (board[n / 3][n % 3] != ' ') {
442                     n = rand.nextInt(9);
443                 }
444                 board[n / 3][n % 3] = xo[1];
445                 currentTurn = 0;
446             }
447         }
448 
449 
450         /***
451          * handle a player's move.
452          * 
453          * @param playerName
454          *            players name
455          * @param loc
456          *            location on the board
457          * @return valid move
458          */
459         public boolean playerMove(String playerName, int loc) {
460             if ((loc < 1) || (loc > 9)) {
461                 return false;
462             }
463             if (getCurrentPlayer().equalsIgnoreCase(playerName)) {
464                 loc = loc - 1;
465                 if (board[loc % 3][loc / 3] == ' ') {
466                     board[loc % 3][loc / 3] = xo[currentTurn];
467                     currentTurn = (currentTurn + 1) % 2;
468                     return true;
469                 } else {
470                     return false;
471                 }
472             } else {
473                 return false;
474             }
475         }
476 
477 
478         /***
479          * display the possible moves.
480          * 
481          * @return ttt board
482          */
483         public String displayMoves() {
484             String b = "";
485             for (int i = 0; i < 3; i++) { // Y dir
486                 for (int j = 0; j < 3; j++) { // X dir
487                     if (board[j][i] == ' ') {
488                         b += ((i * 3) + (j + 1));
489                     } else {
490                         b += "<b>" + board[j][i] + "</b>";
491                     }
492                     if (j != 2) {
493                         b += "|";
494                     } else {
495                         b += "\n";
496                     }
497                 }
498                 if (i != 2) {
499                     b += "-+-+-\n";
500                 }
501             }
502             return b;
503         }
504     }
505 }