awacke1 commited on
Commit
af906b3
·
verified ·
1 Parent(s): a8b9e19

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +501 -0
app.py ADDED
@@ -0,0 +1,501 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ import numpy as np
3
+ import random
4
+ import json
5
+ import math
6
+ import time
7
+ import pandas as pd
8
+ import graphviz
9
+ from scipy.sparse import csr_matrix
10
+
11
+ # -----------------------------------------------------------------------------
12
+ # Page Configuration
13
+ # -----------------------------------------------------------------------------
14
+ st.set_page_config(page_title="NeuroDungeon: Cortical Column Game", layout="wide")
15
+
16
+ # -----------------------------------------------------------------------------
17
+ # Initialize Game & Memory State
18
+ # -----------------------------------------------------------------------------
19
+ if 'game_state' not in st.session_state:
20
+ st.session_state.game_state = {
21
+ 'hex_grid': [[{'type': 'empty', 'emoji': '', 'alive': False} for _ in range(12)] for _ in range(16)],
22
+ 'heroes': {}, # {player_id: {x, y, hp, atk, def, xp, level, gear}}
23
+ 'monsters': [],
24
+ 'loot': [],
25
+ 'exit': {'x': 15, 'y': 11},
26
+ 'overlord': {'x': 14, 'y': 10, 'hp': 50, 'atk': 5, 'alive': True},
27
+ 'players': {},
28
+ 'story': [], # Memory events (episodic/semantic)
29
+ 'drawn_cards': 0,
30
+ 'turn': 0
31
+ }
32
+
33
+ # -----------------------------------------------------------------------------
34
+ # Card Deck for Narrative Events (Episodic Memory)
35
+ # -----------------------------------------------------------------------------
36
+ if 'deck' not in st.session_state:
37
+ def create_deck():
38
+ suits = ["Hearts", "Diamonds", "Clubs", "Spades"]
39
+ ranks = list(range(1, 14))
40
+ deck = [(suit, rank) for suit in suits for rank in ranks]
41
+ random.shuffle(deck)
42
+ return deck
43
+ st.session_state.deck = create_deck()
44
+
45
+ # -----------------------------------------------------------------------------
46
+ # Constants and UI Elements for Both Systems
47
+ # -----------------------------------------------------------------------------
48
+ HEX_SIZE = 40
49
+ PLAYER_NAMES = ["SkyWalker", "ForestRanger", "CityBuilder", "MonsterTamer", "RailMaster"]
50
+ PLANTS = ["🌱", "🌲", "🌳", "🌴", "🌵"]
51
+ LOOT_EMOJIS = ["⚔️", "🛡️", "💰", "🔑"]
52
+ TRAPS = ["⚡", "🕳️"]
53
+ SUIT_PROPERTIES = {"Hearts": "heroic", "Diamonds": "treacherous", "Clubs": "fierce", "Spades": "enigmatic"}
54
+
55
+ # -----------------------------------------------------------------------------
56
+ # Initialize Hero if Not Already Set
57
+ # -----------------------------------------------------------------------------
58
+ if 'player_id' not in st.session_state:
59
+ st.session_state.player_id = random.choice(PLAYER_NAMES)
60
+ st.session_state.game_state['heroes'][st.session_state.player_id] = {
61
+ 'x': 0, 'y': 0, 'hp': 20, 'atk': 3, 'def': 1, 'xp': 0, 'level': 1, 'gear': []
62
+ }
63
+
64
+ player_id = st.sidebar.selectbox("Choose Hero", PLAYER_NAMES, index=PLAYER_NAMES.index(st.session_state.player_id))
65
+ st.session_state.player_id = player_id
66
+ hero = st.session_state.game_state['heroes'].get(player_id, {'x': 0, 'y': 0, 'hp': 20, 'atk': 3, 'def': 1, 'xp': 0, 'level': 1, 'gear': []})
67
+
68
+ st.sidebar.subheader("🗡️ Hero Stats")
69
+ st.sidebar.write(f"HP: {hero.get('hp', 20)} | ATK: {hero.get('atk', 3)} | DEF: {hero.get('def', 1)}")
70
+ st.sidebar.write(f"Level: {hero.get('level', 1)} | XP: {hero.get('xp', 0)}")
71
+ st.sidebar.write(f"Gear: {', '.join(hero.get('gear', [])) or 'None'}")
72
+
73
+ st.sidebar.subheader("🏆 Scores")
74
+ for p, s in st.session_state.game_state['players'].items():
75
+ st.sidebar.write(f"{p}: {s}")
76
+
77
+ # -----------------------------------------------------------------------------
78
+ # Utility Functions for Game Dynamics & Neural Decay
79
+ # -----------------------------------------------------------------------------
80
+ def apply_game_of_life(grid):
81
+ new_grid = [[cell.copy() for cell in row] for row in grid]
82
+ for i in range(len(grid)):
83
+ for j in range(len(grid[0])):
84
+ neighbors = count_neighbors(grid, i, j)
85
+ if grid[i][j]['type'] in ['plant', 'trap'] and grid[i][j]['alive']:
86
+ if neighbors < 2 or neighbors > 3:
87
+ new_grid[i][j]['alive'] = False
88
+ new_grid[i][j]['type'] = 'empty'
89
+ new_grid[i][j]['emoji'] = ''
90
+ elif grid[i][j]['type'] == 'empty' and neighbors == 3:
91
+ new_grid[i][j]['type'] = 'plant'
92
+ new_grid[i][j]['emoji'] = random.choice(PLANTS)
93
+ new_grid[i][j]['alive'] = True
94
+ return new_grid
95
+
96
+ def count_neighbors(grid, x, y):
97
+ count = 0
98
+ for di in [-1, 0, 1]:
99
+ for dj in [-1, 0, 1]:
100
+ if di == 0 and dj == 0:
101
+ continue
102
+ ni, nj = x + di, y + dj
103
+ if 0 <= ni < len(grid) and 0 <= nj < len(grid[0]) and grid[ni][nj]['alive']:
104
+ count += 1
105
+ return count
106
+
107
+ def reset_game():
108
+ st.session_state.game_state = {
109
+ 'hex_grid': [[{'type': 'empty', 'emoji': '', 'alive': False} for _ in range(12)] for _ in range(16)],
110
+ 'heroes': {player_id: {'x': 0, 'y': 0, 'hp': 20, 'atk': 3, 'def': 1, 'xp': 0, 'level': 1, 'gear': []}},
111
+ 'monsters': [],
112
+ 'loot': [],
113
+ 'exit': {'x': 15, 'y': 11},
114
+ 'overlord': {'x': 14, 'y': 10, 'hp': 50, 'atk': 5, 'alive': True},
115
+ 'players': {},
116
+ 'story': [],
117
+ 'drawn_cards': 0,
118
+ 'turn': 0
119
+ }
120
+ for i in range(16):
121
+ for j in range(12):
122
+ if random.random() < 0.1:
123
+ st.session_state.game_state['hex_grid'][i][j] = {'type': 'wall', 'emoji': '🧱', 'alive': False}
124
+
125
+ # Place random walls in the dungeon initially
126
+ for i in range(16):
127
+ for j in range(12):
128
+ if random.random() < 0.1:
129
+ st.session_state.game_state['hex_grid'][i][j] = {'type': 'wall', 'emoji': '🧱', 'alive': False}
130
+
131
+ # -----------------------------------------------------------------------------
132
+ # p5.js Code for the HexCitySaga Game Rendering (with Narrative Integration)
133
+ # -----------------------------------------------------------------------------
134
+ p5js_code = """
135
+ const HEX_SIZE = 40;
136
+ const SQRT_3 = Math.sqrt(3);
137
+ let hexGrid = [];
138
+ let heroes = {};
139
+ let monsters = [];
140
+ let loot = [];
141
+ let exit = {};
142
+ let overlord = {};
143
+ let playerId;
144
+ let story = [];
145
+
146
+ function setup() {
147
+ createCanvas(640, 480);
148
+ updateFromState();
149
+ }
150
+
151
+ function updateFromState() {
152
+ hexGrid = JSON.parse(document.getElementById('hex_grid').innerHTML);
153
+ heroes = JSON.parse(document.getElementById('heroes').innerHTML);
154
+ monsters = JSON.parse(document.getElementById('monsters').innerHTML);
155
+ loot = JSON.parse(document.getElementById('loot').innerHTML);
156
+ exit = JSON.parse(document.getElementById('exit').innerHTML);
157
+ overlord = JSON.parse(document.getElementById('overlord').innerHTML);
158
+ playerId = document.getElementById('player_id').innerHTML;
159
+ story = JSON.parse(document.getElementById('story').innerHTML);
160
+ }
161
+
162
+ function draw() {
163
+ background(169, 169, 169);
164
+ drawHexGrid();
165
+ drawLoot();
166
+ drawHeroes();
167
+ drawMonsters();
168
+ drawExit();
169
+ drawOverlord();
170
+ drawStory();
171
+ }
172
+
173
+ function drawHexGrid() {
174
+ for (let i = 0; i < hexGrid.length; i++) {
175
+ for (let j = 0; j < hexGrid[i].length; j++) {
176
+ let x = i * HEX_SIZE * 1.5;
177
+ let y = j * HEX_SIZE * SQRT_3 + (i % 2 ? HEX_SIZE * SQRT_3 / 2 : 0);
178
+ fill(hexGrid[i][j].type === 'wall' ? '#555' : hexGrid[i][j].alive ? '#90EE90' : '#A9A9A9');
179
+ stroke(0);
180
+ drawHex(x, y);
181
+ if (hexGrid[i][j].emoji) {
182
+ textSize(20);
183
+ text(hexGrid[i][j].emoji, x - 10, y + 5);
184
+ }
185
+ }
186
+ }
187
+ }
188
+
189
+ function drawHex(x, y) {
190
+ beginShape();
191
+ for (let a = 0; a < 6; a++) {
192
+ let angle = TWO_PI / 6 * a;
193
+ vertex(x + HEX_SIZE * cos(angle), y + HEX_SIZE * sin(angle));
194
+ }
195
+ endShape(CLOSE);
196
+ }
197
+
198
+ function drawHeroes() {
199
+ Object.keys(heroes).forEach(h => {
200
+ let hero = heroes[h];
201
+ let x = hero.x * HEX_SIZE * 1.5;
202
+ let y = hero.y * HEX_SIZE * SQRT_3 + (hero.x % 2 ? HEX_SIZE * SQRT_3 / 2 : 0);
203
+ fill(0, 255, 0);
204
+ ellipse(x, y, HEX_SIZE * 0.8);
205
+ textSize(14);
206
+ text(h.slice(0,2), x - 10, y + 5);
207
+ });
208
+ }
209
+
210
+ function drawMonsters() {
211
+ monsters.forEach(m => {
212
+ let x = m.x * HEX_SIZE * 1.5;
213
+ let y = m.y * HEX_SIZE * SQRT_3 + (m.x % 2 ? HEX_SIZE * SQRT_3 / 2 : 0);
214
+ fill(255, 0, 0);
215
+ ellipse(x, y, HEX_SIZE * 0.8);
216
+ textSize(20);
217
+ text(m.type === 'Godzilla' ? '🦖' : '🤖', x - 10, y + 5);
218
+ });
219
+ }
220
+
221
+ function drawLoot() {
222
+ loot.forEach(l => {
223
+ let x = l.x * HEX_SIZE * 1.5;
224
+ let y = l.y * HEX_SIZE * SQRT_3 + (l.x % 2 ? HEX_SIZE * SQRT_3 / 2 : 0);
225
+ fill(255, 215, 0);
226
+ ellipse(x, y, HEX_SIZE * 0.6);
227
+ textSize(20);
228
+ text(l.type, x - 10, y + 5);
229
+ });
230
+ }
231
+
232
+ function drawExit() {
233
+ let x = exit.x * HEX_SIZE * 1.5;
234
+ let y = exit.y * HEX_SIZE * SQRT_3 + (exit.x % 2 ? HEX_SIZE * SQRT_3 / 2 : 0);
235
+ fill(0, 191, 255);
236
+ ellipse(x, y, HEX_SIZE * 0.8);
237
+ textSize(20);
238
+ text('🚪', x - 10, y + 5);
239
+ }
240
+
241
+ function drawOverlord() {
242
+ if (overlord.alive) {
243
+ let x = overlord.x * HEX_SIZE * 1.5;
244
+ let y = overlord.y * HEX_SIZE * SQRT_3 + (overlord.x % 2 ? HEX_SIZE * SQRT_3 / 2 : 0);
245
+ fill(139, 0, 139);
246
+ ellipse(x, y, HEX_SIZE * 1.2);
247
+ textSize(20);
248
+ text('👑', x - 10, y + 5);
249
+ }
250
+ }
251
+
252
+ function drawStory() {
253
+ fill(0);
254
+ textSize(14);
255
+ for (let i = 0; i < Math.min(story.length, 5); i++) {
256
+ text(story[story.length - 1 - i], 10, 20 + i * 20);
257
+ }
258
+ }
259
+
260
+ function mousePressed() {
261
+ let i = Math.floor(mouseX / (HEX_SIZE * 1.5));
262
+ let j = Math.floor((mouseY - (i % 2 ? HEX_SIZE * SQRT_3 / 2 : 0)) / (HEX_SIZE * SQRT_3));
263
+ if (i >= 0 && i < hexGrid.length && j >= 0 && j < hexGrid[0].length) {
264
+ let hero = heroes[playerId];
265
+ if (hexGrid[i][j].type === 'empty' && Math.abs(hero.x - i) <= 1 && Math.abs(hero.y - j) <= 1) {
266
+ moveHero(i, j);
267
+ }
268
+ }
269
+ }
270
+
271
+ function keyPressed() {
272
+ let hero = heroes[playerId];
273
+ if (key === 'w' || key === 'W') moveHero(hero.x, hero.y - 1);
274
+ if (key === 's' || key === 'S') moveHero(hero.x, hero.y + 1);
275
+ if (key === 'a' || key === 'A') moveHero(hero.x - 1, hero.y);
276
+ if (key === 'd' || key === 'D') moveHero(hero.x + 1, hero.y);
277
+ if (key === 'q' || key === 'Q') moveHero(hero.x - 1, hero.y - 1);
278
+ if (key === 'e' || key === 'E') moveHero(hero.x + 1, hero.y - 1);
279
+ }
280
+
281
+ function moveHero(newX, newY) {
282
+ if (newX < 0 || newX >= hexGrid.length || newY < 0 || newY >= hexGrid[0].length) return;
283
+ let hero = heroes[playerId];
284
+ let cell = hexGrid[newX][newY];
285
+ if (cell.type === 'empty' || cell.type === 'plant') {
286
+ hero.x = newX;
287
+ hero.y = newY;
288
+ handleInteractions();
289
+ updateState();
290
+ }
291
+ }
292
+
293
+ function handleInteractions() {
294
+ let hero = heroes[playerId];
295
+ // Loot Interaction
296
+ let lootIdx = loot.findIndex(l => l.x === hero.x && l.y === hero.y);
297
+ if (lootIdx !== -1) {
298
+ let item = loot[lootIdx].type;
299
+ if (item === '⚔️') hero.atk += 2;
300
+ if (item === '🛡️') hero.def += 2;
301
+ if (item === '💰') hero.xp += 10;
302
+ if (item === '🔑') hero.gear.push('🔑');
303
+ loot.splice(lootIdx, 1);
304
+ addStory('Loot', item);
305
+ }
306
+ // Trap Interaction
307
+ if (hexGrid[hero.x][hero.y].type === 'trap') {
308
+ hero.hp -= Math.floor(random(1, 5));
309
+ addStory('Trap', hexGrid[hero.x][hero.y].emoji);
310
+ }
311
+ // Monster Combat
312
+ let monsterIdx = monsters.findIndex(m => m.x === hero.x && m.y === hero.y);
313
+ if (monsterIdx !== -1) {
314
+ let monster = monsters[monsterIdx];
315
+ let damage = Math.max(0, hero.atk - 1);
316
+ monster.hp -= damage;
317
+ hero.hp -= Math.max(0, monster.atk - hero.def);
318
+ if (monster.hp <= 0) {
319
+ monsters.splice(monsterIdx, 1);
320
+ hero.xp += 10;
321
+ addStory('Monster', monster.type + ' slain');
322
+ }
323
+ }
324
+ // Overlord Combat
325
+ if (overlord.alive && hero.x === overlord.x && hero.y === overlord.y) {
326
+ let damage = Math.max(0, hero.atk - 2);
327
+ overlord.hp -= damage;
328
+ hero.hp -= Math.max(0, overlord.atk - hero.def);
329
+ if (overlord.hp <= 0) {
330
+ overlord.alive = false;
331
+ hero.xp += 50;
332
+ addStory('Monster', 'Overlord defeated');
333
+ }
334
+ }
335
+ // Exit Check
336
+ if (hero.x === exit.x && hero.y === exit.y && hero.gear.includes('🔑')) {
337
+ alert('Victory! You escaped the Hex Dungeon!');
338
+ resetGame();
339
+ }
340
+ // Level Up
341
+ if (hero.xp >= hero.level * 20) {
342
+ hero.level += 1;
343
+ hero.hp += 5;
344
+ hero.atk += 1;
345
+ hero.def += 1;
346
+ addStory('Hero', 'leveled up');
347
+ }
348
+ }
349
+
350
+ function addStory(type, word) {
351
+ let deck = JSON.parse(document.getElementById('deck').innerHTML);
352
+ let cardIndex = st.session_state.drawn_cards % 52;
353
+ let card = deck[cardIndex];
354
+ let suit = card[0];
355
+ let sentence = `A ${SUIT_PROPERTIES[suit]} event: ${type.toLowerCase()} ${word}`;
356
+ story.push(sentence);
357
+ st.session_state.drawn_cards += 1;
358
+ }
359
+
360
+ function updateState() {
361
+ fetch('/update_state', {
362
+ method: 'POST',
363
+ headers: { 'Content-Type': 'application/json' },
364
+ body: JSON.stringify({
365
+ hex_grid: hexGrid,
366
+ heroes: heroes,
367
+ monsters: monsters,
368
+ loot: loot,
369
+ exit: exit,
370
+ overlord: overlord,
371
+ story: story,
372
+ player_id: playerId
373
+ })
374
+ });
375
+ }
376
+ """
377
+
378
+ # -----------------------------------------------------------------------------
379
+ # Multi-Tab UI: Cross Breeding Cortical Theory and Dungeon Crawl
380
+ # -----------------------------------------------------------------------------
381
+ tabs = st.tabs(["Cortical Theory", "HexCitySaga", "Memory Integration", "Self Reward NPS", "Extra UI"])
382
+
383
+ # --- Tab 1: Cortical Column Theory Demonstration ---
384
+ with tabs[0]:
385
+ st.header("Cortical Column Theory: Self-Modifying Memory Systems")
386
+ st.markdown("""
387
+ **Theory Overview:**
388
+ Life’s essential attribute is the capacity for self-modification. This demonstration illustrates:
389
+
390
+ - **Episodic Memory (E):** Short-term, introspective attention (≈5–10 seconds).
391
+ - **Semantic Memory (K):** Accumulated knowledge formed by experiences.
392
+ - **Neural Connectivity:** Modeled via sparse matrices and graph structures representing voting neurons.
393
+ - **Free Energy & Bonding:** The drive that connects entities—analogous to love and maximal energy states.
394
+ """)
395
+
396
+ st.subheader("Neural Connectivity Sparse Matrix")
397
+ size = 10
398
+ density = 0.2
399
+ random_matrix = np.random.binomial(1, density, size=(size, size))
400
+ sparse_matrix = csr_matrix(random_matrix)
401
+ st.write("Sparse Matrix Representation:")
402
+ st.write(sparse_matrix)
403
+ st.write("Dense Matrix Representation:")
404
+ st.write(random_matrix)
405
+
406
+ st.subheader("Concept Graph Visualization")
407
+ graph_source = """
408
+ digraph G {
409
+ "Cortical Column 🧠" -> "Episodic Memory (E) ⏱️" [label="short-term"];
410
+ "Cortical Column 🧠" -> "Semantic Memory (K) 📚" [label="knowledge"];
411
+ "Episodic Memory (E) ⏱️" -> "Introspective Attention 🔍" [label="focus"];
412
+ "Semantic Memory (K) 📚" -> "Free Energy ⚡" [label="agency"];
413
+ "Free Energy ⚡" -> "Love ❤️" [label="bond"];
414
+ "Love ❤️" -> "Humanity 🌍" [label="connection"];
415
+ }
416
+ """
417
+ st.graphviz_chart(graph_source)
418
+
419
+ # --- Tab 2: HexCitySaga: Dungeon Crawl Game ---
420
+ with tabs[1]:
421
+ st.header("HexCitySaga: Dungeon Crawl")
422
+ st.write(f"Hero: **{player_id}**. Use WASD/QE to move. Goal: escape (🚪) with the key (🔑) or defeat the Overlord (👑).")
423
+ game_html = f"""
424
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.2/p5.min.js"></script>
425
+ <div id="hex_grid" style="display:none">{json.dumps(st.session_state.game_state['hex_grid'])}</div>
426
+ <div id="heroes" style="display:none">{json.dumps(st.session_state.game_state['heroes'])}</div>
427
+ <div id="monsters" style="display:none">{json.dumps(st.session_state.game_state['monsters'])}</div>
428
+ <div id="loot" style="display:none">{json.dumps(st.session_state.game_state['loot'])}</div>
429
+ <div id="exit" style="display:none">{json.dumps(st.session_state.game_state['exit'])}</div>
430
+ <div id="overlord" style="display:none">{json.dumps(st.session_state.game_state['overlord'])}</div>
431
+ <div id="player_id" style="display:none">{player_id}</div>
432
+ <div id="story" style="display:none">{json.dumps(st.session_state.game_state['story'])}</div>
433
+ <div id="deck" style="display:none">{json.dumps(st.session_state.deck)}</div>
434
+ <script>{p5js_code}</script>
435
+ """
436
+ st.components.v1.html(game_html, height=500)
437
+
438
+ # --- Tab 3: Memory Integration ---
439
+ with tabs[2]:
440
+ st.header("Memory Integration")
441
+ st.write("Mapping game events as nodes in an episodic/semantic memory network:")
442
+ if st.session_state.game_state['story']:
443
+ nodes = []
444
+ edges = []
445
+ for idx, event in enumerate(st.session_state.game_state['story']):
446
+ node_label = f"Event {idx+1}"
447
+ # Shorten the event text for node labels if needed
448
+ safe_event = event.replace('"', '\'')
449
+ nodes.append(f'"{node_label}" [label="{safe_event}"];')
450
+ if idx > 0:
451
+ edges.append(f'"Event {idx}" -> "Event {idx+1}";')
452
+ graph_def = "digraph MemoryGraph {\n" + "\n".join(nodes + edges) + "\n}"
453
+ st.graphviz_chart(graph_def)
454
+ else:
455
+ st.write("No memory events recorded yet. Engage in the dungeon to generate memories!")
456
+
457
+ # --- Tab 4: Self Reward Learning NPS ---
458
+ with tabs[3]:
459
+ st.header("Self Reward Learning NPS Score")
460
+ nps_score = st.slider("Rate Self Reward Learning (0-10):", 0, 10, 5)
461
+ if nps_score <= 6:
462
+ nps_comment = "Needs Improvement - Refine self-modification algorithms."
463
+ elif nps_score <= 8:
464
+ nps_comment = "Good, but can be better - Fine-tuning required."
465
+ else:
466
+ nps_comment = "Excellent! The system demonstrates robust self-reward learning."
467
+ st.write(f"**NPS Score:** {nps_score} - {nps_comment}")
468
+
469
+ # --- Tab 5: Extra UI Components ---
470
+ with tabs[4]:
471
+ st.header("Extra UI Components")
472
+ with st.expander("More Details"):
473
+ st.write("Additional interactive widgets and data visualizations can be added here.")
474
+
475
+ col1, col2 = st.columns(2)
476
+ with col1:
477
+ st.write("**Column 1:** Neural Signal Simulation (Line Chart)")
478
+ st.line_chart(np.random.randn(20, 1))
479
+ with col2:
480
+ st.write("**Column 2:** Energy Consumption (Bar Chart)")
481
+ st.bar_chart(np.random.randn(20, 1))
482
+
483
+ st.subheader("Data Table")
484
+ df = pd.DataFrame({
485
+ "Component": ["Neuron", "Synapse", "Dendrite", "Axon"],
486
+ "Status": ["Active", "Active", "Inactive", "Active"]
487
+ })
488
+ st.dataframe(df)
489
+
490
+ st.subheader("JSON Configuration")
491
+ sample_json = {
492
+ "Episodic": {"Duration": "5-10 sec", "Type": "Conscious"},
493
+ "Semantic": {"Label": "Cortical Column Theory"}
494
+ }
495
+ st.json(sample_json)
496
+
497
+ # -----------------------------------------------------------------------------
498
+ # Sidebar: Reset Game Button
499
+ # -----------------------------------------------------------------------------
500
+ if st.sidebar.button("Reset Game"):
501
+ reset_game()