awacke1 commited on
Commit
c136415
Β·
verified Β·
1 Parent(s): 866cbed

Update index.html

Browse files
Files changed (1) hide show
  1. index.html +1738 -19
index.html CHANGED
@@ -1,19 +1,1738 @@
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>Enhanced AI Flocking Evolution Simulator</title>
7
+ <style>
8
+ body {
9
+ margin: 0;
10
+ overflow: hidden;
11
+ font-family: Arial, sans-serif;
12
+ background: #000;
13
+ }
14
+ #ui {
15
+ position: absolute;
16
+ top: 10px;
17
+ left: 10px;
18
+ color: white;
19
+ background-color: rgba(0,0,0,0.9);
20
+ padding: 15px;
21
+ border-radius: 8px;
22
+ z-index: 100;
23
+ font-size: 14px;
24
+ min-width: 200px;
25
+ }
26
+ #controls {
27
+ position: absolute;
28
+ top: 10px;
29
+ right: 10px;
30
+ color: white;
31
+ background-color: rgba(0,0,0,0.9);
32
+ padding: 15px;
33
+ border-radius: 8px;
34
+ z-index: 100;
35
+ }
36
+ button {
37
+ background-color: #4CAF50;
38
+ border: none;
39
+ color: white;
40
+ padding: 8px 16px;
41
+ margin: 5px;
42
+ cursor: pointer;
43
+ border-radius: 4px;
44
+ font-size: 12px;
45
+ }
46
+ button:hover {
47
+ background-color: #45a049;
48
+ }
49
+ #stats {
50
+ position: absolute;
51
+ bottom: 10px;
52
+ left: 10px;
53
+ color: white;
54
+ background-color: rgba(0,0,0,0.9);
55
+ padding: 15px;
56
+ border-radius: 8px;
57
+ z-index: 100;
58
+ font-size: 12px;
59
+ min-width: 200px;
60
+ }
61
+ #flockingStats {
62
+ position: absolute;
63
+ bottom: 10px;
64
+ right: 10px;
65
+ color: white;
66
+ background-color: rgba(0,0,0,0.9);
67
+ padding: 15px;
68
+ border-radius: 8px;
69
+ z-index: 100;
70
+ font-size: 12px;
71
+ min-width: 180px;
72
+ }
73
+ #aiStats {
74
+ position: absolute;
75
+ top: 50%;
76
+ right: 10px;
77
+ transform: translateY(-50%);
78
+ color: white;
79
+ background-color: rgba(0,0,0,0.9);
80
+ padding: 15px;
81
+ border-radius: 8px;
82
+ z-index: 100;
83
+ font-size: 12px;
84
+ min-width: 180px;
85
+ }
86
+ .highlight { color: #ffcc00; font-weight: bold; }
87
+ .success { color: #00ff00; font-weight: bold; }
88
+ .flocking { color: #00aaff; }
89
+ .solo { color: #ff8800; }
90
+ .leader { color: #ff00ff; font-weight: bold; }
91
+ .explorer { color: #00ffff; }
92
+ .follower { color: #88ff88; }
93
+ .species-0 { color: #ff6b6b; }
94
+ .species-1 { color: #4ecdc4; }
95
+ .species-2 { color: #45b7d1; }
96
+ .species-3 { color: #96ceb4; }
97
+ .species-4 { color: #ffd93d; }
98
+ .progress-bar {
99
+ width: 100%;
100
+ height: 10px;
101
+ background-color: #333;
102
+ border-radius: 5px;
103
+ overflow: hidden;
104
+ margin: 5px 0;
105
+ }
106
+ .progress-fill {
107
+ height: 100%;
108
+ background: linear-gradient(90deg, #ff6b6b, #4ecdc4, #45b7d1);
109
+ transition: width 0.3s ease;
110
+ }
111
+ </style>
112
+ </head>
113
+ <body>
114
+ <div id="ui">
115
+ <div class="highlight">Enhanced AI Evolution Simulator</div>
116
+ <div>Epoch: <span id="epoch">1</span></div>
117
+ <div>Time: <span id="epochTime">60</span>s</div>
118
+ <div class="progress-bar"><div class="progress-fill" id="timeProgress"></div></div>
119
+ <div>Population: <span id="population">100</span></div>
120
+ <div>Species: <span id="speciesCount">1</span></div>
121
+ <div>Best Fitness: <span id="bestFitness">0</span></div>
122
+ <div>Avg IQ: <span id="avgIQ">50</span></div>
123
+ <div>Innovation: <span id="innovationCount">0</span></div>
124
+ </div>
125
+
126
+ <div id="controls">
127
+ <button id="pauseBtn">Pause</button>
128
+ <button id="resetBtn">Reset</button>
129
+ <button id="speedBtn">Speed: 1x</button>
130
+ <button id="viewBtn">View: Follow</button>
131
+ <button id="flockBtn">Flocks: ON</button>
132
+ <button id="adaptiveBtn">Adaptive: ON</button>
133
+ <button id="challengeBtn">Challenge: Normal</button>
134
+ </div>
135
+
136
+ <div id="stats">
137
+ <div><span class="highlight">Top Performers:</span></div>
138
+ <div id="topPerformers"></div>
139
+ <div style="margin-top: 10px;"><span class="highlight">Generation Stats:</span></div>
140
+ <div>Crashes: <span id="crashCount">0</span></div>
141
+ <div>Total Distance: <span id="totalDistance">0</span></div>
142
+ <div>Exploration: <span id="explorationBonus">0</span></div>
143
+ <div>Cooperation: <span id="cooperationScore">0</span></div>
144
+ <div>Road Mastery: <span id="roadMastery">0</span>%</div>
145
+ </div>
146
+
147
+ <div id="flockingStats">
148
+ <div><span class="highlight">Flocking Dynamics:</span></div>
149
+ <div><span class="leader">Leaders:</span> <span id="leaderCount">0</span></div>
150
+ <div><span class="flocking">Followers:</span> <span id="followerCount">0</span></div>
151
+ <div><span class="explorer">Explorers:</span> <span id="explorerCount">0</span></div>
152
+ <div><span class="solo">Solo:</span> <span id="soloCount">0</span></div>
153
+ <div>Largest Flock: <span id="largestFlock">0</span></div>
154
+ <div>Avg Coordination: <span id="avgCoordination">0</span>%</div>
155
+ <div>Group Efficiency: <span id="groupEfficiency">0</span>%</div>
156
+ </div>
157
+
158
+ <div id="aiStats">
159
+ <div><span class="highlight">AI Intelligence:</span></div>
160
+ <div>Neural Complexity: <span id="neuralComplexity">100</span></div>
161
+ <div>Decision Quality: <span id="decisionQuality">50</span>%</div>
162
+ <div>Learning Rate: <span id="learningRate">1.0</span></div>
163
+ <div>Memory Usage: <span id="memoryUsage">0</span>%</div>
164
+ <div style="margin-top: 10px;"><span class="highlight">Behaviors:</span></div>
165
+ <div>Predictive: <span id="predictiveBehavior">0</span>%</div>
166
+ <div>Adaptive: <span id="adaptiveBehavior">0</span>%</div>
167
+ <div>Emergent: <span id="emergentBehavior">0</span>%</div>
168
+ </div>
169
+
170
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
171
+ <script>
172
+ // Global variables
173
+ let scene, camera, renderer, clock;
174
+ let world = {
175
+ roads: [],
176
+ intersections: [],
177
+ buildings: [],
178
+ jumpRamps: [],
179
+ flockLines: [],
180
+ dynamicObstacles: [],
181
+ targets: []
182
+ };
183
+
184
+ // Enhanced evolution system
185
+ let epoch = 1;
186
+ let epochTime = 60;
187
+ let timeLeft = 60;
188
+ let population = [];
189
+ let species = [];
190
+ let populationSize = 100;
191
+ let bestFitness = 0;
192
+ let totalDistance = 0;
193
+ let groupDistance = 0;
194
+ let crashCount = 0;
195
+ let paused = false;
196
+ let speedMultiplier = 1;
197
+ let cameraMode = 'follow';
198
+ let showFlockLines = true;
199
+ let adaptiveEnvironment = true;
200
+ let challengeLevel = 'normal'; // normal, hard, extreme
201
+ let innovationCounter = 0;
202
+ let globalMemory = new Map();
203
+
204
+ // Enhanced AI parameters
205
+ const NEIGHBOR_RADIUS = 30;
206
+ const SEPARATION_RADIUS = 10;
207
+ const LEADERSHIP_RADIUS = 40;
208
+ const MEMORY_SIZE = 10;
209
+ const SPECIES_THRESHOLD = 3.0;
210
+ const TARGET_SPECIES = 5;
211
+
212
+ // Dynamic challenge system
213
+ let dynamicChallenges = {
214
+ obstacles: [],
215
+ targets: [],
216
+ weather: 'clear',
217
+ timeOfDay: 'day'
218
+ };
219
+
220
+ // Enhanced Neural Network with memory and multiple layers
221
+ class EnhancedNeuralNetwork {
222
+ constructor() {
223
+ this.inputSize = 24; // Expanded sensory inputs
224
+ this.hiddenLayers = [32, 24, 16]; // Multi-layer deep network
225
+ this.outputSize = 8; // More nuanced outputs
226
+ this.memorySize = MEMORY_SIZE;
227
+
228
+ // Initialize all weight matrices and biases
229
+ this.weights = [];
230
+ this.biases = [];
231
+ this.memory = new Array(this.memorySize).fill(0);
232
+ this.memoryPointer = 0;
233
+
234
+ // Build network layers
235
+ let prevSize = this.inputSize + this.memorySize;
236
+ for (let i = 0; i < this.hiddenLayers.length; i++) {
237
+ this.weights.push(this.randomMatrix(prevSize, this.hiddenLayers[i]));
238
+ this.biases.push(this.randomArray(this.hiddenLayers[i]));
239
+ prevSize = this.hiddenLayers[i];
240
+ }
241
+
242
+ // Output layer
243
+ this.weights.push(this.randomMatrix(prevSize, this.outputSize));
244
+ this.biases.push(this.randomArray(this.outputSize));
245
+
246
+ // Specialized modules
247
+ this.attentionWeights = this.randomArray(this.inputSize);
248
+ this.innovationGenes = this.randomArray(10);
249
+ this.personalityTraits = {
250
+ leadership: Math.random(),
251
+ exploration: Math.random(),
252
+ cooperation: Math.random(),
253
+ caution: Math.random(),
254
+ adaptability: Math.random()
255
+ };
256
+ }
257
+
258
+ randomMatrix(rows, cols) {
259
+ let matrix = [];
260
+ for (let i = 0; i < rows; i++) {
261
+ matrix[i] = [];
262
+ for (let j = 0; j < cols; j++) {
263
+ matrix[i][j] = (Math.random() - 0.5) * 2;
264
+ }
265
+ }
266
+ return matrix;
267
+ }
268
+
269
+ randomArray(size) {
270
+ return Array(size).fill().map(() => (Math.random() - 0.5) * 2);
271
+ }
272
+
273
+ // Advanced activation with attention mechanism
274
+ activate(inputs) {
275
+ // Apply attention mechanism to inputs
276
+ const attentionScores = inputs.map((input, i) =>
277
+ input * this.sigmoid(this.attentionWeights[i])
278
+ );
279
+
280
+ // Combine inputs with memory
281
+ let currentInput = [...attentionScores, ...this.memory];
282
+
283
+ // Forward pass through hidden layers
284
+ for (let layer = 0; layer < this.hiddenLayers.length; layer++) {
285
+ currentInput = this.forwardLayer(currentInput, this.weights[layer], this.biases[layer]);
286
+ }
287
+
288
+ // Output layer
289
+ const outputs = this.forwardLayer(currentInput,
290
+ this.weights[this.weights.length - 1],
291
+ this.biases[this.biases.length - 1]);
292
+
293
+ // Update memory with current state
294
+ this.updateMemory(inputs, outputs);
295
+
296
+ return outputs;
297
+ }
298
+
299
+ forwardLayer(inputs, weights, biases) {
300
+ const outputs = new Array(weights[0].length).fill(0);
301
+
302
+ for (let i = 0; i < outputs.length; i++) {
303
+ for (let j = 0; j < inputs.length; j++) {
304
+ outputs[i] += inputs[j] * weights[j][i];
305
+ }
306
+ outputs[i] += biases[i];
307
+ outputs[i] = this.advancedActivation(outputs[i]);
308
+ }
309
+
310
+ return outputs;
311
+ }
312
+
313
+ // Advanced activation function combining sigmoid and tanh
314
+ advancedActivation(x) {
315
+ const clampedX = Math.max(-10, Math.min(10, x));
316
+ return (this.sigmoid(clampedX) + Math.tanh(clampedX)) / 2;
317
+ }
318
+
319
+ sigmoid(x) {
320
+ return 1 / (1 + Math.exp(-Math.max(-500, Math.min(500, x))));
321
+ }
322
+
323
+ updateMemory(inputs, outputs) {
324
+ // Store important environmental information
325
+ const importance = Math.max(...inputs.slice(0, 8)); // Obstacle sensor max
326
+ this.memory[this.memoryPointer] = importance;
327
+ this.memoryPointer = (this.memoryPointer + 1) % this.memorySize;
328
+ }
329
+
330
+ // Advanced mutation with adaptive rates
331
+ mutate(baseRate = 0.1, innovation = false) {
332
+ const adaptiveRate = baseRate * (1 + this.personalityTraits.adaptability);
333
+
334
+ // Mutate weights
335
+ this.weights.forEach(weightMatrix => {
336
+ this.mutateMatrix(weightMatrix, adaptiveRate);
337
+ });
338
+
339
+ // Mutate biases
340
+ this.biases.forEach(biasArray => {
341
+ this.mutateArray(biasArray, adaptiveRate);
342
+ });
343
+
344
+ // Mutate attention weights
345
+ this.mutateArray(this.attentionWeights, adaptiveRate * 0.5);
346
+
347
+ // Mutate personality traits
348
+ Object.keys(this.personalityTraits).forEach(trait => {
349
+ if (Math.random() < adaptiveRate) {
350
+ this.personalityTraits[trait] += (Math.random() - 0.5) * 0.2;
351
+ this.personalityTraits[trait] = Math.max(0, Math.min(1, this.personalityTraits[trait]));
352
+ }
353
+ });
354
+
355
+ // Innovation mutations
356
+ if (innovation) {
357
+ this.mutateArray(this.innovationGenes, adaptiveRate * 2);
358
+ innovationCounter++;
359
+ }
360
+ }
361
+
362
+ mutateMatrix(matrix, rate) {
363
+ for (let i = 0; i < matrix.length; i++) {
364
+ for (let j = 0; j < matrix[i].length; j++) {
365
+ if (Math.random() < rate) {
366
+ const mutationStrength = 0.5 * (1 + Math.random());
367
+ matrix[i][j] += (Math.random() - 0.5) * mutationStrength;
368
+ matrix[i][j] = Math.max(-5, Math.min(5, matrix[i][j])); // Clamp weights
369
+ }
370
+ }
371
+ }
372
+ }
373
+
374
+ mutateArray(array, rate) {
375
+ for (let i = 0; i < array.length; i++) {
376
+ if (Math.random() < rate) {
377
+ const mutationStrength = 0.5 * (1 + Math.random());
378
+ array[i] += (Math.random() - 0.5) * mutationStrength;
379
+ array[i] = Math.max(-5, Math.min(5, array[i])); // Clamp values
380
+ }
381
+ }
382
+ }
383
+
384
+ // Crossover with compatibility checking
385
+ crossover(other) {
386
+ const child = new EnhancedNeuralNetwork();
387
+
388
+ // Blend weights and biases
389
+ for (let layer = 0; layer < this.weights.length; layer++) {
390
+ for (let i = 0; i < this.weights[layer].length; i++) {
391
+ for (let j = 0; j < this.weights[layer][i].length; j++) {
392
+ child.weights[layer][i][j] = Math.random() < 0.5 ?
393
+ this.weights[layer][i][j] : other.weights[layer][i][j];
394
+ }
395
+ }
396
+
397
+ for (let i = 0; i < this.biases[layer].length; i++) {
398
+ child.biases[layer][i] = Math.random() < 0.5 ?
399
+ this.biases[layer][i] : other.biases[layer][i];
400
+ }
401
+ }
402
+
403
+ // Blend personality traits
404
+ Object.keys(this.personalityTraits).forEach(trait => {
405
+ child.personalityTraits[trait] = (this.personalityTraits[trait] + other.personalityTraits[trait]) / 2;
406
+ });
407
+
408
+ return child;
409
+ }
410
+
411
+ copy() {
412
+ const newNN = new EnhancedNeuralNetwork();
413
+
414
+ // Deep copy all components
415
+ newNN.weights = this.weights.map(matrix =>
416
+ matrix.map(row => [...row])
417
+ );
418
+ newNN.biases = this.biases.map(bias => [...bias]);
419
+ newNN.attentionWeights = [...this.attentionWeights];
420
+ newNN.memory = [...this.memory];
421
+ newNN.memoryPointer = this.memoryPointer;
422
+ newNN.innovationGenes = [...this.innovationGenes];
423
+ newNN.personalityTraits = {...this.personalityTraits};
424
+
425
+ return newNN;
426
+ }
427
+
428
+ // Calculate network complexity for visualization
429
+ getComplexity() {
430
+ let totalConnections = 0;
431
+ this.weights.forEach(matrix => {
432
+ totalConnections += matrix.length * matrix[0].length;
433
+ });
434
+ return totalConnections;
435
+ }
436
+ }
437
+
438
+ // Enhanced AI Car with advanced behaviors
439
+ class EnhancedAICar {
440
+ constructor(x = 0, z = 0) {
441
+ this.brain = new EnhancedNeuralNetwork();
442
+ this.mesh = this.createCarMesh();
443
+ this.mesh.position.set(x, 1, z);
444
+
445
+ // Enhanced movement properties
446
+ this.velocity = new THREE.Vector3(
447
+ (Math.random() - 0.5) * 10, 0, (Math.random() - 0.5) * 10
448
+ );
449
+ this.acceleration = new THREE.Vector3();
450
+ this.maxSpeed = 25;
451
+ this.minSpeed = 3;
452
+ this.accelerationForce = 0.6;
453
+ this.turnSpeed = 0.1;
454
+
455
+ // Advanced flocking and behavior
456
+ this.neighbors = [];
457
+ this.role = 'follower'; // leader, follower, explorer, scout
458
+ this.flockId = -1;
459
+ this.speciesId = 0;
460
+ this.leadership = this.brain.personalityTraits.leadership;
461
+ this.exploration = this.brain.personalityTraits.exploration;
462
+ this.cooperation = this.brain.personalityTraits.cooperation;
463
+
464
+ // Enhanced fitness and metrics
465
+ this.fitness = 0;
466
+ this.rawFitness = 0;
467
+ this.adjustedFitness = 0;
468
+ this.distanceTraveled = 0;
469
+ this.explorationBonus = 0;
470
+ this.cooperationScore = 0;
471
+ this.leadershipScore = 0;
472
+ this.innovationScore = 0;
473
+ this.decisionQuality = 50;
474
+ this.predictiveAccuracy = 0;
475
+
476
+ // State tracking
477
+ this.timeAlive = 100;
478
+ this.crashed = false;
479
+ this.lastPosition = new THREE.Vector3(x, 1, z);
480
+ this.visitedAreas = new Set();
481
+ this.decisions = [];
482
+ this.predictions = [];
483
+
484
+ // Enhanced sensors
485
+ this.sensors = Array(12).fill(0); // More sensors
486
+ this.environmentSensors = Array(4).fill(0);
487
+ this.socialSensors = Array(8).fill(0);
488
+ this.sensorRays = [];
489
+ this.flockLines = [];
490
+
491
+ this.createSensorRays();
492
+ this.createFlockVisualization();
493
+ this.initializeMovement();
494
+ }
495
+
496
+ createCarMesh() {
497
+ const group = new THREE.Group();
498
+
499
+ // Enhanced car body with role-based styling
500
+ const bodyGeometry = new THREE.BoxGeometry(1.5, 0.8, 3);
501
+ this.bodyMaterial = new THREE.MeshLambertMaterial({
502
+ color: new THREE.Color().setHSL(Math.random(), 0.8, 0.6)
503
+ });
504
+ const body = new THREE.Mesh(bodyGeometry, this.bodyMaterial);
505
+ body.position.y = 0.4;
506
+ body.castShadow = true;
507
+ group.add(body);
508
+
509
+ // Role indicator
510
+ const indicatorGeometry = new THREE.SphereGeometry(0.2, 8, 6);
511
+ this.roleIndicator = new THREE.Mesh(indicatorGeometry,
512
+ new THREE.MeshLambertMaterial({ color: 0xffffff }));
513
+ this.roleIndicator.position.set(0, 1.5, 0);
514
+ group.add(this.roleIndicator);
515
+
516
+ // Intelligence indicator (size based on neural complexity)
517
+ const complexity = this.brain.getComplexity();
518
+ const brainSize = 0.1 + (complexity / 10000) * 0.4;
519
+ const brainGeometry = new THREE.SphereGeometry(brainSize, 6, 4);
520
+ this.brainIndicator = new THREE.Mesh(brainGeometry,
521
+ new THREE.MeshLambertMaterial({
522
+ color: 0x00ffff,
523
+ transparent: true,
524
+ opacity: 0.7
525
+ }));
526
+ this.brainIndicator.position.set(0, 1.8, 0);
527
+ group.add(this.brainIndicator);
528
+
529
+ // Enhanced wheels with rotation
530
+ const wheelGeometry = new THREE.CylinderGeometry(0.3, 0.3, 0.2, 8);
531
+ const wheelMaterial = new THREE.MeshLambertMaterial({ color: 0x333333 });
532
+
533
+ this.wheels = [];
534
+ const wheelPositions = [
535
+ [-0.8, 0, 1.2], [0.8, 0, 1.2],
536
+ [-0.8, 0, -1.2], [0.8, 0, -1.2]
537
+ ];
538
+
539
+ wheelPositions.forEach((pos, i) => {
540
+ const wheel = new THREE.Mesh(wheelGeometry, wheelMaterial);
541
+ wheel.position.set(...pos);
542
+ wheel.rotation.z = Math.PI / 2;
543
+ this.wheels.push(wheel);
544
+ group.add(wheel);
545
+ });
546
+
547
+ return group;
548
+ }
549
+
550
+ createSensorRays() {
551
+ const sensorMaterial = new THREE.LineBasicMaterial({
552
+ color: 0xff0000,
553
+ transparent: true,
554
+ opacity: 0.3
555
+ });
556
+
557
+ // 12 sensors for comprehensive environment detection
558
+ for (let i = 0; i < 12; i++) {
559
+ const geometry = new THREE.BufferGeometry().setFromPoints([
560
+ new THREE.Vector3(0, 0, 0),
561
+ new THREE.Vector3(0, 0, 8)
562
+ ]);
563
+ const ray = new THREE.Line(geometry, sensorMaterial);
564
+ this.sensorRays.push(ray);
565
+ this.mesh.add(ray);
566
+ }
567
+ }
568
+
569
+ createFlockVisualization() {
570
+ const flockMaterial = new THREE.LineBasicMaterial({
571
+ color: 0x00ff00,
572
+ transparent: true,
573
+ opacity: 0.3
574
+ });
575
+
576
+ for (let i = 0; i < 8; i++) {
577
+ const geometry = new THREE.BufferGeometry().setFromPoints([
578
+ new THREE.Vector3(0, 2, 0),
579
+ new THREE.Vector3(0, 2, 0)
580
+ ]);
581
+ const line = new THREE.Line(geometry, flockMaterial);
582
+ this.flockLines.push(line);
583
+ if (showFlockLines) scene.add(line);
584
+ }
585
+ }
586
+
587
+ initializeMovement() {
588
+ this.mesh.rotation.y = Math.random() * Math.PI * 2;
589
+ this.velocity.set(
590
+ Math.sin(this.mesh.rotation.y) * (8 + Math.random() * 7),
591
+ 0,
592
+ Math.cos(this.mesh.rotation.y) * (8 + Math.random() * 7)
593
+ );
594
+ }
595
+
596
+ updateEnhancedSensors() {
597
+ const maxDistance = 8;
598
+ const raycaster = new THREE.Raycaster();
599
+
600
+ // 12-direction sensor array
601
+ const sensorAngles = [];
602
+ for (let i = 0; i < 12; i++) {
603
+ sensorAngles.push((i * Math.PI * 2) / 12);
604
+ }
605
+
606
+ sensorAngles.forEach((angle, i) => {
607
+ const direction = new THREE.Vector3(
608
+ Math.sin(angle), 0, Math.cos(angle)
609
+ );
610
+ direction.applyQuaternion(this.mesh.quaternion);
611
+
612
+ raycaster.set(this.mesh.position, direction);
613
+ const intersects = raycaster.intersectObjects(this.getObstacles(), true);
614
+
615
+ if (intersects.length > 0 && intersects[0].distance <= maxDistance) {
616
+ this.sensors[i] = 1 - (intersects[0].distance / maxDistance);
617
+ } else {
618
+ this.sensors[i] = 0;
619
+ }
620
+
621
+ // Update visual ray
622
+ const endDistance = intersects.length > 0 ?
623
+ Math.min(intersects[0].distance, maxDistance) : maxDistance;
624
+
625
+ const rayEnd = direction.clone().multiplyScalar(endDistance);
626
+ this.sensorRays[i].geometry.setFromPoints([
627
+ new THREE.Vector3(0, 0, 0), rayEnd
628
+ ]);
629
+ });
630
+
631
+ // Environment sensors
632
+ this.updateEnvironmentSensors();
633
+ }
634
+
635
+ updateEnvironmentSensors() {
636
+ const pos = this.mesh.position;
637
+
638
+ // Road detection with direction
639
+ this.environmentSensors[0] = this.detectRoadPosition();
640
+
641
+ // Obstacle density in area
642
+ let nearbyObstacles = 0;
643
+ population.forEach(other => {
644
+ if (other !== this && !other.crashed) {
645
+ const dist = pos.distanceTo(other.mesh.position);
646
+ if (dist < 20) nearbyObstacles++;
647
+ }
648
+ });
649
+ this.environmentSensors[1] = Math.min(nearbyObstacles / 5, 1);
650
+
651
+ // Target/goal direction (if any targets exist)
652
+ this.environmentSensors[2] = this.getTargetDirection();
653
+
654
+ // Exploration potential
655
+ this.environmentSensors[3] = this.getExplorationPotential();
656
+ }
657
+
658
+ updateAdvancedFlocking() {
659
+ this.neighbors = [];
660
+ this.socialSensors.fill(0);
661
+
662
+ let separation = new THREE.Vector3();
663
+ let alignment = new THREE.Vector3();
664
+ let cohesion = new THREE.Vector3();
665
+ let leadership = new THREE.Vector3();
666
+
667
+ let neighborCount = 0;
668
+ let leaderInfluence = 0;
669
+
670
+ population.forEach(other => {
671
+ if (other !== this && !other.crashed) {
672
+ const distance = this.mesh.position.distanceTo(other.mesh.position);
673
+
674
+ if (distance < NEIGHBOR_RADIUS && distance > 0) {
675
+ this.neighbors.push(other);
676
+
677
+ // Traditional flocking forces
678
+ cohesion.add(other.mesh.position);
679
+ alignment.add(other.velocity);
680
+
681
+ // Leadership dynamics
682
+ if (other.role === 'leader' && distance < LEADERSHIP_RADIUS) {
683
+ const influence = other.leadership * (1 - distance / LEADERSHIP_RADIUS);
684
+ leadership.add(other.velocity.clone().multiplyScalar(influence));
685
+ leaderInfluence += influence;
686
+ }
687
+
688
+ neighborCount++;
689
+ }
690
+
691
+ if (distance < SEPARATION_RADIUS && distance > 0) {
692
+ const diff = this.mesh.position.clone().sub(other.mesh.position);
693
+ diff.normalize().divideScalar(distance);
694
+ separation.add(diff);
695
+ }
696
+ }
697
+ });
698
+
699
+ // Finalize flocking forces
700
+ if (neighborCount > 0) {
701
+ cohesion.divideScalar(neighborCount).sub(this.mesh.position).normalize();
702
+ alignment.divideScalar(neighborCount).normalize();
703
+ this.cooperationScore += neighborCount * 0.1;
704
+ }
705
+
706
+ if (leaderInfluence > 0) {
707
+ leadership.normalize();
708
+ }
709
+
710
+ // Update social sensors
711
+ this.socialSensors[0] = Math.min(neighborCount / 10, 1); // Neighbor density
712
+ this.socialSensors[1] = separation.length(); // Separation strength
713
+ this.socialSensors[2] = alignment.length(); // Alignment strength
714
+ this.socialSensors[3] = cohesion.length(); // Cohesion strength
715
+ this.socialSensors[4] = leadership.length(); // Leadership influence
716
+ this.socialSensors[5] = this.leadership; // Own leadership
717
+ this.socialSensors[6] = this.cooperation; // Cooperation tendency
718
+ this.socialSensors[7] = this.role === 'leader' ? 1 : 0; // Role indicator
719
+
720
+ // Store forces for neural network
721
+ this.flockingForces = { separation, alignment, cohesion, leadership };
722
+
723
+ // Update role based on behavior
724
+ this.updateRole();
725
+ }
726
+
727
+ updateRole() {
728
+ const neighborCount = this.neighbors.length;
729
+
730
+ if (this.leadership > 0.7 && neighborCount > 2) {
731
+ this.role = 'leader';
732
+ this.leadershipScore += 1;
733
+ } else if (this.exploration > 0.8 && neighborCount < 2) {
734
+ this.role = 'explorer';
735
+ this.explorationBonus += this.velocity.length() * 0.1;
736
+ } else if (neighborCount > 0) {
737
+ this.role = 'follower';
738
+ } else {
739
+ this.role = 'scout';
740
+ }
741
+
742
+ // Update visual indicator
743
+ const colors = {
744
+ leader: 0xff00ff,
745
+ explorer: 0x00ffff,
746
+ follower: 0x88ff88,
747
+ scout: 0xffff00
748
+ };
749
+ this.roleIndicator.material.color.setHex(colors[this.role]);
750
+ }
751
+
752
+ getEnhancedInputs() {
753
+ // Comprehensive input vector
754
+ return [
755
+ ...this.sensors, // 12 obstacle sensors
756
+ ...this.environmentSensors, // 4 environment sensors
757
+ ...this.socialSensors, // 8 social sensors
758
+ ];
759
+ }
760
+
761
+ makeDecision(inputs, outputs) {
762
+ // Enhanced decision making with prediction
763
+ const decision = {
764
+ timestamp: Date.now(),
765
+ inputs: [...inputs],
766
+ outputs: [...outputs],
767
+ prediction: this.makePrediction(inputs),
768
+ confidence: this.calculateConfidence(outputs)
769
+ };
770
+
771
+ this.decisions.push(decision);
772
+ if (this.decisions.length > 20) {
773
+ this.decisions.shift();
774
+ }
775
+
776
+ // Update decision quality based on outcomes
777
+ this.updateDecisionQuality();
778
+
779
+ return outputs;
780
+ }
781
+
782
+ makePrediction(inputs) {
783
+ // Simple prediction: where will I be in 5 steps?
784
+ const prediction = this.mesh.position.clone().add(
785
+ this.velocity.clone().multiplyScalar(5)
786
+ );
787
+
788
+ this.predictions.push({
789
+ timestamp: Date.now(),
790
+ predicted: prediction,
791
+ actual: null // Will be filled later
792
+ });
793
+
794
+ return prediction;
795
+ }
796
+
797
+ calculateConfidence(outputs) {
798
+ // Confidence based on output certainty
799
+ const variance = outputs.reduce((sum, val) => sum + Math.pow(val - 0.5, 2), 0);
800
+ return Math.min(variance * 2, 1);
801
+ }
802
+
803
+ updateDecisionQuality() {
804
+ // Evaluate prediction accuracy
805
+ let accuracy = 0;
806
+ let validPredictions = 0;
807
+
808
+ this.predictions.forEach(pred => {
809
+ if (pred.actual) {
810
+ const error = pred.predicted.distanceTo(pred.actual);
811
+ accuracy += Math.max(0, 1 - error / 50); // Normalize error
812
+ validPredictions++;
813
+ }
814
+ });
815
+
816
+ if (validPredictions > 0) {
817
+ this.predictiveAccuracy = accuracy / validPredictions;
818
+ this.decisionQuality = this.predictiveAccuracy * 100;
819
+ }
820
+ }
821
+
822
+ detectRoadPosition() {
823
+ const pos = this.mesh.position;
824
+ const roadWidth = 12;
825
+ const roadSpacing = 150;
826
+
827
+ const nearestHorizontalRoad = Math.round(pos.z / roadSpacing) * roadSpacing;
828
+ const distToHorizontalRoad = Math.abs(pos.z - nearestHorizontalRoad);
829
+ const onHorizontalRoad = distToHorizontalRoad <= roadWidth / 2;
830
+
831
+ const nearestVerticalRoad = Math.round(pos.x / roadSpacing) * roadSpacing;
832
+ const distToVerticalRoad = Math.abs(pos.x - nearestVerticalRoad);
833
+ const onVerticalRoad = distToVerticalRoad <= roadWidth / 2;
834
+
835
+ if (onHorizontalRoad || onVerticalRoad) {
836
+ return Math.max(
837
+ onHorizontalRoad ? 1 - (distToHorizontalRoad / (roadWidth / 2)) : 0,
838
+ onVerticalRoad ? 1 - (distToVerticalRoad / (roadWidth / 2)) : 0
839
+ );
840
+ }
841
+
842
+ return 0;
843
+ }
844
+
845
+ getTargetDirection() {
846
+ // Find nearest unexplored area or target
847
+ if (world.targets.length > 0) {
848
+ const nearest = world.targets.reduce((closest, target) => {
849
+ const dist = this.mesh.position.distanceTo(target.position);
850
+ return dist < closest.distance ? { target, distance: dist } : closest;
851
+ }, { distance: Infinity });
852
+
853
+ if (nearest.distance < 100) {
854
+ const direction = nearest.target.position.clone()
855
+ .sub(this.mesh.position).normalize();
856
+ return (direction.dot(this.velocity.clone().normalize()) + 1) / 2;
857
+ }
858
+ }
859
+ return 0.5;
860
+ }
861
+
862
+ getExplorationPotential() {
863
+ // Calculate exploration potential based on visited areas
864
+ const currentArea = `${Math.floor(this.mesh.position.x / 50)},${Math.floor(this.mesh.position.z / 50)}`;
865
+ return this.visitedAreas.has(currentArea) ? 0.2 : 0.8;
866
+ }
867
+
868
+ update(deltaTime) {
869
+ if (this.crashed) return;
870
+
871
+ this.timeAlive -= deltaTime;
872
+ if (this.timeAlive <= 0) {
873
+ this.crashed = true;
874
+ return;
875
+ }
876
+
877
+ // Update all sensors and behaviors
878
+ this.updateEnhancedSensors();
879
+ this.updateAdvancedFlocking();
880
+ this.updateVisuals();
881
+
882
+ // Get comprehensive neural network inputs
883
+ const inputs = this.getEnhancedInputs();
884
+
885
+ // Get brain decision
886
+ const outputs = this.brain.activate(inputs);
887
+
888
+ // Process decision with prediction
889
+ const processedOutputs = this.makeDecision(inputs, outputs);
890
+
891
+ // Apply enhanced movement
892
+ this.applyEnhancedMovement(processedOutputs, deltaTime);
893
+
894
+ // Update fitness with advanced metrics
895
+ this.updateAdvancedFitness(deltaTime);
896
+
897
+ // Track exploration
898
+ this.trackExploration();
899
+
900
+ this.lastPosition.copy(this.mesh.position);
901
+ this.checkCollisions();
902
+ this.keepInBounds();
903
+ }
904
+
905
+ applyEnhancedMovement(outputs, deltaTime) {
906
+ // Enhanced output interpretation
907
+ const [
908
+ forwardForce, turnLeft, turnRight, brake,
909
+ emergencyStop, boost, preciseTurn, formation
910
+ ] = outputs;
911
+
912
+ // Turning with precision control
913
+ const baseTurn = (turnRight - turnLeft) * this.turnSpeed;
914
+ const precisionTurn = (preciseTurn - 0.5) * this.turnSpeed * 0.5;
915
+ const totalTurn = (baseTurn + precisionTurn) * deltaTime;
916
+
917
+ this.mesh.rotation.y += totalTurn;
918
+
919
+ // Advanced acceleration
920
+ const forward = new THREE.Vector3(0, 0, 1);
921
+ forward.applyQuaternion(this.mesh.quaternion);
922
+
923
+ let acceleration = this.accelerationForce;
924
+
925
+ // Boost behavior
926
+ if (boost > 0.7) {
927
+ acceleration *= 1.5;
928
+ this.maxSpeed = 30;
929
+ } else {
930
+ this.maxSpeed = 25;
931
+ }
932
+
933
+ // Emergency stop
934
+ if (emergencyStop > 0.8) {
935
+ this.velocity.multiplyScalar(0.8);
936
+ } else if (forwardForce > 0.1) {
937
+ this.acceleration.add(forward.multiplyScalar(acceleration * forwardForce * deltaTime));
938
+ }
939
+
940
+ // Braking
941
+ if (brake > 0.5) {
942
+ this.velocity.multiplyScalar(1 - brake * deltaTime * 2);
943
+ }
944
+
945
+ // Apply flocking forces
946
+ if (this.flockingForces) {
947
+ const flockingStrength = formation * 0.5;
948
+ this.acceleration.add(this.flockingForces.separation.multiplyScalar(0.3));
949
+ this.acceleration.add(this.flockingForces.alignment.multiplyScalar(0.2 * flockingStrength));
950
+ this.acceleration.add(this.flockingForces.cohesion.multiplyScalar(0.2 * flockingStrength));
951
+ this.acceleration.add(this.flockingForces.leadership.multiplyScalar(0.4 * (1 - this.leadership)));
952
+ }
953
+
954
+ // Apply acceleration and velocity
955
+ this.velocity.add(this.acceleration);
956
+ this.acceleration.multiplyScalar(0.1); // Decay acceleration
957
+
958
+ // Speed limits
959
+ const currentSpeed = this.velocity.length();
960
+ if (currentSpeed > this.maxSpeed) {
961
+ this.velocity.normalize().multiplyScalar(this.maxSpeed);
962
+ } else if (currentSpeed < this.minSpeed) {
963
+ this.velocity.normalize().multiplyScalar(this.minSpeed);
964
+ }
965
+
966
+ // Apply movement
967
+ this.mesh.position.add(this.velocity.clone().multiplyScalar(deltaTime));
968
+
969
+ // Wheel rotation animation
970
+ this.wheels.forEach(wheel => {
971
+ wheel.rotation.x += this.velocity.length() * deltaTime * 0.1;
972
+ });
973
+ }
974
+
975
+ updateAdvancedFitness(deltaTime) {
976
+ const distance = this.mesh.position.distanceTo(this.lastPosition);
977
+ this.distanceTraveled += distance;
978
+
979
+ // Multi-objective fitness function
980
+ const roadBonus = this.detectRoadPosition() * distance * 3;
981
+ const groupBonus = Math.min(this.neighbors.length, 8) * distance * 2;
982
+ const roleBonus = this.getRoleBonus() * deltaTime;
983
+ const innovationBonus = this.innovationScore * 0.5;
984
+ const efficiencyBonus = this.getEfficiencyBonus();
985
+
986
+ this.rawFitness = this.distanceTraveled +
987
+ roadBonus +
988
+ groupBonus +
989
+ roleBonus +
990
+ this.explorationBonus +
991
+ this.cooperationScore +
992
+ innovationBonus +
993
+ efficiencyBonus;
994
+
995
+ // Update predictions
996
+ this.predictions.forEach(pred => {
997
+ if (!pred.actual && Date.now() - pred.timestamp > 5000) {
998
+ pred.actual = this.mesh.position.clone();
999
+ }
1000
+ });
1001
+ }
1002
+
1003
+ getRoleBonus() {
1004
+ switch (this.role) {
1005
+ case 'leader': return this.leadershipScore * 0.5;
1006
+ case 'explorer': return this.explorationBonus * 0.3;
1007
+ case 'follower': return this.cooperationScore * 0.2;
1008
+ case 'scout': return this.distanceTraveled * 0.1;
1009
+ default: return 0;
1010
+ }
1011
+ }
1012
+
1013
+ getEfficiencyBonus() {
1014
+ // Reward efficient decision making
1015
+ return this.decisionQuality * 0.1 + this.predictiveAccuracy * 50;
1016
+ }
1017
+
1018
+ trackExploration() {
1019
+ const area = `${Math.floor(this.mesh.position.x / 25)},${Math.floor(this.mesh.position.z / 25)}`;
1020
+ if (!this.visitedAreas.has(area)) {
1021
+ this.visitedAreas.add(area);
1022
+ this.explorationBonus += 10;
1023
+ }
1024
+ }
1025
+
1026
+ updateVisuals() {
1027
+ // Update car color based on role and performance
1028
+ this.updateCarColor();
1029
+ this.updateFlockVisualization();
1030
+
1031
+ // Brain indicator pulsing based on activity
1032
+ const brainActivity = this.brain.memory.reduce((sum, val) => sum + Math.abs(val), 0);
1033
+ this.brainIndicator.material.opacity = 0.5 + (brainActivity * 0.1);
1034
+ }
1035
+
1036
+ updateCarColor() {
1037
+ const hue = this.speciesId * 0.2;
1038
+ let saturation = 0.8;
1039
+ let lightness = 0.6;
1040
+
1041
+ // Role-based color modifications
1042
+ switch (this.role) {
1043
+ case 'leader':
1044
+ saturation = 1.0;
1045
+ lightness = 0.7;
1046
+ break;
1047
+ case 'explorer':
1048
+ saturation = 0.9;
1049
+ lightness = 0.8;
1050
+ break;
1051
+ case 'follower':
1052
+ saturation = 0.7;
1053
+ lightness = 0.5;
1054
+ break;
1055
+ }
1056
+
1057
+ // Performance-based brightness
1058
+ const performanceBonus = Math.min(this.rawFitness / 1000, 0.3);
1059
+ lightness += performanceBonus;
1060
+
1061
+ this.bodyMaterial.color.setHSL(hue, saturation, lightness);
1062
+ }
1063
+
1064
+ updateFlockVisualization() {
1065
+ if (!showFlockLines) return;
1066
+
1067
+ const nearestNeighbors = this.neighbors
1068
+ .sort((a, b) => {
1069
+ const distA = this.mesh.position.distanceTo(a.mesh.position);
1070
+ const distB = this.mesh.position.distanceTo(b.mesh.position);
1071
+ return distA - distB;
1072
+ })
1073
+ .slice(0, 8);
1074
+
1075
+ for (let i = 0; i < this.flockLines.length; i++) {
1076
+ if (i < nearestNeighbors.length) {
1077
+ const start = this.mesh.position.clone();
1078
+ start.y = 2;
1079
+ const end = nearestNeighbors[i].mesh.position.clone();
1080
+ end.y = 2;
1081
+
1082
+ this.flockLines[i].geometry.setFromPoints([start, end]);
1083
+ this.flockLines[i].visible = true;
1084
+
1085
+ // Color based on relationship
1086
+ if (nearestNeighbors[i].role === 'leader') {
1087
+ this.flockLines[i].material.color.setHex(0xff00ff);
1088
+ } else {
1089
+ this.flockLines[i].material.color.setHex(0x00ff00);
1090
+ }
1091
+ } else {
1092
+ this.flockLines[i].visible = false;
1093
+ }
1094
+ }
1095
+ }
1096
+
1097
+ getObstacles() {
1098
+ let obstacles = [];
1099
+ population.forEach(car => {
1100
+ if (car !== this && !car.crashed) {
1101
+ obstacles.push(car.mesh);
1102
+ }
1103
+ });
1104
+
1105
+ world.buildings.forEach(building => {
1106
+ obstacles.push(building.mesh);
1107
+ });
1108
+
1109
+ world.dynamicObstacles.forEach(obstacle => {
1110
+ obstacles.push(obstacle.mesh);
1111
+ });
1112
+
1113
+ return obstacles;
1114
+ }
1115
+
1116
+ checkCollisions() {
1117
+ const carBox = new THREE.Box3().setFromObject(this.mesh);
1118
+
1119
+ // Enhanced collision detection
1120
+ population.forEach(otherCar => {
1121
+ if (otherCar !== this && !otherCar.crashed) {
1122
+ const otherBox = new THREE.Box3().setFromObject(otherCar.mesh);
1123
+ if (carBox.intersectsBox(otherBox)) {
1124
+ // Soft collision - reduce speed instead of crash
1125
+ const collisionForce = new THREE.Vector3()
1126
+ .subVectors(this.mesh.position, otherCar.mesh.position)
1127
+ .normalize()
1128
+ .multiplyScalar(5);
1129
+
1130
+ this.velocity.add(collisionForce);
1131
+ otherCar.velocity.sub(collisionForce);
1132
+
1133
+ // Small fitness penalty
1134
+ this.rawFitness -= 10;
1135
+ otherCar.rawFitness -= 10;
1136
+ }
1137
+ }
1138
+ });
1139
+
1140
+ // Building collisions
1141
+ world.buildings.forEach(building => {
1142
+ const buildingBox = new THREE.Box3().setFromObject(building.mesh);
1143
+ if (carBox.intersectsBox(buildingBox)) {
1144
+ this.crashed = true;
1145
+ crashCount++;
1146
+ }
1147
+ });
1148
+ }
1149
+
1150
+ keepInBounds() {
1151
+ const bounds = 400;
1152
+ if (Math.abs(this.mesh.position.x) > bounds ||
1153
+ Math.abs(this.mesh.position.z) > bounds) {
1154
+ if (Math.abs(this.mesh.position.x) > bounds) {
1155
+ this.mesh.position.x = Math.sign(this.mesh.position.x) * bounds;
1156
+ this.velocity.x *= -0.7;
1157
+ }
1158
+ if (Math.abs(this.mesh.position.z) > bounds) {
1159
+ this.mesh.position.z = Math.sign(this.mesh.position.z) * bounds;
1160
+ this.velocity.z *= -0.7;
1161
+ }
1162
+ this.rawFitness -= 5; // Boundary penalty
1163
+ }
1164
+ }
1165
+
1166
+ destroy() {
1167
+ this.flockLines.forEach(line => {
1168
+ if (line.parent) scene.remove(line);
1169
+ });
1170
+ if (this.mesh.parent) {
1171
+ scene.remove(this.mesh);
1172
+ }
1173
+ }
1174
+ }
1175
+
1176
+ // Enhanced speciation system
1177
+ function calculateCompatibility(brain1, brain2) {
1178
+ let weightDiff = 0;
1179
+ let totalWeights = 0;
1180
+
1181
+ // Compare all weight matrices
1182
+ for (let layer = 0; layer < brain1.weights.length; layer++) {
1183
+ for (let i = 0; i < brain1.weights[layer].length; i++) {
1184
+ for (let j = 0; j < brain1.weights[layer][i].length; j++) {
1185
+ weightDiff += Math.abs(brain1.weights[layer][i][j] - brain2.weights[layer][i][j]);
1186
+ totalWeights++;
1187
+ }
1188
+ }
1189
+ }
1190
+
1191
+ // Compare personality traits
1192
+ let traitDiff = 0;
1193
+ Object.keys(brain1.personalityTraits).forEach(trait => {
1194
+ traitDiff += Math.abs(brain1.personalityTraits[trait] - brain2.personalityTraits[trait]);
1195
+ });
1196
+
1197
+ return (weightDiff / totalWeights) + (traitDiff / 5);
1198
+ }
1199
+
1200
+ function speciate() {
1201
+ species = [];
1202
+
1203
+ population.forEach(individual => {
1204
+ let foundSpecies = false;
1205
+
1206
+ for (let s of species) {
1207
+ if (s.members.length > 0) {
1208
+ const representative = s.members[0];
1209
+ const compatibility = calculateCompatibility(individual.brain, representative.brain);
1210
+
1211
+ if (compatibility < SPECIES_THRESHOLD) {
1212
+ s.members.push(individual);
1213
+ individual.speciesId = s.id;
1214
+ foundSpecies = true;
1215
+ break;
1216
+ }
1217
+ }
1218
+ }
1219
+
1220
+ if (!foundSpecies) {
1221
+ const newSpecies = {
1222
+ id: species.length,
1223
+ members: [individual],
1224
+ avgFitness: 0,
1225
+ staleness: 0,
1226
+ bestFitness: 0
1227
+ };
1228
+ species.push(newSpecies);
1229
+ individual.speciesId = newSpecies.id;
1230
+ }
1231
+ });
1232
+
1233
+ // Calculate species fitness
1234
+ species.forEach(s => {
1235
+ if (s.members.length > 0) {
1236
+ s.avgFitness = s.members.reduce((sum, ind) => sum + ind.rawFitness, 0) / s.members.length;
1237
+ s.bestFitness = Math.max(...s.members.map(ind => ind.rawFitness));
1238
+
1239
+ // Adjust individual fitness by species size (fitness sharing)
1240
+ s.members.forEach(ind => {
1241
+ ind.adjustedFitness = ind.rawFitness / s.members.length;
1242
+ });
1243
+ }
1244
+ });
1245
+
1246
+ // Remove empty species
1247
+ species = species.filter(s => s.members.length > 0);
1248
+ }
1249
+
1250
+ function init() {
1251
+ // Enhanced scene setup
1252
+ scene = new THREE.Scene();
1253
+ scene.background = new THREE.Color(0x87CEEB);
1254
+ scene.fog = new THREE.Fog(0x87CEEB, 400, 1200);
1255
+
1256
+ camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 2000);
1257
+ camera.position.set(0, 120, 120);
1258
+ camera.lookAt(0, 0, 0);
1259
+
1260
+ renderer = new THREE.WebGLRenderer({ antialias: true });
1261
+ renderer.setSize(window.innerWidth, window.innerHeight);
1262
+ renderer.shadowMap.enabled = true;
1263
+ renderer.shadowMap.type = THREE.PCFSoftShadowMap;
1264
+ renderer.setClearColor(0x001122);
1265
+ document.body.appendChild(renderer.domElement);
1266
+
1267
+ // Enhanced lighting
1268
+ const ambientLight = new THREE.AmbientLight(0x404040, 0.6);
1269
+ scene.add(ambientLight);
1270
+
1271
+ const directionalLight = new THREE.DirectionalLight(0xffffff, 0.8);
1272
+ directionalLight.position.set(100, 100, 50);
1273
+ directionalLight.castShadow = true;
1274
+ directionalLight.shadow.mapSize.width = 2048;
1275
+ directionalLight.shadow.mapSize.height = 2048;
1276
+ scene.add(directionalLight);
1277
+
1278
+ // Create enhanced world
1279
+ createEnhancedWorld();
1280
+ createInitialPopulation();
1281
+
1282
+ clock = new THREE.Clock();
1283
+
1284
+ // Event listeners
1285
+ window.addEventListener('resize', onWindowResize);
1286
+ setupEventListeners();
1287
+
1288
+ animate();
1289
+ }
1290
+
1291
+ function createEnhancedWorld() {
1292
+ // Enhanced ground with texture variation
1293
+ const groundGeometry = new THREE.PlaneGeometry(1000, 1000);
1294
+ const groundMaterial = new THREE.MeshLambertMaterial({
1295
+ color: 0x228B22,
1296
+ transparent: true,
1297
+ opacity: 0.9
1298
+ });
1299
+ const ground = new THREE.Mesh(groundGeometry, groundMaterial);
1300
+ ground.rotation.x = -Math.PI / 2;
1301
+ ground.receiveShadow = true;
1302
+ scene.add(ground);
1303
+
1304
+ createRoadNetwork();
1305
+ createObstacles();
1306
+ createDynamicEnvironment();
1307
+ }
1308
+
1309
+ function createRoadNetwork() {
1310
+ const roadMaterial = new THREE.MeshLambertMaterial({ color: 0x444444 });
1311
+
1312
+ for (let i = -300; i <= 300; i += 150) {
1313
+ // Horizontal roads
1314
+ const hRoadGeometry = new THREE.PlaneGeometry(600, 12);
1315
+ const hRoad = new THREE.Mesh(hRoadGeometry, roadMaterial);
1316
+ hRoad.rotation.x = -Math.PI / 2;
1317
+ hRoad.position.set(0, 0.1, i);
1318
+ scene.add(hRoad);
1319
+
1320
+ // Vertical roads
1321
+ const vRoadGeometry = new THREE.PlaneGeometry(12, 600);
1322
+ const vRoad = new THREE.Mesh(vRoadGeometry, roadMaterial);
1323
+ vRoad.rotation.x = -Math.PI / 2;
1324
+ vRoad.position.set(i, 0.1, 0);
1325
+ scene.add(vRoad);
1326
+ }
1327
+ }
1328
+
1329
+ function createObstacles() {
1330
+ world.buildings = [];
1331
+ const buildingMaterial = new THREE.MeshLambertMaterial({ color: 0x666666 });
1332
+
1333
+ for (let i = 0; i < 20; i++) {
1334
+ const x = (Math.random() - 0.5) * 700;
1335
+ const z = (Math.random() - 0.5) * 700;
1336
+ const width = 12 + Math.random() * 25;
1337
+ const height = 8 + Math.random() * 35;
1338
+ const depth = 12 + Math.random() * 25;
1339
+
1340
+ const buildingGeometry = new THREE.BoxGeometry(width, height, depth);
1341
+ const building = new THREE.Mesh(buildingGeometry, buildingMaterial);
1342
+ building.position.set(x, height / 2, z);
1343
+ building.castShadow = true;
1344
+ scene.add(building);
1345
+
1346
+ world.buildings.push({ mesh: building });
1347
+ }
1348
+ }
1349
+
1350
+ function createDynamicEnvironment() {
1351
+ // Create exploration targets
1352
+ world.targets = [];
1353
+ for (let i = 0; i < 8; i++) {
1354
+ const target = {
1355
+ position: new THREE.Vector3(
1356
+ (Math.random() - 0.5) * 600,
1357
+ 5,
1358
+ (Math.random() - 0.5) * 600
1359
+ ),
1360
+ discovered: false
1361
+ };
1362
+
1363
+ // Visual target
1364
+ const targetGeometry = new THREE.SphereGeometry(3, 8, 6);
1365
+ const targetMaterial = new THREE.MeshLambertMaterial({
1366
+ color: 0x00ff00,
1367
+ transparent: true,
1368
+ opacity: 0.7
1369
+ });
1370
+ target.mesh = new THREE.Mesh(targetGeometry, targetMaterial);
1371
+ target.mesh.position.copy(target.position);
1372
+ scene.add(target.mesh);
1373
+
1374
+ world.targets.push(target);
1375
+ }
1376
+ }
1377
+
1378
+ function createInitialPopulation() {
1379
+ population = [];
1380
+
1381
+ for (let i = 0; i < populationSize; i++) {
1382
+ const angle = (i / populationSize) * Math.PI * 2;
1383
+ const radius = 40 + Math.random() * 60;
1384
+ const x = Math.cos(angle) * radius;
1385
+ const z = Math.sin(angle) * radius;
1386
+
1387
+ const car = new EnhancedAICar(x, z);
1388
+ population.push(car);
1389
+ scene.add(car.mesh);
1390
+ }
1391
+
1392
+ speciate();
1393
+ }
1394
+
1395
+ function evolvePopulation() {
1396
+ speciate();
1397
+
1398
+ // Advanced evolution with speciation
1399
+ const totalAdjustedFitness = population.reduce((sum, ind) => sum + ind.adjustedFitness, 0);
1400
+ const newPopulation = [];
1401
+
1402
+ // Determine offspring allocation per species
1403
+ species.forEach(s => {
1404
+ if (s.members.length === 0) return;
1405
+
1406
+ const speciesFitness = s.members.reduce((sum, ind) => sum + ind.adjustedFitness, 0);
1407
+ const offspringCount = Math.floor((speciesFitness / totalAdjustedFitness) * populationSize);
1408
+
1409
+ // Sort species members by fitness
1410
+ s.members.sort((a, b) => b.adjustedFitness - a.adjustedFitness);
1411
+
1412
+ // Elite selection
1413
+ const eliteCount = Math.max(1, Math.floor(offspringCount * 0.2));
1414
+ for (let i = 0; i < eliteCount && i < s.members.length; i++) {
1415
+ const elite = s.members[i];
1416
+ const angle = Math.random() * Math.PI * 2;
1417
+ const radius = 40 + Math.random() * 60;
1418
+ const newCar = new EnhancedAICar(
1419
+ Math.cos(angle) * radius,
1420
+ Math.sin(angle) * radius
1421
+ );
1422
+ newCar.brain = elite.brain.copy();
1423
+ newCar.speciesId = s.id;
1424
+ newPopulation.push(newCar);
1425
+ }
1426
+
1427
+ // Crossover and mutation
1428
+ while (newPopulation.filter(car => car.speciesId === s.id).length < offspringCount) {
1429
+ const parent1 = tournamentSelection(s.members);
1430
+ const parent2 = tournamentSelection(s.members);
1431
+
1432
+ const angle = Math.random() * Math.PI * 2;
1433
+ const radius = 40 + Math.random() * 60;
1434
+ const child = new EnhancedAICar(
1435
+ Math.cos(angle) * radius,
1436
+ Math.sin(angle) * radius
1437
+ );
1438
+
1439
+ if (Math.random() < 0.7) {
1440
+ child.brain = parent1.brain.crossover(parent2.brain);
1441
+ } else {
1442
+ child.brain = parent1.brain.copy();
1443
+ }
1444
+
1445
+ // Adaptive mutation
1446
+ const mutationRate = 0.05 + (s.staleness * 0.01);
1447
+ child.brain.mutate(mutationRate, Math.random() < 0.1);
1448
+
1449
+ child.speciesId = s.id;
1450
+ newPopulation.push(child);
1451
+ }
1452
+ });
1453
+
1454
+ // Fill any remaining slots
1455
+ while (newPopulation.length < populationSize) {
1456
+ const randomSpecies = species[Math.floor(Math.random() * species.length)];
1457
+ if (randomSpecies.members.length > 0) {
1458
+ const parent = randomSpecies.members[0];
1459
+ const angle = Math.random() * Math.PI * 2;
1460
+ const radius = 40 + Math.random() * 60;
1461
+ const child = new EnhancedAICar(
1462
+ Math.cos(angle) * radius,
1463
+ Math.sin(angle) * radius
1464
+ );
1465
+ child.brain = parent.brain.copy();
1466
+ child.brain.mutate(0.3, true); // High mutation for diversity
1467
+ child.speciesId = parent.speciesId;
1468
+ newPopulation.push(child);
1469
+ }
1470
+ }
1471
+
1472
+ // Clean up old population
1473
+ population.forEach(car => car.destroy());
1474
+
1475
+ // Replace population
1476
+ population = newPopulation;
1477
+ population.forEach(car => scene.add(car.mesh));
1478
+
1479
+ // Update epoch
1480
+ epoch++;
1481
+ timeLeft = epochTime;
1482
+ bestFitness = Math.max(bestFitness, ...population.map(car => car.rawFitness));
1483
+ crashCount = 0;
1484
+
1485
+ console.log(`Epoch ${epoch}: ${species.length} species, best fitness: ${bestFitness.toFixed(1)}`);
1486
+ }
1487
+
1488
+ function tournamentSelection(individuals, tournamentSize = 3) {
1489
+ let best = null;
1490
+ let bestFitness = -1;
1491
+
1492
+ for (let i = 0; i < tournamentSize; i++) {
1493
+ const candidate = individuals[Math.floor(Math.random() * individuals.length)];
1494
+ if (candidate.adjustedFitness > bestFitness) {
1495
+ best = candidate;
1496
+ bestFitness = candidate.adjustedFitness;
1497
+ }
1498
+ }
1499
+
1500
+ return best;
1501
+ }
1502
+
1503
+ function animate() {
1504
+ requestAnimationFrame(animate);
1505
+
1506
+ if (!paused) {
1507
+ const deltaTime = Math.min(clock.getDelta() * speedMultiplier, 0.1);
1508
+
1509
+ // Update timer
1510
+ timeLeft -= deltaTime;
1511
+ if (timeLeft <= 0) {
1512
+ evolvePopulation();
1513
+ }
1514
+
1515
+ // Update population
1516
+ updatePopulation(deltaTime);
1517
+ updateCamera();
1518
+ updateUI();
1519
+ updateDynamicEnvironment(deltaTime);
1520
+ }
1521
+
1522
+ renderer.render(scene, camera);
1523
+ }
1524
+
1525
+ function updatePopulation(deltaTime) {
1526
+ let stats = {
1527
+ alive: 0,
1528
+ leaders: 0,
1529
+ followers: 0,
1530
+ explorers: 0,
1531
+ scouts: 0,
1532
+ totalVelocity: 0,
1533
+ totalCooperation: 0,
1534
+ totalExploration: 0,
1535
+ totalDecisionQuality: 0,
1536
+ totalNeuralComplexity: 0,
1537
+ maxGroupSize: 0
1538
+ };
1539
+
1540
+ population.forEach(car => {
1541
+ car.update(deltaTime);
1542
+
1543
+ if (!car.crashed) {
1544
+ stats.alive++;
1545
+ stats.totalVelocity += car.velocity.length();
1546
+ stats.totalDecisionQuality += car.decisionQuality;
1547
+ stats.totalNeuralComplexity += car.brain.getComplexity();
1548
+ stats.maxGroupSize = Math.max(stats.maxGroupSize, car.neighbors.length + 1);
1549
+
1550
+ switch (car.role) {
1551
+ case 'leader': stats.leaders++; break;
1552
+ case 'follower': stats.followers++; break;
1553
+ case 'explorer': stats.explorers++; break;
1554
+ case 'scout': stats.scouts++; break;
1555
+ }
1556
+
1557
+ stats.totalCooperation += car.cooperationScore;
1558
+ stats.totalExploration += car.explorationBonus;
1559
+ }
1560
+ });
1561
+
1562
+ // Store stats for UI
1563
+ window.populationStats = stats;
1564
+ }
1565
+
1566
+ function updateCamera() {
1567
+ if (cameraMode === 'follow') {
1568
+ // Follow the best performing car or largest flock
1569
+ let target = population.reduce((best, car) => {
1570
+ if (car.crashed) return best;
1571
+ return !best || car.rawFitness > best.rawFitness ? car : best;
1572
+ }, null);
1573
+
1574
+ if (target) {
1575
+ const targetPos = target.mesh.position.clone();
1576
+ targetPos.y += 50;
1577
+ targetPos.add(target.velocity.clone().normalize().multiplyScalar(30));
1578
+
1579
+ camera.position.lerp(targetPos, 0.02);
1580
+ camera.lookAt(target.mesh.position);
1581
+ }
1582
+ } else {
1583
+ camera.position.lerp(new THREE.Vector3(0, 200, 200), 0.02);
1584
+ camera.lookAt(0, 0, 0);
1585
+ }
1586
+ }
1587
+
1588
+ function updateUI() {
1589
+ const stats = window.populationStats || {};
1590
+
1591
+ // Main UI
1592
+ document.getElementById('epoch').textContent = epoch;
1593
+ document.getElementById('epochTime').textContent = Math.ceil(timeLeft);
1594
+ document.getElementById('population').textContent = stats.alive || 0;
1595
+ document.getElementById('speciesCount').textContent = species.length;
1596
+ document.getElementById('bestFitness').textContent = Math.round(bestFitness);
1597
+ document.getElementById('innovationCount').textContent = innovationCounter;
1598
+
1599
+ // Progress bar
1600
+ const progress = ((epochTime - timeLeft) / epochTime) * 100;
1601
+ document.getElementById('timeProgress').style.width = `${progress}%`;
1602
+
1603
+ // AI Stats
1604
+ if (stats.alive > 0) {
1605
+ document.getElementById('avgIQ').textContent = Math.round(stats.totalDecisionQuality / stats.alive);
1606
+ document.getElementById('neuralComplexity').textContent = Math.round(stats.totalNeuralComplexity / stats.alive);
1607
+ document.getElementById('decisionQuality').textContent = Math.round(stats.totalDecisionQuality / stats.alive);
1608
+ document.getElementById('avgCoordination').textContent = Math.round((stats.totalCooperation / stats.alive) * 10);
1609
+ }
1610
+
1611
+ // Flocking stats
1612
+ document.getElementById('leaderCount').textContent = stats.leaders || 0;
1613
+ document.getElementById('followerCount').textContent = stats.followers || 0;
1614
+ document.getElementById('explorerCount').textContent = stats.explorers || 0;
1615
+ document.getElementById('soloCount').textContent = stats.scouts || 0;
1616
+ document.getElementById('largestFlock').textContent = stats.maxGroupSize || 0;
1617
+
1618
+ // Generation stats
1619
+ const totalDistance = population.reduce((sum, car) => sum + car.distanceTraveled, 0);
1620
+ const totalExploration = population.reduce((sum, car) => sum + car.explorationBonus, 0);
1621
+ const totalCooperation = population.reduce((sum, car) => sum + car.cooperationScore, 0);
1622
+
1623
+ document.getElementById('totalDistance').textContent = Math.round(totalDistance);
1624
+ document.getElementById('explorationBonus').textContent = Math.round(totalExploration);
1625
+ document.getElementById('cooperationScore').textContent = Math.round(totalCooperation);
1626
+ document.getElementById('crashCount').textContent = crashCount;
1627
+
1628
+ // Top performers
1629
+ updateTopPerformers();
1630
+ }
1631
+
1632
+ function updateTopPerformers() {
1633
+ const sorted = [...population]
1634
+ .filter(car => !car.crashed)
1635
+ .sort((a, b) => b.rawFitness - a.rawFitness)
1636
+ .slice(0, 5);
1637
+
1638
+ const topPerformersDiv = document.getElementById('topPerformers');
1639
+ topPerformersDiv.innerHTML = '';
1640
+
1641
+ sorted.forEach((car, i) => {
1642
+ const div = document.createElement('div');
1643
+ const roleIcon = {
1644
+ leader: 'πŸ‘‘',
1645
+ explorer: 'πŸ”',
1646
+ follower: '🀝',
1647
+ scout: 'πŸ‘οΈ'
1648
+ }[car.role] || 'πŸš—';
1649
+
1650
+ div.innerHTML = `${i + 1}. ${roleIcon} S${car.speciesId} | IQ:${Math.round(car.decisionQuality)} | F:${Math.round(car.rawFitness)}`;
1651
+ div.className = `species-${car.speciesId % 5}`;
1652
+ topPerformersDiv.appendChild(div);
1653
+ });
1654
+ }
1655
+
1656
+ function updateDynamicEnvironment(deltaTime) {
1657
+ // Update targets
1658
+ world.targets.forEach(target => {
1659
+ // Pulsing animation
1660
+ target.mesh.scale.setScalar(1 + Math.sin(Date.now() * 0.005) * 0.1);
1661
+
1662
+ // Check if discovered
1663
+ population.forEach(car => {
1664
+ if (!car.crashed && target.mesh.position.distanceTo(car.mesh.position) < 10) {
1665
+ if (!target.discovered) {
1666
+ target.discovered = true;
1667
+ car.explorationBonus += 50;
1668
+ target.mesh.material.color.setHex(0xffff00);
1669
+ }
1670
+ }
1671
+ });
1672
+ });
1673
+ }
1674
+
1675
+ function setupEventListeners() {
1676
+ document.getElementById('pauseBtn').addEventListener('click', togglePause);
1677
+ document.getElementById('resetBtn').addEventListener('click', resetSimulation);
1678
+ document.getElementById('speedBtn').addEventListener('click', toggleSpeed);
1679
+ document.getElementById('viewBtn').addEventListener('click', toggleView);
1680
+ document.getElementById('flockBtn').addEventListener('click', toggleFlockLines);
1681
+ document.getElementById('adaptiveBtn').addEventListener('click', toggleAdaptive);
1682
+ document.getElementById('challengeBtn').addEventListener('click', toggleChallenge);
1683
+ }
1684
+
1685
+ function togglePause() {
1686
+ paused = !paused;
1687
+ document.getElementById('pauseBtn').textContent = paused ? 'Resume' : 'Pause';
1688
+ if (!paused) clock.start();
1689
+ }
1690
+
1691
+ function resetSimulation() {
1692
+ epoch = 1;
1693
+ timeLeft = epochTime;
1694
+ bestFitness = 0;
1695
+ crashCount = 0;
1696
+ innovationCounter = 0;
1697
+
1698
+ population.forEach(car => car.destroy());
1699
+ createInitialPopulation();
1700
+ }
1701
+
1702
+ function toggleSpeed() {
1703
+ speedMultiplier = speedMultiplier === 1 ? 2 : speedMultiplier === 2 ? 5 : 1;
1704
+ document.getElementById('speedBtn').textContent = `Speed: ${speedMultiplier}x`;
1705
+ }
1706
+
1707
+ function toggleView() {
1708
+ cameraMode = cameraMode === 'follow' ? 'overview' : 'follow';
1709
+ document.getElementById('viewBtn').textContent = `View: ${cameraMode === 'follow' ? 'Follow' : 'Overview'}`;
1710
+ }
1711
+
1712
+ function toggleFlockLines() {
1713
+ showFlockLines = !showFlockLines;
1714
+ document.getElementById('flockBtn').textContent = `Flocks: ${showFlockLines ? 'ON' : 'OFF'}`;
1715
+ }
1716
+
1717
+ function toggleAdaptive() {
1718
+ adaptiveEnvironment = !adaptiveEnvironment;
1719
+ document.getElementById('adaptiveBtn').textContent = `Adaptive: ${adaptiveEnvironment ? 'ON' : 'OFF'}`;
1720
+ }
1721
+
1722
+ function toggleChallenge() {
1723
+ const levels = ['normal', 'hard', 'extreme'];
1724
+ const currentIndex = levels.indexOf(challengeLevel);
1725
+ challengeLevel = levels[(currentIndex + 1) % levels.length];
1726
+ document.getElementById('challengeBtn').textContent = `Challenge: ${challengeLevel}`;
1727
+ }
1728
+
1729
+ function onWindowResize() {
1730
+ camera.aspect = window.innerWidth / window.innerHeight;
1731
+ camera.updateProjectionMatrix();
1732
+ renderer.setSize(window.innerWidth, window.innerHeight);
1733
+ }
1734
+
1735
+ init();
1736
+ </script>
1737
+ </body>
1738
+ </html>