kolaslab commited on
Commit
81ed4a3
β€’
1 Parent(s): ea33c31

Update index.html

Browse files
Files changed (1) hide show
  1. index.html +64 -53
index.html CHANGED
@@ -10,7 +10,6 @@
10
  padding: 0;
11
  box-sizing: border-box;
12
  }
13
-
14
  body {
15
  display: flex;
16
  flex-direction: column;
@@ -20,14 +19,12 @@
20
  font-family: Arial, sans-serif;
21
  padding: 20px;
22
  }
23
-
24
  .game-container {
25
  background: #DEB887;
26
  padding: 20px;
27
  border-radius: 10px;
28
  box-shadow: 0 0 20px rgba(0,0,0,0.1);
29
  }
30
-
31
  .board {
32
  display: grid;
33
  grid-template-columns: repeat(19, 30px);
@@ -37,14 +34,12 @@
37
  border: 2px solid #000;
38
  position: relative;
39
  }
40
-
41
  .intersection {
42
  width: 30px;
43
  height: 30px;
44
  position: relative;
45
  cursor: pointer;
46
  }
47
-
48
  .intersection::before {
49
  content: '';
50
  position: absolute;
@@ -54,7 +49,6 @@
54
  height: 1px;
55
  background: #000;
56
  }
57
-
58
  .intersection::after {
59
  content: '';
60
  position: absolute;
@@ -64,7 +58,6 @@
64
  width: 1px;
65
  background: #000;
66
  }
67
-
68
  .stone {
69
  position: absolute;
70
  width: 26px;
@@ -75,23 +68,19 @@
75
  z-index: 1;
76
  transition: all 0.2s ease;
77
  }
78
-
79
  .black {
80
  background: #000;
81
  box-shadow: 2px 2px 2px rgba(0,0,0,0.2);
82
  }
83
-
84
  .white {
85
  background: #fff;
86
  box-shadow: 2px 2px 2px rgba(0,0,0,0.2);
87
  }
88
-
89
  .controls {
90
  margin-top: 20px;
91
  display: flex;
92
  gap: 10px;
93
  }
94
-
95
  button {
96
  padding: 10px 20px;
97
  font-size: 16px;
@@ -102,22 +91,18 @@
102
  color: white;
103
  transition: background 0.3s;
104
  }
105
-
106
  button:hover {
107
  background: #45a049;
108
  }
109
-
110
  .score {
111
  margin-top: 20px;
112
  font-size: 18px;
113
  display: flex;
114
  gap: 20px;
115
  }
116
-
117
  .mode-select {
118
  margin-bottom: 20px;
119
  }
120
-
121
  select {
122
  padding: 8px;
123
  font-size: 16px;
@@ -129,7 +114,9 @@
129
  <div class="mode-select">
130
  <select id="gameMode">
131
  <option value="pvp">Player vs Player</option>
132
- <option value="ai">Player vs AI</option>
 
 
133
  </select>
134
  </div>
135
 
@@ -156,12 +143,12 @@
156
  this.lastMove = null;
157
  this.passes = 0;
158
  this.gameMode = 'pvp';
 
159
  this.score = { black: 0, white: 0 };
160
  this.capturedStones = { black: 0, white: 0 };
161
 
162
  this.initialize();
163
  }
164
-
165
  initialize() {
166
  const boardElement = document.getElementById('board');
167
  boardElement.innerHTML = '';
@@ -176,19 +163,18 @@
176
  boardElement.appendChild(intersection);
177
  }
178
  }
179
-
180
  document.getElementById('passBtn').addEventListener('click', () => this.pass());
181
  document.getElementById('resetBtn').addEventListener('click', () => this.reset());
182
  document.getElementById('gameMode').addEventListener('change', (e) => {
183
- this.gameMode = e.target.value;
 
 
184
  this.reset();
185
  });
186
  }
187
-
188
  handleMove(e) {
189
  const row = parseInt(e.target.dataset.row);
190
  const col = parseInt(e.target.dataset.col);
191
-
192
  if(this.isValidMove(row, col)) {
193
  this.placeStone(row, col);
194
 
@@ -197,21 +183,17 @@
197
  }
198
  }
199
  }
200
-
201
  isValidMove(row, col) {
202
  if(this.board[row][col] !== null) return false;
203
 
204
- // Place stone temporarily to check if it would be immediately captured
205
  this.board[row][col] = this.currentPlayer;
206
  const group = this.getGroup(row, col);
207
  const liberties = this.countLiberties(group);
208
 
209
- // Revert the temporary stone
210
  this.board[row][col] = null;
211
 
212
  return liberties > 0;
213
  }
214
-
215
  placeStone(row, col) {
216
  if(this.board[row][col] === null) {
217
  this.board[row][col] = this.currentPlayer;
@@ -222,14 +204,12 @@
222
  this.updateScore();
223
  }
224
  }
225
-
226
  renderStone(row, col) {
227
  const intersection = document.querySelector(`[data-row="${row}"][data-col="${col}"]`);
228
  const stone = document.createElement('div');
229
  stone.className = `stone ${this.currentPlayer}`;
230
  intersection.appendChild(stone);
231
  }
232
-
233
  getGroup(row, col) {
234
  const color = this.board[row][col];
235
  const group = new Set();
@@ -253,7 +233,6 @@
253
 
254
  return group;
255
  }
256
-
257
  countLiberties(group) {
258
  const liberties = new Set();
259
 
@@ -270,7 +249,6 @@
270
 
271
  return liberties.size;
272
  }
273
-
274
  getNeighbors(row, col) {
275
  const neighbors = [];
276
  const directions = [[-1,0], [1,0], [0,-1], [0,1]];
@@ -286,7 +264,62 @@
286
 
287
  return neighbors;
288
  }
289
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
290
  captures() {
291
  for(let i = 0; i < this.size; i++) {
292
  for(let j = 0; j < this.size; j++) {
@@ -306,25 +339,6 @@
306
  }
307
  }
308
  }
309
-
310
- makeAIMove() {
311
- const validMoves = [];
312
- for(let i = 0; i < this.size; i++) {
313
- for(let j = 0; j < this.size; j++) {
314
- if(this.isValidMove(i, j)) {
315
- validMoves.push([i, j]);
316
- }
317
- }
318
- }
319
-
320
- if(validMoves.length > 0) {
321
- const [row, col] = validMoves[Math.floor(Math.random() * validMoves.length)];
322
- this.placeStone(row, col);
323
- } else {
324
- this.pass();
325
- }
326
- }
327
-
328
  pass() {
329
  this.passes++;
330
  if(this.passes === 2) {
@@ -336,7 +350,6 @@
336
  setTimeout(() => this.makeAIMove(), 500);
337
  }
338
  }
339
-
340
  reset() {
341
  this.board = Array(this.size).fill().map(() => Array(this.size).fill(null));
342
  this.currentPlayer = 'black';
@@ -347,7 +360,6 @@
347
  intersections.forEach(intersection => intersection.innerHTML = '');
348
  this.updateScore();
349
  }
350
-
351
  updateScore() {
352
  document.getElementById('blackScore').textContent =
353
  this.score.black + this.capturedStones.black;
@@ -355,8 +367,7 @@
355
  this.score.white + this.capturedStones.white;
356
  }
357
  }
358
-
359
  const game = new GoGame();
360
  </script>
361
  </body>
362
- </html><script async data-explicit-opt-in="true" data-cookie-opt-in="true" src="https://vercel.live/_next-live/feedback/feedback.js"></script>
 
10
  padding: 0;
11
  box-sizing: border-box;
12
  }
 
13
  body {
14
  display: flex;
15
  flex-direction: column;
 
19
  font-family: Arial, sans-serif;
20
  padding: 20px;
21
  }
 
22
  .game-container {
23
  background: #DEB887;
24
  padding: 20px;
25
  border-radius: 10px;
26
  box-shadow: 0 0 20px rgba(0,0,0,0.1);
27
  }
 
28
  .board {
29
  display: grid;
30
  grid-template-columns: repeat(19, 30px);
 
34
  border: 2px solid #000;
35
  position: relative;
36
  }
 
37
  .intersection {
38
  width: 30px;
39
  height: 30px;
40
  position: relative;
41
  cursor: pointer;
42
  }
 
43
  .intersection::before {
44
  content: '';
45
  position: absolute;
 
49
  height: 1px;
50
  background: #000;
51
  }
 
52
  .intersection::after {
53
  content: '';
54
  position: absolute;
 
58
  width: 1px;
59
  background: #000;
60
  }
 
61
  .stone {
62
  position: absolute;
63
  width: 26px;
 
68
  z-index: 1;
69
  transition: all 0.2s ease;
70
  }
 
71
  .black {
72
  background: #000;
73
  box-shadow: 2px 2px 2px rgba(0,0,0,0.2);
74
  }
 
75
  .white {
76
  background: #fff;
77
  box-shadow: 2px 2px 2px rgba(0,0,0,0.2);
78
  }
 
79
  .controls {
80
  margin-top: 20px;
81
  display: flex;
82
  gap: 10px;
83
  }
 
84
  button {
85
  padding: 10px 20px;
86
  font-size: 16px;
 
91
  color: white;
92
  transition: background 0.3s;
93
  }
 
94
  button:hover {
95
  background: #45a049;
96
  }
 
97
  .score {
98
  margin-top: 20px;
99
  font-size: 18px;
100
  display: flex;
101
  gap: 20px;
102
  }
 
103
  .mode-select {
104
  margin-bottom: 20px;
105
  }
 
106
  select {
107
  padding: 8px;
108
  font-size: 16px;
 
114
  <div class="mode-select">
115
  <select id="gameMode">
116
  <option value="pvp">Player vs Player</option>
117
+ <option value="ai-easy">Player vs AI (Easy)</option>
118
+ <option value="ai-middle">Player vs AI (Middle)</option>
119
+ <option value="ai-hard">Player vs AI (Hard)</option>
120
  </select>
121
  </div>
122
 
 
143
  this.lastMove = null;
144
  this.passes = 0;
145
  this.gameMode = 'pvp';
146
+ this.aiDifficulty = 'easy';
147
  this.score = { black: 0, white: 0 };
148
  this.capturedStones = { black: 0, white: 0 };
149
 
150
  this.initialize();
151
  }
 
152
  initialize() {
153
  const boardElement = document.getElementById('board');
154
  boardElement.innerHTML = '';
 
163
  boardElement.appendChild(intersection);
164
  }
165
  }
 
166
  document.getElementById('passBtn').addEventListener('click', () => this.pass());
167
  document.getElementById('resetBtn').addEventListener('click', () => this.reset());
168
  document.getElementById('gameMode').addEventListener('change', (e) => {
169
+ const mode = e.target.value;
170
+ this.gameMode = mode.startsWith('ai') ? 'ai' : 'pvp';
171
+ this.aiDifficulty = mode.split('-')[1] || 'easy';
172
  this.reset();
173
  });
174
  }
 
175
  handleMove(e) {
176
  const row = parseInt(e.target.dataset.row);
177
  const col = parseInt(e.target.dataset.col);
 
178
  if(this.isValidMove(row, col)) {
179
  this.placeStone(row, col);
180
 
 
183
  }
184
  }
185
  }
 
186
  isValidMove(row, col) {
187
  if(this.board[row][col] !== null) return false;
188
 
 
189
  this.board[row][col] = this.currentPlayer;
190
  const group = this.getGroup(row, col);
191
  const liberties = this.countLiberties(group);
192
 
 
193
  this.board[row][col] = null;
194
 
195
  return liberties > 0;
196
  }
 
197
  placeStone(row, col) {
198
  if(this.board[row][col] === null) {
199
  this.board[row][col] = this.currentPlayer;
 
204
  this.updateScore();
205
  }
206
  }
 
207
  renderStone(row, col) {
208
  const intersection = document.querySelector(`[data-row="${row}"][data-col="${col}"]`);
209
  const stone = document.createElement('div');
210
  stone.className = `stone ${this.currentPlayer}`;
211
  intersection.appendChild(stone);
212
  }
 
213
  getGroup(row, col) {
214
  const color = this.board[row][col];
215
  const group = new Set();
 
233
 
234
  return group;
235
  }
 
236
  countLiberties(group) {
237
  const liberties = new Set();
238
 
 
249
 
250
  return liberties.size;
251
  }
 
252
  getNeighbors(row, col) {
253
  const neighbors = [];
254
  const directions = [[-1,0], [1,0], [0,-1], [0,1]];
 
264
 
265
  return neighbors;
266
  }
267
+ evaluatePosition(row, col) {
268
+ let score = 0;
269
+
270
+ // λ³΄λ“œ 쀑앙에 κ°€κΉŒμšΈμˆ˜λ‘ 높은 점수
271
+ const centerDistance = Math.abs(row - 9) + Math.abs(col - 9);
272
+ score += (18 - centerDistance) * 2;
273
+ // μ£Όλ³€ 돌의 μƒνƒœ 평가
274
+ const neighbors = this.getNeighbors(row, col);
275
+ let friendlyStones = 0;
276
+ let enemyStones = 0;
277
+ let liberties = 0;
278
+ for (const [nr, nc] of neighbors) {
279
+ if (this.board[nr][nc] === this.currentPlayer) friendlyStones++;
280
+ else if (this.board[nr][nc] === null) liberties++;
281
+ else enemyStones++;
282
+ }
283
+ score += friendlyStones * 10;
284
+ score += liberties * 5;
285
+ score += enemyStones * 3;
286
+ return score;
287
+ }
288
+ makeAIMove() {
289
+ const validMoves = [];
290
+ const scoredMoves = [];
291
+ for (let i = 0; i < this.size; i++) {
292
+ for (let j = 0; j < this.size; j++) {
293
+ if (this.isValidMove(i, j)) {
294
+ const score = this.evaluatePosition(i, j);
295
+ scoredMoves.push({ row: i, col: j, score: score });
296
+ validMoves.push([i, j]);
297
+ }
298
+ }
299
+ }
300
+ if (validMoves.length === 0) {
301
+ this.pass();
302
+ return;
303
+ }
304
+ let selectedMove;
305
+ switch (this.aiDifficulty) {
306
+ case 'easy':
307
+ selectedMove = validMoves[Math.floor(Math.random() * validMoves.length)];
308
+ break;
309
+ case 'middle':
310
+ scoredMoves.sort((a, b) => b.score - a.score);
311
+ const middlePool = scoredMoves.slice(0, Math.floor(scoredMoves.length / 2));
312
+ const middleChoice = middlePool[Math.floor(Math.random() * middlePool.length)];
313
+ selectedMove = [middleChoice.row, middleChoice.col];
314
+ break;
315
+ case 'hard':
316
+ scoredMoves.sort((a, b) => b.score - a.score);
317
+ const bestMove = scoredMoves[0];
318
+ selectedMove = [bestMove.row, bestMove.col];
319
+ break;
320
+ }
321
+ this.placeStone(selectedMove[0], selectedMove[1]);
322
+ }
323
  captures() {
324
  for(let i = 0; i < this.size; i++) {
325
  for(let j = 0; j < this.size; j++) {
 
339
  }
340
  }
341
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
342
  pass() {
343
  this.passes++;
344
  if(this.passes === 2) {
 
350
  setTimeout(() => this.makeAIMove(), 500);
351
  }
352
  }
 
353
  reset() {
354
  this.board = Array(this.size).fill().map(() => Array(this.size).fill(null));
355
  this.currentPlayer = 'black';
 
360
  intersections.forEach(intersection => intersection.innerHTML = '');
361
  this.updateScore();
362
  }
 
363
  updateScore() {
364
  document.getElementById('blackScore').textContent =
365
  this.score.black + this.capturedStones.black;
 
367
  this.score.white + this.capturedStones.white;
368
  }
369
  }
 
370
  const game = new GoGame();
371
  </script>
372
  </body>
373
+ </html>