PHhTTPS commited on
Commit
ceddf7c
·
verified ·
1 Parent(s): 145e980

Upload folder using huggingface_hub

Browse files
Files changed (1) hide show
  1. index.html +1230 -19
index.html CHANGED
@@ -1,19 +1,1230 @@
1
- <!doctype html>
2
- <html>
3
- <head>
4
- <meta charset="utf-8" />
5
- <meta name="viewport" content="width=device-width" />
6
- <title>My static Space</title>
7
- <link rel="stylesheet" href="style.css" />
8
- </head>
9
- <body>
10
- <div class="card">
11
- <h1>Welcome to your static Space!</h1>
12
- <p>You can modify this app directly by editing <i>index.html</i> in the Files and versions tab.</p>
13
- <p>
14
- Also don't forget to check the
15
- <a href="https://huggingface.co/docs/hub/spaces" target="_blank">Spaces documentation</a>.
16
- </p>
17
- </div>
18
- </body>
19
- </html>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>GO - The Ancient Board Game</title>
7
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
8
+ <style>
9
+ * {
10
+ margin: 0;
11
+ padding: 0;
12
+ box-sizing: border-box;
13
+ }
14
+
15
+ :root {
16
+ --wood-dark: #5d4037;
17
+ --wood-light: #8d6e63;
18
+ --wood-surface: #a1887f;
19
+ --board-border: #3e2723;
20
+ --black-stone: #1a1a1a;
21
+ --white-stone: #f5f5f5;
22
+ --highlight: #ffd54f;
23
+ --shadow: rgba(0, 0, 0, 0.3);
24
+ }
25
+
26
+ body {
27
+ font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
28
+ background: linear-gradient(135deg, #1a1a2e 0%, #16213e 50%, #0f3460 100%);
29
+ min-height: 100vh;
30
+ color: #fff;
31
+ overflow-x: hidden;
32
+ }
33
+
34
+ /* Header */
35
+ .header {
36
+ background: linear-gradient(90deg, var(--board-border) 0%, #2c1810 100%);
37
+ padding: 1rem 2rem;
38
+ display: flex;
39
+ justify-content: space-between;
40
+ align-items: center;
41
+ box-shadow: 0 4px 20px rgba(0, 0, 0, 0.4);
42
+ position: relative;
43
+ z-index: 10;
44
+ }
45
+
46
+ .logo {
47
+ display: flex;
48
+ align-items: center;
49
+ gap: 1rem;
50
+ }
51
+
52
+ .logo-icon {
53
+ width: 50px;
54
+ height: 50px;
55
+ background: linear-gradient(145deg, #fff, #e0e0e0);
56
+ border-radius: 50%;
57
+ display: flex;
58
+ align-items: center;
59
+ justify-content: center;
60
+ font-size: 1.5rem;
61
+ color: var(--board-border);
62
+ font-weight: bold;
63
+ box-shadow: 0 4px 15px rgba(0, 0, 0, 0.3);
64
+ }
65
+
66
+ .logo-text {
67
+ font-size: 2rem;
68
+ font-weight: 700;
69
+ background: linear-gradient(90deg, #ffd700, #ffecb3);
70
+ -webkit-background-clip: text;
71
+ -webkit-text-fill-color: transparent;
72
+ background-clip: text;
73
+ text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.3);
74
+ }
75
+
76
+ .header-links {
77
+ display: flex;
78
+ gap: 1.5rem;
79
+ align-items: center;
80
+ }
81
+
82
+ .header-link {
83
+ color: #ffd700;
84
+ text-decoration: none;
85
+ font-weight: 500;
86
+ padding: 0.5rem 1rem;
87
+ border-radius: 8px;
88
+ transition: all 0.3s ease;
89
+ border: 1px solid transparent;
90
+ }
91
+
92
+ .header-link:hover {
93
+ background: rgba(255, 215, 0, 0.1);
94
+ border-color: #ffd700;
95
+ }
96
+
97
+ /* Main Container */
98
+ .main-container {
99
+ display: flex;
100
+ justify-content: center;
101
+ align-items: flex-start;
102
+ padding: 2rem;
103
+ gap: 2rem;
104
+ flex-wrap: wrap;
105
+ }
106
+
107
+ /* Game Area */
108
+ .game-area {
109
+ display: flex;
110
+ flex-direction: column;
111
+ align-items: center;
112
+ }
113
+
114
+ .game-info {
115
+ background: rgba(255, 255, 255, 0.1);
116
+ backdrop-filter: blur(10px);
117
+ border-radius: 16px;
118
+ padding: 1.5rem 2rem;
119
+ margin-bottom: 1.5rem;
120
+ display: flex;
121
+ gap: 2rem;
122
+ align-items: center;
123
+ border: 1px solid rgba(255, 255, 255, 0.1);
124
+ }
125
+
126
+ .current-player {
127
+ display: flex;
128
+ align-items: center;
129
+ gap: 1rem;
130
+ }
131
+
132
+ .player-indicator {
133
+ width: 40px;
134
+ height: 40px;
135
+ border-radius: 50%;
136
+ box-shadow: 0 4px 10px rgba(0, 0, 0, 0.3);
137
+ transition: all 0.3s ease;
138
+ }
139
+
140
+ .player-indicator.black {
141
+ background: radial-gradient(circle at 30% 30%, #444, #000);
142
+ }
143
+
144
+ .player-indicator.white {
145
+ background: radial-gradient(circle at 30% 30%, #fff, #ccc);
146
+ }
147
+
148
+ .player-label {
149
+ font-size: 1.1rem;
150
+ font-weight: 600;
151
+ }
152
+
153
+ .turn-indicator {
154
+ animation: pulse 1.5s infinite;
155
+ }
156
+
157
+ @keyframes pulse {
158
+ 0%, 100% { transform: scale(1); }
159
+ 50% { transform: scale(1.1); }
160
+ }
161
+
162
+ /* Board */
163
+ .board-container {
164
+ position: relative;
165
+ padding: 2rem;
166
+ background: linear-gradient(145deg, var(--wood-dark), var(--wood-light));
167
+ border-radius: 12px;
168
+ box-shadow:
169
+ 0 20px 60px rgba(0, 0, 0, 0.5),
170
+ inset 0 2px 10px rgba(255, 255, 255, 0.1);
171
+ border: 8px solid var(--board-border);
172
+ }
173
+
174
+ .board {
175
+ position: relative;
176
+ background: linear-gradient(145deg, #deb887, #d2a679);
177
+ border-radius: 4px;
178
+ box-shadow: inset 0 0 30px rgba(0, 0, 0, 0.2);
179
+ }
180
+
181
+ .grid-lines {
182
+ position: absolute;
183
+ top: 0;
184
+ left: 0;
185
+ width: 100%;
186
+ height: 100%;
187
+ pointer-events: none;
188
+ }
189
+
190
+ .grid-line {
191
+ position: absolute;
192
+ background: #4a3728;
193
+ }
194
+
195
+ .grid-line.horizontal {
196
+ width: calc(100% - 2px);
197
+ height: 1px;
198
+ left: 1px;
199
+ }
200
+
201
+ .grid-line.vertical {
202
+ width: 1px;
203
+ height: calc(100% - 2px);
204
+ top: 1px;
205
+ }
206
+
207
+ /* Star Points */
208
+ .star-point {
209
+ position: absolute;
210
+ width: 10px;
211
+ height: 10px;
212
+ background: #4a3728;
213
+ border-radius: 50%;
214
+ transform: translate(-50%, -50%);
215
+ }
216
+
217
+ /* Stones */
218
+ .stones-container {
219
+ position: absolute;
220
+ top: 0;
221
+ left: 0;
222
+ width: 100%;
223
+ height: 100%;
224
+ }
225
+
226
+ .stone {
227
+ position: absolute;
228
+ width: 92%;
229
+ height: 92%;
230
+ border-radius: 50%;
231
+ transform: translate(-50%, -50%);
232
+ cursor: pointer;
233
+ transition: transform 0.2s ease;
234
+ box-shadow:
235
+ 2px 4px 8px rgba(0, 0, 0, 0.4),
236
+ inset 2px 4px 8px rgba(255, 255, 255, 0.2),
237
+ inset -2px -4px 8px rgba(0, 0, 0, 0.3);
238
+ }
239
+
240
+ .stone:hover {
241
+ transform: translate(-50%, -50%) scale(1.05);
242
+ }
243
+
244
+ .stone.black {
245
+ background: radial-gradient(circle at 30% 30%, #555, #1a1a1a);
246
+ }
247
+
248
+ .stone.white {
249
+ background: radial-gradient(circle at 30% 30%, #fff, #ccc);
250
+ }
251
+
252
+ .stone.last-move {
253
+ box-shadow:
254
+ 2px 4px 8px rgba(0, 0, 0, 0.4),
255
+ inset 2px 4px 8px rgba(255, 255, 255, 0.2),
256
+ inset -2px -4px 8px rgba(0, 0, 0, 0.3),
257
+ 0 0 15px #ffd700;
258
+ }
259
+
260
+ /* Ghost Stone */
261
+ .ghost-stone {
262
+ position: absolute;
263
+ width: 92%;
264
+ height: 92%;
265
+ border-radius: 50%;
266
+ transform: translate(-50%, -50%);
267
+ pointer-events: none;
268
+ opacity: 0;
269
+ transition: opacity 0.2s ease;
270
+ box-shadow: 0 0 20px rgba(255, 255, 255, 0.5);
271
+ }
272
+
273
+ .ghost-stone.visible {
274
+ opacity: 0.5;
275
+ }
276
+
277
+ .ghost-stone.black {
278
+ background: radial-gradient(circle at 30% 30%, #555, #1a1a1a);
279
+ }
280
+
281
+ .ghost-stone.white {
282
+ background: radial-gradient(circle at 30% 30%, #fff, #ccc);
283
+ }
284
+
285
+ /* Capture Display */
286
+ .captures {
287
+ display: flex;
288
+ gap: 2rem;
289
+ background: rgba(0, 0, 0, 0.2);
290
+ padding: 1rem 1.5rem;
291
+ border-radius: 12px;
292
+ }
293
+
294
+ .capture-item {
295
+ display: flex;
296
+ align-items: center;
297
+ gap: 0.5rem;
298
+ }
299
+
300
+ .capture-stone {
301
+ width: 24px;
302
+ height: 24px;
303
+ border-radius: 50%;
304
+ }
305
+
306
+ .capture-stone.black {
307
+ background: radial-gradient(circle at 30% 30%, #555, #1a1a1a);
308
+ }
309
+
310
+ .capture-stone.white {
311
+ background: radial-gradient(circle at 30% 30%, #fff, #ccc);
312
+ border: 1px solid #ccc;
313
+ }
314
+
315
+ /* Sidebar */
316
+ .sidebar {
317
+ width: 320px;
318
+ display: flex;
319
+ flex-direction: column;
320
+ gap: 1.5rem;
321
+ }
322
+
323
+ .panel {
324
+ background: rgba(255, 255, 255, 0.1);
325
+ backdrop-filter: blur(10px);
326
+ border-radius: 16px;
327
+ padding: 1.5rem;
328
+ border: 1px solid rgba(255, 255, 255, 0.1);
329
+ }
330
+
331
+ .panel-title {
332
+ font-size: 1.2rem;
333
+ font-weight: 600;
334
+ margin-bottom: 1rem;
335
+ display: flex;
336
+ align-items: center;
337
+ gap: 0.5rem;
338
+ color: #ffd700;
339
+ }
340
+
341
+ /* Game Controls */
342
+ .controls {
343
+ display: flex;
344
+ flex-direction: column;
345
+ gap: 0.75rem;
346
+ }
347
+
348
+ .btn {
349
+ padding: 0.875rem 1.5rem;
350
+ border: none;
351
+ border-radius: 10px;
352
+ font-size: 1rem;
353
+ font-weight: 600;
354
+ cursor: pointer;
355
+ transition: all 0.3s ease;
356
+ display: flex;
357
+ align-items: center;
358
+ justify-content: center;
359
+ gap: 0.5rem;
360
+ }
361
+
362
+ .btn-primary {
363
+ background: linear-gradient(135deg, #ffd700, #ffb300);
364
+ color: #1a1a2e;
365
+ box-shadow: 0 4px 15px rgba(255, 215, 0, 0.3);
366
+ }
367
+
368
+ .btn-primary:hover {
369
+ transform: translateY(-2px);
370
+ box-shadow: 0 6px 20px rgba(255, 215, 0, 0.4);
371
+ }
372
+
373
+ .btn-secondary {
374
+ background: rgba(255, 255, 255, 0.1);
375
+ color: #fff;
376
+ border: 1px solid rgba(255, 255, 255, 0.2);
377
+ }
378
+
379
+ .btn-secondary:hover {
380
+ background: rgba(255, 255, 255, 0.2);
381
+ }
382
+
383
+ /* Move History */
384
+ .move-history {
385
+ max-height: 200px;
386
+ overflow-y: auto;
387
+ display: flex;
388
+ flex-direction: column;
389
+ gap: 0.25rem;
390
+ }
391
+
392
+ .move-history::-webkit-scrollbar {
393
+ width: 6px;
394
+ }
395
+
396
+ .move-history::-webkit-scrollbar-track {
397
+ background: rgba(255, 255, 255, 0.1);
398
+ border-radius: 3px;
399
+ }
400
+
401
+ .move-history::-webkit-scrollbar-thumb {
402
+ background: rgba(255, 215, 0, 0.5);
403
+ border-radius: 3px;
404
+ }
405
+
406
+ .move-entry {
407
+ padding: 0.5rem 0.75rem;
408
+ background: rgba(0, 0, 0, 0.2);
409
+ border-radius: 6px;
410
+ font-size: 0.9rem;
411
+ display: flex;
412
+ justify-content: space-between;
413
+ transition: background 0.2s ease;
414
+ }
415
+
416
+ .move-entry:hover {
417
+ background: rgba(0, 0, 0, 0.3);
418
+ }
419
+
420
+ .move-number {
421
+ color: #ffd700;
422
+ font-weight: 600;
423
+ }
424
+
425
+ /* Game Rules */
426
+ .rules-list {
427
+ list-style: none;
428
+ display: flex;
429
+ flex-direction: column;
430
+ gap: 0.75rem;
431
+ }
432
+
433
+ .rules-list li {
434
+ display: flex;
435
+ align-items: flex-start;
436
+ gap: 0.75rem;
437
+ font-size: 0.95rem;
438
+ line-height: 1.4;
439
+ }
440
+
441
+ .rules-list i {
442
+ color: #ffd700;
443
+ margin-top: 2px;
444
+ }
445
+
446
+ /* Modal */
447
+ .modal-overlay {
448
+ position: fixed;
449
+ top: 0;
450
+ left: 0;
451
+ width: 100%;
452
+ height: 100%;
453
+ background: rgba(0, 0, 0, 0.7);
454
+ display: none;
455
+ justify-content: center;
456
+ align-items: center;
457
+ z-index: 1000;
458
+ backdrop-filter: blur(5px);
459
+ }
460
+
461
+ .modal-overlay.active {
462
+ display: flex;
463
+ }
464
+
465
+ .modal {
466
+ background: linear-gradient(145deg, #2c1810, #1a1a2e);
467
+ border-radius: 20px;
468
+ padding: 2.5rem;
469
+ text-align: center;
470
+ max-width: 400px;
471
+ border: 2px solid #ffd700;
472
+ box-shadow: 0 25px 50px rgba(0, 0, 0, 0.5);
473
+ animation: modalSlide 0.3s ease;
474
+ }
475
+
476
+ @keyframes modalSlide {
477
+ from {
478
+ transform: translateY(-50px);
479
+ opacity: 0;
480
+ }
481
+ to {
482
+ transform: translateY(0);
483
+ opacity: 1;
484
+ }
485
+ }
486
+
487
+ .modal h2 {
488
+ font-size: 2rem;
489
+ margin-bottom: 1rem;
490
+ color: #ffd700;
491
+ }
492
+
493
+ .modal p {
494
+ margin-bottom: 1.5rem;
495
+ font-size: 1.1rem;
496
+ line-height: 1.6;
497
+ }
498
+
499
+ .modal .btn-group {
500
+ display: flex;
501
+ gap: 1rem;
502
+ justify-content: center;
503
+ }
504
+
505
+ /* Responsive */
506
+ @media (max-width: 900px) {
507
+ .main-container {
508
+ flex-direction: column;
509
+ align-items: center;
510
+ }
511
+
512
+ .sidebar {
513
+ width: 100%;
514
+ max-width: 500px;
515
+ flex-direction: row;
516
+ flex-wrap: wrap;
517
+ }
518
+
519
+ .sidebar .panel {
520
+ flex: 1;
521
+ min-width: 200px;
522
+ }
523
+ }
524
+
525
+ @media (max-width: 600px) {
526
+ .header {
527
+ flex-direction: column;
528
+ gap: 1rem;
529
+ }
530
+
531
+ .header-links {
532
+ flex-wrap: wrap;
533
+ justify-content: center;
534
+ }
535
+
536
+ .game-info {
537
+ flex-direction: column;
538
+ gap: 1rem;
539
+ }
540
+
541
+ .sidebar {
542
+ flex-direction: column;
543
+ }
544
+ }
545
+
546
+ /* Animations */
547
+ @keyframes stonePlace {
548
+ 0% {
549
+ transform: translate(-50%, -50%) scale(0);
550
+ opacity: 0;
551
+ }
552
+ 50% {
553
+ transform: translate(-50%, -50%) scale(1.2);
554
+ }
555
+ 100% {
556
+ transform: translate(-50%, -50%) scale(1);
557
+ opacity: 1;
558
+ }
559
+ }
560
+
561
+ .stone.new {
562
+ animation: stonePlace 0.3s ease forwards;
563
+ }
564
+
565
+ @keyframes captureEffect {
566
+ 0% {
567
+ transform: translate(-50%, -50%) scale(1);
568
+ opacity: 1;
569
+ }
570
+ 100% {
571
+ transform: translate(-50%, -50%) scale(0);
572
+ opacity: 0;
573
+ }
574
+ }
575
+
576
+ .stone.captured {
577
+ animation: captureEffect 0.5s ease forwards;
578
+ }
579
+ </style>
580
+ </head>
581
+ <body>
582
+ <!-- Header -->
583
+ <header class="header">
584
+ <div class="logo">
585
+ <div class="logo-icon">囲</div>
586
+ <span class="logo-text">GO</span>
587
+ </div>
588
+ <nav class="header-links">
589
+ <a href="#" class="header-link">Rules</a>
590
+ <a href="#" class="header-link">History</a>
591
+ <a href="#" class="header-link" onclick="openAbout()">About</a>
592
+ <a href="https://huggingface.co/spaces/akhaliq/anycoder" class="header-link" target="_blank">Built with anycoder</a>
593
+ </nav>
594
+ </header>
595
+
596
+ <!-- Main Container -->
597
+ <main class="main-container">
598
+ <!-- Game Area -->
599
+ <div class="game-area">
600
+ <div class="game-info">
601
+ <div class="current-player">
602
+ <div class="player-indicator black" id="playerIndicator"></div>
603
+ <div class="player-label">
604
+ <span id="playerLabel">Black's Turn</span>
605
+ </div>
606
+ </div>
607
+ <div class="captures">
608
+ <div class="capture-item">
609
+ <div class="capture-stone white"></div>
610
+ <span id="whiteCaptures">0</span>
611
+ </div>
612
+ <div class="capture-item">
613
+ <div class="capture-stone black"></div>
614
+ <span id="blackCaptures">0</span>
615
+ </div>
616
+ </div>
617
+ </div>
618
+
619
+ <div class="board-container">
620
+ <div class="board" id="board">
621
+ <div class="grid-lines" id="gridLines"></div>
622
+ <div class="star-points" id="starPoints"></div>
623
+ <div class="stones-container" id="stonesContainer">
624
+ <div class="ghost-stone black" id="ghostStone"></div>
625
+ </div>
626
+ </div>
627
+ </div>
628
+ </div>
629
+
630
+ <!-- Sidebar -->
631
+ <aside class="sidebar">
632
+ <div class="panel">
633
+ <h3 class="panel-title">
634
+ <i class="fas fa-gamepad"></i>
635
+ Game Controls
636
+ </h3>
637
+ <div class="controls">
638
+ <button class="btn btn-primary" onclick="newGame()">
639
+ <i class="fas fa-plus"></i>
640
+ New Game
641
+ </button>
642
+ <button class="btn btn-secondary" onclick="passTurn()">
643
+ <i class="fas fa-hand"></i>
644
+ Pass
645
+ </button>
646
+ <button class="btn btn-secondary" onclick="undoMove()">
647
+ <i class="fas fa-undo"></i>
648
+ Undo
649
+ </button>
650
+ </div>
651
+ </div>
652
+
653
+ <div class="panel">
654
+ <h3 class="panel-title">
655
+ <i class="fas fa-history"></i>
656
+ Move History
657
+ </h3>
658
+ <div class="move-history" id="moveHistory">
659
+ <div style="color: rgba(255,255,255,0.5); text-align: center;">No moves yet</div>
660
+ </div>
661
+ </div>
662
+
663
+ <div class="panel">
664
+ <h3 class="panel-title">
665
+ <i class="fas fa-book"></i>
666
+ How to Play
667
+ </h3>
668
+ <ul class="rules-list">
669
+ <li>
670
+ <i class="fas fa-circle"></i>
671
+ Players take turns placing stones on grid intersections
672
+ </li>
673
+ <li>
674
+ <i class="fas fa-circle"></i>
675
+ Capture stones by surrounding them (removing all liberties)
676
+ </li>
677
+ <li>
678
+ <i class="fas fa-circle"></i>
679
+ The goal is to control more territory than your opponent
680
+ </li>
681
+ <li>
682
+ <i class="fas fa-circle"></i>
683
+ Two consecutive passes end the game
684
+ </li>
685
+ </ul>
686
+ </div>
687
+ </aside>
688
+ </main>
689
+
690
+ <!-- Game Over Modal -->
691
+ <div class="modal-overlay" id="gameOverModal">
692
+ <div class="modal">
693
+ <h2><i class="fas fa-trophy"></i> Game Over!</h2>
694
+ <p id="gameResult"></p>
695
+ <div class="btn-group">
696
+ <button class="btn btn-secondary" onclick="closeModal()">Close</button>
697
+ <button class="btn btn-primary" onclick="newGame(); closeModal();">New Game</button>
698
+ </div>
699
+ </div>
700
+ </div>
701
+
702
+ <!-- About Modal -->
703
+ <div class="modal-overlay" id="aboutModal">
704
+ <div class="modal">
705
+ <h2><i class="fas fa-info-circle"></i> About Go</h2>
706
+ <p>Go (囲碁) is an ancient board game originating in China over 2,500 years ago. It's considered one of the most complex and intellectually demanding strategy games in the world.</p>
707
+ <p>The game is played on a 19×19 grid where two players take turns placing black and white stones. The objective is to control more territory than your opponent by surrounding empty points and capturing enemy stones.</p>
708
+ <div class="btn-group">
709
+ <button class="btn btn-primary" onclick="closeAbout()">Got it!</button>
710
+ </div>
711
+ </div>
712
+ </div>
713
+
714
+ <script>
715
+ // Game Configuration
716
+ const BOARD_SIZE = 19;
717
+ const CELL_SIZE = 30;
718
+ const BOARD_PIXELS = (BOARD_SIZE - 1) * CELL_SIZE + 1;
719
+
720
+ // Game State
721
+ let board = [];
722
+ let currentPlayer = 'black';
723
+ let moveHistory = [];
724
+ let captures = { black: 0, white: 0 };
725
+ let passCount = 0;
726
+ let gameOver = false;
727
+ let lastMove = null;
728
+
729
+ // DOM Elements
730
+ const boardElement = document.getElementById('board');
731
+ const gridLinesElement = document.getElementById('gridLines');
732
+ const starPointsElement = document.getElementById('starPoints');
733
+ const stonesContainer = document.getElementById('stonesContainer');
734
+ const ghostStone = document.getElementById('ghostStone');
735
+ const playerIndicator = document.getElementById('playerIndicator');
736
+ const playerLabel = document.getElementById('playerLabel');
737
+ const moveHistoryElement = document.getElementById('moveHistory');
738
+ const whiteCapturesElement = document.getElementById('whiteCaptures');
739
+ const blackCapturesElement = document.getElementById('blackCaptures');
740
+ const gameOverModal = document.getElementById('gameOverModal');
741
+ const aboutModal = document.getElementById('aboutModal');
742
+
743
+ // Initialize Board
744
+ function initBoard() {
745
+ // Set board dimensions
746
+ boardElement.style.width = BOARD_PIXELS + 'px';
747
+ boardElement.style.height = BOARD_PIXELS + 'px';
748
+
749
+ // Clear previous content
750
+ gridLinesElement.innerHTML = '';
751
+ starPointsElement.innerHTML = '';
752
+
753
+ // Create grid lines
754
+ for (let i = 0; i < BOARD_SIZE; i++) {
755
+ // Horizontal lines
756
+ const hLine = document.createElement('div');
757
+ hLine.className = 'grid-line horizontal';
758
+ hLine.style.top = (i * CELL_SIZE) + 'px';
759
+ gridLinesElement.appendChild(hLine);
760
+
761
+ // Vertical lines
762
+ const vLine = document.createElement('div');
763
+ vLine.className = 'grid-line vertical';
764
+ vLine.style.left = (i * CELL_SIZE) + 'px';
765
+ gridLinesElement.appendChild(vLine);
766
+ }
767
+
768
+ // Create star points (hoshi) - standard 19x19 board has 9 star points
769
+ const starPositions = [3, 9, 15];
770
+ for (let row of starPositions) {
771
+ for (let col of starPositions) {
772
+ const starPoint = document.createElement('div');
773
+ starPoint.className = 'star-point';
774
+ starPoint.style.left = (col * CELL_SIZE) + 'px';
775
+ starPoint.style.top = (row * CELL_SIZE) + 'px';
776
+ starPointsElement.appendChild(starPoint);
777
+ }
778
+ }
779
+
780
+ // Initialize internal board state
781
+ resetGame();
782
+ }
783
+
784
+ // Reset Game
785
+ function resetGame() {
786
+ board = Array(BOARD_SIZE).fill(null).map(() => Array(BOARD_SIZE).fill(null));
787
+ currentPlayer = 'black';
788
+ moveHistory = [];
789
+ captures = { black: 0, white: 0 };
790
+ passCount = 0;
791
+ gameOver = false;
792
+ lastMove = null;
793
+
794
+ // Clear stones (keep ghost stone)
795
+ const stones = stonesContainer.querySelectorAll('.stone');
796
+ stones.forEach(stone => stone.remove());
797
+
798
+ updateUI();
799
+ updateMoveHistory();
800
+ }
801
+
802
+ // Get Coordinates from Mouse Event
803
+ function getCoordinates(e) {
804
+ const rect = boardElement.getBoundingClientRect();
805
+ const x = e.clientX - rect.left;
806
+ const y = e.clientY - rect.top;
807
+
808
+ const col = Math.round(x / CELL_SIZE);
809
+ const row = Math.round(y / CELL_SIZE);
810
+
811
+ if (col >= 0 && col < BOARD_SIZE && row >= 0 && row < BOARD_SIZE) {
812
+ return { row, col };
813
+ }
814
+ return null;
815
+ }
816
+
817
+ // Place Stone
818
+ function placeStone(row, col) {
819
+ if (gameOver || board[row][col] !== null) return false;
820
+
821
+ const newBoard = board.map(r => [...r]);
822
+ newBoard[row][col] = currentPlayer;
823
+
824
+ // Check for captures
825
+ const opponent = currentPlayer === 'black' ? 'white' : 'black';
826
+ const capturedStones = [];
827
+
828
+ // Check all four directions for opponent stones
829
+ const directions = [[-1, 0], [1, 0], [0, -1], [0, 1]];
830
+ for (const [dr, dc] of directions) {
831
+ const nr = row + dr;
832
+ const nc = col + dc;
833
+ if (nr >= 0 && nr < BOARD_SIZE && nc >= 0 && nc < BOARD_SIZE && newBoard[nr][nc] === opponent) {
834
+ const group = getGroup(newBoard, nr, nc);
835
+ if (getLiberties(newBoard, group) === 0 && !capturedStones.some(s => s.row === nr && s.col === nc)) {
836
+ capturedStones.push(...group);
837
+ }
838
+ }
839
+ }
840
+
841
+ // Remove captured stones
842
+ for (const stone of capturedStones) {
843
+ newBoard[stone.row][stone.col] = null;
844
+ }
845
+
846
+ // Check for suicide (placing stone where it has no liberties after capture)
847
+ const group = getGroup(newBoard, row, col);
848
+ if (getLiberties(newBoard, group) === 0 && capturedStones.length === 0) {
849
+ return false;
850
+ }
851
+
852
+ // Check for ko (simple version - can't recapture immediately)
853
+ if (moveHistory.length > 0) {
854
+ const lastState = moveHistory[moveHistory.length - 1].boardState;
855
+ if (JSON.stringify(newBoard) === JSON.stringify(lastState)) {
856
+ return false;
857
+ }
858
+ }
859
+
860
+ // Valid move - update game state
861
+ board = newBoard;
862
+ captures[currentPlayer] += capturedStones.length;
863
+
864
+ // Remove captured stones from DOM
865
+ for (const stone of capturedStones) {
866
+ const stoneElement = stonesContainer.querySelector(`[data-row="${stone.row}"][data-col="${stone.col}"]`);
867
+ if (stoneElement) {
868
+ stoneElement.classList.add('captured');
869
+ setTimeout(() => stoneElement.remove(), 500);
870
+ }
871
+ }
872
+
873
+ // Add new stone
874
+ addStoneVisual(row, col, currentPlayer);
875
+
876
+ // Update last move indicator
877
+ const prevLastMove = lastMove;
878
+ lastMove = { row, col, player: currentPlayer };
879
+ updateLastMoveIndicator(prevLastMove);
880
+
881
+ // Save move to history
882
+ moveHistory.push({
883
+ boardState: board.map(r => [...r]),
884
+ player: currentPlayer,
885
+ position: { row, col },
886
+ captures: { ...captures }
887
+ });
888
+
889
+ // Switch player
890
+ currentPlayer = opponent;
891
+ passCount = 0;
892
+
893
+ updateUI();
894
+ updateMoveHistory();
895
+
896
+ return true;
897
+ }
898
+
899
+ // Get group of connected stones
900
+ function getGroup(boardState, row, col) {
901
+ const color = boardState[row][col];
902
+ if (!color) return [];
903
+
904
+ const group = [];
905
+ const visited = new Set();
906
+ const stack = [{ row, col }];
907
+
908
+ while (stack.length > 0) {
909
+ const { row: r, col: c } = stack.pop();
910
+ const key = `${r},${c}`;
911
+ if (visited.has(key)) continue;
912
+ if (boardState[r][c] !== color) continue;
913
+
914
+ visited.add(key);
915
+ group.push({ row: r, col: c });
916
+
917
+ const directions = [[-1, 0], [1, 0], [0, -1], [0, 1]];
918
+ for (const [dr, dc] of directions) {
919
+ const nr = r + dr;
920
+ const nc = c + dc;
921
+ if (nr >= 0 && nr < BOARD_SIZE && nc >= 0 && nc < BOARD_SIZE) {
922
+ stack.push({ row: nr, col: nc });
923
+ }
924
+ }
925
+ }
926
+
927
+ return group;
928
+ }
929
+
930
+ // Count liberties of a group
931
+ function getLiberties(boardState, group) {
932
+ const liberties = new Set();
933
+
934
+ for (const { row, col } of group) {
935
+ const directions = [[-1, 0], [1, 0], [0, -1], [0, 1]];
936
+ for (const [dr, dc] of directions) {
937
+ const nr = row + dr;
938
+ const nc = col + dc;
939
+ if (nr >= 0 && nr < BOARD_SIZE && nc >= 0 && nc < BOARD_SIZE) {
940
+ if (boardState[nr][nc] === null) {
941
+ liberties.add(`${nr},${nc}`);
942
+ }
943
+ }
944
+ }
945
+ }
946
+
947
+ return liberties.size;
948
+ }
949
+
950
+ // Add Stone Visual
951
+ function addStoneVisual(row, col, color) {
952
+ const stone = document.createElement('div');
953
+ stone.className = `stone ${color} new`;
954
+ stone.dataset.row = row;
955
+ stone.dataset.col = col;
956
+ stone.style.left = (col * CELL_SIZE) + 'px';
957
+ stone.style.top = (row * CELL_SIZE) + 'px';
958
+ stonesContainer.appendChild(stone);
959
+
960
+ setTimeout(() => stone.classList.remove('new'), 300);
961
+ }
962
+
963
+ // Update Last Move Indicator
964
+ function updateLastMoveIndicator(prevMove) {
965
+ // Remove previous indicator
966
+ const prevIndicator = stonesContainer.querySelector('.last-move');
967
+ if (prevIndicator) prevIndicator.classList.remove('last-move');
968
+
969
+ // Add new indicator
970
+ if (lastMove) {
971
+ const stone = stonesContainer.querySelector(`[data-row="${lastMove.row}"][data-col="${lastMove.col}"]`);
972
+ if (stone) stone.classList.add('last-move');
973
+ }
974
+ }
975
+
976
+ // Update UI
977
+ function updateUI() {
978
+ // Update player indicator
979
+ playerIndicator.className = `player-indicator ${currentPlayer} turn-indicator`;
980
+ playerLabel.textContent = `${currentPlayer.charAt(0).toUpperCase() + currentPlayer.slice(1)}'s Turn`;
981
+
982
+ // Update captures
983
+ whiteCapturesElement.textContent = captures.white;
984
+ blackCapturesElement.textContent = captures.black;
985
+
986
+ // Update ghost stone
987
+ ghostStone.className = `ghost-stone ${currentPlayer}`;
988
+ }
989
+
990
+ // Update Move History Display
991
+ function updateMoveHistory() {
992
+ if (moveHistory.length === 0) {
993
+ moveHistoryElement.innerHTML = '<div style="color: rgba(255,255,255,0.5); text-align: center;">No moves yet</div>';
994
+ return;
995
+ }
996
+
997
+ const columns = 2;
998
+ const movesPerColumn = Math.ceil(moveHistory.length / columns);
999
+ let html = '<div style="display: grid; grid-template-columns: repeat(2, 1fr); gap: 0.5rem;">';
1000
+
1001
+ for (let i = 0; i < moveHistory.length; i++) {
1002
+ const move = moveHistory[i];
1003
+ const col = Math.floor(i / movesPerColumn) + 1;
1004
+ html += `
1005
+ <div class="move-entry">
1006
+ <span class="move-number">${i + 1}.</span>
1007
+ <span>${move.player.charAt(0).toUpperCase()} @ ${String.fromCharCode(65 + move.position.col)}${move.position.row + 1}</span>
1008
+ </div>
1009
+ `;
1010
+ }
1011
+ html += '</div>';
1012
+ moveHistoryElement.innerHTML = html;
1013
+ }
1014
+
1015
+ // Pass Turn
1016
+ function passTurn() {
1017
+ if (gameOver) return;
1018
+
1019
+ passCount++;
1020
+
1021
+ if (passCount >= 2) {
1022
+ endGame();
1023
+ return;
1024
+ }
1025
+
1026
+ moveHistory.push({
1027
+ boardState: board.map(r => [...r]),
1028
+ player: currentPlayer,
1029
+ position: null,
1030
+ captures: { ...captures },
1031
+ passed: true
1032
+ });
1033
+
1034
+ currentPlayer = currentPlayer === 'black' ? 'white' : 'black';
1035
+ passCount++;
1036
+ lastMove = null;
1037
+ updateUI();
1038
+ updateMoveHistory();
1039
+ }
1040
+
1041
+ // Undo Move
1042
+ function undoMove() {
1043
+ if (moveHistory.length === 0 || gameOver) return;
1044
+
1045
+ moveHistory.pop();
1046
+
1047
+ if (moveHistory.length === 0) {
1048
+ resetGame();
1049
+ return;
1050
+ }
1051
+
1052
+ const lastState = moveHistory[moveHistory.length - 1];
1053
+ board = lastState.boardState.map(r => [...r]);
1054
+ captures = { ...lastState.captures };
1055
+ currentPlayer = lastState.player;
1056
+ passCount = 0;
1057
+
1058
+ // Redraw all stones
1059
+ const stones = stonesContainer.querySelectorAll('.stone:not(#ghostStone)');
1060
+ stones.forEach(stone => stone.remove());
1061
+
1062
+ for (let row = 0; row < BOARD_SIZE; row++) {
1063
+ for (let col = 0; col < BOARD_SIZE; col++) {
1064
+ if (board[row][col]) {
1065
+ addStoneVisual(row, col, board[row][col]);
1066
+ }
1067
+ }
1068
+ }
1069
+
1070
+ lastMove = moveHistory.length > 0 ? moveHistory[moveHistory.length - 1] : null;
1071
+ updateLastMoveIndicator(null);
1072
+ updateUI();
1073
+ updateMoveHistory();
1074
+ }
1075
+
1076
+ // End Game
1077
+ function endGame() {
1078
+ gameOver = true;
1079
+
1080
+ // Simple scoring: territory + captures
1081
+ const blackScore = calculateTerritory('black') + captures.black;
1082
+ const whiteScore = calculateTerritory('white') + captures.white + 6.5; // Komi (handicap compensation)
1083
+
1084
+ const winner = blackScore > whiteScore ? 'Black' : 'White';
1085
+ const margin = Math.abs(blackScore - whiteScore).toFixed(1);
1086
+
1087
+ document.getElementById('gameResult').innerHTML = `
1088
+ <strong>${winner}</strong> wins by <strong>${margin} points</strong>!<br><br>
1089
+ <small>Black: ${blackScore.toFixed(1)} | White: ${whiteScore.toFixed(1)} (includes 6.5 komi)</small>
1090
+ `;
1091
+
1092
+ gameOverModal.classList.add('active');
1093
+ }
1094
+
1095
+ // Calculate Territory
1096
+ function calculateTerritory(player) {
1097
+ const visited = new Set();
1098
+ let territory = 0;
1099
+
1100
+ for (let row = 0; row < BOARD_SIZE; row++) {
1101
+ for (let col = 0; col < BOARD_SIZE; col++) {
1102
+ if (board[row][col] === null && !visited.has(`${row},${col}`)) {
1103
+ const region = getEmptyRegion(row, col);
1104
+ const owners = new Set();
1105
+
1106
+ for (const { r, c } of region) {
1107
+ const directions = [[-1, 0], [1, 0], [0, -1], [0, 1]];
1108
+ for (const [dr, dc] of directions) {
1109
+ const nr = r + dr;
1110
+ const nc = c + dc;
1111
+ if (nr >= 0 && nr < BOARD_SIZE && nc >= 0 && nc < BOARD_SIZE && board[nr][nc]) {
1112
+ owners.add(board[nr][nc]);
1113
+ }
1114
+ }
1115
+ }
1116
+
1117
+ if (owners.size === 1 && owners.has(player)) {
1118
+ territory += region.length;
1119
+ }
1120
+
1121
+ region.forEach(p => visited.add(`${p.r},${p.c}`));
1122
+ }
1123
+ }
1124
+ }
1125
+
1126
+ return territory;
1127
+ }
1128
+
1129
+ // Get empty region
1130
+ function getEmptyRegion(row, col) {
1131
+ const region = [];
1132
+ const visited = new Set();
1133
+ const stack = [{ r: row, c: col }];
1134
+
1135
+ while (stack.length > 0) {
1136
+ const { r, c } = stack.pop();
1137
+ const key = `${r},${c}`;
1138
+ if (visited.has(key)) continue;
1139
+ if (board[r][c] !== null) continue;
1140
+
1141
+ visited.add(key);
1142
+ region.push({ r, c });
1143
+
1144
+ const directions = [[-1, 0], [1, 0], [0, -1], [0, 1]];
1145
+ for (const [dr, dc] of directions) {
1146
+ const nr = r + dr;
1147
+ const nc = c + dc;
1148
+ if (nr >= 0 && nr < BOARD_SIZE && nc >= 0 && nc < BOARD_SIZE) {
1149
+ stack.push({ r: nr, c: nc });
1150
+ }
1151
+ }
1152
+ }
1153
+
1154
+ return region;
1155
+ }
1156
+
1157
+ // New Game
1158
+ function newGame() {
1159
+ resetGame();
1160
+ }
1161
+
1162
+ // Modal functions
1163
+ function closeModal() {
1164
+ gameOverModal.classList.remove('active');
1165
+ }
1166
+
1167
+ function openAbout() {
1168
+ aboutModal.classList.add('active');
1169
+ }
1170
+
1171
+ function closeAbout() {
1172
+ aboutModal.classList.remove('active');
1173
+ }
1174
+
1175
+ // Event Listeners
1176
+ boardElement.addEventListener('mousemove', (e) => {
1177
+ const coords = getCoordinates(e);
1178
+ if (coords && !gameOver) {
1179
+ ghostStone.style.left = (coords.col * CELL_SIZE) + 'px';
1180
+ ghostStone.style.top = (coords.row * CELL_SIZE) + 'px';
1181
+ ghostStone.classList.add('visible');
1182
+ } else {
1183
+ ghostStone.classList.remove('visible');
1184
+ }
1185
+ });
1186
+
1187
+ boardElement.addEventListener('mouseleave', () => {
1188
+ ghostStone.classList.remove('visible');
1189
+ });
1190
+
1191
+ boardElement.addEventListener('click', (e) => {
1192
+ const coords = getCoordinates(e);
1193
+ if (coords) {
1194
+ placeStone(coords.row, coords.col);
1195
+ }
1196
+ });
1197
+
1198
+ // Close modals on outside click
1199
+ gameOverModal.addEventListener('click', (e) => {
1200
+ if (e.target === gameOverModal) closeModal();
1201
+ });
1202
+
1203
+ aboutModal.addEventListener('click', (e) => {
1204
+ if (e.target === aboutModal) closeAbout();
1205
+ });
1206
+
1207
+ // Keyboard shortcuts
1208
+ document.addEventListener('keydown', (e) => {
1209
+ if (e.key === 'n' || e.key === 'N') newGame();
1210
+ if (e.key === 'p' || e.key === 'P') passTurn();
1211
+ if (e.key === 'z' && (e.ctrlKey || e.metaKey)) {
1212
+ e.preventDefault();
1213
+ undoMove();
1214
+ }
1215
+ if (e.key === 'Escape') {
1216
+ closeModal();
1217
+ closeAbout();
1218
+ }
1219
+ });
1220
+
1221
+ // Initialize on load
1222
+ window.addEventListener('load', initBoard);
1223
+
1224
+ // Handle window resize
1225
+ window.addEventListener('resize', () => {
1226
+ ghostStone.classList.remove('visible');
1227
+ });
1228
+ </script>
1229
+ </body>
1230
+ </html>