tictactoe.htm 43 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497
  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <title>Tic Tac Toe</title>
  5. <style type='text/css'>
  6. .Hidden {
  7. display:none;
  8. }
  9. .LB {
  10. border-left: 1px solid black;
  11. }
  12. .RB {
  13. border-right: 1px solid black;
  14. }
  15. .TB {
  16. border-top: 1px solid black;
  17. }
  18. .BB {
  19. border-bottom: 1px solid black;
  20. }
  21. .CurrentUser {
  22. background-color:yellow;
  23. }
  24. </style>
  25. <script type='text/javascript src='/Scripts/promise.js'></script>
  26. <script type='text/javascript' src='/Scripts/jquery-1.7.min.js'></script>
  27. <script type='text/javascript'>
  28. // MessageHolder is used to wait for a message response.
  29. var MessageHolder = function(messageid,method,result,reject) {
  30. var now = new Date();
  31. this.MessageID = messageid; // Every message sent has a unique id. The response will have the same id.
  32. this.Method = method; // The method that was called such as startsimplegame.
  33. this.Result = result; // The function to call if the response arrives.
  34. this.Reject = reject; // The function to call if the response is an error or times out.
  35. this.CreateDate = now.getTime()/1000; // Used to determine if this message timed out.
  36. }
  37. // Start of ChatClient object definition:
  38. var ChatClient = function() {
  39. this.Connection = 0;
  40. this.IsConnected = false;
  41. this.OnClose = 0; // You can set this to a function to run when the client closes.
  42. this.MessageHolders = [];
  43. this.NextMessageID = Math.floor(Math.random()*99999+1);
  44. this.ChatClientID = "0";
  45. // Events:
  46. this.OnClose = 0; // You can set this to a function to run when the client closes.
  47. this.SimpleGameJoined = 0; // You can set this to a function to run when a user joins a game you're in.
  48. this.SimpleGameLeft = 0; // You can set this to a function to run when a user leaves a game you're in.
  49. this.SimpleGameReceivedChat = 0; // You can set this to a function to run when a chat message arrives from a game you're in.
  50. this.SimpleGameDataChanged = 0; // You can set this to a function to run when a simple game has a data change.
  51. this.SimpleGameUsers = 0; // You can set this to a function to run when a simple game changes the list of users.
  52. this.SimpleGameUserData = 0; // You can set this to a function to run when a simple game user data changes.
  53. }
  54. ChatClient.prototype.RejectOldMessages = function(ageInSeconds)
  55. {
  56. var count = this.MessageHolders.length;
  57. var loop;
  58. var message;
  59. var old = [];
  60. if (count == 0) {
  61. return;
  62. }
  63. var now = new Date();
  64. var expired = now.getTime() / 1000 - ageInSeconds;
  65. for(loop = count-1;loop >= 0;loop--) {
  66. message = this.MessageHolders[loop];
  67. if (message.CreateDate < expired) {
  68. this.MessageHolders.splice(loop,1);
  69. old.push(message);
  70. }
  71. }
  72. count = old.length;
  73. for(loop=0;loop<count;loop++) {
  74. message = old[loop];
  75. if (message.Reject) {
  76. message.Reject("Message timeout.");
  77. }
  78. }
  79. }
  80. // Parses the parameters of a chat return data. Returns an array of parameters or an error string.
  81. // types is the type of each parameter as i or s.
  82. ChatClient.prototype.ParseParameters = function(parameters,types) {
  83. var result = [];
  84. var pos = 0;
  85. var search;
  86. var len;
  87. var loop;
  88. for(loop=1;loop<=types.length;loop++) {
  89. switch (types.substring(loop-1,loop)) {
  90. case "i": {
  91. // Integer
  92. search = parameters.indexOf(',',pos);
  93. if (search < 0) {
  94. if (loop == types.length) {
  95. len = parseInt(parameters.substring(pos,parameters.length));
  96. pos = parameters.length;
  97. } else {
  98. return "parameter " + loop + " was incorrect in ("+types+")";
  99. }
  100. } else {
  101. len = parseInt(parameters.substring(pos,search));
  102. pos = search + 1;
  103. }
  104. result.push(len);
  105. break;
  106. }
  107. case "s": {
  108. // String. The string length then a comma then the string.
  109. search = parameters.indexOf(',',pos);
  110. if (search < 0) {
  111. return "parameter " + loop + " was incorrect in ("+types+")";
  112. }
  113. len = parseInt(parameters.substring(pos,search));
  114. pos = search + 1;
  115. if ((len < 0) || (pos + len > parameters.length)) {
  116. return "parameter " +loop + " was incorrect in ("+types+")";
  117. }
  118. result.push(parameters.substring(pos,pos+len));
  119. pos += len;
  120. break;
  121. }
  122. case "v": {
  123. // The rest of the parameter is a variable size list of strings.
  124. while(pos < parameters.length) {
  125. search = parameters.indexOf(',',pos);
  126. if (search < 0) {
  127. break;
  128. }
  129. len = parseInt(parameters.substring(pos,search));
  130. pos = search + 1;
  131. if ((len < 0) || (pos + len > parameters.length)) {
  132. return "parameter " +loop + " was incorrect in ("+types+")";
  133. }
  134. result.push(parameters.substring(pos,pos+len));
  135. pos += len;
  136. }
  137. break;
  138. }
  139. default: {
  140. return "parameter " + loop + " was incorrect in ("+types+")";
  141. }
  142. }
  143. }
  144. return result;
  145. }
  146. ChatClient.prototype.FindMessageHolderByMessageID = function(messageid) {
  147. var count = this.MessageHolders.length;
  148. var loop;
  149. for(loop=0;loop<count;loop++) {
  150. if (this.MessageHolders[loop].MessageID === messageid) {
  151. return loop;
  152. }
  153. }
  154. return -1;
  155. }
  156. ChatClient.prototype.FindMessageHolderByMethod = function(method) {
  157. var count = this.MessageHolders.length;
  158. var loop;
  159. for(loop=0;loop<count;loop++) {
  160. if (this.MessageHolders[loop].Method === method) {
  161. return loop;
  162. }
  163. }
  164. return -1;
  165. }
  166. ChatClient.prototype.ProcessMessage = function(message) {
  167. var start = message.indexOf("(");
  168. var method = "";
  169. var parameters;
  170. var parsed;
  171. var search;
  172. var index;
  173. var holder;
  174. if ((start > 0) && (message.substring(message.length-1,message.length) == ")")) {
  175. method = message.substring(0,start);
  176. parameters = message.substring(start+1,message.length-1);
  177. }
  178. switch (method) {
  179. case "yourchatclientid": {
  180. parsed = this.ParseParameters(parameters,"i");
  181. if (parsed.length == 1) {
  182. this.ChatClientID = parsed[0];
  183. }
  184. index = this.FindMessageHolderByMethod(method);
  185. if (index >= 0) {
  186. holder = this.MessageHolders[index];
  187. this.MessageHolders.splice(index,1);
  188. holder.Result(parsed[0]);
  189. }
  190. break;
  191. }
  192. case "error": {
  193. parsed = this.ParseParameters(parameters,"si");
  194. if ((typeof parsed === 'string') || (parsed instanceof String)) {
  195. alert("Error:" + parsed+"\nmessage="+message);
  196. } else {
  197. if (parsed[1] != '0') {
  198. index = this.FindMessageHolderByMessageID(parsed[1]);
  199. if (index >= 0) {
  200. holder = this.MessageHolders[index];
  201. this.MessageHolders.splice(index,1);
  202. holder.Reject(parsed[0]);
  203. break;
  204. }
  205. }
  206. // This is a programming error.
  207. alert("Error:Error message =\n"+parsed[0]);
  208. }
  209. break;
  210. }
  211. case "success": {
  212. parsed = this.ParseParameters(parameters,"i");
  213. index = this.FindMessageHolderByMessageID(parsed[0]);
  214. if (index >= 0) {
  215. holder = this.MessageHolders[index];
  216. this.MessageHolders.splice(index,1);
  217. holder.Result(0);
  218. }
  219. break;
  220. }
  221. case "simplegameleave": {
  222. parsed = this.ParseParameters(parameters,"isss");
  223. index = this.FindMessageHolderByMessageID(parsed[0]);
  224. if (index >= 0) {
  225. holder = this.MessageHolders[index];
  226. this.MessageHolders.splice(index,1);
  227. holder.Result(parsed);
  228. break;
  229. }
  230. if (this.SimpleGameLeft !== 0) {
  231. this.SimpleGameLeft(parsed);
  232. }
  233. break;
  234. }
  235. case "simplegamestarted": {
  236. parsed = this.ParseParameters(parameters,"is");
  237. index = this.FindMessageHolderByMessageID(parsed[0]);
  238. if (index >= 0) {
  239. holder = this.MessageHolders[index];
  240. this.MessageHolders.splice(index,1);
  241. holder.Result(parsed[1]);
  242. }
  243. break;
  244. }
  245. case "simplegamejoined": {
  246. parsed = this.ParseParameters(parameters,"issv");
  247. index = this.FindMessageHolderByMessageID(parsed[0]);
  248. if (index < 0) {
  249. index = this.FindMessageHolderByMethod(method);
  250. }
  251. if (index >= 0) {
  252. holder = this.MessageHolders[index];
  253. this.MessageHolders.splice(index,1);
  254. holder.Result(parsed); // parsed = [messageid,gameid,gamedata,user list]
  255. break;
  256. }
  257. if (this.SimpleGameJoined !== 0) {
  258. this.SimpleGameJoined(parsed);
  259. }
  260. break;
  261. }
  262. case "simplegamedata": {
  263. parsed = this.ParseParameters(parameters,"isss");
  264. index = this.FindMessageHolderByMessageID(parsed[0]);
  265. if (index >= 0) {
  266. holder = this.MessageHolders[index];
  267. this.MessageHolders.splice(index,1);
  268. holder.Result(parsed);
  269. break;
  270. }
  271. if (this.SimpleGameDataChanged !== 0) {
  272. this.SimpleGameDataChanged(parsed);
  273. }
  274. break;
  275. }
  276. case "simplegameusers": {
  277. parsed = this.ParseParameters(parameters,"isv");
  278. if (parsed[0] != 0) {
  279. index = this.FindMessageHolderByMessageID(parsed[0]);
  280. if (index >= 0) {
  281. holder = this.MessageHolders[index];
  282. this.MessageHolders.splice(index,1);
  283. holder.Result(parsed);
  284. break;
  285. }
  286. }
  287. if (this.SimpleGameUsers !== 0) {
  288. this.SimpleGameUsers(parsed);
  289. }
  290. break;
  291. }
  292. case "simplegamechat": {
  293. parsed = this.ParseParameters(parameters,"isss");
  294. index = this.FindMessageHolderByMessageID(parsed[0]);
  295. if (index >= 0) {
  296. holder = this.MessageHolders[index];
  297. this.MessageHolders.splice(index,1);
  298. holder.Result(parsed);
  299. break;
  300. }
  301. if (this.SimpleGameReceivedChat !== 0) {
  302. this.SimpleGameReceivedChat(parsed);
  303. }
  304. break;
  305. }
  306. case "simplegameuserdata": {
  307. parsed = this.ParseParameters(parameters,"isss");
  308. index = this.FindMessageHolderByMessageID(parsed[0]);
  309. if (index >= 0) {
  310. holder = this.MessageHolders[index];
  311. this.MessageHolders.splice(index,1);
  312. holder.Result(parsed);
  313. break;
  314. }
  315. if (this.SimpleGameUserData !== 0) {
  316. this.SimpleGameUserData(parsed);
  317. }
  318. break;
  319. }
  320. default: {
  321. alert("Error 2:" + message);
  322. break;
  323. }
  324. }
  325. }
  326. // Connect to the server.
  327. ChatClient.prototype.Connect = function() {
  328. var that = this;
  329. that.IsConnected = false;
  330. var promise = new Promise(function(result,reject) {
  331. try {
  332. if ((that.Connection !== 0) && (that.Connection.readyState === WebSocket.OPEN)) {
  333. if (result) {
  334. result();
  335. }
  336. return;
  337. }
  338. that.Connection = new WebSocket((document.URL.toLowerCase().substring(0,5)=="https" ? 'wss' : 'ws') +'://' + document.domain + ':' + location.port + '/websocket/','chatroom-protocol');
  339. that.Connection.onopen = function() {
  340. that.IsConnected = true;
  341. if (result) {
  342. result();
  343. }
  344. }
  345. that.Connection.onerror = function(e) {
  346. that.IsConnected = false;
  347. if (reject) {
  348. reject("Error connecting to the server.");
  349. }
  350. }
  351. that.Connection.onclose = function() {
  352. that.IsConnected = false;
  353. if (that.OnClose !== 0) {
  354. that.OnClose();
  355. }
  356. }
  357. that.Connection.onmessage = function(e) {
  358. that.ProcessMessage(e.data);
  359. }
  360. } catch(err) {
  361. if (reject) {
  362. reject(err);
  363. }
  364. }
  365. });
  366. return promise;
  367. }
  368. // Disconnect from the server.
  369. ChatClient.prototype.Disconnect = function() {
  370. if ((this.Connection !== 0) && (this.Connection.readyState === WebSocket.OPEN)) {
  371. this.Connection.close();
  372. } else {
  373. if (this.OnClose !== 0) {
  374. this.OnClose();
  375. }
  376. }
  377. }
  378. ChatClient.prototype.StartSimpleGame = function(gameid,player1name,gamedata) {
  379. var that = this;
  380. var promise = new Promise(function(result,reject) {
  381. var messageholder = new MessageHolder(that.NextMessageID++,"startsimplegame",result,reject);
  382. that.MessageHolders.push(messageholder);
  383. var message = "startsimplegame("+messageholder.MessageID+","+gameid.length+","+gameid+player1name.length+","+player1name+gamedata.length+","+gamedata+")";
  384. that.Connection.send(message);
  385. });
  386. return promise;
  387. }
  388. ChatClient.prototype.JoinSimpleGame = function(gameid,username,gamedata) {
  389. var that = this;
  390. var promise = new Promise(function(result,reject) {
  391. var messageholder = new MessageHolder(that.NextMessageID++,"simplegamejoined",result,reject);
  392. that.MessageHolders.push(messageholder);
  393. var message = "joinsimplegame("+messageholder.MessageID+","+gameid.length+","+gameid+username.length+","+username+gamedata.length+","+gamedata+")";
  394. that.Connection.send(message);
  395. });
  396. return promise;
  397. }
  398. ChatClient.prototype.SimpleGameChat = function(gameid,username,output_message) {
  399. var that = this;
  400. var promise = new Promise(function(result,reject) {
  401. var messageholder = new MessageHolder(that.NextMessageID++,"simplegamechat",result,reject);
  402. that.MessageHolders.push(messageholder);
  403. var message = "simplegamechat("+messageholder.MessageID+","+gameid.length+","+gameid+username.length+","+username+output_message.length+","+output_message+")";
  404. that.Connection.send(message);
  405. });
  406. return promise;
  407. }
  408. ChatClient.prototype.SimpleGameSetData = function(gameid,offset,newgamedata) {
  409. var that = this;
  410. var promise = new Promise(function(result,reject) {
  411. var messageholder = new MessageHolder(that.NextMessageID++,"simplegamedata",result,reject);
  412. that.MessageHolders.push(messageholder);
  413. var message = "simplegamesetdata("+messageholder.MessageID+","+gameid.length+","+gameid+offset+","+newgamedata.length+","+newgamedata+")";
  414. that.Connection.send(message);
  415. });
  416. return promise;
  417. }
  418. ChatClient.prototype.SimpleGameGetUsers = function(gameid) { // get the list of users in a game.
  419. var that = this;
  420. var promise = new Promise(function(result,reject) {
  421. var messageholder = new MessageHolder(that.NextMessageID++,"simplegameusers",result,reject);
  422. that.MessageHolders.push(messageholder);
  423. var message = "simplegameusers("+messageholder.MessageID+","+gameid.length+","+gameid+")";
  424. that.Connection.send(message);
  425. });
  426. return promise;
  427. }
  428. ChatClient.prototype.LeaveSimpleGame = function(gameid,offset,newgamedata) {
  429. var that = this;
  430. var promise = new Promise(function(result,reject) {
  431. var messageholder = new MessageHolder(that.NextMessageID++,"simplegameleave",result,reject);
  432. that.MessageHolders.push(messageholder);
  433. var message = "leavesimplegame("+messageholder.MessageID+","+gameid.length+","+gameid+offset+","+newgamedata.length+","+newgamedata+")";
  434. that.Connection.send(message);
  435. });
  436. return promise;
  437. }
  438. ChatClient.prototype.SimpleGameUserSetData = function(gameid,username,userdata) {
  439. var that = this;
  440. var promise = new Promise(function(result,reject) {
  441. var messageholder = new MessageHolder(that.NextMessageID++,"success",result,reject);
  442. that.MessageHolders.push(messageholder);
  443. var message = "simplegameusersetdata("+messageholder.MessageID+","+gameid.length+","+gameid+username.length+","+username+userdata.length+","+userdata+")";
  444. that.Connection.send(message);
  445. });
  446. return promise;
  447. }
  448. ChatClient.prototype.SimpleGameUserGetData = function(gameid,username) {
  449. var that = this;
  450. var promise = new Promise(function(result,reject) {
  451. var messageholder = new MessageHolder(that.NextMessageID++,"simplegameuserdata",result,reject);
  452. that.MessageHolders.push(messageholder);
  453. var message = "simplegameusergetdata("+messageholder.MessageID+","+gameid.length+","+gameid+username.length+","+username+")";
  454. that.Connection.send(message);
  455. });
  456. return promise;
  457. }
  458. ChatClient.prototype.Nop = function() {
  459. this.Connection.send("nop()");
  460. }
  461. // Start of TicTacToe object
  462. var TicTacToe = function() {
  463. this.Client = 0;
  464. this.GameID = 0;
  465. this.Winner = "None";
  466. this.KeepAlive();
  467. this.RejectOldMessages();
  468. this.GameType = 0;
  469. this.Users = []; // An array of username,Up/Down
  470. this.UserData = []; // An array of username/userdata.
  471. };
  472. TicTacToe.prototype.RejectOldMessages = function() {
  473. var that = this;
  474. if (this.Client !== 0) {
  475. this.Client.RejectOldMessages(10);
  476. }
  477. setTimeout(function() {
  478. that.RejectOldMessages();
  479. },2000);
  480. }
  481. TicTacToe.prototype.KeepAlive = function() {
  482. var that = this;
  483. if ((this.Client !== 0) && (this.Client.IsConnected)) {
  484. this.Client.Nop();
  485. }
  486. setTimeout(function() {
  487. that.KeepAlive();
  488. },20000);
  489. }
  490. TicTacToe.prototype.CreateGameID = function() {
  491. this.GameID = Math.floor(Math.random() * 999999).toString();
  492. }
  493. TicTacToe.prototype.GetSavedUserName = function() {
  494. var username = window.localStorage.getItem("UserName");
  495. return username === null ? "" : username;
  496. }
  497. TicTacToe.prototype.GetUserData = function() {
  498. var userdata = window.localStorage.getItem("UserData");
  499. return userdata === null ? "" : userdata;
  500. }
  501. TicTacToe.prototype.SetUserData = function(userdata) {
  502. var that = this;
  503. if (window.localStorage.getItem("UserData") !== userdata) {
  504. window.localStorage.setItem("UserData",userdata);
  505. if ((this.Client !== 0) && (this.Client.IsConnected)) {
  506. var promise = this.Client.SimpleGameUserSetData(this.GameID,this.MyName,userdata);
  507. promise.then(function(result) {
  508. var count = that.UserData.length;
  509. var loop;
  510. for(loop=0;loop<count;loop+=2) {
  511. if (that.UserData[loop] === that.MyName) {
  512. that.UserData[loop+1] = userdata;
  513. loop = -1;
  514. break;
  515. }
  516. }
  517. if (loop >= 0) {
  518. that.UserData.push(that.MyName);
  519. that.UserData.push(userdata);
  520. }
  521. that.DisplayUsers();
  522. },function(errorMessage) {
  523. alert("Error 11: "+errorMessage);
  524. });
  525. }
  526. }
  527. }
  528. TicTacToe.prototype.SaveUserName = function(username) {
  529. window.localStorage.setItem("UserName", username);
  530. }
  531. TicTacToe.prototype.NewGame = function() {
  532. this.CreateGameID();
  533. $('#divGameStart').hide();
  534. $('#divPlayer1AskName').show();
  535. $('#Player1Name').val(this.GetSavedUserName());
  536. if (this.GameType === 0) {
  537. this.SetGameTypeDropDown('GameTypeID');
  538. }
  539. }
  540. TicTacToe.prototype.GetUserIndex = function(username) {
  541. var count = this.Users.length;
  542. var loop;
  543. for(loop=0;loop<count;loop+=2) {
  544. if (this.Users[loop] === username) {
  545. return loop;
  546. }
  547. }
  548. return -1;
  549. }
  550. TicTacToe.prototype.OnClose = function() {
  551. var that = this;
  552. var userindex = this.GetUserIndex(this.MyName);
  553. if (userindex >= 0) {
  554. this.Users[userindex+1] = "Down";
  555. this.DisplayUsers();
  556. if (this.GameID !== 0) {
  557. // Try to reconnect and join the game.
  558. var promise = this.ReconnectGame();
  559. promise.then(function(result) {
  560. that.Users[userindex+1] = "Up";
  561. that.DisplayUsers();
  562. },function(errorMessage) {
  563. });
  564. }
  565. }
  566. }
  567. TicTacToe.prototype.SimpleGameDataChanged = function(parameters) {
  568. var gameID = parameters[1];
  569. if (gameID !== this.GameID) {
  570. return;
  571. }
  572. this.GameData = parameters[3];
  573. var gameTypeID = this.GameData.substring(2,3);
  574. if (gameTypeID !== this.GameType.GameTypeID) {
  575. this.GameType = this.GetGameType(gameTypeID);
  576. }
  577. this.Winner = this.WhoWon();
  578. this.ShowBoard();
  579. }
  580. TicTacToe.prototype.FigureOutMySymbolBasedOnOrderInTheGame = function() {
  581. var userindex = this.GetUserIndex(this.MyName);
  582. switch (userindex) {
  583. case 0: {
  584. this.MySymbol = this.GameData.substring(0,1);
  585. break;
  586. }
  587. case 2: {
  588. this.MySymbol = this.Opposite(this.GameData.substring(0,1));
  589. break;
  590. }
  591. default:
  592. {
  593. this.MySymbol = undefined;
  594. break;
  595. }
  596. }
  597. }
  598. TicTacToe.prototype.SimpleGameUserData = function(parsed) {
  599. var count;
  600. var loop;
  601. if (parsed[1] === this.GameID) {
  602. count = this.UserData.length;
  603. for(loop=0;loop<count;loop+=2) {
  604. if (this.UserData[loop] === parsed[2]) {
  605. this.UserData[loop+1] = parsed[3];
  606. loop = -1;
  607. break;
  608. }
  609. }
  610. if (loop >= 0) {
  611. this.UserData.push(parsed[2]);
  612. this.UserData.push(parsed[3]);
  613. }
  614. this.DisplayUsers();
  615. }
  616. }
  617. TicTacToe.prototype.SimpleGameLeft = function(parsed) {
  618. // A simplegameleave message was received.
  619. if (parsed[1] != this.GameID) {
  620. return;
  621. }
  622. this.GameData = parsed[3];
  623. var count = this.Users.length;
  624. var loop;
  625. var user = parsed[2];
  626. for(loop=0;loop<count;loop+=2) {
  627. if (this.Users[loop] == user) {
  628. this.Users.splice(loop,2);
  629. this.DisplayUsers();
  630. break;
  631. }
  632. }
  633. this.FigureOutMySymbolBasedOnOrderInTheGame();
  634. this.ShowBoard();
  635. alert(user + " left the game.");
  636. }
  637. TicTacToe.prototype.CreateClient = function() {
  638. var that = this;
  639. this.Client = new ChatClient();
  640. // Add event hooks.
  641. this.Client.SimpleGameDataChanged = function(parsed) {
  642. that.SimpleGameDataChanged(parsed);
  643. };
  644. this.Client.SimpleGameLeft = function(parsed) {
  645. that.SimpleGameLeft(parsed);
  646. };
  647. this.Client.SimpleGameReceivedChat = function(parsed) {
  648. that.SimpleGameReceivedChat(parsed);
  649. }
  650. this.Client.SimpleGameUsers = function(parsed) {
  651. that.SimpleGameUsers(parsed);
  652. }
  653. this.Client.SimpleGameJoined = function(parsed) {
  654. that.SimpleGameJoined(parsed);
  655. }
  656. this.Client.SimpleGameUserData = function(parsed) {
  657. that.SimpleGameUserData(parsed);
  658. }
  659. this.Client.OnClose = function() {
  660. that.OnClose();
  661. }
  662. }
  663. TicTacToe.prototype.SimpleGameUsers = function(parameters) {
  664. if (parameters[1] == this.GameID) {
  665. parameters.splice(0,2);
  666. this.Users = parameters;
  667. this.DisplayUsers();
  668. }
  669. }
  670. TicTacToe.prototype.DisplayUsers = function() {
  671. var count = this.Users.length;
  672. var loop;
  673. var divUsers = $('#divUsers');
  674. var output = [];
  675. var userindex;
  676. var userdataCount = this.UserData.length;
  677. var userdataLoop;
  678. output.push("<table border='1'><tr><td colspan='4' align='center'>Who's Playing</td></tr><tr><td>User</td><td>Symbol</td><td>Connection</td><td>Profile</td></tr>");
  679. for(loop=0;loop<count;loop+=2) {
  680. output.push("<tr");
  681. if (this.Users[loop] === this.MyName) {
  682. output.push(" class='CurrentUser'");
  683. }
  684. output.push("><td>"+this.Users[loop] + "</td><td>");
  685. switch (loop) {
  686. case 0: {
  687. output.push(this.GameData.substring(0,1));
  688. break;
  689. }
  690. case 2: {
  691. output.push(this.Opposite(this.GameData.substring(0,1)));
  692. break;
  693. }
  694. default: {
  695. output.push("&nbsp;");
  696. break;
  697. }
  698. }
  699. if (userindex == -1) {
  700. output.push("&nbsp;");
  701. } else {
  702. if (userindex == loop) {
  703. } else {
  704. }
  705. }
  706. output.push("</td><td>"+this.Users[loop+1]+"</td>");
  707. output.push("<td");
  708. if (this.Users[loop] === this.MyName) {
  709. output.push(" id='tdUserData'");
  710. }
  711. output.push(">");
  712. for(userdataLoop=0;userdataLoop<userdataCount;userdataLoop+=2) {
  713. if (this.UserData[userdataLoop] === this.Users[loop]) {
  714. output.push(this.UserData[userdataLoop+1]
  715. .replace(/&/g, "&amp;")
  716. .replace(/</g, "&lt;")
  717. .replace(/>/g, "&gt;")
  718. .replace(/"/g, "&quot;")
  719. .replace(/'/g, "&#039;"));
  720. break;
  721. }
  722. }
  723. if (this.Users[loop] === this.MyName) {
  724. output.push("<input type='button' value='Edit' onclick='ticTacToe.EditUserData()' />");
  725. }
  726. output.push("</td></tr>");
  727. }
  728. output.push("</table>");
  729. divUsers.show();
  730. divUsers.html(output.join(""));
  731. }
  732. TicTacToe.prototype.EditUserData = function() {
  733. var count = this.UserData.length;
  734. var loop;
  735. $('#tdUserData').html("<textarea name='UserData' id='UserData' rows='6' cols='60'></textarea><br /><input type='button' value='Save' onclick='ticTacToe.SaveUserDataChanges()' /><input type='button' value='Cancel' onclick='ticTacToe.DisplayUsers()' />");
  736. for(loop=0;loop<count;loop+=2) {
  737. if (this.UserData[loop] === this.MyName) {
  738. $('#UserData').val(this.UserData[loop+1]);
  739. break;
  740. }
  741. }
  742. }
  743. TicTacToe.prototype.SaveUserDataChanges = function() {
  744. var userdata = $('#UserData').val();
  745. this.DisplayUsers();
  746. this.SetUserData(userdata);
  747. }
  748. TicTacToe.prototype.SimpleGameReceivedChat = function(parameters) {
  749. var table = $('#tblMessages')[0];
  750. var row;
  751. var cell;
  752. if (parameters[1] !== this.GameID) {
  753. return;
  754. }
  755. while (table.rows.length > 10) {
  756. table.deleteRow(1);
  757. }
  758. row = table.insertRow(table.rows.length-1);
  759. cell = row.insertCell(0);
  760. cell.innerHTML = parameters[2];
  761. cell.className = "RB";
  762. cell = row.insertCell(1);
  763. cell.innerHTML = parameters[3];
  764. }
  765. TicTacToe.prototype.SimpleGameJoined = function(parameters) {
  766. // This event is called by the server when someone joins the game.
  767. var that = this;
  768. if (parameters[1] === this.GameID) {
  769. this.GameData = parameters[2];
  770. this.GameType = this.GetGameType(this.GameData.substring(2,3));
  771. parameters.splice(0,3);
  772. this.Users = parameters;
  773. $('#divWaitingForPlayer2').hide();
  774. $('#divGameBoard').show();
  775. this.ShowBoard();
  776. this.DisplayUsers();
  777. // Request the user data for all the users.
  778. var promise = this.Client.SimpleGameUserGetData(this.GameID,"");
  779. promise.then(function(result) {
  780. },function(errorMessage) {
  781. alert("Error 13: "+errorMessage3);
  782. });
  783. }
  784. }
  785. TicTacToe.prototype.GetGameType = function(gameTypeID) {
  786. var count = this.GameTypes.length;
  787. var loop;
  788. for(loop=0;loop<count;loop++) {
  789. if (this.GameTypes[loop].GameTypeID === gameTypeID) {
  790. return this.GameTypes[loop];
  791. }
  792. }
  793. return 0;
  794. }
  795. TicTacToe.prototype.Spaces = function(length) {
  796. var output = [];
  797. var loop;
  798. for(loop=0;loop<length;loop++) {
  799. output.push(' ');
  800. }
  801. return output.join('');
  802. }
  803. TicTacToe.prototype.WantsToBe = function(XorO) {
  804. // The user is creating a new game and clicks on Wants To Be X or Wants To Be O.
  805. var that = this;
  806. this.MySymbol = XorO;
  807. this.MyName = $('#Player1Name').val();
  808. if (this.MyName.length == 0) {
  809. alert("Please enter your name.");
  810. $('#Player1Name').focus();
  811. return;
  812. }
  813. this.SaveUserName(this.MyName);
  814. this.GameType = this.GetGameType($('#GameTypeID').val());
  815. this.GameData = this.MySymbol+this.MySymbol+this.GameType.GameTypeID+this.Spaces(this.GameType.Width * this.GameType.Height);
  816. $('#divPlayer1AskName').hide();
  817. $('#divCopntactingServer').show();
  818. var userdata = this.GetUserData();
  819. this.UserData.push(this.MyName);
  820. this.UserData.push(userdata);
  821. var StartGame = function() {
  822. that.Users = [that.MyName,((that.Client === 0) || (!that.Client.IsConnected)) ? "Down" : "Up"];
  823. $('#WaitingForPlayer2GameID').html(that.GameID);
  824. var promise2 = that.Client.StartSimpleGame(that.GameID,that.MyName,that.GameData);
  825. promise2.then(function(result2) {
  826. $('#divWaitingForPlayer2').show();
  827. $('#divUsers').show();
  828. that.DisplayUsers();
  829. if (userdata !== "") {
  830. var promise3 = that.Client.SimpleGameUserSetData(that.GameID,that.MyName,userdata);
  831. promise3.then(function(result) {
  832. that.DisplayUsers();
  833. },function(errorMessage) {
  834. alert("Error 13: "+errorMessage);
  835. });
  836. }
  837. },function(errorMessage2) {
  838. alert("Error 3:" + errorMessage2);
  839. $('#divWaitingForPlayer2').hide();
  840. $('#divGameStart').show();
  841. });
  842. }
  843. if (this.Client === 0) {
  844. this.CreateClient();
  845. }
  846. if (this.Client.IsConnected) {
  847. StartGame();
  848. } else {
  849. var promise = this.Client.Connect();
  850. promise.then(function(result) {
  851. StartGame();
  852. },function(errorMessage) {
  853. alert("Error 4:" + errorMessage);
  854. $('#divContactingServer').hide();
  855. $('#divGameStart').show();
  856. });
  857. }
  858. }
  859. TicTacToe.prototype.ReconnectGame = function() {
  860. // When the connection fails during a game, reconnect, then rejoin the game.
  861. var that = this;
  862. var promise = new Promise(function(result,reject) {
  863. var promise2 = that.Client.Connect();
  864. promise2.then(function(result2) {
  865. var promise3 = that.Client.JoinSimpleGame(that.GameID,that.MyName,"");
  866. promise3.then(function(result3) {
  867. if (result) {
  868. result(result3);
  869. }
  870. },function(errorMessage3) {
  871. if (reject) {
  872. reject(errorMessage3);
  873. }
  874. });
  875. },function(errorMessage2) {
  876. if (reject) {
  877. reject(errorMessage2);
  878. }
  879. });
  880. });
  881. return promise;
  882. }
  883. TicTacToe.prototype.Choose = function(spot) {
  884. // This is called when the player clicks on an empty square.
  885. // spot is between 0 and this.GameType.Width * this.GameType.Height - 1
  886. var that = this;
  887. var oldGameData;
  888. var yourTurn = this.Opposite(this.MySymbol);
  889. oldGameData = this.GameData;
  890. this.GameData = this.GameData.substring(0,1) + yourTurn + this.GameType.GameTypeID + this.GameData.substring(3,spot+3)+this.MySymbol+this.GameData.substring(spot+4,this.GameData.length);
  891. this.Winner = this.WhoWon();
  892. this.ShowBoard();
  893. var ReverseMove = function() {
  894. that.GameData = oldGameData;
  895. that.Winner = that.WhoWon();
  896. that.ShowBoard();
  897. }
  898. var SetData = function() {
  899. var promise = that.Client.SimpleGameSetData(that.GameID,0,that.GameData);
  900. promise.then(function(result) {
  901. that.Winner = that.WhoWon();
  902. that.ShowBoard();
  903. },function(errorMessage) {
  904. alert("Error 5:" + errorMessage);
  905. ReverseMove();
  906. });
  907. }
  908. if (this.Client.IsConnected) {
  909. SetData();
  910. } else {
  911. var promise2 = this.ReconnectGame();
  912. promise2.then(function(result2) {
  913. SetData();
  914. },function(errorMessage2) {
  915. alert("Error 8:"+errorMessage2);
  916. ReverseMove();
  917. });
  918. }
  919. }
  920. TicTacToe.prototype.Opposite = function(x) {
  921. return x === "X" ? "O" : "X";
  922. }
  923. TicTacToe.prototype.PlayAgain = function() {
  924. // The user chose the Play Again button.
  925. var that = this;
  926. this.GameType = this.GetGameType($('#GameTypeIDAgain').val());
  927. this.GameData = this.GameData.substring(0,1) + this.Opposite(this.MySymbol) + this.GameType.GameTypeID + this.Spaces(this.GameType.Width * this.GameType.Height); // The other guy goes first.
  928. this.Winner = "None";
  929. var ResetGame = function() {
  930. var promise = that.Client.SimpleGameSetData(that.GameID,0,that.GameData);
  931. $('#divContactingServer').show();
  932. $('#divGameBoard').hide();
  933. promise.then(function(result) {
  934. $('#divContactingServer').hide();
  935. $('#divGameBoard').show();
  936. that.ShowBoard();
  937. },function(errorMessage) {
  938. $('#divContactingServer').hide();
  939. alert(errorMessage);
  940. $('#divGameStart').show();
  941. });
  942. }
  943. if (this.Client.IsConnected) {
  944. ResetGame();
  945. } else {
  946. var promise2 = this.ReconnectGame();
  947. promise2.then(function(result2) {
  948. ResetGame();
  949. },function(errorMessage2) {
  950. });
  951. }
  952. }
  953. TicTacToe.prototype.WhoWon = function() {
  954. // returns X or O or Tie or None
  955. var x;
  956. var y;
  957. var z;
  958. var wasTie;
  959. var result;
  960. var gamedata;
  961. var lineLength = this.GameType.LineLength;
  962. var width = this.GameType.Width;
  963. var height = this.GameType.Height;
  964. var first;
  965. // Fill gamedata array.
  966. gamedata = [];
  967. for(x=0;x<width*height;x++) {
  968. gamedata.push(this.GameData.substring(x+3,x+4));
  969. }
  970. // Look for going across.
  971. for(x=0;x<=width-lineLength;x++) {
  972. for(y=0;y<height;y++) {
  973. first = gamedata[y * height + x];
  974. if (first === ' ') {
  975. continue;
  976. }
  977. for(z=1;z<lineLength;z++) {
  978. if (gamedata[y * height + x + z] != first) {
  979. z = -1;
  980. break;
  981. }
  982. }
  983. if (z != -1) {
  984. return first;
  985. }
  986. }
  987. }
  988. // Look for going down.
  989. for(x=0;x<width;x++) {
  990. for(y=0;y<=height-lineLength;y++) {
  991. first = gamedata[y * height + x];
  992. if (first === ' ') {
  993. continue;
  994. }
  995. for(z=1;z<lineLength;z++) {
  996. if (gamedata[(y + z) * height + x] != first) {
  997. z = -1;
  998. break;
  999. }
  1000. }
  1001. if (z != -1) {
  1002. return first;
  1003. }
  1004. }
  1005. }
  1006. // Look diagonally.
  1007. for(x=0;x<=width-lineLength;x++) {
  1008. for(y=0;y<=height-lineLength;y++) {
  1009. first = gamedata[y * height + x];
  1010. if (first !== ' ') {
  1011. for(z=1;z<lineLength;z++) {
  1012. if (gamedata[(y + z) * height + x + z] != first) {
  1013. z = -1;
  1014. break;
  1015. }
  1016. }
  1017. if (z != -1) {
  1018. return first;
  1019. }
  1020. }
  1021. // Diagonally the other way.
  1022. first = gamedata[y * height + x + lineLength - 1];
  1023. if (first !== ' ') {
  1024. for(z=1;z<lineLength;z++) {
  1025. if (gamedata[(y + z) * height + x + (lineLength - 1 - z)] != first) {
  1026. z = -1;
  1027. break;
  1028. }
  1029. }
  1030. if (z != -1) {
  1031. return first;
  1032. }
  1033. }
  1034. }
  1035. }
  1036. // Look for a tie.
  1037. wasTie = true;
  1038. for(x=width*height-1;x>=0;x--) {
  1039. if (gamedata[x] === ' ') {
  1040. wasTie = false;
  1041. }
  1042. }
  1043. return wasTie ? "Tie" : "None";
  1044. }
  1045. TicTacToe.prototype.JoinGameAskGameID = function() {
  1046. $('#divGameStart').hide();
  1047. $('#divJoinGameAskName').show();
  1048. $('#JoinGameID').val('');
  1049. $('#Player2Name').val(this.GetSavedUserName());
  1050. }
  1051. TicTacToe.prototype.MainMenu = function() {
  1052. $('#divJoinGameAskName').hide();
  1053. $('#divPlayer1AskName').hide();
  1054. if ((this.GameID === 0) || (this.Client === 0) || (!this.Client.IsConnected)) {
  1055. $('#divGameStart').show();
  1056. } else {
  1057. $('#divContactingServer').show();
  1058. var promise = this.Client.LeaveSimpleGame(this.GameID,0,"");
  1059. promise.then(function(result) {
  1060. $('#divContactingServer').hide();
  1061. $('#divGameStart').show();
  1062. },function(errorMessage) {
  1063. alert("Error leaving the game:"+errorMessage);
  1064. $('#divContactingServer').hide();
  1065. $('#divGameStart').show();
  1066. });
  1067. }
  1068. }
  1069. TicTacToe.prototype.JoinGame = function() {
  1070. var that = this;
  1071. this.MyName = $('#Player2Name').val();
  1072. this.GameID = $('#JoinGameID').val();
  1073. if (this.MyName.length == 0) {
  1074. alert("Please enter your name.");
  1075. $('#Player2Name').focus();
  1076. return;
  1077. }
  1078. if (this.GameID.length == 0) {
  1079. alert("Please enter the GameID you got from the other player.");
  1080. $('#JoinGameID').focus();
  1081. return;
  1082. }
  1083. this.SaveUserName(this.MyName);
  1084. var userdata = this.GetUserData();
  1085. this.UserData.push(this.MyName);
  1086. this.UserData.push(userdata);
  1087. $('#divJoinGameAskName').hide();
  1088. $('#divContactingServer').show();
  1089. if (this.Client === 0) {
  1090. this.CreateClient();
  1091. }
  1092. var promise2 = this.Client.Connect();
  1093. promise2.then(function(result2) {
  1094. var promise = that.Client.JoinSimpleGame(that.GameID,that.MyName,"");
  1095. promise.then(function(result) {
  1096. $('#divContactingServer').hide();
  1097. $('#divGameBoard').show();
  1098. that.GameData = result[2];
  1099. that.GameType = that.GetGameType(that.GameData.substring(2,3));
  1100. result.splice(0,3);
  1101. that.Users = result;
  1102. that.FigureOutMySymbolBasedOnOrderInTheGame();
  1103. that.Winner = that.WhoWon();
  1104. that.DisplayUsers();
  1105. that.ShowBoard();
  1106. var userdata = that.GetUserData();
  1107. if (userdata !== "") {
  1108. var promise2 = that.Client.SimpleGameUserSetData(that.GameID,that.MyName,userdata);
  1109. promise2.then(function(result) {
  1110. that.DisplayUsers();
  1111. },function(errorMessage) {
  1112. alert("Error 12: "+errorMessage);
  1113. });
  1114. }
  1115. // Request the user data for all the users.
  1116. var promise3 = that.Client.SimpleGameUserGetData(that.GameID,"");
  1117. promise3.then(function(result3) {
  1118. },function(errorMessage3) {
  1119. alert("Error 13: "+errorMessage3);
  1120. });
  1121. },function(errorMessage) {
  1122. alert("Error 6:" + errorMessage);
  1123. $('#divJoinGameAskName').show();
  1124. $('#divContactingServer').hide();
  1125. });
  1126. },function(reject2) {
  1127. });
  1128. }
  1129. TicTacToe.prototype.LeaveTheGame = function() {
  1130. // The user clicked the Leave The Game button.
  1131. var that = this;
  1132. if (this.Client === 0) {
  1133. alert("You're not connected.");
  1134. return;
  1135. }
  1136. if (this.Users[0] == this.MyName) {
  1137. // If this player is the first player in the list, reverse the first character to show that the second player, who will now be the first player, switched places.
  1138. this.GameData = this.Opposite(this.GameData.substring(0,1)) + this.GameData.substring(1,this.GameData.length);
  1139. }
  1140. var promise = this.Client.LeaveSimpleGame(this.GameID,0,this.GameData);
  1141. promise.then(function(result) {
  1142. that.SimpleGameLeft(result);
  1143. $('#divGameStart').show();
  1144. $('#divGameBoard').hide();
  1145. $('#divUsers').hide();
  1146. that.GameID = 0;
  1147. that.Client.OnClose = function() {
  1148. that.Client = 0;
  1149. }
  1150. that.Client.Disconnect();
  1151. },function(errorMessage) {
  1152. alert("Error 10:"+errorMessage);
  1153. });
  1154. }
  1155. TicTacToe.prototype.SendMessage = function() {
  1156. var that = this;
  1157. var message;
  1158. if (this.Client === 0) {
  1159. alert("You're not connected.");
  1160. return;
  1161. }
  1162. message = $('#NewMessage').val();
  1163. if (message == "") {
  1164. return;
  1165. }
  1166. var SendTheMessage = function() {
  1167. $('#btnSendMessage').attr('disabled',true);
  1168. var promise = that.Client.SimpleGameChat(that.GameID,"",message);
  1169. promise.then(function(result) {
  1170. $('#btnSendMessage').attr('disabled',false);
  1171. that.SimpleGameReceivedChat(result);
  1172. $('#NewMessage').val('');
  1173. },function(errorMessage) {
  1174. $('#btnSendMessage').attr('disabled',false);
  1175. alert("Error 7: " + errorMessage);
  1176. });
  1177. }
  1178. if (this.Client.IsConnected) {
  1179. SendTheMessage();
  1180. } else {
  1181. var promise2 = this.ReconnectGame();
  1182. promise2.then(function(result2) {
  1183. SendTheMessage();
  1184. },function(errorMessage2) {
  1185. alert("Error 9:"+errorMessage2);
  1186. });
  1187. }
  1188. }
  1189. TicTacToe.prototype.BeforePageUnload = function(event) {
  1190. if ((this.Client !== 0) && (this.Client.IsConnected) && (this.GameID !== 0)) {
  1191. this.LeaveTheGame();
  1192. }
  1193. }
  1194. TicTacToe.prototype.GameTypes = [
  1195. {
  1196. "GameTypeID":"1",
  1197. "GameName":"3 in a row (standard Tic Tac Toe)",
  1198. "Width":3,
  1199. "Height":3,
  1200. "LineLength":3
  1201. },
  1202. {
  1203. "GameTypeID":"2",
  1204. "GameName":"4 in a row (7 x 7 grid)",
  1205. "Width":7,
  1206. "Height":7,
  1207. "LineLength":4
  1208. },
  1209. {
  1210. "GameTypeID":"3",
  1211. "GameName":"5 in a row (11 x 11 grid)",
  1212. "Width":11,
  1213. "Height":11,
  1214. "LineLength":5
  1215. },
  1216. {
  1217. "GameTypeID":"4",
  1218. "GameName":"5 in a row (30 x 30 grid)",
  1219. "Width":30,
  1220. "Height":30,
  1221. "LineLength":5
  1222. }
  1223. ];
  1224. TicTacToe.prototype.BuildGameBoard = function(table,width,height)
  1225. {
  1226. var x;
  1227. var y;
  1228. var row;
  1229. var cell;
  1230. var classNames;
  1231. var width = this.GameType.Width;
  1232. var height = this.GameType.Height;
  1233. while(table.rows.length > 0) {
  1234. table.deleteRow(0);
  1235. }
  1236. for(y=0;y<height;y++) {
  1237. row = table.insertRow(-1);
  1238. for(x=0;x<width;x++) {
  1239. cell = row.insertCell(-1);
  1240. cell.innerHTML = " ";
  1241. // Create the class name.
  1242. classNames = [];
  1243. if (x > 0) {
  1244. classNames.push("LB");
  1245. }
  1246. if (x < width-1) {
  1247. classNames.push("RB");
  1248. }
  1249. if (y > 0) {
  1250. classNames.push("TB");
  1251. }
  1252. if (y < height-1) {
  1253. classNames.push("BB");
  1254. }
  1255. cell.className = classNames.join(" ");
  1256. }
  1257. }
  1258. row = table.insertRow(-1);
  1259. cell = row.insertCell(-1);
  1260. cell.colSpan = width;
  1261. cell.style.textAlign = "center";
  1262. }
  1263. TicTacToe.prototype.SetGameTypeDropDown = function(dropDownID) {
  1264. var dropdown = document.getElementById(dropDownID);
  1265. var count = this.GameTypes.length;
  1266. var loop;
  1267. var option;
  1268. for(loop=0;loop<count;loop++) {
  1269. var option = document.createElement('option');
  1270. option.text = this.GameTypes[loop].GameName;
  1271. option.value = this.GameTypes[loop].GameTypeID;
  1272. dropdown.options[loop] = option;
  1273. }
  1274. }
  1275. TicTacToe.prototype.ShowBoard = function() {
  1276. var myTurn = (this.MySymbol === this.GameData.substring(1,2));
  1277. var table = document.getElementById('GameTable');
  1278. var loop;
  1279. var row;
  1280. var cell;
  1281. var stillPlaying = (this.Winner == "None");
  1282. var width = this.GameType.Width;
  1283. var height = this.GameType.Height;
  1284. var select;
  1285. $('#spanGameBoardGameID').html(this.GameID);
  1286. $('#spanGameType').html(this.GameType.GameName);
  1287. if ((table.rows.length != height+1) || (table.rows[0].cells.length != width)) {
  1288. this.BuildGameBoard(table,width,height);
  1289. }
  1290. for(loop=0;loop<width*height;loop++) {
  1291. row = table.rows[Math.floor(loop/height)];
  1292. cell = row.cells[loop%height];
  1293. switch(this.GameData.substring(loop+3,loop+4))
  1294. {
  1295. case 'X': {
  1296. cell.innerHTML = "X";
  1297. break;
  1298. }
  1299. case 'O': {
  1300. cell.innerHTML = "O";
  1301. break;
  1302. }
  1303. default: {
  1304. if (myTurn && stillPlaying) {
  1305. cell.innerHTML = "<input type='button' value=' ' onclick='ticTacToe.Choose("+loop+")' />";
  1306. } else {
  1307. cell.innerHTML = "&nbsp;&nbsp;";
  1308. }
  1309. }
  1310. }
  1311. }
  1312. row = table.rows[height];
  1313. cell = row.cells[0];
  1314. if (stillPlaying) {
  1315. cell.innerHTML = (myTurn ? "It's your turn. You're " + this.MySymbol + ".<br />Click on an empty square." : "It's their turn. You're " + (this.MySymbol === undefined ? "not playing" : this.MySymbol)) + ". <input type='button' value='Leave The Game' onclick='ticTacToe.LeaveTheGame()' />";
  1316. } else {
  1317. select = [];
  1318. select.push("<select name='GameTypeIDAgain' id='GameTypeIDAgain'>");
  1319. for(loop=0;loop<this.GameTypes.length;loop++) {
  1320. select.push("<option value='" + this.GameTypes[loop].GameTypeID + "'");
  1321. if (this.GameTypes[loop].GameTypeID === this.GameType.GameTypeID) {
  1322. select.push(" selected");
  1323. }
  1324. select.push(">"+this.GameTypes[loop].GameName + "</option>");
  1325. }
  1326. select.push("</select>");
  1327. cell.innerHTML = (this.Winner == "Tie" ? "The game was a tie." : this.Winner + " won.") + "<br />Do you want to <input type='button' value='Play Again ?' onclick='ticTacToe.PlayAgain()' /><br />" + select.join("");
  1328. }
  1329. }
  1330. var ticTacToe = new TicTacToe();
  1331. window.addEventListener('beforeunload', (event) => {
  1332. // If the page unloads, try to have them leave the game.
  1333. ticTacToe.BeforePageUnload(event);
  1334. });
  1335. </script>
  1336. </head>
  1337. <body>
  1338. <center><h1>Tic Tac Toe</h1></center>
  1339. <form name='GameForm'>
  1340. <div id='divGameStart'>
  1341. This game was written to test a websocket server I wrote in C++ in Linux.<br />
  1342. I'm hoping to get a job using C/C++ in Windows or Linux.<br />
  1343. I didn't put a lot of work on the client side look because it's supposed to be a simple web socket example.<br />
  1344. <br />
  1345. Click <a href='websocket.zip' target='_blank'>here</a> to download the source
  1346. code to the web socket server.<br />
  1347. <input type='button' value='Create a new game' onclick='ticTacToe.NewGame()' />
  1348. <input type='button' value='Join an existing game' onclick='ticTacToe.JoinGameAskGameID()' />
  1349. </div>
  1350. <div id='divPlayer1AskName' class='Hidden'>
  1351. <table>
  1352. <tr><td>What is your name ?</td><td><input type='text' name='YourName' id='Player1Name' /></td></tr>
  1353. <tr><td>What game do you want ?</td><td><select name='GameTypeID' id='GameTypeID'></select></td></tr>
  1354. <tr><td>Do you want to be</td><td><input type='button' value='X' onclick='ticTacToe.WantsToBe("X")' /> or <input type='button' value='O' onclick='ticTacToe.WantsToBe("O")' /> ? </td></tr>
  1355. <tr><td>Or go back to the</td><td><input type='button' value='Main Menu' onclick='ticTacToe.MainMenu()' /></td></tr>
  1356. </table>
  1357. </div>
  1358. <div id='divJoinGameAskName' class='Hidden'>
  1359. <table>
  1360. <tr><td colspan='2'>To join an existing game, ask the person who</td></tr>
  1361. <tr><td colspan='2'>started the game for the GameID and</td></tr>
  1362. <tr><td>enter it here:</td><td><input type='text' name='JoinGameID' id='JoinGameID' /></td></tr>
  1363. <tr><td>Enter your name:</td><td><input type='text' name='Player2Name' id='Player2Name' /></td></tr>
  1364. <tr><td colspan='2'>Click <input type='button' value='Here' onclick='ticTacToe.JoinGame()' /> to join the game.</td></tr>
  1365. <tr><td colspan='2'>Or go back to the <input type='button' value='Main Menu' onclick='ticTacToe.MainMenu()' /></td></tr>
  1366. </table>
  1367. </div>
  1368. <div id='divWaitingForPlayer2' class='Hidden'>
  1369. Waiting for player 2 to join. Please give this<br />
  1370. GameID so they can join the game: <span id='WaitingForPlayer2GameID'></span><br />
  1371. <br />
  1372. Or give up and go back to the <input type='button' value='Main Menu' onclick='ticTacToe.MainMenu()' />
  1373. </div>
  1374. <div id='divWaitingForOtherPlayer' class='Hidden'>
  1375. Waiting for the other player. . .
  1376. </div>
  1377. <div id='divUsers' class='Hidden'>
  1378. </div>
  1379. <div id='divGameBoard' class='Hidden'>
  1380. GameID: <span id='spanGameBoardGameID'></span><br />
  1381. Game Type: <span id='spanGameType'></span><br />
  1382. <table id='GameTable'>
  1383. <tr>
  1384. <td class='RB BB'>X</td>
  1385. <td class='LB BB RB'>X</td>
  1386. <td class='LB BB'>X</td>
  1387. </tr>
  1388. <tr>
  1389. <td class='RB TB BB'>O</td>
  1390. <td class='LB RB TB BB'>O</td>
  1391. <td class='LB TB BB'>O</td>
  1392. </tr>
  1393. <tr>
  1394. <td class='RB TB'>X</td>
  1395. <td class='LB TB RB'>&nbsp;</td>
  1396. <td class='LB TB'>X</td>
  1397. </tr>
  1398. <tr>
  1399. <td colspan='3' align='center'></td>
  1400. </tr>
  1401. </table>
  1402. <br />
  1403. <div style='border:1px solid black;display:inline-block'>
  1404. <table border='0' id='tblMessages'>
  1405. <tr><td align='center' colspan='2'>Messages</td></tr>
  1406. <tr><td colspan='2'><input type='text' name='NewMessage' id='NewMessage' size='30' /><input type='button' value='Send' id='btnSendMessage' onclick='ticTacToe.SendMessage()' /></td>
  1407. </table>
  1408. </div>
  1409. </div>
  1410. <div id='divContactingServer' class='Hidden'>
  1411. Contacing the game server. Please wait.
  1412. </div>
  1413. </form>
  1414. </body>
  1415. </html>