12 |
13 |
14 |
21 |
(not signed in)
22 |
23 |
24 |

25 |
You must sign in to play!
26 |
27 |
28 |
29 |
30 | - |
31 | - |
32 | - |
33 |
34 |
35 | - |
36 | - |
37 | - |
38 |
39 |
40 | - |
41 | - |
42 | - |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
Recent Games
50 |
51 |
52 |
53 |
54 |
55 |
--------------------------------------------------------------------------------
/war/js/base.js:
--------------------------------------------------------------------------------
1 | // Copyright 2012 Google Inc. All Rights Reserved.
2 |
3 | /**
4 | * @fileoverview
5 | * Provides methods for the TicTacToe sample UI and interaction with the
6 | * TicTacToe API.
7 | *
8 | * @author danielholevoet@google.com (Dan Holevoet)
9 | */
10 |
11 | /** google global namespace for Google projects. */
12 | var google = google || {};
13 |
14 | /** devrel namespace for Google Developer Relations projects. */
15 | google.devrel = google.devrel || {};
16 |
17 | /** samples namespace for DevRel sample code. */
18 | google.devrel.samples = google.devrel.samples || {};
19 |
20 | /** TicTacToe namespace for this sample. */
21 | google.devrel.samples.ttt = google.devrel.samples.ttt || {};
22 |
23 | /**
24 | * Status for an unfinished game.
25 | * @type {number}
26 | */
27 | google.devrel.samples.ttt.NOT_DONE = 0;
28 |
29 | /**
30 | * Status for a victory.
31 | * @type {number}
32 | */
33 | google.devrel.samples.ttt.WON = 1;
34 |
35 | /**
36 | * Status for a loss.
37 | * @type {number}
38 | */
39 | google.devrel.samples.ttt.LOST = 2;
40 |
41 | /**
42 | * Status for a tie.
43 | * @type {number}
44 | */
45 | google.devrel.samples.ttt.TIE = 3;
46 |
47 | /**
48 | * Strings for each numerical status.
49 | * @type {Array.number}
50 | */
51 | google.devrel.samples.ttt.STATUS_STRINGS = [
52 | 'NOT_DONE',
53 | 'WON',
54 | 'LOST',
55 | 'TIE'
56 | ];
57 |
58 | /**
59 | * Whether or not the user is signed in.
60 | * @type {boolean}
61 | */
62 | google.devrel.samples.ttt.signedIn = false;
63 |
64 | /**
65 | * Whether or not the game is waiting for a user's move.
66 | * @type {boolean}
67 | */
68 | google.devrel.samples.ttt.waitingForMove = true;
69 |
70 | /**
71 | * Signs the user out.
72 | */
73 | google.devrel.samples.ttt.signout = function() {
74 | document.getElementById('signinButtonContainer').classList.add('visible');
75 | document.getElementById('signedInStatus').classList.remove('visible');
76 | google.devrel.samples.ttt.setBoardEnablement(false);
77 | google.devrel.samples.ttt.signedIn = false;
78 | }
79 |
80 | /**
81 | * Handles a square click.
82 | * @param {MouseEvent} e Mouse click event.
83 | */
84 | google.devrel.samples.ttt.clickSquare = function(e) {
85 | if (google.devrel.samples.ttt.waitingForMove) {
86 | var button = e.target;
87 | button.innerHTML = 'X';
88 | button.removeEventListener('click', google.devrel.samples.ttt.clickSquare);
89 | google.devrel.samples.ttt.waitingForMove = false;
90 |
91 | var boardString = google.devrel.samples.ttt.getBoardString();
92 | var status = google.devrel.samples.ttt.checkForVictory(boardString);
93 | if (status == google.devrel.samples.ttt.NOT_DONE) {
94 | google.devrel.samples.ttt.getComputerMove(boardString);
95 | } else {
96 | google.devrel.samples.ttt.handleFinish(status);
97 | }
98 | }
99 | };
100 |
101 | /**
102 | * Resets the game board.
103 | */
104 | google.devrel.samples.ttt.resetGame = function() {
105 | var buttons = document.querySelectorAll('td');
106 | for (var i = 0; i < buttons.length; i++) {
107 | var button = buttons[i];
108 | button.removeEventListener('click', google.devrel.samples.ttt.clickSquare);
109 | button.addEventListener('click', google.devrel.samples.ttt.clickSquare);
110 | button.innerHTML = '-';
111 | }
112 | document.getElementById('victory').innerHTML = '';
113 | google.devrel.samples.ttt.waitingForMove = true;
114 | };
115 |
116 | /**
117 | * Gets the computer's move.
118 | * @param {string} boardString Current state of the board.
119 | */
120 | google.devrel.samples.ttt.getComputerMove = function(boardString) {
121 | gapi.client.tictactoe.board.getmove({'state': boardString}).execute(
122 | function(resp) {
123 | google.devrel.samples.ttt.setBoardFilling(resp.state);
124 | var status = google.devrel.samples.ttt.checkForVictory(resp.state);
125 | if (status != google.devrel.samples.ttt.NOT_DONE) {
126 | google.devrel.samples.ttt.handleFinish(status);
127 | } else {
128 | google.devrel.samples.ttt.waitingForMove = true;
129 | }
130 | });
131 | };
132 |
133 | /**
134 | * Sends the result of the game to the server.
135 | * @param {number} status Result of the game.
136 | */
137 | google.devrel.samples.ttt.sendResultToServer = function(status) {
138 | gapi.client.tictactoe.scores.insert({'outcome':
139 | google.devrel.samples.ttt.STATUS_STRINGS[status]}).execute(
140 | function(resp) {
141 | google.devrel.samples.ttt.queryScores();
142 | });
143 | };
144 |
145 | /**
146 | * Queries for results of previous games.
147 | */
148 | google.devrel.samples.ttt.queryScores = function() {
149 | gapi.client.tictactoe.scores.list().execute(function(resp) {
150 | var history = document.getElementById('gameHistory');
151 | history.innerHTML = '';
152 | if (resp.items) {
153 | for (var i = 0; i < resp.items.length; i++) {
154 | var score = document.createElement('li');
155 | score.innerHTML = resp.items[i].outcome;
156 | history.appendChild(score);
157 | }
158 | }
159 | });
160 | };
161 |
162 | /**
163 | * Shows or hides the board and game elements.
164 | * @param {boolean} state Whether to show or hide the board elements.
165 | */
166 | google.devrel.samples.ttt.setBoardEnablement = function(state) {
167 | if (!state) {
168 | document.getElementById('board').classList.add('hidden');
169 | document.getElementById('gameHistoryWrapper').classList.add('hidden');
170 | document.getElementById('warning').classList.remove('hidden');
171 | } else {
172 | document.getElementById('board').classList.remove('hidden');
173 | document.getElementById('gameHistoryWrapper').classList.remove('hidden');
174 | document.getElementById('warning').classList.add('hidden');
175 | }
176 | };
177 |
178 | /**
179 | * Sets the filling of the squares of the board.
180 | * @param {string} boardString Current state of the board.
181 | */
182 | google.devrel.samples.ttt.setBoardFilling = function(boardString) {
183 | var buttons = document.querySelectorAll('td');
184 | for (var i = 0; i < buttons.length; i++) {
185 | var button = buttons[i];
186 | button.innerHTML = boardString.charAt(i);
187 | }
188 | };
189 |
190 | /**
191 | * Checks for a victory condition.
192 | * @param {string} boardString Current state of the board.
193 | * @return {number} Status code for the victory state.
194 | */
195 | google.devrel.samples.ttt.checkForVictory = function(boardString) {
196 | var status = google.devrel.samples.ttt.NOT_DONE;
197 |
198 | // Checks rows and columns.
199 | for (var i = 0; i < 3; i++) {
200 | var rowString = google.devrel.samples.ttt.getStringsAtPositions(
201 | boardString, i*3, (i*3)+1, (i*3)+2);
202 | status |= google.devrel.samples.ttt.checkSectionVictory(rowString);
203 |
204 | var colString = google.devrel.samples.ttt.getStringsAtPositions(
205 | boardString, i, i+3, i+6);
206 | status |= google.devrel.samples.ttt.checkSectionVictory(colString);
207 | }
208 |
209 | // Check top-left to bottom-right.
210 | var diagonal = google.devrel.samples.ttt.getStringsAtPositions(boardString,
211 | 0, 4, 8);
212 | status |= google.devrel.samples.ttt.checkSectionVictory(diagonal);
213 |
214 | // Check top-right to bottom-left.
215 | diagonal = google.devrel.samples.ttt.getStringsAtPositions(boardString, 2,
216 | 4, 6);
217 | status |= google.devrel.samples.ttt.checkSectionVictory(diagonal);
218 |
219 | if (status == google.devrel.samples.ttt.NOT_DONE) {
220 | if (boardString.indexOf('-') == -1) {
221 | return google.devrel.samples.ttt.TIE;
222 | }
223 | }
224 |
225 | return status;
226 | };
227 |
228 | /**
229 | * Checks whether a set of three squares are identical.
230 | * @param {string} section Set of three squares to check.
231 | * @return {number} Status code for the victory state.
232 | */
233 | google.devrel.samples.ttt.checkSectionVictory = function(section) {
234 | var a = section.charAt(0);
235 | var b = section.charAt(1);
236 | var c = section.charAt(2);
237 | if (a == b && a == c) {
238 | if (a == 'X') {
239 | return google.devrel.samples.ttt.WON;
240 | } else if (a == 'O') {
241 | return google.devrel.samples.ttt.LOST
242 | }
243 | }
244 | return google.devrel.samples.ttt.NOT_DONE;
245 | };
246 |
247 | /**
248 | * Handles the end of the game.
249 | * @param {number} status Status code for the victory state.
250 | */
251 | google.devrel.samples.ttt.handleFinish = function(status) {
252 | var victory = document.getElementById('victory');
253 | if (status == google.devrel.samples.ttt.WON) {
254 | victory.innerHTML = 'You win!';
255 | } else if (status == google.devrel.samples.ttt.LOST) {
256 | victory.innerHTML = 'You lost!';
257 | } else {
258 | victory.innerHTML = 'You tied!';
259 | }
260 | google.devrel.samples.ttt.sendResultToServer(status);
261 | };
262 |
263 | /**
264 | * Gets the current representation of the board.
265 | * @return {string} Current state of the board.
266 | */
267 | google.devrel.samples.ttt.getBoardString = function() {
268 | var boardStrings = [];
269 | var buttons = document.querySelectorAll('td');
270 | for (var i = 0; i < buttons.length; i++) {
271 | boardStrings.push(buttons[i].innerHTML);
272 | }
273 | return boardStrings.join('');
274 | };
275 |
276 | /**
277 | * Gets the values of the board at the given positions.
278 | * @param {string} boardString Current state of the board.
279 | * @param {number} first First element to retrieve.
280 | * @param {number} second Second element to retrieve.
281 | * @param {number} third Third element to retrieve.
282 | */
283 | google.devrel.samples.ttt.getStringsAtPositions = function(boardString, first,
284 | second, third) {
285 | return [boardString.charAt(first),
286 | boardString.charAt(second),
287 | boardString.charAt(third)].join('');
288 | };
289 |
290 | /**
291 | * Initializes the application.
292 | * @param {string} apiRoot Root of the API's path.
293 | * @param {string} tokenEmail The email parsed from the auth/ID token.
294 | */
295 | google.devrel.samples.ttt.init = function(apiRoot, tokenEmail) {
296 | // Loads the Tic Tac Toe API asynchronously, and triggers login
297 | // in the UI when loading has completed.
298 | var callback = function() {
299 | google.devrel.samples.ttt.signedIn = true;
300 | document.getElementById('userLabel').innerHTML = tokenEmail;
301 | google.devrel.samples.ttt.setBoardEnablement(true);
302 | google.devrel.samples.ttt.queryScores();
303 | }
304 | gapi.client.load('tictactoe', 'v1', callback, apiRoot);
305 |
306 | var buttons = document.querySelectorAll('td');
307 | for (var i = 0; i < buttons.length; i++) {
308 | var button = buttons[i];
309 | button.addEventListener('click', google.devrel.samples.ttt.clickSquare);
310 | }
311 |
312 | var reset = document.querySelector('#restartButton');
313 | reset.addEventListener('click', google.devrel.samples.ttt.resetGame);
314 | };
315 |
--------------------------------------------------------------------------------
/war/js/render.js:
--------------------------------------------------------------------------------
1 | // Copyright 2013 Google Inc. All Rights Reserved.
2 |
3 | /**
4 | * @fileoverview
5 | * Provides methods for the utility methods needed to render the Google+
6 | * Sign-In button.
7 | *
8 | * @author dhermes@google.com (Danny Hermes)
9 | */
10 |
11 | /** google global namespace for Google projects. */
12 | var google = google || {};
13 |
14 | /** devrel namespace for Google Developer Relations projects. */
15 | google.devrel = google.devrel || {};
16 |
17 | /** samples namespace for DevRel sample code. */
18 | google.devrel.samples = google.devrel.samples || {};
19 |
20 | /** TicTacToe namespace for this sample. */
21 | google.devrel.samples.ttt = google.devrel.samples.ttt || {};
22 |
23 | /**
24 | * Client ID of the application (from the APIs Console).
25 | * @type {string}
26 | */
27 | google.devrel.samples.ttt.CLIENT_ID =
28 | 'YOUR-CLIENT-ID';
29 |
30 | /**
31 | * Scopes used by the application.
32 | * @type {string}
33 | */
34 | google.devrel.samples.ttt.SCOPES =
35 | 'https://www.googleapis.com/auth/userinfo.email ' +
36 | 'https://www.googleapis.com/auth/plus.login';
37 |
38 | /**
39 | * Parses email from the claim set of a JWT ID token.
40 | *
41 | * NOTE: We are not validating the ID token since from a trusted source.
42 | * We are simply parsed the value from the JWT.
43 | *
44 | * See http://www.tbray.org/ongoing/When/201x/2013/04/04/ID-Tokens
45 | * or
46 | * http://openid.net/specs/openid-connect-messages-1_0.html#StandardClaims
47 | * for more info.
48 | *
49 | * @param {string} idToken A base64 JWT containing a user ID token.
50 | * @return {string} The email parsed from the claim set, else undefined
51 | * if one can't be parsed.
52 | */
53 | google.devrel.samples.ttt.getEmailFromIDToken = function(idToken) {
54 | if (typeof idToken !== 'string') {
55 | return;
56 | }
57 |
58 | var segments = idToken.split('.');
59 | if (segments.length !== 3) {
60 | return;
61 | }
62 |
63 | try {
64 | var claimSet = JSON.parse(atob(segments[1]));
65 | } catch (e) {
66 | return;
67 | }
68 |
69 | if (claimSet.email && typeof claimSet.email === 'string') {
70 | return claimSet.email;
71 | }
72 | }
73 |
74 | /**
75 | * Handles the Google+ Sign In response.
76 | *
77 | * Success calls google.devrel.samples.ttt.init. Failure makes the Sign-In
78 | * button visible.
79 | *
80 | * @param {Object} authResult The contents returned from the Google+
81 | * Sign In attempt.
82 | */
83 | google.devrel.samples.ttt.signinCallback = function(authResult) {
84 | var tokenEmail = google.devrel.samples.ttt.getEmailFromIDToken(
85 | authResult.id_token);
86 | if (authResult.access_token && tokenEmail) {
87 | google.devrel.samples.ttt.init('//' + window.location.host + '/_ah/api',
88 | tokenEmail);
89 |
90 | document.getElementById('signinButtonContainer').classList.remove(
91 | 'visible');
92 | document.getElementById('signedInStatus').classList.add('visible');
93 | } else {
94 | document.getElementById('signinButtonContainer').classList.add('visible');
95 | document.getElementById('signedInStatus').classList.remove('visible');
96 |
97 | if (!authResult.error) {
98 | console.log('Unexpected result');
99 | console.log(authResult);
100 | } else if (authResult.error !== 'immediate_failed') {
101 | console.log('Unexpected error occured: ' + authResult.error);
102 | } else {
103 | console.log('Immediate mode failed, user needs to click Sign In.');
104 | }
105 | }
106 | };
107 |
108 | /**
109 | * Renders the Google+ Sign-in button using auth parameters.
110 | */
111 | google.devrel.samples.ttt.render = function() {
112 | gapi.signin.render('signinButton', {
113 | 'callback': google.devrel.samples.ttt.signinCallback,
114 | 'clientid': google.devrel.samples.ttt.CLIENT_ID,
115 | 'cookiepolicy': 'single_host_origin',
116 | 'requestvisibleactions': 'http://schemas.google.com/AddActivity',
117 | 'scope': google.devrel.samples.ttt.SCOPES
118 | });
119 | };
120 | // A quirk of the JSONP callback of the plusone client makes it so
121 | // our callback must exist as an element in window.
122 | window['google.devrel.samples.ttt.render'] = google.devrel.samples.ttt.render;
123 |
124 | // Recommended code to load Google+ JS library.
125 | (function() {
126 | var newScriptElement = document.createElement('script');
127 | newScriptElement.type = 'text/javascript';
128 | newScriptElement.async = true;
129 | newScriptElement.src = 'https://apis.google.com/js/client:plusone.js' +
130 | '?onload=google.devrel.samples.ttt.render';
131 | var firstScriptElement = document.getElementsByTagName('script')[0];
132 | firstScriptElement.parentNode.insertBefore(newScriptElement,
133 | firstScriptElement);
134 | })();
135 |
--------------------------------------------------------------------------------