kimhyunwoo commited on
Commit
018fff2
verified
1 Parent(s): 879c231

Update index.html

Browse files
Files changed (1) hide show
  1. index.html +80 -69
index.html CHANGED
@@ -16,7 +16,7 @@
16
  min-height: 100vh;
17
  margin: 0;
18
  background-color: #f5f5f5;
19
- overflow: hidden;
20
  }
21
 
22
  #game-container {
@@ -24,7 +24,7 @@
24
  flex-direction: column;
25
  align-items: center;
26
  width: 100%;
27
- max-width: 600px;
28
  }
29
 
30
  #game-title {
@@ -41,7 +41,7 @@
41
  margin-bottom: 1em;
42
  color: #666;
43
  user-select: none;
44
- width: 90%; /* Limit width for readability */
45
  }
46
 
47
  #game-board {
@@ -50,18 +50,16 @@
50
  border: 1px solid #ddd;
51
  background-color: #fff;
52
  touch-action: none;
53
- /* Ensure canvas is centered within its container */
54
- display: block; /* Remove any inline spacing */
55
- margin: 0 auto; /* Center horizontally */
56
-
57
  }
58
 
59
  #button-container {
60
- display: flex;
61
- gap: 10px; /* Space between buttons */
62
- margin-top: 1em;
63
- justify-content: center; /* Center buttons horizontally */
64
- width: 100%; /* Make container full-width */
65
  }
66
 
67
  .game-button {
@@ -87,7 +85,6 @@
87
  background-color: #ddd;
88
  }
89
 
90
-
91
  #loading-indicator {
92
  display: none;
93
  margin-top: 20px;
@@ -112,8 +109,9 @@
112
  #game-instructions {
113
  font-size: 0.9em;
114
  }
 
115
  .game-button {
116
- padding: 8px 16px; /* Slightly smaller buttons on mobile */
117
  }
118
  }
119
  </style>
@@ -125,12 +123,12 @@
125
  <p id="game-instructions">Try to connect four stones in a row, a column, or a diagonal.</p>
126
  <canvas id="game-board"></canvas>
127
  <div id="button-container">
128
- <button type="button" id="ai-first" class="game-button">AI First</button>
129
- <button type="button" id="reset-button" class="game-button">Restart</button>
130
  </div>
131
-
132
  <div id="loading-indicator"></div>
133
  </div>
 
134
  <script>
135
  function BoardGame(agent, num_rows, num_cols) {
136
  this.agent = agent;
@@ -141,35 +139,46 @@
141
  this.canvas_ctx = document.getElementById("game-board").getContext("2d");
142
  this.board_scale = 1;
143
 
144
- this.calculateBoardScale = function() {
 
145
  const containerWidth = document.getElementById("game-container").offsetWidth;
146
- // Calculate available height, accounting for other elements
147
- const containerHeight = window.innerHeight - document.getElementById("game-title").offsetHeight
148
- - document.getElementById("game-instructions").offsetHeight
149
- - document.getElementById("button-container").offsetHeight - 80; // Add some margin
150
 
 
 
 
 
 
 
 
 
151
 
 
152
  const canvasWidth = containerWidth * 0.95;
 
 
153
  const canvasHeight = canvasWidth * (num_rows + 1) / (num_cols + 1);
154
 
155
- //If the calculated height is too big for the container, scale by height.
156
- if(canvasHeight > containerHeight) {
157
- const adjustedCanvasHeight = containerHeight * 0.9;
158
- const adjustedCanvasWidth = adjustedCanvasHeight * (num_cols+1) / (num_rows+1);
 
159
  this.board_scale = adjustedCanvasHeight / (num_rows + 1);
160
- this_.canvas_ctx.canvas.width = adjustedCanvasWidth;
161
- this_.canvas_ctx.canvas.height = adjustedCanvasHeight;
162
- }
163
- else{
 
164
  this.board_scale = canvasWidth / (num_cols + 1);
165
- this_.canvas_ctx.canvas.width = canvasWidth;
166
- this_.canvas_ctx.canvas.height = canvasHeight;
167
  }
168
 
169
- this_.canvas_ctx.setTransform(1, 0, 0, 1, 0, 0);
170
- this_.canvas_ctx.scale(this.board_scale, this.board_scale);
171
- this_.canvas_ctx.translate(0.5, 0.5); // Center the board drawing
172
- }
 
173
  this.calculateBoardScale(); // Initial calculation
174
 
175
 
@@ -181,13 +190,16 @@
181
  this.who_play = 1;
182
  this.ai_player = -1;
183
  this.game_ended = false;
184
- this.render(); // Re-render after resetting
185
  };
 
186
 
187
  this.get = function (row, col) {
188
  return this.board[this.num_cols * row + col];
189
- }
 
190
  this.is_terminated = function () {
 
191
  if (this.board.some((x) => x == 0) == false) return true;
192
  for (let i = 0; i < this.num_rows; i++) {
193
  for (let j = 0; j < this.num_cols; j++) {
@@ -209,7 +221,9 @@
209
  }
210
  return false;
211
  };
 
212
  this.submit_board = async function () {
 
213
  document.getElementById("loading-indicator").style.display = "block";
214
  await new Promise(r => setTimeout(r, 1000));
215
  if (this_.is_terminated()) return { "terminated": true, "action": -1 };
@@ -223,14 +237,14 @@
223
  "action": action,
224
  };
225
  };
 
226
  this.end_game = function () {
227
  this.game_ended = true;
228
- // Optional: Display a message to the user here.
229
  setTimeout(function () { this_.reset(); }, 3000);
230
  };
231
 
232
  this.ai_play = function () {
233
- if (this_.game_ended) return; // Don't play if game is over
234
 
235
  this_.submit_board().then(
236
  function (info) {
@@ -243,20 +257,17 @@
243
  this_.who_play = -this_.who_play;
244
  this_.render();
245
  }
246
- if (this_.is_terminated() == true) {
247
  this_.end_game();
248
  }
249
-
250
  }
251
  ).catch(function (e) {
252
  console.error("AI play error:", e);
253
  });
254
  };
255
 
256
-
257
- // Event Handlers (Corrected and Unified)
258
- this.handleClick = function(x, y) {
259
- if (this_.game_ended) return; // Don't allow moves if game is over
260
 
261
  var loc_x = Math.floor(x / this_.board_scale - 0.5);
262
  var loc_y = Math.floor(y / this_.board_scale - 0.5);
@@ -269,17 +280,16 @@
269
  this_.mouse_x < this_.num_cols &&
270
  this_.mouse_y < this_.num_rows
271
  ) {
272
- if (this_.who_play == this_.ai_player) return false;
273
  let i = this_.mouse_y * this_.num_cols + this_.mouse_x;
274
- if (this_.board[i] != 0) return false;
275
  this_.board[i] = this_.who_play;
276
  this_.audio.play();
277
  this_.who_play = -this_.who_play;
278
  this_.render();
279
- this_.ai_play(); // Call AI after player move
280
  }
281
- }
282
-
283
  document.getElementById("game-board").addEventListener('touchstart', function(e) {
284
  e.preventDefault(); // Prevent other events
285
  var rect = this.getBoundingClientRect();
@@ -298,9 +308,9 @@
298
  this_.handleClick(x,y);
299
  }, false);
300
 
301
-
302
  this.draw_stone = function (x, y, color) {
303
- let ctx = this.canvas_ctx;
 
304
  y = this.num_rows - 1 - y;
305
  ctx.beginPath();
306
  ctx.arc(x, y, 0.40, 0, 2 * Math.PI, false);
@@ -310,14 +320,18 @@
310
  ctx.strokeStyle = "rgba(0, 0, 0, 0.1)";
311
  ctx.stroke();
312
  };
 
313
  this.get_candidate = function (x) {
 
314
  for (let i = 0; i < this.num_rows; i++) {
315
  let idx = i * this.num_cols + x;
316
  if (this.board[idx] == 0) return [x, i];
317
  }
318
  return [-1, -1];
319
  };
 
320
  this.render = function () {
 
321
  let ctx = this.canvas_ctx;
322
  ctx.clearRect(-1, -1, num_cols + 1, num_rows + 1);
323
  ctx.fillStyle = "#fff";
@@ -342,8 +356,7 @@
342
  let x = i % this.num_cols;
343
  let y = Math.floor(i / this.num_cols);
344
  if (this.board[i] == 0) continue;
345
- // Blue and Orange colors
346
- let color = (this.board[i] == 1) ? "#007AFF" : "#FF9500"; // iOS Blue and Orange
347
  this.draw_stone(x, y, color);
348
  }
349
 
@@ -357,14 +370,12 @@
357
  if (x == -1) return;
358
  this.mouse_x = x;
359
  this.mouse_y = y;
360
- // Semi-transparent preview
361
  let previewColor = (this.who_play == -1) ? "rgba(255, 149, 0, 0.5)" : "rgba(0, 122, 255, 0.5)";
362
  this.draw_stone(x, y, previewColor);
363
  }
364
  };
365
 
366
- this.handleMove = function(e) {
367
-
368
  let rect = this.canvas_ctx.canvas.getBoundingClientRect();
369
  let x, y;
370
 
@@ -394,27 +405,26 @@
394
  this_.handleMove(e);
395
  };
396
 
397
- document.getElementById("game-board").addEventListener('touchmove', function(e) {
398
  this_.handleMove(e);
399
- }, false);
400
 
401
- window.addEventListener('resize', function() {
402
- this_.calculateBoardScale();
403
- this_.render();
404
  });
405
 
406
- // Button Event Listeners
407
  document.getElementById("ai-first").onclick = function () {
408
- this_.reset(); // Reset the board first
409
  this_.ai_player = 1;
410
  this_.ai_play();
411
  };
412
 
413
- document.getElementById("reset-button").onclick = function() {
414
- this_.reset();
415
  };
 
416
 
417
- };
418
  const modelUrl = '/model.json';
419
 
420
  const init_fn = async function () {
@@ -422,10 +432,11 @@
422
  const model = await tf.loadGraphModel(modelUrl);
423
  return model;
424
  };
 
425
  document.addEventListener("DOMContentLoaded", function (event) {
426
  init_fn().then(function (agent) {
427
  game = new BoardGame(agent, 6, 7);
428
- game.render();
429
 
430
  }).catch(error => {
431
  console.error("Error loading model:", error);
 
16
  min-height: 100vh;
17
  margin: 0;
18
  background-color: #f5f5f5;
19
+ overflow-x: hidden; /* Prevent horizontal scrollbar */
20
  }
21
 
22
  #game-container {
 
24
  flex-direction: column;
25
  align-items: center;
26
  width: 100%;
27
+ max-width: 600px; /* Limits width on very large screens */
28
  }
29
 
30
  #game-title {
 
41
  margin-bottom: 1em;
42
  color: #666;
43
  user-select: none;
44
+ width: 90%;
45
  }
46
 
47
  #game-board {
 
50
  border: 1px solid #ddd;
51
  background-color: #fff;
52
  touch-action: none;
53
+ display: block;
54
+ margin: 0 auto;
 
 
55
  }
56
 
57
  #button-container {
58
+ display: flex;
59
+ gap: 10px;
60
+ margin-top: 1em;
61
+ justify-content: center;
62
+ width: 100%;
63
  }
64
 
65
  .game-button {
 
85
  background-color: #ddd;
86
  }
87
 
 
88
  #loading-indicator {
89
  display: none;
90
  margin-top: 20px;
 
109
  #game-instructions {
110
  font-size: 0.9em;
111
  }
112
+
113
  .game-button {
114
+ padding: 8px 16px;
115
  }
116
  }
117
  </style>
 
123
  <p id="game-instructions">Try to connect four stones in a row, a column, or a diagonal.</p>
124
  <canvas id="game-board"></canvas>
125
  <div id="button-container">
126
+ <button type="button" id="ai-first" class="game-button">AI First</button>
127
+ <button type="button" id="reset-button" class="game-button">Restart</button>
128
  </div>
 
129
  <div id="loading-indicator"></div>
130
  </div>
131
+
132
  <script>
133
  function BoardGame(agent, num_rows, num_cols) {
134
  this.agent = agent;
 
139
  this.canvas_ctx = document.getElementById("game-board").getContext("2d");
140
  this.board_scale = 1;
141
 
142
+ this.calculateBoardScale = function () {
143
+ // 1. Get the container width.
144
  const containerWidth = document.getElementById("game-container").offsetWidth;
 
 
 
 
145
 
146
+ // 2. Calculate the *available* height. This is the crucial part.
147
+ // We subtract the heights of *all* other elements *and* a margin.
148
+ const containerHeight = window.innerHeight
149
+ - document.getElementById("game-title").offsetHeight
150
+ - document.getElementById("game-instructions").offsetHeight
151
+ - document.getElementById("button-container").offsetHeight
152
+ - document.getElementById("loading-indicator").offsetHeight // Include loading indicator
153
+ - 40; // Margin (adjust as needed)
154
 
155
+ // 3. Calculate a *potential* canvas width (most of the container).
156
  const canvasWidth = containerWidth * 0.95;
157
+
158
+ // 4. Calculate the corresponding height to maintain the aspect ratio.
159
  const canvasHeight = canvasWidth * (num_rows + 1) / (num_cols + 1);
160
 
161
+ // 5. Check if the calculated height is *too large* for the available space.
162
+ if (canvasHeight > containerHeight) {
163
+ // 5a. If it's too large, scale based on *height*.
164
+ const adjustedCanvasHeight = containerHeight * 0.9; // Use most of available height
165
+ const adjustedCanvasWidth = adjustedCanvasHeight * (num_cols + 1) / (num_rows + 1);
166
  this.board_scale = adjustedCanvasHeight / (num_rows + 1);
167
+ this.canvas_ctx.canvas.width = adjustedCanvasWidth;
168
+ this.canvas_ctx.canvas.height = adjustedCanvasHeight;
169
+
170
+ } else {
171
+ // 5b. If it fits, use the calculated width and height.
172
  this.board_scale = canvasWidth / (num_cols + 1);
173
+ this.canvas_ctx.canvas.width = canvasWidth;
174
+ this.canvas_ctx.canvas.height = canvasHeight;
175
  }
176
 
177
+ // 6. Reset the transformation and apply the new scale and translation.
178
+ this.canvas_ctx.setTransform(1, 0, 0, 1, 0, 0);
179
+ this.canvas_ctx.scale(this.board_scale, this.board_scale);
180
+ this.canvas_ctx.translate(0.5, 0.5);
181
+ };
182
  this.calculateBoardScale(); // Initial calculation
183
 
184
 
 
190
  this.who_play = 1;
191
  this.ai_player = -1;
192
  this.game_ended = false;
193
+ this.render();
194
  };
195
+ this.reset(); // Initial reset
196
 
197
  this.get = function (row, col) {
198
  return this.board[this.num_cols * row + col];
199
+ };
200
+
201
  this.is_terminated = function () {
202
+ // ... (rest of is_terminated is the same) ...
203
  if (this.board.some((x) => x == 0) == false) return true;
204
  for (let i = 0; i < this.num_rows; i++) {
205
  for (let j = 0; j < this.num_cols; j++) {
 
221
  }
222
  return false;
223
  };
224
+
225
  this.submit_board = async function () {
226
+ // ... (rest of submit_board is the same) ...
227
  document.getElementById("loading-indicator").style.display = "block";
228
  await new Promise(r => setTimeout(r, 1000));
229
  if (this_.is_terminated()) return { "terminated": true, "action": -1 };
 
237
  "action": action,
238
  };
239
  };
240
+
241
  this.end_game = function () {
242
  this.game_ended = true;
 
243
  setTimeout(function () { this_.reset(); }, 3000);
244
  };
245
 
246
  this.ai_play = function () {
247
+ if (this_.game_ended) return;
248
 
249
  this_.submit_board().then(
250
  function (info) {
 
257
  this_.who_play = -this_.who_play;
258
  this_.render();
259
  }
260
+ if (this_.is_terminated() == true) {
261
  this_.end_game();
262
  }
 
263
  }
264
  ).catch(function (e) {
265
  console.error("AI play error:", e);
266
  });
267
  };
268
 
269
+ this.handleClick = function (x, y) {
270
+ if (this_.game_ended) return;
 
 
271
 
272
  var loc_x = Math.floor(x / this_.board_scale - 0.5);
273
  var loc_y = Math.floor(y / this_.board_scale - 0.5);
 
280
  this_.mouse_x < this_.num_cols &&
281
  this_.mouse_y < this_.num_rows
282
  ) {
283
+ if (this_.who_play == this_.ai_player) return;
284
  let i = this_.mouse_y * this_.num_cols + this_.mouse_x;
285
+ if (this_.board[i] != 0) return;
286
  this_.board[i] = this_.who_play;
287
  this_.audio.play();
288
  this_.who_play = -this_.who_play;
289
  this_.render();
290
+ this_.ai_play();
291
  }
292
+ };
 
293
  document.getElementById("game-board").addEventListener('touchstart', function(e) {
294
  e.preventDefault(); // Prevent other events
295
  var rect = this.getBoundingClientRect();
 
308
  this_.handleClick(x,y);
309
  }, false);
310
 
 
311
  this.draw_stone = function (x, y, color) {
312
+ // ... (rest of draw_stone is the same) ...
313
+ let ctx = this.canvas_ctx;
314
  y = this.num_rows - 1 - y;
315
  ctx.beginPath();
316
  ctx.arc(x, y, 0.40, 0, 2 * Math.PI, false);
 
320
  ctx.strokeStyle = "rgba(0, 0, 0, 0.1)";
321
  ctx.stroke();
322
  };
323
+
324
  this.get_candidate = function (x) {
325
+ // ... (rest of get_candidate is the same) ...
326
  for (let i = 0; i < this.num_rows; i++) {
327
  let idx = i * this.num_cols + x;
328
  if (this.board[idx] == 0) return [x, i];
329
  }
330
  return [-1, -1];
331
  };
332
+
333
  this.render = function () {
334
+ // ... (rest of render is the same, except for colors) ...
335
  let ctx = this.canvas_ctx;
336
  ctx.clearRect(-1, -1, num_cols + 1, num_rows + 1);
337
  ctx.fillStyle = "#fff";
 
356
  let x = i % this.num_cols;
357
  let y = Math.floor(i / this.num_cols);
358
  if (this.board[i] == 0) continue;
359
+ let color = (this.board[i] == 1) ? "#007AFF" : "#FF9500";
 
360
  this.draw_stone(x, y, color);
361
  }
362
 
 
370
  if (x == -1) return;
371
  this.mouse_x = x;
372
  this.mouse_y = y;
 
373
  let previewColor = (this.who_play == -1) ? "rgba(255, 149, 0, 0.5)" : "rgba(0, 122, 255, 0.5)";
374
  this.draw_stone(x, y, previewColor);
375
  }
376
  };
377
 
378
+ this.handleMove = function (e) {
 
379
  let rect = this.canvas_ctx.canvas.getBoundingClientRect();
380
  let x, y;
381
 
 
405
  this_.handleMove(e);
406
  };
407
 
408
+ document.getElementById("game-board").addEventListener('touchmove', function(e) {
409
  this_.handleMove(e);
410
+ }, false);
411
 
412
+ window.addEventListener('resize', function () {
413
+ this_.calculateBoardScale(); // Recalculate on resize
414
+ this_.render(); // Redraw
415
  });
416
 
 
417
  document.getElementById("ai-first").onclick = function () {
418
+ this_.reset();
419
  this_.ai_player = 1;
420
  this_.ai_play();
421
  };
422
 
423
+ document.getElementById("reset-button").onclick = function () {
424
+ this_.reset();
425
  };
426
+ }
427
 
 
428
  const modelUrl = '/model.json';
429
 
430
  const init_fn = async function () {
 
432
  const model = await tf.loadGraphModel(modelUrl);
433
  return model;
434
  };
435
+
436
  document.addEventListener("DOMContentLoaded", function (event) {
437
  init_fn().then(function (agent) {
438
  game = new BoardGame(agent, 6, 7);
439
+ game.render(); // Initial render
440
 
441
  }).catch(error => {
442
  console.error("Error loading model:", error);