kamiwork commited on
Commit
eedaa76
·
verified ·
1 Parent(s): 2dfe150

Delete Asad.html

Browse files
Files changed (1) hide show
  1. Asad.html +0 -1040
Asad.html DELETED
@@ -1,1040 +0,0 @@
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>String Carrom - Pocket All</title>
7
- <style>
8
- * {
9
- margin: 0;
10
- padding: 0;
11
- box-sizing: border-box;
12
- }
13
-
14
- body {
15
- background: #000;
16
- overflow: hidden;
17
- font-family: 'Arial', sans-serif;
18
- }
19
-
20
- #gameContainer {
21
- position: relative;
22
- width: 100vw;
23
- height: 100vh;
24
- display: flex;
25
- justify-content: center;
26
- align-items: center;
27
- background: radial-gradient(circle at center, #1a1a2e 0%, #16213e 50%, #0f3460 100%);
28
- }
29
-
30
- canvas {
31
- background: linear-gradient(45deg, #8B4513 0%, #A0522D 100%);
32
- border-radius: 10px;
33
- box-shadow: 0 0 60px rgba(0, 0, 0, 0.8);
34
- cursor: crosshair;
35
- }
36
-
37
- /* HUD - Clean Minimal UI */
38
- .hud {
39
- position: absolute;
40
- top: 20px;
41
- left: 50%;
42
- transform: translateX(-50%);
43
- display: flex;
44
- gap: 30px;
45
- background: rgba(0, 0, 0, 0.7);
46
- padding: 12px 25px;
47
- border-radius: 50px;
48
- border: 2px solid rgba(255, 255, 255, 0.1);
49
- backdrop-filter: blur(10px);
50
- z-index: 100;
51
- }
52
-
53
- .player-score {
54
- display: flex;
55
- align-items: center;
56
- gap: 10px;
57
- color: white;
58
- font-size: 1.1rem;
59
- font-weight: bold;
60
- text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.5);
61
- }
62
-
63
- .player-indicator {
64
- width: 20px;
65
- height: 20px;
66
- border-radius: 50%;
67
- border: 2px solid rgba(255, 255, 255, 0.3);
68
- }
69
-
70
- .player-indicator.white {
71
- background: white;
72
- box-shadow: 0 0 10px white;
73
- }
74
-
75
- .player-indicator.black {
76
- background: black;
77
- box-shadow: 0 0 10px #666;
78
- }
79
-
80
- .player-indicator.active {
81
- animation: pulse 1.5s infinite;
82
- }
83
-
84
- @keyframes pulse {
85
- 0% { transform: scale(1); }
86
- 50% { transform: scale(1.2); }
87
- 100% { transform: scale(1); }
88
- }
89
-
90
- .queen-status {
91
- position: absolute;
92
- top: 20px;
93
- right: 20px;
94
- background: rgba(220, 53, 69, 0.9);
95
- color: white;
96
- padding: 8px 15px;
97
- border-radius: 20px;
98
- font-size: 0.9rem;
99
- font-weight: bold;
100
- display: flex;
101
- align-items: center;
102
- gap: 8px;
103
- box-shadow: 0 4px 15px rgba(220, 53, 69, 0.4);
104
- }
105
-
106
- .power-meter {
107
- position: absolute;
108
- bottom: 30px;
109
- left: 50%;
110
- transform: translateX(-50%);
111
- width: 300px;
112
- height: 10px;
113
- background: rgba(255, 255, 255, 0.1);
114
- border-radius: 10px;
115
- overflow: hidden;
116
- }
117
-
118
- .power-fill {
119
- height: 100%;
120
- background: linear-gradient(90deg, #4CAF50, #FF9800, #F44336);
121
- width: 50%;
122
- border-radius: 10px;
123
- transition: width 0.1s;
124
- }
125
-
126
- .controls {
127
- position: absolute;
128
- bottom: 60px;
129
- left: 20px;
130
- color: white;
131
- font-size: 0.8rem;
132
- opacity: 0.7;
133
- }
134
-
135
- .controls span {
136
- background: rgba(255, 255, 255, 0.1);
137
- padding: 4px 8px;
138
- border-radius: 4px;
139
- margin: 0 2px;
140
- }
141
-
142
- /* Game Messages */
143
- .message {
144
- position: absolute;
145
- top: 50%;
146
- left: 50%;
147
- transform: translate(-50%, -50%);
148
- background: rgba(0, 0, 0, 0.85);
149
- color: white;
150
- padding: 25px 40px;
151
- border-radius: 15px;
152
- text-align: center;
153
- font-size: 2rem;
154
- font-weight: bold;
155
- z-index: 1000;
156
- display: none;
157
- border: 3px solid rgba(255, 255, 255, 0.1);
158
- box-shadow: 0 0 50px rgba(0, 0, 0, 0.9);
159
- }
160
-
161
- .message button {
162
- margin-top: 20px;
163
- padding: 12px 30px;
164
- background: linear-gradient(45deg, #FF416C, #FF4B2B);
165
- color: white;
166
- border: none;
167
- border-radius: 25px;
168
- font-size: 1rem;
169
- font-weight: bold;
170
- cursor: pointer;
171
- transition: transform 0.2s;
172
- }
173
-
174
- .message button:hover {
175
- transform: scale(1.05);
176
- }
177
-
178
- /* Aiming Line */
179
- .aim-line {
180
- position: absolute;
181
- pointer-events: none;
182
- z-index: 10;
183
- }
184
-
185
- /* Loading Screen */
186
- #loadingScreen {
187
- position: absolute;
188
- top: 0;
189
- left: 0;
190
- width: 100%;
191
- height: 100%;
192
- background: #000;
193
- display: flex;
194
- justify-content: center;
195
- align-items: center;
196
- z-index: 10000;
197
- flex-direction: column;
198
- gap: 20px;
199
- }
200
-
201
- .loader {
202
- width: 50px;
203
- height: 50px;
204
- border: 5px solid rgba(255, 255, 255, 0.1);
205
- border-top-color: #8B4513;
206
- border-radius: 50%;
207
- animation: spin 1s linear infinite;
208
- }
209
-
210
- @keyframes spin {
211
- to { transform: rotate(360deg); }
212
- }
213
-
214
- #loadingScreen h2 {
215
- color: white;
216
- font-size: 1.5rem;
217
- }
218
-
219
- /* Mobile Optimizations */
220
- @media (max-width: 768px) {
221
- canvas {
222
- width: 95vw;
223
- height: 95vw;
224
- max-width: 500px;
225
- max-height: 500px;
226
- }
227
-
228
- .hud {
229
- padding: 8px 15px;
230
- gap: 15px;
231
- }
232
-
233
- .queen-status {
234
- font-size: 0.7rem;
235
- padding: 6px 10px;
236
- }
237
-
238
- .power-meter {
239
- width: 250px;
240
- bottom: 40px;
241
- }
242
- }
243
- </style>
244
- </head>
245
- <body>
246
- <div id="loadingScreen">
247
- <div class="loader"></div>
248
- <h2>Loading String Carrom...</h2>
249
- </div>
250
-
251
- <div id="gameContainer">
252
- <canvas id="gameCanvas"></canvas>
253
-
254
- <div class="hud">
255
- <div class="player-score" id="whiteScore">
256
- <div class="player-indicator white active" id="whiteIndicator"></div>
257
- <span>WHITE: <span id="whiteCount">9</span></span>
258
- </div>
259
- <div class="player-score" id="blackScore">
260
- <div class="player-indicator black" id="blackIndicator"></div>
261
- <span>BLACK: <span id="blackCount">9</span></span>
262
- </div>
263
- </div>
264
-
265
- <div class="queen-status" id="queenStatus">
266
- <div style="width: 10px; height: 10px; background: #FF0000; border-radius: 50%;"></div>
267
- <span>QUEEN NOT POCKETED</span>
268
- </div>
269
-
270
- <div class="power-meter">
271
- <div class="power-fill" id="powerFill"></div>
272
- </div>
273
-
274
- <div class="controls">
275
- CLICK & DRAG TO AIM | RELEASE TO SHOOT
276
- </div>
277
-
278
- <div class="message" id="winMessage">
279
- <div id="winnerText"></div>
280
- <button onclick="resetGame()">PLAY AGAIN</button>
281
- </div>
282
- </div>
283
-
284
- <script>
285
- // Game Configuration
286
- const CONFIG = {
287
- BOARD_SIZE: 600,
288
- STRIKER_RADIUS: 20,
289
- PIECE_RADIUS: 15,
290
- POCKET_SIZE: 35,
291
- FRICTION: 0.985,
292
- ELASTICITY: 0.85,
293
- MIN_VELOCITY: 0.3,
294
- MAX_POWER: 15,
295
- AIM_LINE_LENGTH: 300
296
- };
297
-
298
- // Game State
299
- let gameState = {
300
- pieces: [],
301
- striker: null,
302
- currentPlayer: 'white',
303
- scores: { white: 9, black: 9 },
304
- queenPocketed: false,
305
- queenPocketedBy: null,
306
- playerHasPiece: { white: false, black: false },
307
- gameActive: true,
308
- isAiming: false,
309
- aimStart: { x: 0, y: 0 },
310
- power: 0.5,
311
- mousePos: { x: 0, y: 0 }
312
- };
313
-
314
- // DOM Elements
315
- const canvas = document.getElementById('gameCanvas');
316
- const ctx = canvas.getContext('2d');
317
- const whiteCountEl = document.getElementById('whiteCount');
318
- const blackCountEl = document.getElementById('blackCount');
319
- const whiteIndicator = document.getElementById('whiteIndicator');
320
- const blackIndicator = document.getElementById('blackIndicator');
321
- const queenStatusEl = document.getElementById('queenStatus');
322
- const powerFillEl = document.getElementById('powerFill');
323
- const winMessageEl = document.getElementById('winMessage');
324
- const winnerTextEl = document.getElementById('winnerText');
325
- const loadingScreen = document.getElementById('loadingScreen');
326
-
327
- // Initialize Canvas
328
- canvas.width = CONFIG.BOARD_SIZE;
329
- canvas.height = CONFIG.BOARD_SIZE;
330
-
331
- // Piece Class
332
- class Piece {
333
- constructor(x, y, color, isQueen = false) {
334
- this.x = x;
335
- this.y = y;
336
- this.radius = CONFIG.PIECE_RADIUS;
337
- this.color = color;
338
- this.isQueen = isQueen;
339
- this.vx = 0;
340
- this.vy = 0;
341
- this.pocketed = false;
342
- this.alpha = 1;
343
- }
344
-
345
- draw() {
346
- if (this.pocketed) return;
347
-
348
- ctx.save();
349
- ctx.globalAlpha = this.alpha;
350
-
351
- // Draw piece
352
- ctx.beginPath();
353
- ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2);
354
-
355
- if (this.isQueen) {
356
- // Queen (red with gold border)
357
- const gradient = ctx.createRadialGradient(
358
- this.x, this.y, this.radius * 0.3,
359
- this.x, this.y, this.radius
360
- );
361
- gradient.addColorStop(0, '#FF6B6B');
362
- gradient.addColorStop(1, '#C92A2A');
363
-
364
- ctx.fillStyle = gradient;
365
- ctx.fill();
366
-
367
- // Gold border
368
- ctx.strokeStyle = '#FFD700';
369
- ctx.lineWidth = 3;
370
- ctx.stroke();
371
-
372
- // Crown symbol
373
- ctx.fillStyle = '#FFD700';
374
- ctx.font = 'bold 14px Arial';
375
- ctx.textAlign = 'center';
376
- ctx.textBaseline = 'middle';
377
- ctx.fillText('Q', this.x, this.y);
378
- } else {
379
- // Regular piece with gradient
380
- const gradient = ctx.createRadialGradient(
381
- this.x, this.y, this.radius * 0.3,
382
- this.x, this.y, this.radius
383
- );
384
-
385
- if (this.color === 'white') {
386
- gradient.addColorStop(0, '#FFFFFF');
387
- gradient.addColorStop(1, '#E0E0E0');
388
- } else {
389
- gradient.addColorStop(0, '#666666');
390
- gradient.addColorStop(1, '#000000');
391
- }
392
-
393
- ctx.fillStyle = gradient;
394
- ctx.fill();
395
-
396
- // Border
397
- ctx.strokeStyle = this.color === 'white' ? '#CCCCCC' : '#333333';
398
- ctx.lineWidth = 2;
399
- ctx.stroke();
400
- }
401
-
402
- // Highlight
403
- ctx.beginPath();
404
- ctx.arc(this.x - this.radius * 0.3, this.y - this.radius * 0.3,
405
- this.radius * 0.4, 0, Math.PI * 2);
406
- ctx.fillStyle = 'rgba(255, 255, 255, 0.3)';
407
- ctx.fill();
408
-
409
- ctx.restore();
410
- }
411
-
412
- update() {
413
- if (this.pocketed) {
414
- this.alpha -= 0.05;
415
- if (this.alpha <= 0) {
416
- this.alpha = 0;
417
- }
418
- return;
419
- }
420
-
421
- // Apply friction
422
- this.vx *= CONFIG.FRICTION;
423
- this.vy *= CONFIG.FRICTION;
424
-
425
- // Update position
426
- this.x += this.vx;
427
- this.y += this.vy;
428
-
429
- // Boundary collision with damping
430
- const margin = this.radius + 5;
431
- if (this.x < margin) {
432
- this.x = margin;
433
- this.vx = -this.vx * CONFIG.ELASTICITY;
434
- }
435
- if (this.x > CONFIG.BOARD_SIZE - margin) {
436
- this.x = CONFIG.BOARD_SIZE - margin;
437
- this.vx = -this.vx * CONFIG.ELASTICITY;
438
- }
439
- if (this.y < margin) {
440
- this.y = margin;
441
- this.vy = -this.vy * CONFIG.ELASTICITY;
442
- }
443
- if (this.y > CONFIG.BOARD_SIZE - margin) {
444
- this.y = CONFIG.BOARD_SIZE - margin;
445
- this.vy = -this.vy * CONFIG.ELASTICITY;
446
- }
447
-
448
- // Check pocket
449
- if (!this.pocketed) {
450
- this.checkPocket();
451
- }
452
- }
453
-
454
- checkPocket() {
455
- const pockets = [
456
- {x: CONFIG.POCKET_SIZE, y: CONFIG.POCKET_SIZE},
457
- {x: CONFIG.BOARD_SIZE - CONFIG.POCKET_SIZE, y: CONFIG.POCKET_SIZE},
458
- {x: CONFIG.POCKET_SIZE, y: CONFIG.BOARD_SIZE - CONFIG.POCKET_SIZE},
459
- {x: CONFIG.BOARD_SIZE - CONFIG.POCKET_SIZE, y: CONFIG.BOARD_SIZE - CONFIG.POCKET_SIZE}
460
- ];
461
-
462
- for (const pocket of pockets) {
463
- const dx = this.x - pocket.x;
464
- const dy = this.y - pocket.y;
465
- const distance = Math.sqrt(dx * dx + dy * dy);
466
-
467
- if (distance < CONFIG.POCKET_SIZE * 0.8) {
468
- this.pocket();
469
- return;
470
- }
471
- }
472
- }
473
-
474
- pocket() {
475
- if (this.pocketed) return;
476
-
477
- this.pocketed = true;
478
-
479
- if (this.isQueen) {
480
- gameState.queenPocketed = true;
481
- gameState.queenPocketedBy = gameState.currentPlayer;
482
- updateQueenStatus();
483
- } else {
484
- gameState.scores[this.color]--;
485
- updateScore();
486
- gameState.playerHasPiece[gameState.currentPlayer] = true;
487
- }
488
- }
489
- }
490
-
491
- // Striker Class
492
- class Striker {
493
- constructor() {
494
- this.x = CONFIG.BOARD_SIZE / 2;
495
- this.y = CONFIG.BOARD_SIZE - 80;
496
- this.radius = CONFIG.STRIKER_RADIUS;
497
- this.vx = 0;
498
- this.vy = 0;
499
- this.isMoving = false;
500
- this.angle = 0;
501
- this.power = 0;
502
- }
503
-
504
- draw() {
505
- // Draw striker with metal effect
506
- const gradient = ctx.createRadialGradient(
507
- this.x, this.y, this.radius * 0.2,
508
- this.x, this.y, this.radius
509
- );
510
- gradient.addColorStop(0, '#AAAAAA');
511
- gradient.addColorStop(0.5, '#666666');
512
- gradient.addColorStop(1, '#333333');
513
-
514
- ctx.save();
515
-
516
- // Striker body
517
- ctx.beginPath();
518
- ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2);
519
- ctx.fillStyle = gradient;
520
- ctx.fill();
521
-
522
- // Border
523
- ctx.strokeStyle = '#111111';
524
- ctx.lineWidth = 3;
525
- ctx.stroke();
526
-
527
- // Center dot
528
- ctx.fillStyle = '#FFFFFF';
529
- ctx.beginPath();
530
- ctx.arc(this.x, this.y, 4, 0, Math.PI * 2);
531
- ctx.fill();
532
-
533
- // String effect
534
- ctx.strokeStyle = 'rgba(139, 69, 19, 0.8)';
535
- ctx.lineWidth = 2;
536
- ctx.beginPath();
537
- ctx.moveTo(CONFIG.BOARD_SIZE / 2, 30);
538
- ctx.lineTo(this.x, this.y);
539
- ctx.stroke();
540
-
541
- ctx.restore();
542
- }
543
-
544
- update() {
545
- if (!this.isMoving) return;
546
-
547
- // Apply friction
548
- this.vx *= CONFIG.FRICTION;
549
- this.vy *= CONFIG.FRICTION;
550
-
551
- // Update position
552
- this.x += this.vx;
553
- this.y += this.vy;
554
-
555
- // Boundary collision
556
- const margin = this.radius + 2;
557
- if (this.x < margin) {
558
- this.x = margin;
559
- this.vx = -this.vx * CONFIG.ELASTICITY;
560
- }
561
- if (this.x > CONFIG.BOARD_SIZE - margin) {
562
- this.x = CONFIG.BOARD_SIZE - margin;
563
- this.vx = -this.vx * CONFIG.ELASTICITY;
564
- }
565
- if (this.y < margin) {
566
- this.y = margin;
567
- this.vy = -this.vy * CONFIG.ELASTICITY;
568
- }
569
- if (this.y > CONFIG.BOARD_SIZE - margin) {
570
- this.y = CONFIG.BOARD_SIZE - margin;
571
- this.vy = -this.vy * CONFIG.ELASTICITY;
572
- }
573
-
574
- // Check if stopped
575
- if (Math.abs(this.vx) < CONFIG.MIN_VELOCITY && Math.abs(this.vy) < CONFIG.MIN_VELOCITY) {
576
- this.isMoving = false;
577
- this.vx = this.vy = 0;
578
- endTurn();
579
- }
580
-
581
- // Collision with pieces
582
- gameState.pieces.forEach(piece => {
583
- if (!piece.pocketed) {
584
- const dx = this.x - piece.x;
585
- const dy = this.y - piece.y;
586
- const distance = Math.sqrt(dx * dx + dy * dy);
587
- const minDist = this.radius + piece.radius;
588
-
589
- if (distance < minDist) {
590
- // Collision response
591
- const angle = Math.atan2(dy, dx);
592
- const sine = Math.sin(angle);
593
- const cosine = Math.cos(angle);
594
-
595
- // Rotate velocity vectors
596
- const vx1 = this.vx * cosine + this.vy * sine;
597
- const vy1 = this.vy * cosine - this.vx * sine;
598
- const vx2 = piece.vx * cosine + piece.vy * sine;
599
- const vy2 = piece.vy * cosine - piece.vx * sine;
600
-
601
- // Final velocities after collision
602
- const finalVx1 = vx2;
603
- const finalVx2 = vx1;
604
-
605
- // Rotate velocities back
606
- this.vx = finalVx1 * cosine - vy1 * sine;
607
- this.vy = vy1 * cosine + finalVx1 * sine;
608
- piece.vx = finalVx2 * cosine - vy2 * sine;
609
- piece.vy = vy2 * cosine + finalVx2 * sine;
610
-
611
- // Separate pieces
612
- const overlap = minDist - distance;
613
- this.x += cosine * overlap * 0.5;
614
- this.y += sine * overlap * 0.5;
615
- piece.x -= cosine * overlap * 0.5;
616
- piece.y -= sine * overlap * 0.5;
617
- }
618
- }
619
- });
620
- }
621
-
622
- shoot(power, angle) {
623
- if (this.isMoving) return;
624
-
625
- this.power = power * CONFIG.MAX_POWER;
626
- this.angle = angle;
627
- this.vx = Math.sin(angle) * this.power;
628
- this.vy = Math.cos(angle) * this.power;
629
- this.isMoving = true;
630
- }
631
-
632
- reset() {
633
- this.x = CONFIG.BOARD_SIZE / 2;
634
- this.y = CONFIG.BOARD_SIZE - 80;
635
- this.vx = 0;
636
- this.vy = 0;
637
- this.isMoving = false;
638
- }
639
- }
640
-
641
- // Initialize Game
642
- function initGame() {
643
- // Reset game state
644
- gameState = {
645
- pieces: [],
646
- striker: null,
647
- currentPlayer: 'white',
648
- scores: { white: 9, black: 9 },
649
- queenPocketed: false,
650
- queenPocketedBy: null,
651
- playerHasPiece: { white: false, black: false },
652
- gameActive: true,
653
- isAiming: false,
654
- aimStart: { x: 0, y: 0 },
655
- power: 0.5,
656
- mousePos: { x: 0, y: 0 }
657
- };
658
-
659
- // Create pieces in carrom formation
660
- const centerX = CONFIG.BOARD_SIZE / 2;
661
- const centerY = CONFIG.BOARD_SIZE / 2;
662
-
663
- // Add Queen
664
- gameState.pieces.push(new Piece(centerX, centerY, 'red', true));
665
-
666
- // Create circle of pieces
667
- const ringRadius = 70;
668
- const totalPieces = 18;
669
-
670
- for (let i = 0; i < totalPieces; i++) {
671
- const angle = (i * Math.PI * 2) / totalPieces;
672
- const x = centerX + Math.cos(angle) * ringRadius;
673
- const y = centerY + Math.sin(angle) * ringRadius;
674
- const color = i % 2 === 0 ? 'white' : 'black';
675
- gameState.pieces.push(new Piece(x, y, color));
676
- }
677
- gameState.striker = new Striker();
678
-
679
- // Update UI
680
- updateScore();
681
- updateQueenStatus();
682
- updatePlayerIndicator();
683
- winMessageEl.style.display = 'none';
684
-
685
- // Hide loading screen
686
- setTimeout(() => {
687
- loadingScreen.style.display = 'none';
688
- }, 500);
689
- }
690
-
691
- // Draw Board
692
- function drawBoard() {
693
- // Board surface with wood grain effect
694
- ctx.fillStyle = '#8B4513';
695
- ctx.fillRect(0, 0, CONFIG.BOARD_SIZE, CONFIG.BOARD_SIZE);
696
-
697
- // Wood grain effect
698
- ctx.strokeStyle = 'rgba(139, 69, 19, 0.3)';
699
- ctx.lineWidth = 1;
700
- for (let i = 0; i < CONFIG.BOARD_SIZE; i += 20) {
701
- ctx.beginPath();
702
- ctx.moveTo(i, 0);
703
- ctx.lineTo(i, CONFIG.BOARD_SIZE);
704
- ctx.stroke();
705
- }
706
-
707
- // Border
708
- ctx.strokeStyle = '#5D2906';
709
- ctx.lineWidth = 20;
710
- ctx.strokeRect(10, 10, CONFIG.BOARD_SIZE - 20, CONFIG.BOARD_SIZE - 20);
711
-
712
- // Inner border
713
- ctx.strokeStyle = '#A0522D';
714
- ctx.lineWidth = 2;
715
- ctx.strokeRect(25, 25, CONFIG.BOARD_SIZE - 50, CONFIG.BOARD_SIZE - 50);
716
-
717
- // Center circle
718
- ctx.strokeStyle = '#5D2906';
719
- ctx.lineWidth = 3;
720
- ctx.beginPath();
721
- ctx.arc(CONFIG.BOARD_SIZE / 2, CONFIG.BOARD_SIZE / 2, 60, 0, Math.PI * 2);
722
- ctx.stroke();
723
-
724
- // Pockets
725
- const pockets = [
726
- {x: CONFIG.POCKET_SIZE, y: CONFIG.POCKET_SIZE},
727
- {x: CONFIG.BOARD_SIZE - CONFIG.POCKET_SIZE, y: CONFIG.POCKET_SIZE},
728
- {x: CONFIG.POCKET_SIZE, y: CONFIG.BOARD_SIZE - CONFIG.POCKET_SIZE},
729
- {x: CONFIG.BOARD_SIZE - CONFIG.POCKET_SIZE, y: CONFIG.BOARD_SIZE - CONFIG.POCKET_SIZE}
730
- ];
731
-
732
- pockets.forEach(pocket => {
733
- // Pocket shadow
734
- ctx.fillStyle = 'rgba(0, 0, 0, 0.5)';
735
- ctx.beginPath();
736
- ctx.arc(pocket.x, pocket.y, CONFIG.POCKET_SIZE, 0, Math.PI * 2);
737
- ctx.fill();
738
-
739
- // Pocket hole
740
- const gradient = ctx.createRadialGradient(
741
- pocket.x, pocket.y, CONFIG.POCKET_SIZE * 0.3,
742
- pocket.x, pocket.y, CONFIG.POCKET_SIZE
743
- );
744
- gradient.addColorStop(0, '#111111');
745
- gradient.addColorStop(1, '#000000');
746
-
747
- ctx.fillStyle = gradient;
748
- ctx.beginPath();
749
- ctx.arc(pocket.x, pocket.y, CONFIG.POCKET_SIZE, 0, Math.PI * 2);
750
- ctx.fill();
751
- });
752
-
753
- // Center lines
754
- ctx.strokeStyle = 'rgba(93, 41, 6, 0.3)';
755
- ctx.lineWidth = 1;
756
- ctx.beginPath();
757
- ctx.moveTo(CONFIG.BOARD_SIZE / 2, 0);
758
- ctx.lineTo(CONFIG.BOARD_SIZE / 2, CONFIG.BOARD_SIZE);
759
- ctx.moveTo(0, CONFIG.BOARD_SIZE / 2);
760
- ctx.lineTo(CONFIG.BOARD_SIZE, CONFIG.BOARD_SIZE / 2);
761
- ctx.stroke();
762
- }
763
-
764
- // Draw Aiming Line
765
- function drawAimingLine() {
766
- if (!gameState.isAiming || gameState.striker.isMoving) return;
767
-
768
- const striker = gameState.striker;
769
- const dx = gameState.mousePos.x - striker.x;
770
- const dy = gameState.mousePos.y - striker.y;
771
- const distance = Math.min(Math.sqrt(dx * dx + dy * dy), CONFIG.AIM_LINE_LENGTH);
772
- const angle = Math.atan2(dy, dx);
773
-
774
- gameState.power = distance / CONFIG.AIM_LINE_LENGTH;
775
- powerFillEl.style.width = (gameState.power * 100) + '%';
776
-
777
- // Draw aiming line
778
- ctx.save();
779
- ctx.strokeStyle = 'rgba(255, 255, 255, 0.7)';
780
- ctx.lineWidth = 2;
781
- ctx.setLineDash([5, 5]);
782
- ctx.beginPath();
783
- ctx.moveTo(striker.x, striker.y);
784
- ctx.lineTo(
785
- striker.x + Math.cos(angle) * distance,
786
- striker.y + Math.sin(angle) * distance
787
- );
788
- ctx.stroke();
789
-
790
- // Draw power indicator at end
791
- ctx.fillStyle = gameState.power > 0.8 ? '#FF4444' :
792
- gameState.power > 0.5 ? '#FFAA44' : '#44FF44';
793
- ctx.beginPath();
794
- ctx.arc(
795
- striker.x + Math.cos(angle) * distance,
796
- striker.y + Math.sin(angle) * distance,
797
- 8, 0, Math.PI * 2
798
- );
799
- ctx.fill();
800
-
801
- ctx.restore();
802
- }
803
-
804
- // Update Score Display
805
- function updateScore() {
806
- whiteCountEl.textContent = gameState.scores.white;
807
- blackCountEl.textContent = gameState.scores.black;
808
- }
809
-
810
- // Update Queen Status
811
- function updateQueenStatus() {
812
- if (gameState.queenPocketed) {
813
- queenStatusEl.innerHTML = `
814
- <div style="width: 10px; height: 10px; background: #00FF00; border-radius: 50%;"></div>
815
- <span>QUEEN POCKETED BY ${gameState.queenPocketedBy.toUpperCase()}</span>
816
- `;
817
- queenStatusEl.style.background = 'rgba(76, 175, 80, 0.9)';
818
- } else {
819
- queenStatusEl.innerHTML = `
820
- <div style="width: 10px; height: 10px; background: #FF0000; border-radius: 50%;"></div>
821
- <span>QUEEN NOT POCKETED</span>
822
- `;
823
- queenStatusEl.style.background = 'rgba(220, 53, 69, 0.9)';
824
- }
825
- }
826
-
827
- // Update Player Indicator
828
- function updatePlayerIndicator() {
829
- if (gameState.currentPlayer === 'white') {
830
- whiteIndicator.classList.add('active');
831
- blackIndicator.classList.remove('active');
832
- } else {
833
- whiteIndicator.classList.remove('active');
834
- blackIndicator.classList.add('active');
835
- }
836
- }
837
-
838
- // End Turn
839
- function endTurn() {
840
- if (!gameState.gameActive) return;
841
-
842
- // Check for invalid queen pocket
843
- if (gameState.queenPocketed && gameState.queenPocketedBy === gameState.currentPlayer) {
844
- if (!gameState.playerHasPiece[gameState.currentPlayer]) {
845
- // Invalid: Pocketed queen before first piece
846
- gameState.queenPocketed = false;
847
- gameState.queenPocketedBy = null;
848
- // Return queen to board
849
- const queen = gameState.pieces.find(p => p.isQueen);
850
- if (queen) {
851
- queen.pocketed = false;
852
- queen.alpha = 1;
853
- queen.x = CONFIG.BOARD_SIZE / 2;
854
- queen.y = CONFIG.BOARD_SIZE / 2;
855
- }
856
- updateQueenStatus();
857
- }
858
- }
859
-
860
- // Switch player
861
- gameState.currentPlayer = gameState.currentPlayer === 'white' ? 'black' : 'white';
862
-
863
- // Reset striker for next player
864
- gameState.striker.reset();
865
-
866
- // Update UI
867
- updatePlayerIndicator();
868
- checkWinCondition();
869
- }
870
-
871
- // Check Win Condition
872
- function checkWinCondition() {
873
- if (!gameState.gameActive) return;
874
-
875
- const whiteWins = gameState.scores.white === 0 &&
876
- gameState.queenPocketed &&
877
- gameState.queenPocketedBy === 'white';
878
-
879
- const blackWins = gameState.scores.black === 0 &&
880
- gameState.queenPocketed &&
881
- gameState.queenPocketedBy === 'black';
882
-
883
- if (whiteWins) {
884
- showWinMessage('WHITE PLAYER WINS!');
885
- } else if (blackWins) {
886
- showWinMessage('BLACK PLAYER WINS!');
887
- }
888
- }
889
-
890
- // Show Win Message
891
- function showWinMessage(message) {
892
- gameState.gameActive = false;
893
- winnerTextEl.textContent = message;
894
- winMessageEl.style.display = 'block';
895
- }
896
-
897
- // Reset Game
898
- function resetGame() {
899
- winMessageEl.style.display = 'none';
900
- initGame();
901
- }
902
-
903
- // Game Loop
904
- function gameLoop() {
905
- // Clear canvas
906
- ctx.clearRect(0, 0, CONFIG.BOARD_SIZE, CONFIG.BOARD_SIZE);
907
-
908
- // Draw board
909
- drawBoard();
910
-
911
- // Update and draw pieces
912
- gameState.pieces.forEach(piece => {
913
- piece.update();
914
- piece.draw();
915
- });
916
-
917
- // Update and draw striker
918
- if (gameState.striker) {
919
- gameState.striker.update();
920
- gameState.striker.draw();
921
- }
922
-
923
- // Draw aiming line
924
- drawAimingLine();
925
-
926
- // Continue game loop
927
- requestAnimationFrame(gameLoop);
928
- }
929
-
930
- // Event Listeners
931
- canvas.addEventListener('mousedown', (e) => {
932
- if (!gameState.gameActive || gameState.striker.isMoving) return;
933
-
934
- const rect = canvas.getBoundingClientRect();
935
- const x = e.clientX - rect.left;
936
- const y = e.clientY - rect.top;
937
-
938
- // Check if clicking on striker
939
- const dx = x - gameState.striker.x;
940
- const dy = y - gameState.striker.y;
941
- const distance = Math.sqrt(dx * dx + dy * dy);
942
-
943
- if (distance < gameState.striker.radius * 1.5) {
944
- gameState.isAiming = true;
945
- gameState.aimStart = { x, y };
946
- gameState.mousePos = { x, y };
947
- }
948
- });
949
-
950
- canvas.addEventListener('mousemove', (e) => {
951
- if (!gameState.isAiming) return;
952
-
953
- const rect = canvas.getBoundingClientRect();
954
- gameState.mousePos = {
955
- x: e.clientX - rect.left,
956
- y: e.clientY - rect.top
957
- };
958
- });
959
- canvas.addEventListener('mouseup', (e) => {
960
- if (!gameState.isAiming || !gameState.gameActive) return;
961
-
962
- gameState.isAiming = false;
963
-
964
- const rect = canvas.getBoundingClientRect();
965
- const x = e.clientX - rect.left;
966
- const y = e.clientY - rect.top;
967
-
968
- const dx = x - gameState.striker.x;
969
- const dy = y - gameState.striker.y;
970
- const distance = Math.sqrt(dx * dx + dy * dy);
971
- const angle = Math.atan2(dy, dx);
972
-
973
- gameState.striker.shoot(gameState.power, angle);
974
-
975
- // Reset power meter
976
- powerFillEl.style.width = '50%';
977
- });
978
-
979
- // Touch events for mobile
980
- canvas.addEventListener('touchstart', (e) => {
981
- e.preventDefault();
982
- if (!gameState.gameActive || gameState.striker.isMoving) return;
983
-
984
- const rect = canvas.getBoundingClientRect();
985
- const touch = e.touches[0];
986
- const x = touch.clientX - rect.left;
987
- const y = touch.clientY - rect.top;
988
-
989
- const dx = x - gameState.striker.x;
990
- const dy = y - gameState.striker.y;
991
- const distance = Math.sqrt(dx * dx + dy * dy);
992
-
993
- if (distance < gameState.striker.radius * 1.5) {
994
- gameState.isAiming = true;
995
- gameState.aimStart = { x, y };
996
- gameState.mousePos = { x, y };
997
- }
998
- });
999
-
1000
- canvas.addEventListener('touchmove', (e) => {
1001
- e.preventDefault();
1002
- if (!gameState.isAiming) return;
1003
-
1004
- const rect = canvas.getBoundingClientRect();
1005
- const touch = e.touches[0];
1006
- gameState.mousePos = {
1007
- x: touch.clientX - rect.left,
1008
- y: touch.clientY - rect.top
1009
- };
1010
- });
1011
-
1012
- canvas.addEventListener('touchend', (e) => {
1013
- e.preventDefault();
1014
- if (!gameState.isAiming || !gameState.gameActive) return;
1015
-
1016
- gameState.isAiming = false;
1017
-
1018
- const rect = canvas.getBoundingClientRect();
1019
- const touch = e.changedTouches[0];
1020
- const x = touch.clientX - rect.left;
1021
- const y = touch.clientY - rect.top;
1022
-
1023
- const dx = x - gameState.striker.x;
1024
- const dy = y - gameState.striker.y;
1025
- const distance = Math.sqrt(dx * dx + dy * dy);
1026
- const angle = Math.atan2(dy, dx);
1027
-
1028
- gameState.striker.shoot(gameState.power, angle);
1029
- powerFillEl.style.width = '50%';
1030
- });
1031
-
1032
- // Prevent context menu
1033
- canvas.addEventListener('contextmenu', (e) => e.preventDefault());
1034
-
1035
- // Initialize and start game
1036
- initGame();
1037
- gameLoop();
1038
- </script>
1039
- </body>
1040
- </html>