1. // TIC TAC TOE
  2. // A server script for ArtyOnline server application
  3. // by Arty-fishL
  4. // 4 Aug 2012
  5. /* ----------
  6. * IMPORTS
  7. */
  8. /* ----------
  9. * VARIABLES
  10. */
  11. var
  12. started = false,
  13. xPlayer = null,
  14. oPlayer = null,
  15. mrStage = 0,
  16. readyX = false,
  17. readyO = false,
  18. whosGo = null;
  19. // board
  20. var
  21. line1 = [0, 0, 0],
  22. line2 = [0, 0, 0],
  23. line3 = [0, 0, 0];
  24. /* ----------
  25. * FUNCTIONS
  26. */
  27. function menuDisplayPlayers() {
  28. // shows who is playing
  29. if(xPlayer != null)
  30. print("X: " + xPlayer.getUsername());
  31. else
  32. print("X: NOT SET YET");
  33. if(oPlayer != null)
  34. print("O: " + oPlayer.getUsername());
  35. else
  36. print("O: NOT SET YET");
  37. }
  38. function menuDisplayBoard() {
  39. // shows the current game board
  40. print("_____");
  41. var board = [line1, line2, line3];
  42. for(v in board) {
  43. var text = " ";
  44. for(i in board[v]) {
  45. if(board[v][i] === 1)
  46. text += "X ";
  47. else if(board[v][i] === 2)
  48. text += "O ";
  49. else
  50. text += "# ";
  51. }
  52. print(text);
  53. }
  54. print("_____");
  55. }
  56. function menuInformHurryUp() {
  57. // tell the current player to hurry up
  58. if(whosGo != null) {
  59. print("Telling " + whosGo.getUsername() + " to hurry up");
  60. var message = Messages.SimpleMessage(whosGo, Messages.MessageBank.get("hurry up"), []);
  61. Messages.sendMessage(message);
  62. } else {
  63. print("ERROR: The game has not started yet");
  64. }
  65. }
  66. function setupCustomMenu() {
  67. // sets up a custom menu for the server application
  68. var
  69. customMenu = AppUtil.SimpleMenu("Game");
  70. displayPlayersItem = AppUtil.SimpleMenu.SimpleMenuItem("Display Players", menuDisplayPlayers);
  71. displayBoardItem = AppUtil.SimpleMenu.SimpleMenuItem("Display Game Board", menuDisplayBoard);
  72. hurryUpItem = AppUtil.SimpleMenu.SimpleMenuItem("Tell Current Player To Hurry Up", menuInformHurryUp);
  73. customMenu.add(displayPlayersItem);
  74. customMenu.add(displayBoardItem);
  75. customMenu.add(hurryUpItem);
  76. AppUtil.enableCustomGuiScriptMenu(customMenu);
  77. }
  78. function setupGame() {
  79. // randomly choose x and o player
  80. if (Math.round( Math.random() ) === 0) {
  81. // first player is x
  82. xPlayer = Users.getUsers()[0];
  83. oPlayer = Users.getUsers()[1];
  84. } else {
  85. // second player is x
  86. xPlayer = Users.getUsers()[1];
  87. oPlayer = Users.getUsers()[0];
  88. }
  89. // randomly choose who plays first
  90. if (Math.round( Math.random() ) === 0) {
  91. // x goes first
  92. whosGo = xPlayer;
  93. } else {
  94. // o goes first
  95. whosGo = oPlayer;
  96. }
  97. // inform who is playing what
  98. print("X: " + xPlayer.getUsername() + ", O: " + oPlayer.getUsername());
  99. var xoro = null;
  100. if(whosGo.getUsername() === xPlayer.getUsername()) {
  101. xoro = "X";
  102. } else {
  103. xoro = "O";
  104. }
  105. print(whosGo.getUsername() + " (" + xoro + ") is playing first");
  106. var message = Messages.SimpleMessage(xPlayer, Messages.MessageBank.get("play as"), Messages.Var.getVarsFromArray(["x", (whosGo === xPlayer), oPlayer.getUsername()]));
  107. Messages.sendMessage(message);
  108. message = Messages.SimpleMessage(oPlayer, Messages.MessageBank.get("play as"), Messages.Var.getVarsFromArray(["o", (whosGo === oPlayer), xPlayer.getUsername()]));
  109. Messages.sendMessage(message);
  110. // replies will be received in onMessageReceived event
  111. mrStage = 1;
  112. }
  113. function replyWhoXO(message) {
  114. // - reply to who is x and o
  115. if (message.getMessage() === Messages.MessageBank.get("understood")) {
  116. // confirmed player is ready
  117. if (message.getUser().getUsername() === xPlayer.getUsername()) {
  118. readyX = true;
  119. } else if (message.getUser().getUsername() === oPlayer.getUsername()) {
  120. readyO = true;
  121. } else {
  122. print("ERROR: Invalid user - " + message.getUser().getUsername());
  123. }
  124. // if both players are ready start play
  125. if (readyX && readyO) {
  126. // let play commence
  127. print("Both players ready, let play commence");
  128. mrStage = 2;
  129. informNextMove();
  130. }
  131. } else {
  132. print("ERROR: Invalid message with code: " + message.getMessage().toString())
  133. // somebody didnt understand, try sending again
  134. var message2 = null;
  135. if (message.getUser().getUsername() === xPlayer.getUsername()) {
  136. message2 = Messages.SimpleMessage(message.getUser(), Messages.MessageBank.get("play as"), [Messages.Var("x")]);
  137. } else if (message.getUser().getUsername() === oPlayer.getUsername()) {
  138. message2 = Messages.SimpleMessage(message.getUser(), Messages.MessageBank.get("play as"), [Messages.Var("o")]);
  139. }
  140. Messages.sendMessage(message2);
  141. }
  142. }
  143. function changePlayer() {
  144. // next persons go
  145. if (whosGo.getUsername() === xPlayer.getUsername()) {
  146. whosGo = oPlayer;
  147. } else {
  148. whosGo = xPlayer;
  149. }
  150. }
  151. function checkForWin() {
  152. // check to see if a player has won
  153. var
  154. sequence = line1.concat(line2, line3),
  155. winningSequences = [
  156. ["tl", "tm", "tr"] ,
  157. ["ml", "mm", "mr"] ,
  158. ["bl", "bm", "br"] ,
  159. ["tl", "ml", "bl"] ,
  160. ["tm", "mm", "bm"] ,
  161. ["tr", "mr", "br"] ,
  162. ["tl", "mm", "br"] ,
  163. ["tr", "mm", "bl"]
  164. ],
  165. playingPiece = 0;
  166. if (whosGo.getUsername() === xPlayer.getUsername()) {
  167. playingPiece = 1;
  168. } else {
  169. playingPiece = 2;
  170. }
  171. var placeMap = {
  172. 0: "tl", 1: "tm", 2: "tr",
  173. 3: "ml", 4: "mm", 5: "mr",
  174. 6: "bl", 7: "bm", 8: "br"
  175. },
  176. playedPlaces = [];
  177. for (i=0; i<9; i++) {
  178. if (sequence[i] === playingPiece) {
  179. playedPlaces.push(placeMap[i]);
  180. }
  181. }
  182. for (i=0; i < winningSequences.length; i++) {
  183. if (playedPlaces.indexOf(winningSequences[i][0]) > -1 && playedPlaces.indexOf(winningSequences[i][1]) > -1 && playedPlaces.indexOf(winningSequences[i][2]) > -1) {
  184. // matched a winning sequence
  185. return true;
  186. }
  187. }
  188. // no winning matches
  189. return false;
  190. }
  191. function checkForTie() {
  192. // check to see if no player has won
  193. var board = [line1, line2, line3];
  194. for(v in board) {
  195. for(i in board[v]) {
  196. if(board[v][i] === 0)
  197. // found an empty space, so cannot be a tie
  198. return false;
  199. }
  200. }
  201. // no 0 (empty space) found, is a tie
  202. return true
  203. }
  204. function informCurrentMove(line, box) {
  205. var xoro = null;
  206. if(whosGo.getUsername() === xPlayer.getUsername()) {
  207. xoro = "X";
  208. } else {
  209. xoro = "O";
  210. }
  211. print(whosGo.getUsername() + " placed an " + xoro + " at (" + (box + 1).toString() + ", " + line.toString() + ")");
  212. var mp = null;
  213. if (whosGo.getUsername() === xPlayer.getUsername()) {
  214. mp = oPlayer;
  215. } else {
  216. mp = xPlayer;
  217. }
  218. var message = Messages.SimpleMessage(mp, Messages.MessageBank.get("other player moved"), Messages.Var.getVarsFromArray([line, box]));
  219. Messages.sendMessage(message);
  220. }
  221. function informNextMove() {
  222. var xoro = null;
  223. if(whosGo.getUsername() === xPlayer.getUsername()) {
  224. xoro = "X";
  225. } else {
  226. xoro = "O";
  227. }
  228. print("It is now " + whosGo.getUsername() + "'s (" + xoro + ") go");
  229. var message = Messages.SimpleMessage(whosGo, Messages.MessageBank.get("your go"), []);
  230. Messages.sendMessage(message);
  231. }
  232. function informWinner() {
  233. var winner = "";
  234. if (whosGo.getUsername() === xPlayer.getUsername()) {
  235. winner = "X";
  236. print("X won (" + xPlayer.getUsername() + ")");
  237. } else {
  238. winner = "O";
  239. print("O won (" + oPlayer.getUsername() + ")");
  240. }
  241. var message = Messages.SimpleMessage(xPlayer, Messages.MessageBank.get("winner"), [Messages.Var(winner)]);
  242. Messages.sendMessage(message);
  243. message = Messages.SimpleMessage(oPlayer, Messages.MessageBank.get("winner"), [Messages.Var(winner)]);
  244. Messages.sendMessage(message);
  245. }
  246. function informTie() {
  247. var winner = "tie";
  248. var message = Messages.SimpleMessage(xPlayer, Messages.MessageBank.get("winner"), [Messages.Var(winner)]);
  249. Messages.sendMessage(message);
  250. message = Messages.SimpleMessage(oPlayer, Messages.MessageBank.get("winner"), [Messages.Var(winner)]);
  251. Messages.sendMessage(message);
  252. }
  253. function makeMove(message) {
  254. // current player chose position
  255. var
  256. line = message.getVars()[0].asInt();
  257. box = message.getVars()[1].asInt();
  258. xo = 0;
  259. if( (0 < line < 4) && (0 <= box < 3) ) {
  260. // valid move
  261. if (whosGo.getUsername() === xPlayer.getUsername()) {
  262. xo = 1;
  263. } else {
  264. xo = 2;
  265. }
  266. if(line === 1) {
  267. // play in line 1
  268. line1[box] = xo;
  269. } else if(line === 2) {
  270. // play in line 2
  271. line2[box] = xo;
  272. } else if(line === 3) {
  273. // play in line 3
  274. line3[box] = xo;
  275. }
  276. // use move data
  277. informCurrentMove(line, box);
  278. if (checkForWin() === false) {
  279. if (checkForTie() === false) {
  280. // next move
  281. changePlayer();
  282. informNextMove();
  283. } else {
  284. // tie game
  285. resetBoard();
  286. informTie();
  287. changePlayer();
  288. }
  289. } else {
  290. // somebody won
  291. resetBoard();
  292. informWinner();
  293. changePlayer();
  294. }
  295. } else {
  296. // invalid move
  297. // kick player for possible cheating
  298. message.getUser().kick("Invalid move was played")
  299. }
  300. }
  301. function resetBoard() {
  302. // reset for a new round
  303. line1 = [0, 0, 0];
  304. line2 = [0, 0, 0];
  305. line3 = [0, 0, 0];
  306. readyX = false;
  307. readyY = false;
  308. mrStage = 3;
  309. }
  310. function startNewRound(message) {
  311. // game is over and player is ready to start a new round
  312. if (message.getUser().getUsername() === xPlayer.getUsername()) {
  313. readyX = true;
  314. } else if (message.getUser().getUsername() === oPlayer.getUsername()) {
  315. readyO = true;
  316. } else {
  317. print("ERROR: Invalid user - " + message.getUser().getUsername());
  318. }
  319. // if both players are ready start round
  320. if (readyX && readyO) {
  321. // let round commence
  322. print("\nNew round");
  323. print("Both players ready, let play commence");
  324. mrStage = 2;
  325. informNextMove();
  326. }
  327. }
  328. /* ---------
  329. * EVENTS
  330. */
  331. Events.onLoad = function(vars) {
  332. // SETUP
  333. // limit players to 2
  334. Users.setMaxUsers(2);
  335. // add messages to message bank
  336. Messages.MessageBank.add( ["wait other player", "play as", "understood", "your go", "make move", "other player moved", "winner", "hurry up", "ready next round"] );
  337. // setup custom menu
  338. setupCustomMenu();
  339. };
  340. Events.onJoin = function(vars){
  341. // wait for 2 players to join
  342. if (Users.getUsers().length === 2) {
  343. // start game
  344. print("Game started");
  345. started = true;
  346. setupGame();
  347. } else {
  348. // still waiting for players to join
  349. print("Waiting for other player to join");
  350. // inform user who just joined
  351. var message = Messages.SimpleMessage(vars[0], Messages.MessageBank.get("wait other player"), []);
  352. Messages.sendMessage(message);
  353. }
  354. };
  355. Events.onDisconnect = function(vars){
  356. // wait for 2 players to be in game again
  357. if (Users.getUsers().length < 2) {
  358. // not enough players
  359. print("Not enough players in game");
  360. print("Restarting server ...");
  361. AppUtil.restartApplication();
  362. }
  363. };
  364. Events.onMessageReceive = function(vars) {
  365. // get message
  366. var message = vars[0];
  367. // check for various functions
  368. if (mrStage === 1) {
  369. // reply to who is x and o
  370. replyWhoXO(message);
  371. } else if (mrStage === 2 && message.getMessage() === Messages.MessageBank.get("make move") && message.getUser().getUsername() === whosGo.getUsername()) {
  372. // telling where player will move
  373. makeMove(message);
  374. } else if (mrStage === 3 && message.getMessage() === Messages.MessageBank.get("ready next round")) {
  375. // telling where player will move
  376. startNewRound(message);
  377. }
  378. };
  379. Events.onCommand = function(vars) {
  380. // print understood
  381. var command = vars[0];
  382. //print(command.getCommand());
  383. };