awacke1 commited on
Commit
db57c27
·
verified ·
1 Parent(s): a373b48

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +266 -0
app.py ADDED
@@ -0,0 +1,266 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+
3
+ # Set wide layout
4
+ st.set_page_config(layout="wide", page_title="Galaxian 3D Evolution", initial_sidebar_state="expanded")
5
+
6
+ # Sidebar instructions
7
+ st.sidebar.markdown("## Galaxian 3D Evolution Controls")
8
+ st.sidebar.markdown("""
9
+ - **Controls:**
10
+ - **WASD:** Move camera (forward, left, back, right)
11
+ - **QE:** Rotate camera up/down
12
+ - **Mouse:** Orbit camera (click and drag)
13
+ - **Arrow Keys:** Direct snake (Up, Down, Left, Right)
14
+ - **R:** Reset game
15
+
16
+ - **Features:**
17
+ - 3D snake navigates a space grid.
18
+ - Eat alien food (👾) to grow and trigger L-system growth.
19
+ - Creatures exchange quine messages (hover to see).
20
+ - Avoid walls and self-collision.
21
+
22
+ Enjoy the 3D Galaxian experience!
23
+ """)
24
+
25
+ # Three.js HTML/JavaScript code
26
+ html_code = r"""
27
+ <!DOCTYPE html>
28
+ <html>
29
+ <head>
30
+ <meta charset="UTF-8">
31
+ <title>Galaxian 3D Evolution</title>
32
+ <style>
33
+ body { margin: 0; padding: 0; overflow: hidden; background: black; }
34
+ canvas { display: block; }
35
+ </style>
36
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r134/three.min.js"></script>
37
+ <script src="https://cdn.jsdelivr.net/npm/[email protected]/examples/js/controls/OrbitControls.js"></script>
38
+ </head>
39
+ <body>
40
+ <script>
41
+ let scene, camera, renderer, controls, snake, food, creatures = [], messages = [];
42
+ const gridSize = 20;
43
+ const worldSize = 400;
44
+
45
+ function init() {
46
+ // Scene setup
47
+ scene = new THREE.Scene();
48
+ camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
49
+ renderer = new THREE.WebGLRenderer();
50
+ renderer.setSize(window.innerWidth, window.innerHeight);
51
+ document.body.appendChild(renderer.domElement);
52
+
53
+ // Orbit controls
54
+ controls = new THREE.OrbitControls(camera, renderer.domElement);
55
+ controls.enableDamping = true;
56
+ controls.dampingFactor = 0.05;
57
+
58
+ // Lighting
59
+ const ambientLight = new THREE.AmbientLight(0x404040);
60
+ scene.add(ambientLight);
61
+ const directionalLight = new THREE.DirectionalLight(0xffffff, 0.5);
62
+ directionalLight.position.set(1, 1, 1);
63
+ scene.add(directionalLight);
64
+
65
+ // Starfield
66
+ const starsGeometry = new THREE.BufferGeometry();
67
+ const starsMaterial = new THREE.PointsMaterial({ color: 0xffffff, size: 2 });
68
+ const starPositions = new Float32Array(1000 * 3);
69
+ for (let i = 0; i < 1000; i++) {
70
+ starPositions[i * 3] = (Math.random() - 0.5) * worldSize;
71
+ starPositions[i * 3 + 1] = (Math.random() - 0.5) * worldSize;
72
+ starPositions[i * 3 + 2] = (Math.random() - 0.5) * worldSize;
73
+ }
74
+ starsGeometry.setAttribute('position', new THREE.BufferAttribute(starPositions, 3));
75
+ const stars = new THREE.Points(starsGeometry, starsMaterial);
76
+ scene.add(stars);
77
+
78
+ // Initialize snake
79
+ snake = [];
80
+ const snakeMaterial = new THREE.MeshPhongMaterial({ color: 0x00ff00 });
81
+ for (let i = 0; i < 3; i++) {
82
+ const segment = new THREE.Mesh(new THREE.SphereGeometry(gridSize / 2, 32, 32), snakeMaterial);
83
+ segment.position.set(-i * gridSize, 0, 0);
84
+ snake.push(segment);
85
+ scene.add(segment);
86
+ }
87
+ snake.direction = new THREE.Vector3(gridSize, 0, 0);
88
+
89
+ // Food (alien)
90
+ placeFood();
91
+
92
+ // L-system creature
93
+ createLSysCreature();
94
+
95
+ // Camera position
96
+ camera.position.set(0, 100, 200);
97
+ camera.lookAt(0, 0, 0);
98
+
99
+ animate();
100
+ }
101
+
102
+ function placeFood() {
103
+ if (food) scene.remove(food);
104
+ const foodGeometry = new THREE.DodecahedronGeometry(gridSize / 2);
105
+ const foodMaterial = new THREE.MeshPhongMaterial({ color: 0xff00ff });
106
+ food = new THREE.Mesh(foodGeometry, foodMaterial);
107
+ food.position.set(
108
+ (Math.floor(Math.random() * (worldSize / gridSize)) - worldSize / (2 * gridSize)) * gridSize,
109
+ 0,
110
+ (Math.floor(Math.random() * (worldSize / gridSize)) - worldSize / (2 * gridSize)) * gridSize
111
+ );
112
+ scene.add(food);
113
+ }
114
+
115
+ function createLSysCreature() {
116
+ const lSys = {
117
+ axiom: "F",
118
+ rules: { "F": "F[+F]F[-F]F" },
119
+ angle: 25,
120
+ length: gridSize,
121
+ iterations: 3
122
+ };
123
+ let turtleString = lSys.axiom;
124
+ for (let i = 0; i < lSys.iterations; i++) {
125
+ turtleString = applyLSysRules(turtleString, lSys.rules);
126
+ }
127
+ const creatureMaterial = new THREE.MeshPhongMaterial({ color: 0x0000ff });
128
+ const creature = new THREE.Group();
129
+ let stack = [];
130
+ let pos = new THREE.Vector3(worldSize / 4, 0, worldSize / 4);
131
+ let dir = new THREE.Vector3(0, lSys.length, 0);
132
+
133
+ for (let char of turtleString) {
134
+ if (char === "F") {
135
+ const segment = new THREE.Mesh(new THREE.CylinderGeometry(2, 2, lSys.length, 16), creatureMaterial);
136
+ segment.position.copy(pos).add(dir.clone().multiplyScalar(0.5));
137
+ segment.quaternion.setFromUnitVectors(new THREE.Vector3(0, 1, 0), dir.clone().normalize());
138
+ creature.add(segment);
139
+ pos.add(dir);
140
+ } else if (char === "+") {
141
+ dir.applyAxisAngle(new THREE.Vector3(0, 0, 1), lSys.angle * Math.PI / 180);
142
+ } else if (char === "-") {
143
+ dir.applyAxisAngle(new THREE.Vector3(0, 0, 1), -lSys.angle * Math.PI / 180);
144
+ } else if (char === "[") {
145
+ stack.push({ pos: pos.clone(), dir: dir.clone() });
146
+ } else if (char === "]") {
147
+ const state = stack.pop();
148
+ pos = state.pos;
149
+ dir = state.dir;
150
+ }
151
+ }
152
+ scene.add(creature);
153
+ creatures.push(creature);
154
+ sendQuineMessage(creature);
155
+ }
156
+
157
+ function applyLSysRules(str, rules) {
158
+ return str.split("").map(char => rules[char] || char).join("");
159
+ }
160
+
161
+ function sendQuineMessage(sender) {
162
+ const quine = "function q(){console.log('Message from creature: '+q.toString())}q()";
163
+ const messageGeometry = new THREE.TextGeometry("Quine Msg", {
164
+ font: new THREE.FontLoader().parse({}), // Placeholder: requires font file
165
+ size: 10,
166
+ height: 2
167
+ });
168
+ const messageMaterial = new THREE.MeshBasicMaterial({ color: 0xffff00 });
169
+ const message = new THREE.Mesh(messageGeometry, messageMaterial);
170
+ message.position.copy(sender.position).add(new THREE.Vector3(0, 50, 0));
171
+ scene.add(message);
172
+ messages.push({ mesh: message, ttl: 100 });
173
+ setTimeout(() => creatures.forEach(c => c !== sender && listenToMessage(c, quine)), 1000);
174
+ }
175
+
176
+ function listenToMessage(creature, msg) {
177
+ const response = new THREE.Mesh(
178
+ new THREE.SphereGeometry(5, 32, 32),
179
+ new THREE.MeshBasicMaterial({ color: 0xff0000 })
180
+ );
181
+ response.position.copy(creature.position).add(new THREE.Vector3(0, 30, 0));
182
+ scene.add(response);
183
+ setTimeout(() => scene.remove(response), 2000);
184
+ }
185
+
186
+ function updateSnake() {
187
+ const head = snake[0];
188
+ const newHead = head.clone();
189
+ newHead.position.add(snake.direction);
190
+
191
+ if (Math.abs(newHead.position.x) > worldSize / 2 || Math.abs(newHead.position.z) > worldSize / 2) {
192
+ resetGame();
193
+ return;
194
+ }
195
+ for (let i = 1; i < snake.length; i++) {
196
+ if (newHead.position.distanceTo(snake[i].position) < gridSize) {
197
+ resetGame();
198
+ return;
199
+ }
200
+ }
201
+
202
+ snake.unshift(newHead);
203
+ scene.add(newHead);
204
+ if (newHead.position.distanceTo(food.position) < gridSize) {
205
+ placeFood();
206
+ createLSysCreature();
207
+ } else {
208
+ scene.remove(snake.pop());
209
+ }
210
+ }
211
+
212
+ function resetGame() {
213
+ snake.forEach(seg => scene.remove(seg));
214
+ snake = [];
215
+ const snakeMaterial = new THREE.MeshPhongMaterial({ color: 0x00ff00 });
216
+ for (let i = 0; i < 3; i++) {
217
+ const segment = new THREE.Mesh(new THREE.SphereGeometry(gridSize / 2, 32, 32), snakeMaterial);
218
+ segment.position.set(-i * gridSize, 0, 0);
219
+ snake.push(segment);
220
+ scene.add(segment);
221
+ }
222
+ snake.direction = new THREE.Vector3(gridSize, 0, 0);
223
+ placeFood();
224
+ }
225
+
226
+ let moveCounter = 0;
227
+ const moveDelay = 10;
228
+ function animate() {
229
+ requestAnimationFrame(animate);
230
+ controls.update();
231
+ moveCounter++;
232
+ if (moveCounter >= moveDelay) {
233
+ updateSnake();
234
+ moveCounter = 0;
235
+ }
236
+ messages = messages.filter(m => {
237
+ m.ttl--;
238
+ if (m.ttl <= 0) scene.remove(m.mesh);
239
+ return m.ttl > 0;
240
+ });
241
+ renderer.render(scene, camera);
242
+ }
243
+
244
+ document.addEventListener("keydown", (e) => {
245
+ switch (e.key) {
246
+ case "ArrowUp": snake.direction.set(0, 0, -gridSize); break;
247
+ case "ArrowDown": snake.direction.set(0, 0, gridSize); break;
248
+ case "ArrowLeft": snake.direction.set(-gridSize, 0, 0); break;
249
+ case "ArrowRight": snake.direction.set(gridSize, 0, 0); break;
250
+ case "r": resetGame(); break;
251
+ }
252
+ });
253
+
254
+ window.addEventListener("resize", () => {
255
+ camera.aspect = window.innerWidth / window.innerHeight;
256
+ camera.updateProjectionMatrix();
257
+ renderer.setSize(window.innerWidth, window.innerHeight);
258
+ });
259
+
260
+ init();
261
+ </script>
262
+ </body>
263
+ </html>
264
+ """
265
+
266
+ st.components.v1.html(html_code, height=700, scrolling=False)