mrwhy06 commited on
Commit
3200b3e
·
verified ·
1 Parent(s): f90c6ff

Add 2 files

Browse files
Files changed (2) hide show
  1. README.md +7 -5
  2. index.html +804 -19
README.md CHANGED
@@ -1,10 +1,12 @@
1
  ---
2
- title: Solitaire
3
- emoji: 🏢
4
- colorFrom: green
5
- colorTo: gray
6
  sdk: static
7
  pinned: false
 
 
8
  ---
9
 
10
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
1
  ---
2
+ title: solitaire
3
+ emoji: 🐳
4
+ colorFrom: blue
5
+ colorTo: blue
6
  sdk: static
7
  pinned: false
8
+ tags:
9
+ - deepsite
10
  ---
11
 
12
+ Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
index.html CHANGED
@@ -1,19 +1,804 @@
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>Solitaire</title>
7
+ <style>
8
+ @import url('https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap');
9
+
10
+ * {
11
+ margin: 0;
12
+ padding: 0;
13
+ box-sizing: border-box;
14
+ user-select: none;
15
+ }
16
+
17
+ body {
18
+ font-family: 'Roboto', sans-serif;
19
+ background: linear-gradient(135deg, #1e5799, #207cca, #2989d8, #7db9e8);
20
+ height: 100vh;
21
+ display: flex;
22
+ flex-direction: column;
23
+ align-items: center;
24
+ color: #333;
25
+ overflow: hidden;
26
+ }
27
+
28
+ .game-container {
29
+ width: 100%;
30
+ max-width: 1000px;
31
+ margin: 20px auto;
32
+ display: flex;
33
+ flex-direction: column;
34
+ height: calc(100vh - 100px);
35
+ }
36
+
37
+ .header {
38
+ display: flex;
39
+ justify-content: space-between;
40
+ align-items: center;
41
+ padding: 10px 0;
42
+ margin-bottom: 10px;
43
+ color: white;
44
+ }
45
+
46
+ .score {
47
+ font-size: 1.2rem;
48
+ font-weight: bold;
49
+ }
50
+
51
+ .restart-btn {
52
+ background: rgba(255, 255, 255, 0.2);
53
+ border: none;
54
+ color: white;
55
+ padding: 8px 15px;
56
+ border-radius: 5px;
57
+ cursor: pointer;
58
+ font-size: 1rem;
59
+ transition: background 0.3s;
60
+ }
61
+
62
+ .restart-btn:hover {
63
+ background: rgba(255, 255, 255, 0.3);
64
+ }
65
+
66
+ .game-board {
67
+ display: flex;
68
+ flex-direction: column;
69
+ flex-grow: 1;
70
+ }
71
+
72
+ .top-section {
73
+ display: flex;
74
+ justify-content: space-between;
75
+ margin-bottom: 20px;
76
+ }
77
+
78
+ .deck {
79
+ width: 70px;
80
+ height: 100px;
81
+ position: relative;
82
+ }
83
+
84
+ .stock {
85
+ cursor: pointer;
86
+ position: relative;
87
+ }
88
+
89
+ .waste {
90
+ position: relative;
91
+ margin-left: 10px;
92
+ }
93
+
94
+ .foundations {
95
+ display: flex;
96
+ gap: 10px;
97
+ }
98
+
99
+ .foundation {
100
+ width: 70px;
101
+ height: 100px;
102
+ border: 2px dashed rgba(255, 255, 255, 0.2);
103
+ border-radius: 5px;
104
+ }
105
+
106
+ .tableau-section {
107
+ display: flex;
108
+ justify-content: space-between;
109
+ flex-grow: 1;
110
+ }
111
+
112
+ .pile {
113
+ display: flex;
114
+ flex-direction: column;
115
+ gap: 3px;
116
+ min-height: 100px;
117
+ position: relative;
118
+ }
119
+
120
+ .pile.bottom {
121
+ margin-top: 30px;
122
+ }
123
+
124
+ .card {
125
+ width: 70px;
126
+ height: 100px;
127
+ background: white;
128
+ border-radius: 5px;
129
+ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12), 0 1px 2px rgba(0, 0, 0, 0.24);
130
+ position: absolute;
131
+ transition: transform 0.2s;
132
+ cursor: pointer;
133
+ display: flex;
134
+ flex-direction: column;
135
+ justify-content: space-between;
136
+ padding: 5px;
137
+ font-weight: bold;
138
+ font-size: 1.2rem;
139
+ overflow: hidden;
140
+ }
141
+
142
+ .card.red {
143
+ color: red;
144
+ }
145
+
146
+ .card.black {
147
+ color: black;
148
+ }
149
+
150
+ .card.hidden {
151
+ background: linear-gradient(135deg, #3498db, #2980b9);
152
+ color: transparent;
153
+ box-shadow: inset 0 0 10px rgba(0, 0, 0, 0.2);
154
+ border: 2px solid rgba(255, 255, 255, 0.2);
155
+ }
156
+
157
+ .card.hidden .card-value,
158
+ .card.hidden .card-suit {
159
+ display: none;
160
+ }
161
+
162
+ .card-suit {
163
+ text-align: center;
164
+ font-size: 30px;
165
+ }
166
+
167
+ .card-bottom-suit {
168
+ transform: rotate(180deg);
169
+ }
170
+
171
+ .card-placeholder {
172
+ border: 2px dashed rgba(255, 255, 255, 0.3);
173
+ border-radius: 5px;
174
+ }
175
+
176
+ .card.dragging {
177
+ opacity: 0.8;
178
+ z-index: 100;
179
+ transform: rotate(2deg);
180
+ box-shadow: 0 10px 20px rgba(0, 0, 0, 0.3);
181
+ }
182
+
183
+ .card.selected {
184
+ transform: translateY(-10px);
185
+ }
186
+
187
+ .win-message {
188
+ position: fixed;
189
+ top: 0;
190
+ left: 0;
191
+ width: 100%;
192
+ height: 100%;
193
+ background: rgba(0, 0, 0, 0.7);
194
+ display: flex;
195
+ flex-direction: column;
196
+ justify-content: center;
197
+ align-items: center;
198
+ z-index: 1000;
199
+ color: white;
200
+ opacity: 0;
201
+ pointer-events: none;
202
+ transition: opacity 0.5s;
203
+ }
204
+
205
+ .win-message.show {
206
+ opacity: 1;
207
+ pointer-events: all;
208
+ }
209
+
210
+ .win-text {
211
+ font-size: 3rem;
212
+ margin-bottom: 20px;
213
+ text-align: center;
214
+ text-shadow: 0 2px 10px rgba(0, 0, 0, 0.5);
215
+ }
216
+
217
+ .win-details {
218
+ font-size: 1.2rem;
219
+ margin-bottom: 30px;
220
+ }
221
+
222
+ .move-counter {
223
+ font-size: 1.1rem;
224
+ margin-bottom: 5px;
225
+ color: rgba(255, 255, 255, 0.8);
226
+ }
227
+
228
+ @media (max-width: 768px) {
229
+ .game-container {
230
+ transform: scale(0.8);
231
+ transform-origin: top center;
232
+ }
233
+ }
234
+
235
+ @media (max-width: 480px) {
236
+ .game-container {
237
+ transform: scale(0.6);
238
+ }
239
+ }
240
+ </style>
241
+ </head>
242
+ <body>
243
+ <div class="game-container">
244
+ <div class="header">
245
+ <div class="score">Score: <span id="score">0</span></div>
246
+ <div class="move-counter">Moves: <span id="moves">0</span></div>
247
+ <button class="restart-btn" id="restart">New Game</button>
248
+ </div>
249
+
250
+ <div class="game-board">
251
+ <div class="top-section">
252
+ <div class="deck">
253
+ <div class="card-placeholder stock" id="stock"></div>
254
+ <div class="card-placeholder waste" id="waste"></div>
255
+ </div>
256
+ <div class="foundations">
257
+ <div class="card-placeholder foundation" id="foundation-1"></div>
258
+ <div class="card-placeholder foundation" id="foundation-2"></div>
259
+ <div class="card-placeholder foundation" id="foundation-3"></div>
260
+ <div class="card-placeholder foundation" id="foundation-4"></div>
261
+ </div>
262
+ </div>
263
+
264
+ <div class="tableau-section">
265
+ <div class="pile" id="pile-1"></div>
266
+ <div class="pile" id="pile-2"></div>
267
+ <div class="pile" id="pile-3"></div>
268
+ <div class="pile" id="pile-4"></div>
269
+ <div class="pile" id="pile-5"></div>
270
+ <div class="pile" id="pile-6"></div>
271
+ <div class="pile" id="pile-7"></div>
272
+ </div>
273
+ </div>
274
+ </div>
275
+
276
+ <div class="win-message" id="win-message">
277
+ <div class="win-text">You Won!</div>
278
+ <div class="win-details">Congratulations on completing Solitaire!</div>
279
+ <div>Final Score: <span id="final-score">0</span></div>
280
+ <div>Total Moves: <span id="final-moves">0</span></div>
281
+ <button class="restart-btn" style="margin-top: 20px;">Play Again</button>
282
+ </div>
283
+
284
+ <script>
285
+ document.addEventListener('DOMContentLoaded', () => {
286
+ // Game state
287
+ const game = {
288
+ deck: [],
289
+ stock: [],
290
+ waste: [],
291
+ foundations: [[], [], [], []],
292
+ piles: [[], [], [], [], [], [], []],
293
+ score: 0,
294
+ moves: 0,
295
+ draggingCards: [],
296
+ dragSource: null,
297
+ gameStarted: false
298
+ };
299
+
300
+ // DOM elements
301
+ const elements = {
302
+ stock: document.getElementById('stock'),
303
+ waste: document.getElementById('waste'),
304
+ foundations: [
305
+ document.getElementById('foundation-1'),
306
+ document.getElementById('foundation-2'),
307
+ document.getElementById('foundation-3'),
308
+ document.getElementById('foundation-4')
309
+ ],
310
+ piles: [
311
+ document.getElementById('pile-1'),
312
+ document.getElementById('pile-2'),
313
+ document.getElementById('pile-3'),
314
+ document.getElementById('pile-4'),
315
+ document.getElementById('pile-5'),
316
+ document.getElementById('pile-6'),
317
+ document.getElementById('pile-7')
318
+ ],
319
+ scoreDisplay: document.getElementById('score'),
320
+ movesDisplay: document.getElementById('moves'),
321
+ restartBtn: document.getElementById('restart'),
322
+ winMessage: document.getElementById('win-message'),
323
+ finalScore: document.getElementById('final-score'),
324
+ finalMoves: document.getElementById('final-moves')
325
+ };
326
+
327
+ // Card suits and values
328
+ const suits = ['♥', '♦', '♠', '♣'];
329
+ const values = ['A', '2', '3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K'];
330
+
331
+ // Initialize game
332
+ function initGame() {
333
+ resetGame();
334
+ createDeck();
335
+ shuffleDeck();
336
+ dealCards();
337
+ updateUI();
338
+ game.gameStarted = true;
339
+ }
340
+
341
+ // Reset game state
342
+ function resetGame() {
343
+ game.deck = [];
344
+ game.stock = [];
345
+ game.waste = [];
346
+ game.foundations = [[], [], [], []];
347
+ game.piles = [[], [], [], [], [], [], []];
348
+ game.score = 0;
349
+ game.moves = 0;
350
+ game.draggingCards = [];
351
+ game.dragSource = null;
352
+ game.gameStarted = false;
353
+
354
+ // Clear all piles and foundations
355
+ elements.piles.forEach(pile => pile.innerHTML = '');
356
+ elements.foundations.forEach(foundation => foundation.innerHTML = '');
357
+ elements.waste.innerHTML = '';
358
+ }
359
+
360
+ // Create a standard deck of 52 cards
361
+ function createDeck() {
362
+ game.deck = [];
363
+ for (let suitIndex = 0; suitIndex < suits.length; suitIndex++) {
364
+ for (let valueIndex = 0; valueIndex < values.length; valueIndex++) {
365
+ const card = {
366
+ suit: suits[suitIndex],
367
+ value: values[valueIndex],
368
+ color: (suitIndex < 2) ? 'red' : 'black', // Hearts and diamonds are red
369
+ rank: valueIndex + 1, // A=1, K=13
370
+ hidden: true
371
+ };
372
+ game.deck.push(card);
373
+ }
374
+ }
375
+ }
376
+
377
+ // Shuffle the deck using Fisher-Yates algorithm
378
+ function shuffleDeck() {
379
+ for (let i = game.deck.length - 1; i > 0; i--) {
380
+ const j = Math.floor(Math.random() * (i + 1));
381
+ [game.deck[i], game.deck[j]] = [game.deck[j], game.deck[i]];
382
+ }
383
+ }
384
+
385
+ // Deal cards to piles
386
+ function dealCards() {
387
+ let cardIndex = 0;
388
+
389
+ // Deal to each pile
390
+ for (let pileIndex = 0; pileIndex < game.piles.length; pileIndex++) {
391
+ const pile = game.piles[pileIndex];
392
+
393
+ // Number of cards to deal to this pile is pileIndex + 1
394
+ for (let i = 0; i <= pileIndex; i++) {
395
+ const card = game.deck[cardIndex++];
396
+
397
+ // Only the last card in each pile is face up
398
+ card.hidden = i !== pileIndex;
399
+ pile.push(card);
400
+ }
401
+ }
402
+
403
+ // Remaining cards go to stock
404
+ game.stock = game.deck.slice(cardIndex);
405
+ }
406
+
407
+ // Update the UI based on game state
408
+ function updateUI() {
409
+ updateStock();
410
+ updateWaste();
411
+ updateFoundations();
412
+ updatePiles();
413
+ updateScore();
414
+ checkWin();
415
+ }
416
+
417
+ // Update stock display
418
+ function updateStock() {
419
+ elements.stock.innerHTML = '';
420
+
421
+ if (game.stock.length > 0) {
422
+ const cardBack = document.createElement('div');
423
+ cardBack.className = 'card hidden';
424
+ elements.stock.appendChild(cardBack);
425
+ } else {
426
+ elements.stock.classList.add('empty');
427
+ }
428
+ }
429
+
430
+ // Update waste display
431
+ function updateWaste() {
432
+ elements.waste.innerHTML = '';
433
+
434
+ if (game.waste.length > 0) {
435
+ const lastCard = game.waste[game.waste.length - 1];
436
+ const cardEl = createCardElement(lastCard);
437
+ cardEl.style.left = '0';
438
+ cardEl.style.top = '0';
439
+ elements.waste.appendChild(cardEl);
440
+ }
441
+ }
442
+
443
+ // Update foundations display
444
+ function updateFoundations() {
445
+ game.foundations.forEach((foundation, index) => {
446
+ elements.foundations[index].innerHTML = '';
447
+
448
+ if (foundation.length > 0) {
449
+ const lastCard = foundation[foundation.length - 1];
450
+ const cardEl = createCardElement(lastCard);
451
+ elements.foundations[index].appendChild(cardEl);
452
+ }
453
+ });
454
+ }
455
+
456
+ // Update tableaux (piles) display
457
+ function updatePiles() {
458
+ game.piles.forEach((pile, pileIndex) => {
459
+ elements.piles[pileIndex].innerHTML = '';
460
+
461
+ pile.forEach((card, cardIndex) => {
462
+ const cardEl = createCardElement(card);
463
+ cardEl.style.top = `${cardIndex * 25}px`; // Stack cards vertically
464
+ cardEl.setAttribute('data-pile-index', pileIndex);
465
+ cardEl.setAttribute('data-card-index', cardIndex);
466
+ elements.piles[pileIndex].appendChild(cardEl);
467
+ });
468
+ });
469
+ }
470
+
471
+ // Create a card DOM element
472
+ function createCardElement(card) {
473
+ const cardEl = document.createElement('div');
474
+ cardEl.className = `card ${card.color}`;
475
+ cardEl.innerHTML = `
476
+ <div class="card-value">${card.value}</div>
477
+ <div class="card-suit">${card.suit}</div>
478
+ <div class="card-suit card-bottom-suit">${card.suit}</div>
479
+ `;
480
+
481
+ if (card.hidden) {
482
+ cardEl.classList.add('hidden');
483
+ }
484
+
485
+ // Add drag event listeners
486
+ cardEl.draggable = true;
487
+ cardEl.addEventListener('dragstart', handleDragStart);
488
+ cardEl.addEventListener('mouseup', handleCardClick);
489
+
490
+ return cardEl;
491
+ }
492
+
493
+ // Update score display
494
+ function updateScore() {
495
+ elements.scoreDisplay.textContent = game.score;
496
+ elements.movesDisplay.textContent = game.moves;
497
+ }
498
+
499
+ // Draw card from stock to waste
500
+ function drawCard() {
501
+ if (!game.gameStarted) return;
502
+
503
+ if (game.stock.length === 0) {
504
+ // If stock is empty, return all waste cards to stock
505
+ game.waste.reverse().forEach(card => {
506
+ card.hidden = true;
507
+ });
508
+ game.stock = [...game.waste];
509
+ game.waste = [];
510
+ game.score = Math.max(0, game.score - 100); // Penalty for recycling waste
511
+ } else {
512
+ // Draw the top card from stock
513
+ const card = game.stock.pop();
514
+ card.hidden = false;
515
+ game.waste.push(card);
516
+ game.score += 5; // Small points for drawing
517
+ }
518
+
519
+ game.moves++;
520
+ updateUI();
521
+ }
522
+
523
+ // Handle drag start
524
+ function handleDragStart(e) {
525
+ if (!game.gameStarted) return;
526
+
527
+ const cardEl = e.target.closest('.card');
528
+ if (!cardEl || cardEl.classList.contains('hidden')) {
529
+ e.preventDefault();
530
+ return;
531
+ }
532
+
533
+ const pileIndex = parseInt(cardEl.getAttribute('data-pile-index'));
534
+ const cardIndex = parseInt(cardEl.getAttribute('data-card-index'));
535
+
536
+ // Get all cards from this one to the end of the pile
537
+ game.draggingCards = game.piles[pileIndex].slice(cardIndex);
538
+ game.dragSource = { type: 'pile', index: pileIndex };
539
+
540
+ // For foundation or waste, just move the top card
541
+ if (isNaN(pileIndex)) {
542
+ if (cardEl.parentElement === elements.waste) {
543
+ game.draggingCards = [game.waste[game.waste.length - 1]];
544
+ game.dragSource = { type: 'waste' };
545
+ } else {
546
+ const foundationIndex = elements.foundations.findIndex(f => cardEl.parentElement === f);
547
+ if (foundationIndex !== -1) {
548
+ game.draggingCards = [game.foundations[foundationIndex][game.foundations[foundationIndex].length - 1]];
549
+ game.dragSource = { type: 'foundation', index: foundationIndex };
550
+ }
551
+ }
552
+ }
553
+
554
+ // Set drag image
555
+ const dragImage = cardEl.cloneNode(true);
556
+ dragImage.style.position = 'fixed';
557
+ dragImage.style.left = '-1000px';
558
+ dragImage.style.top = '0';
559
+ dragImage.style.zIndex = '10000';
560
+ document.body.appendChild(dragImage);
561
+ e.dataTransfer.setDragImage(dragImage, 35, 50);
562
+ setTimeout(() => document.body.removeChild(dragImage), 0);
563
+
564
+ // Set effect allowed
565
+ e.dataTransfer.effectAllowed = 'move';
566
+
567
+ // Add dragging class
568
+ setTimeout(() => cardEl.classList.add('dragging'), 0);
569
+ }
570
+
571
+ // Handle drop on a pile or foundation
572
+ function handleDrop(target, e) {
573
+ e.preventDefault();
574
+ if (!game.draggingCards.length) return;
575
+
576
+ const card = game.draggingCards[0];
577
+
578
+ // Determine target type
579
+ let targetType, targetIndex;
580
+ if (target === elements.waste) {
581
+ return; // Can't drop on waste
582
+ } else if (target === elements.stock) {
583
+ return; // Can't drop on stock
584
+ } else if (elements.foundations.includes(target)) {
585
+ targetType = 'foundation';
586
+ targetIndex = elements.foundations.indexOf(target);
587
+ } else if (elements.piles.includes(target)) {
588
+ targetType = 'pile';
589
+ targetIndex = elements.piles.indexOf(target);
590
+ } else {
591
+ return;
592
+ }
593
+
594
+ // Check if move is valid
595
+ let isValid = false;
596
+
597
+ if (targetType === 'foundation') {
598
+ isValid = canMoveToFoundation(card, targetIndex);
599
+ } else if (targetType === 'pile') {
600
+ isValid = canMoveToPile(card, targetIndex);
601
+ }
602
+
603
+ if (isValid) {
604
+ // Remove cards from source
605
+ if (game.dragSource.type === 'pile') {
606
+ game.piles[game.dragSource.index].splice(
607
+ game.piles[game.dragSource.index].length - game.draggingCards.length,
608
+ game.draggingCards.length
609
+ );
610
+
611
+ // Reveal next card in source pile if needed
612
+ const sourcePile = game.piles[game.dragSource.index];
613
+ if (sourcePile.length > 0 && sourcePile[sourcePile.length - 1].hidden) {
614
+ sourcePile[sourcePile.length - 1].hidden = false;
615
+ game.score += 5; // Points for revealing a card
616
+ }
617
+ } else if (game.dragSource.type === 'waste') {
618
+ game.waste.pop();
619
+ } else if (game.dragSource.type === 'foundation') {
620
+ game.foundations[game.dragSource.index].pop();
621
+ }
622
+
623
+ // Add cards to target
624
+ if (targetType === 'foundation') {
625
+ game.foundations[targetIndex].push(card);
626
+ game.score += 10; // Points for moving to foundation
627
+ } else if (targetType === 'pile') {
628
+ game.piles[targetIndex].push(...game.draggingCards);
629
+
630
+ // Points for moving from waste or another pile
631
+ game.score += (game.draggingCards.length === 1) ? 5 : 0;
632
+ }
633
+
634
+ game.moves++;
635
+ game.draggingCards = [];
636
+ game.dragSource = null;
637
+ updateUI();
638
+ }
639
+ }
640
+
641
+ // Check if card can be moved to foundation
642
+ function canMoveToFoundation(card, foundationIndex) {
643
+ const foundation = game.foundations[foundationIndex];
644
+
645
+ if (foundation.length === 0) {
646
+ // Only Aces can start a foundation
647
+ return card.value === 'A';
648
+ } else {
649
+ const topCard = foundation[foundation.length - 1];
650
+ // Must be same suit and next in sequence
651
+ return topCard.suit === card.suit && card.rank === topCard.rank + 1;
652
+ }
653
+ }
654
+
655
+ // Check if card can be moved to a pile
656
+ function canMoveToPile(card, pileIndex) {
657
+ const pile = game.piles[pileIndex];
658
+
659
+ if (pile.length === 0) {
660
+ // Only Kings can be placed on empty pile
661
+ return card.value === 'K';
662
+ } else {
663
+ const topCard = pile[pile.length - 1];
664
+ // Must be opposite color and one rank lower
665
+ return topCard.color !== card.color && card.rank === topCard.rank - 1;
666
+ }
667
+ }
668
+
669
+ // Handle card click
670
+ function handleCardClick(e) {
671
+ if (!game.gameStarted) return;
672
+
673
+ const cardEl = e.target.closest('.card');
674
+ if (!cardEl || cardEl.classList.contains('hidden')) return;
675
+
676
+ // If clicked on waste, try to auto-move to foundation
677
+ if (cardEl.parentElement === elements.waste && game.waste.length > 0) {
678
+ const card = game.waste[game.waste.length - 1];
679
+
680
+ // Check all foundations for possible moves
681
+ for (let i = 0; i < game.foundations.length; i++) {
682
+ if (canMoveToFoundation(card, i)) {
683
+ game.foundations[i].push(game.waste.pop());
684
+ game.score += 10;
685
+ game.moves++;
686
+ updateUI();
687
+ return;
688
+ }
689
+ }
690
+ }
691
+
692
+ // If clicked on pile card, try to auto-move to foundation if it's the top card
693
+ const pileIndex = parseInt(cardEl.getAttribute('data-pile-index'));
694
+ const cardIndex = parseInt(cardEl.getAttribute('data-card-index'));
695
+
696
+ if (!isNaN(pileIndex) && cardIndex === game.piles[pileIndex].length - 1) {
697
+ const card = game.piles[pileIndex][cardIndex];
698
+
699
+ for (let i = 0; i < game.foundations.length; i++) {
700
+ if (canMoveToFoundation(card, i)) {
701
+ game.foundations[i].push(game.piles[pileIndex].pop());
702
+ game.score += 10;
703
+ game.moves++;
704
+
705
+ // Reveal next card if needed
706
+ if (game.piles[pileIndex].length > 0 && game.piles[pileIndex][game.piles[pileIndex].length - 1].hidden) {
707
+ game.piles[pileIndex][game.piles[pileIndex].length - 1].hidden = false;
708
+ game.score += 5;
709
+ }
710
+
711
+ updateUI();
712
+ return;
713
+ }
714
+ }
715
+ }
716
+ }
717
+
718
+ // Check if player has won
719
+ function checkWin() {
720
+ const allCardsInFoundations = game.foundations.every(foundation => foundation.length === 13);
721
+
722
+ if (allCardsInFoundations) {
723
+ showWinMessage();
724
+ }
725
+ }
726
+
727
+ // Show win message
728
+ function showWinMessage() {
729
+ elements.finalScore.textContent = game.score;
730
+ elements.finalMoves.textContent = game.moves;
731
+ elements.winMessage.classList.add('show');
732
+ }
733
+
734
+ // Setup event listeners
735
+ function setupEventListeners() {
736
+ // Stock click to draw card
737
+ elements.stock.addEventListener('click', drawCard);
738
+
739
+ // Restart button
740
+ elements.restartBtn.addEventListener('click', initGame);
741
+ elements.winMessage.querySelector('.restart-btn').addEventListener('click', () => {
742
+ elements.winMessage.classList.remove('show');
743
+ initGame();
744
+ });
745
+
746
+ // Drag and drop setup
747
+ document.addEventListener('dragover', e => {
748
+ e.preventDefault();
749
+ const target = document.elementFromPoint(e.clientX, e.clientY)?.closest('.pile, .foundation, .waste, .stock');
750
+ if (target) {
751
+ const rect = target.getBoundingClientRect();
752
+ const isOver = e.clientX > rect.left && e.clientX < rect.right &&
753
+ e.clientY > rect.top && e.clientY < rect.bottom;
754
+ if (isOver) {
755
+ if (target === elements.stock || target === elements.waste) return;
756
+ target.classList.add('highlight');
757
+ }
758
+ }
759
+ });
760
+
761
+ document.addEventListener('dragleave', e => {
762
+ const target = document.elementFromPoint(e.clientX, e.clientY)?.closest('.pile, .foundation');
763
+ if (!target || e.target !== target) {
764
+ elements.piles.forEach(pile => pile.classList.remove('highlight'));
765
+ elements.foundations.forEach(foundation => foundation.classList.remove('highlight'));
766
+ }
767
+ });
768
+
769
+ document.addEventListener('drop', e => {
770
+ e.preventDefault();
771
+ elements.piles.forEach(pile => pile.classList.remove('highlight'));
772
+ elements.foundations.forEach(foundation => foundation.classList.remove('highlight'));
773
+
774
+ const target = document.elementFromPoint(e.clientX, e.clientY)?.closest('.pile, .foundation, .waste, .stock');
775
+ if (target && game.draggingCards.length) {
776
+ handleDrop(target, e);
777
+ }
778
+ });
779
+
780
+ document.addEventListener('dragend', () => {
781
+ document.querySelectorAll('.card').forEach(card => card.classList.remove('dragging'));
782
+ elements.piles.forEach(pile => pile.classList.remove('highlight'));
783
+ elements.foundations.forEach(foundation => foundation.classList.remove('highlight'));
784
+ });
785
+
786
+ // Keyboard shortcuts
787
+ document.addEventListener('keydown', e => {
788
+ if (e.code === 'Space' && !e.target.matches('button, input, textarea')) {
789
+ e.preventDefault();
790
+ drawCard();
791
+ } else if (e.code === 'KeyR' && !e.target.matches('button, input, textarea')) {
792
+ e.preventDefault();
793
+ initGame();
794
+ }
795
+ });
796
+ }
797
+
798
+ // Initialize the game
799
+ setupEventListeners();
800
+ initGame();
801
+ });
802
+ </script>
803
+ <p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <a href="https://enzostvs-deepsite.hf.space" style="color: #fff;" target="_blank" >DeepSite</a> <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;"></p></body>
804
+ </html>