X commited on
Commit
b1257b3
·
verified ·
1 Parent(s): 8209b33

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +49 -94
app.py CHANGED
@@ -3,22 +3,19 @@ import gradio as gr
3
  import numpy as np
4
  import random
5
  from PIL import Image, ImageDraw
6
- import math
7
 
8
  # ============== НАСТРОЙКИ ==============
9
  WORLD_SIZE = 30
10
  CELL_SIZE = 12
11
  MAX_CREATURES = 30
12
 
13
- # ============== ПРОСТАЯ НЕЙРОСЕТЬ (без PyTorch) ==============
14
  class SimpleBrain:
15
  def __init__(self):
16
- # Простая матрица весов
17
  self.weights = np.random.randn(8, 5) * 0.5
18
  self.bias = np.random.randn(5) * 0.5
19
 
20
  def forward(self, inputs):
21
- # Простой перцептрон
22
  x = np.array(inputs)
23
  output = np.tanh(np.dot(x, self.weights) + self.bias)
24
  return output
@@ -29,20 +26,19 @@ class SimpleBrain:
29
  new_brain.bias = self.bias.copy()
30
  return new_brain
31
 
32
- def mutate(self, rate=0.2, scale=0.3):
33
- if random.random() < rate:
34
- self.weights += np.random.randn(*self.weights.shape) * scale
35
- if random.random() < rate:
36
- self.bias += np.random.randn(*self.bias.shape) * scale
37
 
38
  # ============== СУЩЕСТВО ==============
39
  class Creature:
40
- def __init__(self, x, y, color, team, brain=None):
41
  self.x = x
42
  self.y = y
43
  self.color = color
44
  self.team = team
45
-
46
  self.health = 100
47
  self.energy = 80
48
  self.food = 50
@@ -51,18 +47,16 @@ class Creature:
51
  self.age = 0
52
  self.alive = True
53
  self.fitness = 0
54
- self.children = 0
55
-
56
- self.brain = brain if brain else SimpleBrain()
57
 
58
  def think(self, world, creatures):
59
- # Собираем входные данные
60
  hunger = 1.0 - self.food / 100.0
61
  thirst = 1.0 - self.water / 100.0
62
  health = self.health / 100.0
63
  energy = self.energy / 100.0
64
 
65
- # Смотрим вокруг
66
  nearby = []
67
  for dx in [-1, 0, 1]:
68
  for dy in [-1, 0, 1]:
@@ -82,7 +76,7 @@ class Creature:
82
  else:
83
  nearby.append(0.0)
84
 
85
- # Ищем врагов и друзей
86
  partners = 0
87
  enemies = 0
88
  for other in creatures:
@@ -95,21 +89,18 @@ class Creature:
95
  else:
96
  enemies = max(enemies, 1.0 - dist/3.0)
97
 
98
- # Входные данные (8 признаков)
99
  inputs = [hunger, thirst, health, energy, partners, enemies]
100
- inputs.extend(nearby[:4]) # берем первые 4 направления
101
 
102
- # Прогоняем через нейросеть
103
  output = self.brain.forward(inputs)
104
 
105
- # Декодируем действия
106
  dx = int(round(output[0] * 2))
107
  dy = int(round(output[1] * 2))
108
  build = output[2] > 0.3
109
  reproduce = output[3] > 0.5
110
  attack = output[4] > 0.4
111
 
112
- # Выполняем действия
113
  self.move(dx, dy)
114
 
115
  if build and self.resources >= 2:
@@ -147,7 +138,6 @@ class Creature:
147
  if len(creatures) >= MAX_CREATURES:
148
  return None
149
 
150
- # Создаем ребенка
151
  child_brain = self.brain.copy()
152
  child_brain.mutate()
153
 
@@ -155,16 +145,15 @@ class Creature:
155
  self.x + random.randint(-2, 2),
156
  self.y + random.randint(-2, 2),
157
  self.color,
158
- self.team,
159
- child_brain
160
  )
 
161
  child.food = 30
162
  child.water = 30
163
  child.energy = 40
164
 
165
  self.food -= 30
166
  self.energy -= 20
167
- self.children += 1
168
  self.fitness += 25
169
 
170
  creatures.append(child)
@@ -239,7 +228,7 @@ class Creature:
239
 
240
  return True
241
 
242
- # ============== СОЗДАНИЕ МИРА ==============
243
  def create_world():
244
  world = np.zeros((WORLD_SIZE, WORLD_SIZE, 3), dtype=np.uint8)
245
  world[:, :] = [100, 200, 100]
@@ -273,24 +262,14 @@ def create_world():
273
  world[x, y] = [0, 100, 255]
274
  break
275
 
276
- # Существа
277
  creatures = []
278
-
279
- # Красный вид
280
- c1 = Creature(5, 5, [255, 50, 50], "red")
281
- creatures.append(c1)
282
-
283
- # Синий вид
284
- c2 = Creature(25, 25, [50, 50, 255], "blue")
285
- creatures.append(c2)
286
-
287
- # Золотой вид
288
- c3 = Creature(15, 15, [255, 215, 0], "gold")
289
- creatures.append(c3)
290
 
291
  return world, creatures
292
 
293
- # ============== ШАГ СИМУЛЯЦИИ ==============
294
  def simulate_step(world, creatures, step):
295
  new_creatures = []
296
 
@@ -313,7 +292,6 @@ def simulate_step(world, creatures, step):
313
  creatures.extend(new_creatures)
314
  creatures = [c for c in creatures if c.alive]
315
 
316
- # Восстановление ресурсов
317
  if step % 5 == 0:
318
  for _ in range(2):
319
  for _ in range(20):
@@ -322,7 +300,6 @@ def simulate_step(world, creatures, step):
322
  world[x, y] = [0, 150, 0]
323
  break
324
 
325
- # Естественный отбор
326
  if len(creatures) > MAX_CREATURES:
327
  creatures.sort(key=lambda c: c.fitness, reverse=True)
328
  for c in creatures[MAX_CREATURES:]:
@@ -333,36 +310,29 @@ def simulate_step(world, creatures, step):
333
 
334
  # ============== ОТРИСОВКА ==============
335
  def render_world(world, creatures, step):
336
- img = Image.new('RGB', (WORLD_SIZE * CELL_SIZE, WORLD_SIZE * CELL_SIZE + 80), (30, 30, 30))
337
  draw = ImageDraw.Draw(img)
338
 
339
- # Мир
340
  for i in range(WORLD_SIZE):
341
  for j in range(WORLD_SIZE):
342
- x, y = i * CELL_SIZE, j * CELL_SIZE
343
- color = tuple(world[i, j].tolist())
344
- draw.rectangle([x, y, x + CELL_SIZE, y + CELL_SIZE], fill=color)
345
 
346
- # Существа
347
  for creature in creatures:
348
  if not creature.alive:
349
  continue
350
- x, y = creature.x * CELL_SIZE, creature.y * CELL_SIZE
351
- color = tuple(creature.color)
352
- draw.ellipse([x+1, y+1, x+CELL_SIZE-1, y+CELL_SIZE-1],
353
- fill=color, outline=(255,255,255))
354
 
355
- # Индикаторы
356
- hw = int((creature.health / 100) * CELL_SIZE)
357
- fw = int((creature.food / 100) * CELL_SIZE)
358
- ww = int((creature.water / 100) * CELL_SIZE)
359
 
360
  draw.rectangle([x, y-6, x + hw, y-4], fill=(255, 0, 0))
361
  draw.rectangle([x, y-4, x + fw, y-2], fill=(255, 165, 0))
362
  draw.rectangle([x, y-2, x + ww, y], fill=(0, 200, 255))
363
 
364
- # Статистика
365
- y_offset = WORLD_SIZE * CELL_SIZE + 10
366
 
367
  red = sum(1 for c in creatures if c.alive and c.team == "red")
368
  blue = sum(1 for c in creatures if c.alive and c.team == "blue")
@@ -375,16 +345,16 @@ def render_world(world, creatures, step):
375
  stones = sum(1 for i in range(WORLD_SIZE) for j in range(WORLD_SIZE)
376
  if world[i, j][0] == 128 and world[i, j][1] == 128 and world[i, j][2] == 128)
377
 
378
- best_fitness = max([c.fitness for c in creatures if c.alive] + [0])
379
 
380
- draw.text([10, y_offset], f"Шаг: {step} | Существ: {len(creatures)}", fill=(255,255,255))
381
  draw.text([10, y_offset + 20], f"🔴:{red} 🔵:{blue} 🟡:{gold}", fill=(255,255,255))
382
  draw.text([10, y_offset + 40], f"🌳:{trees} 🫐:{foods} 🪨:{stones}", fill=(255,255,255))
383
- draw.text([10, y_offset + 60], f"⭐ Лучший фитнес: {best_fitness:.0f}", fill=(255,255,255))
384
 
385
  return img
386
 
387
- # ============== GRADIO ФУНКЦИИ ==============
388
  world, creatures = create_world()
389
  step_counter = 0
390
 
@@ -412,10 +382,9 @@ def run_simulation(steps):
412
  if world[i, j][0] == 0 and world[i, j][1] == 150 and world[i, j][2] == 0)
413
  stones = sum(1 for i in range(WORLD_SIZE) for j in range(WORLD_SIZE)
414
  if world[i, j][0] == 128 and world[i, j][1] == 128 and world[i, j][2] == 128)
 
415
 
416
- best_fitness = max([c.fitness for c in creatures if c.alive] + [0])
417
-
418
- stats_text = f"""📊 СТАТИСТИКА
419
 
420
  Шаг: {step_counter}
421
  Существ: {len(creatures)}
@@ -428,47 +397,33 @@ def run_simulation(steps):
428
  🫐 Ягод: {foods}
429
  🪨 Камней: {stones}
430
 
431
- ⭐ Лучший фитнес: {best_fitness:.0f}"""
432
 
433
- return images, stats_text
434
 
435
  def reset_simulation():
436
  global world, creatures, step_counter
437
  world, creatures = create_world()
438
  step_counter = 0
439
  img = render_world(world, creatures, 0)
440
- return [img], "Мир сброшен! Нажмите 'Запустить'"
441
 
442
  # ============== ИНТЕРФЕЙС ==============
443
- with gr.Blocks(title="🧬 Эволюция") as demo:
444
- gr.Markdown("""
445
- # 🧬 Эволюционная симуляция
446
-
447
- 🔴 Красные | 🔵 Синие | 🟡 Золотые
448
-
449
- Существа **едят**, **пьют**, **строят**, **воюют** и **размножаются**!
450
- """)
451
 
452
  with gr.Row():
453
  gallery = gr.Gallery(label="Мир", columns=1, rows=1, height=500)
454
- stats = gr.Textbox(label="Статистика", lines=20, interactive=False)
455
 
456
  with gr.Row():
457
- steps = gr.Slider(label="Шагов", minimum=5, maximum=50, value=20, step=5)
458
- run_btn = gr.Button("▶️ Запустить", variant="primary")
459
- reset_btn = gr.Button("🔄 Сбросить", variant="secondary")
460
-
461
- run_btn.click(
462
- run_simulation,
463
- inputs=[steps],
464
- outputs=[gallery, stats]
465
- )
466
-
467
- reset_btn.click(
468
- reset_simulation,
469
- outputs=[gallery, stats]
470
- )
471
 
472
- # ============== ЗАПУСК ==============
473
  if __name__ == "__main__":
474
- demo.launch(share=True)
 
3
  import numpy as np
4
  import random
5
  from PIL import Image, ImageDraw
 
6
 
7
  # ============== НАСТРОЙКИ ==============
8
  WORLD_SIZE = 30
9
  CELL_SIZE = 12
10
  MAX_CREATURES = 30
11
 
12
+ # ============== ПРОСТАЯ НЕЙРОСЕТЬ ==============
13
  class SimpleBrain:
14
  def __init__(self):
 
15
  self.weights = np.random.randn(8, 5) * 0.5
16
  self.bias = np.random.randn(5) * 0.5
17
 
18
  def forward(self, inputs):
 
19
  x = np.array(inputs)
20
  output = np.tanh(np.dot(x, self.weights) + self.bias)
21
  return output
 
26
  new_brain.bias = self.bias.copy()
27
  return new_brain
28
 
29
+ def mutate(self):
30
+ if random.random() < 0.2:
31
+ self.weights += np.random.randn(*self.weights.shape) * 0.3
32
+ if random.random() < 0.2:
33
+ self.bias += np.random.randn(*self.bias.shape) * 0.3
34
 
35
  # ============== СУЩЕСТВО ==============
36
  class Creature:
37
+ def __init__(self, x, y, color, team):
38
  self.x = x
39
  self.y = y
40
  self.color = color
41
  self.team = team
 
42
  self.health = 100
43
  self.energy = 80
44
  self.food = 50
 
47
  self.age = 0
48
  self.alive = True
49
  self.fitness = 0
50
+ self.brain = SimpleBrain()
 
 
51
 
52
  def think(self, world, creatures):
53
+ # Входные данные
54
  hunger = 1.0 - self.food / 100.0
55
  thirst = 1.0 - self.water / 100.0
56
  health = self.health / 100.0
57
  energy = self.energy / 100.0
58
 
59
+ # Обзор
60
  nearby = []
61
  for dx in [-1, 0, 1]:
62
  for dy in [-1, 0, 1]:
 
76
  else:
77
  nearby.append(0.0)
78
 
79
+ # Друзья и враги
80
  partners = 0
81
  enemies = 0
82
  for other in creatures:
 
89
  else:
90
  enemies = max(enemies, 1.0 - dist/3.0)
91
 
 
92
  inputs = [hunger, thirst, health, energy, partners, enemies]
93
+ inputs.extend(nearby[:4])
94
 
 
95
  output = self.brain.forward(inputs)
96
 
97
+ # Действия
98
  dx = int(round(output[0] * 2))
99
  dy = int(round(output[1] * 2))
100
  build = output[2] > 0.3
101
  reproduce = output[3] > 0.5
102
  attack = output[4] > 0.4
103
 
 
104
  self.move(dx, dy)
105
 
106
  if build and self.resources >= 2:
 
138
  if len(creatures) >= MAX_CREATURES:
139
  return None
140
 
 
141
  child_brain = self.brain.copy()
142
  child_brain.mutate()
143
 
 
145
  self.x + random.randint(-2, 2),
146
  self.y + random.randint(-2, 2),
147
  self.color,
148
+ self.team
 
149
  )
150
+ child.brain = child_brain
151
  child.food = 30
152
  child.water = 30
153
  child.energy = 40
154
 
155
  self.food -= 30
156
  self.energy -= 20
 
157
  self.fitness += 25
158
 
159
  creatures.append(child)
 
228
 
229
  return True
230
 
231
+ # ============== МИР ==============
232
  def create_world():
233
  world = np.zeros((WORLD_SIZE, WORLD_SIZE, 3), dtype=np.uint8)
234
  world[:, :] = [100, 200, 100]
 
262
  world[x, y] = [0, 100, 255]
263
  break
264
 
 
265
  creatures = []
266
+ creatures.append(Creature(5, 5, [255, 50, 50], "red"))
267
+ creatures.append(Creature(25, 25, [50, 50, 255], "blue"))
268
+ creatures.append(Creature(15, 15, [255, 215, 0], "gold"))
 
 
 
 
 
 
 
 
 
269
 
270
  return world, creatures
271
 
272
+ # ============== СИМУЛЯЦИЯ ==============
273
  def simulate_step(world, creatures, step):
274
  new_creatures = []
275
 
 
292
  creatures.extend(new_creatures)
293
  creatures = [c for c in creatures if c.alive]
294
 
 
295
  if step % 5 == 0:
296
  for _ in range(2):
297
  for _ in range(20):
 
300
  world[x, y] = [0, 150, 0]
301
  break
302
 
 
303
  if len(creatures) > MAX_CREATURES:
304
  creatures.sort(key=lambda c: c.fitness, reverse=True)
305
  for c in creatures[MAX_CREATURES:]:
 
310
 
311
  # ============== ОТРИСОВКА ==============
312
  def render_world(world, creatures, step):
313
+ img = Image.new('RGB', (WORLD_SIZE * 12, WORLD_SIZE * 12 + 80), (30, 30, 30))
314
  draw = ImageDraw.Draw(img)
315
 
 
316
  for i in range(WORLD_SIZE):
317
  for j in range(WORLD_SIZE):
318
+ x, y = i * 12, j * 12
319
+ draw.rectangle([x, y, x + 12, y + 12], fill=tuple(world[i, j].tolist()))
 
320
 
 
321
  for creature in creatures:
322
  if not creature.alive:
323
  continue
324
+ x, y = creature.x * 12, creature.y * 12
325
+ draw.ellipse([x+1, y+1, x+11, y+11], fill=tuple(creature.color), outline=(255,255,255))
 
 
326
 
327
+ hw = int((creature.health / 100) * 12)
328
+ fw = int((creature.food / 100) * 12)
329
+ ww = int((creature.water / 100) * 12)
 
330
 
331
  draw.rectangle([x, y-6, x + hw, y-4], fill=(255, 0, 0))
332
  draw.rectangle([x, y-4, x + fw, y-2], fill=(255, 165, 0))
333
  draw.rectangle([x, y-2, x + ww, y], fill=(0, 200, 255))
334
 
335
+ y_offset = WORLD_SIZE * 12 + 10
 
336
 
337
  red = sum(1 for c in creatures if c.alive and c.team == "red")
338
  blue = sum(1 for c in creatures if c.alive and c.team == "blue")
 
345
  stones = sum(1 for i in range(WORLD_SIZE) for j in range(WORLD_SIZE)
346
  if world[i, j][0] == 128 and world[i, j][1] == 128 and world[i, j][2] == 128)
347
 
348
+ best = max([c.fitness for c in creatures if c.alive] + [0])
349
 
350
+ draw.text([10, y_offset], f"Шаг:{step} | Существ:{len(creatures)}", fill=(255,255,255))
351
  draw.text([10, y_offset + 20], f"🔴:{red} 🔵:{blue} 🟡:{gold}", fill=(255,255,255))
352
  draw.text([10, y_offset + 40], f"🌳:{trees} 🫐:{foods} 🪨:{stones}", fill=(255,255,255))
353
+ draw.text([10, y_offset + 60], f"⭐ Лучший:{best}", fill=(255,255,255))
354
 
355
  return img
356
 
357
+ # ============== GRADIO ==============
358
  world, creatures = create_world()
359
  step_counter = 0
360
 
 
382
  if world[i, j][0] == 0 and world[i, j][1] == 150 and world[i, j][2] == 0)
383
  stones = sum(1 for i in range(WORLD_SIZE) for j in range(WORLD_SIZE)
384
  if world[i, j][0] == 128 and world[i, j][1] == 128 and world[i, j][2] == 128)
385
+ best = max([c.fitness for c in creatures if c.alive] + [0])
386
 
387
+ stats = f"""СТАТИСТИКА
 
 
388
 
389
  Шаг: {step_counter}
390
  Существ: {len(creatures)}
 
397
  🫐 Ягод: {foods}
398
  🪨 Камней: {stones}
399
 
400
+ ⭐ Лучший фитнес: {best}"""
401
 
402
+ return images, stats
403
 
404
  def reset_simulation():
405
  global world, creatures, step_counter
406
  world, creatures = create_world()
407
  step_counter = 0
408
  img = render_world(world, creatures, 0)
409
+ return [img], "Мир сброшен"
410
 
411
  # ============== ИНТЕРФЕЙС ==============
412
+ with gr.Blocks() as demo:
413
+ gr.Markdown("# 🧬 Эволюционная симуляция")
414
+ gr.Markdown("🔴 Красные | 🔵 Синие | 🟡 Золотые")
 
 
 
 
 
415
 
416
  with gr.Row():
417
  gallery = gr.Gallery(label="Мир", columns=1, rows=1, height=500)
418
+ stats = gr.Textbox(label="Статистика", lines=15)
419
 
420
  with gr.Row():
421
+ steps = gr.Slider(minimum=5, maximum=50, value=20, step=5, label="Шагов")
422
+ run_btn = gr.Button("▶️ Запустить")
423
+ reset_btn = gr.Button("🔄 Сбросить")
424
+
425
+ run_btn.click(run_simulation, inputs=[steps], outputs=[gallery, stats])
426
+ reset_btn.click(reset_simulation, outputs=[gallery, stats])
 
 
 
 
 
 
 
 
427
 
 
428
  if __name__ == "__main__":
429
+ demo.launch(share=False)