knoeter commited on
Commit
3327c96
·
verified ·
1 Parent(s): 70f3a08

hello, i want a towestacking browser game where you habe one start block in the center and you need to drop moving blocks to build a tower as high as possible

Browse files
README.md CHANGED
@@ -1,10 +1,13 @@
1
  ---
2
- title: Towerstack Frenzy
3
- emoji: 📉
4
- colorFrom: indigo
5
  colorTo: pink
 
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: TowerStack Frenzy 🏗️
3
+ colorFrom: yellow
 
4
  colorTo: pink
5
+ emoji: 🐳
6
  sdk: static
7
  pinned: false
8
+ tags:
9
+ - deepsite-v3
10
  ---
11
 
12
+ # Welcome to your new DeepSite project!
13
+ This project was created with [DeepSite](https://huggingface.co/deepsite).
components/controls.js ADDED
@@ -0,0 +1,57 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ class CustomControls extends HTMLElement {
2
+ connectedCallback() {
3
+ this.attachShadow({ mode: 'open' });
4
+ this.shadowRoot.innerHTML = `
5
+ <style>
6
+ .controls-container {
7
+ @apply bg-gray-800 p-4 rounded-lg shadow-xl;
8
+ }
9
+ .control-group {
10
+ @apply mb-4;
11
+ }
12
+ .control-label {
13
+ @apply block text-sm font-medium mb-1;
14
+ }
15
+ .control-select {
16
+ @apply mt-1 block w-full pl-3 pr-10 py-2 text-base border-gray-600 focus:outline-none focus:ring-blue-500 focus:border-blue-500 sm:text-sm rounded-md bg-gray-700 text-white;
17
+ }
18
+ .btn {
19
+ @apply w-full flex justify-center py-2 px-4 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-blue-600 hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500;
20
+ }
21
+ .btn-secondary {
22
+ @apply mt-2 w-full flex justify-center py-2 px-4 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-gray-600 hover:bg-gray-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-gray-500;
23
+ }
24
+ </style>
25
+ <div class="controls-container">
26
+ <div class="control-group">
27
+ <label class="control-label">Mode:</label>
28
+ <select id="mode-select" class="control-select">
29
+ <option value="draw">Draw Mode</option>
30
+ <option value="start">Set Start</option>
31
+ <option value="end">Set End</option>
32
+ <option value="wall">Place Walls</option>
33
+ </select>
34
+ </div>
35
+
36
+ <button id="solve-btn" class="btn">
37
+ <i data-feather="play" class="mr-2"></i> Solve Puzzle
38
+ </button>
39
+
40
+ <button id="reset-btn" class="btn-secondary">
41
+ <i data-feather="refresh-cw" class="mr-2"></i> Reset Board
42
+ </button>
43
+
44
+ <div class="control-group mt-6">
45
+ <h3 class="font-bold mb-2">Instructions:</h3>
46
+ <p class="text-sm text-gray-300">
47
+ 1. Set start and end points<br>
48
+ 2. Add walls to create obstacles<br>
49
+ 3. Click "Solve Puzzle" to find path
50
+ </p>
51
+ </div>
52
+ </div>
53
+ `;
54
+ }
55
+ }
56
+
57
+ customElements.define('custom-controls', CustomControls);
components/game-board.js ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ class CustomGameBoard extends HTMLElement {
2
+ connectedCallback() {
3
+ this.attachShadow({ mode: 'open' });
4
+ this.shadowRoot.innerHTML = `
5
+ <style>
6
+ .game-container {
7
+ @apply bg-gray-800 p-4 rounded-lg shadow-xl;
8
+ }
9
+ .game-title {
10
+ @apply text-xl font-bold mb-4 text-center;
11
+ }
12
+ </style>
13
+ <div class="game-container">
14
+ <h2 class="game-title">Logic Puzzle Board</h2>
15
+ <div class="game-board"></div>
16
+ </div>
17
+ `;
18
+ }
19
+ }
20
+
21
+ customElements.define('custom-game-board', CustomGameBoard);
components/navbar.js ADDED
@@ -0,0 +1,50 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ class CustomNavbar extends HTMLElement {
2
+ connectedCallback() {
3
+ this.attachShadow({ mode: 'open' });
4
+ this.shadowRoot.innerHTML = `
5
+ <style>
6
+ nav {
7
+ @apply bg-gray-800 text-white shadow-lg;
8
+ }
9
+ .container {
10
+ @apply max-w-7xl mx-auto px-4 sm:px-6 lg:px-8;
11
+ }
12
+ .nav-content {
13
+ @apply flex items-center justify-between h-16;
14
+ }
15
+ .logo {
16
+ @apply flex-shrink-0 flex items-center text-xl font-bold;
17
+ }
18
+ .nav-links {
19
+ @apply hidden md:flex space-x-8;
20
+ }
21
+ .nav-link {
22
+ @apply px-3 py-2 rounded-md text-sm font-medium hover:bg-gray-700;
23
+ }
24
+ .mobile-menu-btn {
25
+ @apply md:hidden inline-flex items-center justify-center p-2 rounded-md text-gray-400 hover:text-white hover:bg-gray-700;
26
+ }
27
+ </style>
28
+ <nav>
29
+ <div class="container">
30
+ <div class="nav-content">
31
+ <div class="logo">
32
+ <i data-feather="cpu"></i>
33
+ <span class="ml-2">MindBender Logic Lab</span>
34
+ </div>
35
+ <div class="nav-links">
36
+ <a href="#" class="nav-link active">Home</a>
37
+ <a href="#" class="nav-link">About</a>
38
+ <a href="#" class="nav-link">Tutorial</a>
39
+ </div>
40
+ <button class="mobile-menu-btn">
41
+ <i data-feather="menu"></i>
42
+ </button>
43
+ </div>
44
+ </div>
45
+ </nav>
46
+ `;
47
+ }
48
+ }
49
+
50
+ customElements.define('custom-navbar', CustomNavbar);
components/tower-game.js ADDED
@@ -0,0 +1,117 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ class TowerGame extends HTMLElement {
2
+ connectedCallback() {
3
+ this.attachShadow({ mode: 'open' });
4
+ this.shadowRoot.innerHTML = `
5
+ <style>
6
+ .game-container {
7
+ width: 100%;
8
+ height: 500px;
9
+ background: #f0f0f0;
10
+ position: relative;
11
+ overflow: hidden;
12
+ border-radius: 8px;
13
+ border: 2px solid #333;
14
+ }
15
+ .block {
16
+ position: absolute;
17
+ background: linear-gradient(135deg, #667eea, #764ba2);
18
+ border-radius: 4px;
19
+ box-shadow: 0 4px 8px rgba(0,0,0,0.2);
20
+ transition: transform 0.2s;
21
+ }
22
+ .active-block {
23
+ background: linear-gradient(135deg, #f56565, #ed8936);
24
+ }
25
+ .score-display {
26
+ position: absolute;
27
+ top: 10px;
28
+ right: 10px;
29
+ font-size: 1.5rem;
30
+ font-weight: bold;
31
+ color: #333;
32
+ z-index: 10;
33
+ }
34
+ </style>
35
+ <div class="game-container">
36
+ <div class="score-display">Height: 0</div>
37
+ </div>
38
+ `;
39
+ this.initGame();
40
+ }
41
+
42
+ initGame() {
43
+ this.gameWidth = 300;
44
+ this.gameHeight = 500;
45
+ this.blockWidth = 60;
46
+ this.blockHeight = 20;
47
+ this.speed = 2;
48
+ this.direction = 1;
49
+ this.tower = [];
50
+ this.score = 0;
51
+ this.gameOver = false;
52
+
53
+ // Create base block
54
+ this.createBlock(this.gameWidth/2 - this.blockWidth/2, this.gameHeight - this.blockHeight, true);
55
+
56
+ // Start game loop
57
+ this.gameLoop();
58
+
59
+ // Set up controls
60
+ this.shadowRoot.querySelector('.game-container').addEventListener('click', () => this.placeBlock());
61
+ }
62
+
63
+ createBlock(x, y, isBase = false) {
64
+ const block = document.createElement('div');
65
+ block.className = isBase ? 'block' : 'block active-block';
66
+ block.style.width = `${this.blockWidth}px`;
67
+ block.style.height = `${this.blockHeight}px`;
68
+ block.style.left = `${x}px`;
69
+ block.style.top = `${y}px`;
70
+ this.shadowRoot.querySelector('.game-container').appendChild(block);
71
+
72
+ if (!isBase) {
73
+ this.activeBlock = { element: block, x, y, movingRight: true };
74
+ } else {
75
+ this.tower.push({ element: block, x, y });
76
+ }
77
+ }
78
+
79
+ gameLoop() {
80
+ if (this.gameOver) return;
81
+
82
+ if (this.activeBlock) {
83
+ // Move active block
84
+ this.activeBlock.x += this.direction * this.speed;
85
+ this.activeBlock.element.style.left = `${this.activeBlock.x}px`;
86
+
87
+ // Change direction at edges
88
+ if (this.activeBlock.x <= 0) this.direction = 1;
89
+ if (this.activeBlock.x + this.blockWidth >= this.gameWidth) this.direction = -1;
90
+ }
91
+
92
+ requestAnimationFrame(() => this.gameLoop());
93
+ }
94
+
95
+ placeBlock() {
96
+ if (!this.activeBlock || this.gameOver) return;
97
+
98
+ // Add active block to tower
99
+ this.activeBlock.element.classList.remove('active-block');
100
+ this.tower.push(this.activeBlock);
101
+ this.score++;
102
+ this.updateScore();
103
+
104
+ // Create new active block
105
+ const newY = this.tower[this.tower.length-1].y - this.blockHeight;
106
+ this.createBlock(0, newY);
107
+
108
+ // Increase speed slightly
109
+ this.speed = Math.min(5, this.speed + 0.1);
110
+ }
111
+
112
+ updateScore() {
113
+ this.shadowRoot.querySelector('.score-display').textContent = `Height: ${this.score}`;
114
+ }
115
+ }
116
+
117
+ customElements.define('tower-game', TowerGame);
index.html CHANGED
@@ -1,19 +1,34 @@
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>MindBender Logic Lab</title>
7
+ <link rel="stylesheet" href="style.css">
8
+ <script src="https://cdn.tailwindcss.com"></script>
9
+ <script src="https://cdn.jsdelivr.net/npm/feather-icons/dist/feather.min.js"></script>
10
+ <script src="https://unpkg.com/feather-icons"></script>
11
+ <script src="components/navbar.js"></script>
12
+ <script src="components/tower-game.js"></script>
13
+ </head>
14
+ <body class="bg-gray-900 text-gray-100 min-h-screen">
15
+ <custom-navbar></custom-navbar>
16
+
17
+ <main class="container mx-auto px-4 py-8">
18
+ <div class="flex flex-col lg:flex-row gap-8">
19
+ <div class="lg:w-3/4">
20
+ <tower-game></tower-game>
21
+ </div>
22
+ <div class="lg:w-1/4">
23
+ <div class="mt-4 text-center">
24
+ <p class="text-gray-300">Click to drop blocks and build your tower!</p>
25
+ </div>
26
+ </div>
27
+ </div>
28
+ </main>
29
+
30
+ <script src="script.js"></script>
31
+ <script>feather.replace();</script>
32
+ <script src="https://huggingface.co/deepsite/deepsite-badge.js"></script>
33
+ </body>
34
+ </html>
script.js ADDED
@@ -0,0 +1,200 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ document.addEventListener('DOMContentLoaded', () => {
2
+ // Game state
3
+ const gameState = {
4
+ boardSize: 10,
5
+ cells: [],
6
+ startPos: null,
7
+ endPos: null,
8
+ walls: [],
9
+ mode: 'draw', // 'draw', 'start', 'end', 'wall'
10
+ isSolving: false,
11
+ solutionPath: []
12
+ };
13
+
14
+ // Initialize the game
15
+ function initGame() {
16
+ createBoard();
17
+ setupEventListeners();
18
+ }
19
+
20
+ // Create the game board
21
+ function createBoard() {
22
+ const gameBoard = document.querySelector('custom-game-board');
23
+ gameBoard.shadowRoot.innerHTML = `
24
+ <style>
25
+ .game-board {
26
+ display: grid;
27
+ gap: 0;
28
+ grid-template-columns: repeat(${gameState.boardSize}, 1fr);
29
+ }
30
+ </style>
31
+ <div class="game-board bg-gray-800 p-2 rounded-lg shadow-xl"></div>
32
+ `;
33
+
34
+ const boardElement = gameBoard.shadowRoot.querySelector('.game-board');
35
+ boardElement.innerHTML = '';
36
+
37
+ gameState.cells = [];
38
+ for (let y = 0; y < gameState.boardSize; y++) {
39
+ for (let x = 0; x < gameState.boardSize; x++) {
40
+ const cell = document.createElement('div');
41
+ cell.className = 'cell';
42
+ cell.dataset.x = x;
43
+ cell.dataset.y = y;
44
+ boardElement.appendChild(cell);
45
+ gameState.cells.push({ x, y, element: cell });
46
+ }
47
+ }
48
+ }
49
+
50
+ // Setup event listeners
51
+ function setupEventListeners() {
52
+ const gameBoard = document.querySelector('custom-game-board');
53
+ gameBoard.shadowRoot.querySelector('.game-board').addEventListener('click', handleCellClick);
54
+
55
+ const controls = document.querySelector('custom-controls');
56
+ controls.shadowRoot.querySelector('#solve-btn').addEventListener('click', solvePuzzle);
57
+ controls.shadowRoot.querySelector('#reset-btn').addEventListener('click', resetBoard);
58
+ controls.shadowRoot.querySelector('#mode-select').addEventListener('change', (e) => {
59
+ gameState.mode = e.target.value;
60
+ });
61
+ }
62
+
63
+ // Handle cell clicks
64
+ function handleCellClick(e) {
65
+ if (gameState.isSolving) return;
66
+
67
+ const cell = e.target.closest('.cell');
68
+ if (!cell) return;
69
+
70
+ const x = parseInt(cell.dataset.x);
71
+ const y = parseInt(cell.dataset.y);
72
+
73
+ switch (gameState.mode) {
74
+ case 'start':
75
+ setStartPosition(x, y);
76
+ break;
77
+ case 'end':
78
+ setEndPosition(x, y);
79
+ break;
80
+ case 'wall':
81
+ toggleWall(x, y);
82
+ break;
83
+ default:
84
+ // Do nothing
85
+ break;
86
+ }
87
+ }
88
+
89
+ // Set start position
90
+ function setStartPosition(x, y) {
91
+ // Clear previous start
92
+ if (gameState.startPos) {
93
+ const prevCell = document.querySelector(`.cell[data-x="${gameState.startPos.x}"][data-y="${gameState.startPos.y}"]`);
94
+ prevCell?.classList.remove('start');
95
+ }
96
+
97
+ // Set new start
98
+ const cell = document.querySelector(`.cell[data-x="${x}"][data-y="${y}"]`);
99
+ cell.classList.add('start');
100
+ gameState.startPos = { x, y };
101
+ }
102
+
103
+ // Set end position
104
+ function setEndPosition(x, y) {
105
+ // Clear previous end
106
+ if (gameState.endPos) {
107
+ const prevCell = document.querySelector(`.cell[data-x="${gameState.endPos.x}"][data-y="${gameState.endPos.y}"]`);
108
+ prevCell?.classList.remove('end');
109
+ }
110
+
111
+ // Set new end
112
+ const cell = document.querySelector(`.cell[data-x="${x}"][data-y="${y}"]`);
113
+ cell.classList.add('end');
114
+ gameState.endPos = { x, y };
115
+ }
116
+
117
+ // Toggle wall
118
+ function toggleWall(x, y) {
119
+ const cell = document.querySelector(`.cell[data-x="${x}"][data-y="${y}"]`);
120
+ const isWall = cell.classList.contains('wall');
121
+
122
+ if (isWall) {
123
+ cell.classList.remove('wall');
124
+ gameState.walls = gameState.walls.filter(wall => !(wall.x === x && wall.y === y));
125
+ } else {
126
+ cell.classList.add('wall');
127
+ gameState.walls.push({ x, y });
128
+ }
129
+ }
130
+
131
+ // Solve the puzzle
132
+ function solvePuzzle() {
133
+ if (!gameState.startPos || !gameState.endPos) {
134
+ alert('Please set both start and end positions!');
135
+ return;
136
+ }
137
+
138
+ gameState.isSolving = true;
139
+ gameState.solutionPath = findPath();
140
+ animateSolution();
141
+ }
142
+
143
+ // Find path (simplified for demo)
144
+ function findPath() {
145
+ // This is a simplified pathfinding algorithm
146
+ // In a real implementation, you would use A* or similar
147
+ const path = [];
148
+ let current = { ...gameState.startPos };
149
+
150
+ while (current.x !== gameState.endPos.x || current.y !== gameState.endPos.y) {
151
+ path.push({ ...current });
152
+
153
+ // Simple movement towards target
154
+ if (current.x < gameState.endPos.x) current.x++;
155
+ else if (current.x > gameState.endPos.x) current.x--;
156
+
157
+ if (current.y < gameState.endPos.y) current.y++;
158
+ else if (current.y > gameState.endPos.y) current.y--;
159
+
160
+ // Prevent infinite loops
161
+ if (path.length > gameState.boardSize * 2) break;
162
+ }
163
+
164
+ path.push({ ...gameState.endPos });
165
+ return path;
166
+ }
167
+
168
+ // Animate the solution
169
+ function animateSolution() {
170
+ if (gameState.solutionPath.length === 0) {
171
+ gameState.isSolving = false;
172
+ return;
173
+ }
174
+
175
+ const step = gameState.solutionPath.shift();
176
+ const cell = document.querySelector(`.cell[data-x="${step.x}"][data-y="${step.y}"]`);
177
+
178
+ if (!cell.classList.contains('start') && !cell.classList.contains('end')) {
179
+ cell.classList.add('path', 'trace-animation');
180
+ }
181
+
182
+ setTimeout(animateSolution, 200);
183
+ }
184
+
185
+ // Reset the board
186
+ function resetBoard() {
187
+ gameState.startPos = null;
188
+ gameState.endPos = null;
189
+ gameState.walls = [];
190
+ gameState.solutionPath = [];
191
+ gameState.isSolving = false;
192
+
193
+ document.querySelectorAll('.cell').forEach(cell => {
194
+ cell.className = 'cell';
195
+ });
196
+ }
197
+
198
+ // Initialize the game
199
+ initGame();
200
+ });
style.css CHANGED
@@ -1,28 +1,48 @@
1
- body {
2
- padding: 2rem;
3
- font-family: -apple-system, BlinkMacSystemFont, "Arial", sans-serif;
 
 
 
 
 
 
 
 
 
 
 
 
 
4
  }
5
 
6
- h1 {
7
- font-size: 16px;
8
- margin-top: 0;
9
  }
10
 
11
- p {
12
- color: rgb(107, 114, 128);
13
- font-size: 15px;
14
- margin-bottom: 10px;
15
- margin-top: 5px;
16
  }
17
 
18
- .card {
19
- max-width: 620px;
20
- margin: 0 auto;
21
- padding: 16px;
22
- border: 1px solid lightgray;
23
- border-radius: 16px;
24
  }
25
 
26
- .card p:last-child {
27
- margin-bottom: 0;
28
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ @tailwind base;
2
+ @tailwind components;
3
+ @tailwind utilities;
4
+
5
+ /* Custom styles for the game elements */
6
+ .cell {
7
+ @apply w-12 h-12 flex items-center justify-center border border-gray-700 cursor-pointer;
8
+ transition: all 0.2s ease;
9
+ }
10
+
11
+ .cell:hover {
12
+ @apply bg-gray-800;
13
+ }
14
+
15
+ .cell.active {
16
+ @apply bg-blue-600 text-white;
17
  }
18
 
19
+ .cell.wall {
20
+ @apply bg-gray-700;
 
21
  }
22
 
23
+ .cell.start {
24
+ @apply bg-green-600;
 
 
 
25
  }
26
 
27
+ .cell.end {
28
+ @apply bg-red-600;
 
 
 
 
29
  }
30
 
31
+ .cell.path {
32
+ @apply bg-yellow-500;
33
  }
34
+ /* Tower game animations */
35
+ @keyframes blockDrop {
36
+ 0% { transform: translateY(-20px); }
37
+ 100% { transform: translateY(0); }
38
+ }
39
+
40
+ .block {
41
+ animation: blockDrop 0.2s ease-out;
42
+ }
43
+
44
+ /* Responsive game container */
45
+ .game-board {
46
+ @apply grid gap-0;
47
+ grid-template-columns: repeat(auto-fill, minmax(48px, 1fr));
48
+ }