1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
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();
142 String you = buddy.getName();
143 TicTacToeGame tttg = (TicTacToeGame) games.get(you);
144 if (tttg == null) {
145
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
154
155
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
165
166 if (games.get(competitor.getName()) != null) {
167 sendMessage(buddy, "Sorry, " + competitor.getName() + " is in another tic tac toe game.");
168 } else {
169
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
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
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++) {
486 for (int j = 0; j < 3; j++) {
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 }