TeacherPuffy commited on
Commit
a498893
·
verified ·
1 Parent(s): 2719f89

Update index.html

Browse files
Files changed (1) hide show
  1. index.html +61 -31
index.html CHANGED
@@ -107,11 +107,11 @@
107
  <div class="rules">
108
  <h2>Simulation Rules</h2>
109
  <ul>
110
- <li>Cancer cells die when surrounded by 3+ cells within <span id="deathProxDisplay">20</span>px</li>
111
- <li>Healthy cells die when near 2+ cancer cells within 30px</li>
112
- <li>Cancer cells convert isolated healthy cells (no nearby healthy)</li>
113
- <li>Cells reproduce based on type-specific rates</li>
114
- <li>Cancer cells move 50% faster than healthy cells</li>
115
  <li>Neural networks control movement decisions</li>
116
  </ul>
117
  </div>
@@ -119,14 +119,14 @@
119
  <div class="controls">
120
  <h2>Simulation Parameters</h2>
121
  <div class="param-group">
122
- <label>Death Proximity (px): <input type="number" id="deathProximity" value="20" min="1"></label>
123
- <label>Healthy Death Threshold: <input type="number" id="healthyDeathThreshold" value="2" min="1"></label>
124
- <label>Healthy Death Radius: <input type="number" id="healthyDeathRadius" value="30" min="1"></label>
125
  <label>Hidden Dimension: <input type="number" id="hiddenDim" value="6" min="1"></label>
126
- <label>Initial Healthy: <input type="number" id="initialHealthy" value="15" min="1"></label>
127
- <label>Initial Cancer: <input type="number" id="initialCancer" value="8" min="1"></label>
128
- <label>Mutation Rate: <input type="number" id="mutationRate" value="0.1" step="0.01" min="0"></label>
129
- <label>Healthy Repro Rate: <input type="number" id="healthyRepro" value="2" min="0"></label>
130
  <label>Cancer Repro Rate: <input type="number" id="cancerRepro" value="1" min="0"></label>
131
  </div>
132
 
@@ -237,6 +237,7 @@
237
  parent.y + (Math.random() * 40 - 20) :
238
  Math.random() * canvas.height;
239
  this.speed = 0;
 
240
  }
241
 
242
  getNearbyCells() {
@@ -260,14 +261,14 @@
260
 
261
  const [vx, vy] = this.brain.predict(inputs);
262
 
263
- this.x += vx;
264
- this.y += vy;
265
- this.speed = Math.hypot(vx, vy);
266
-
267
- if(this.type === 'cancer') {
268
- this.x += vx * 0.5;
269
- this.y += vy * 0.5;
270
- this.speed *= 1.5;
271
  }
272
 
273
  this.x = (this.x + canvas.width) % canvas.width;
@@ -275,7 +276,11 @@
275
  }
276
 
277
  draw() {
278
- ctx.fillStyle = this.type === 'healthy' ? '#00ff00' : '#ff0000';
 
 
 
 
279
  ctx.beginPath();
280
  ctx.arc(this.x, this.y, cellRadius, 0, Math.PI * 2);
281
  ctx.fill();
@@ -293,21 +298,36 @@
293
 
294
  cellsCopy.forEach((cell) => {
295
  if(cell.type === 'healthy') {
 
 
 
 
 
 
296
  const nearbyCancer = cellsCopy.filter(c =>
297
  c.type === 'cancer' &&
298
  Math.hypot(c.x - cell.x, c.y - cell.y) < healthyDeathRadius
299
  );
300
- if(nearbyCancer.length >= healthyDeathThreshold) {
 
 
301
  cellsToRemove.add(cell);
302
  }
303
  }
304
 
305
  if(cell.type === 'cancer') {
 
 
 
 
 
 
306
  const neighbors = cellsCopy.filter(c =>
307
  c !== cell &&
308
  Math.hypot(c.x - cell.x, c.y - cell.y) < deathProximity
309
  );
310
- if(neighbors.length >= 3) {
 
311
  cellsToRemove.add(cell);
312
  }
313
 
@@ -315,12 +335,8 @@
315
  if(other.type === 'healthy' &&
316
  Math.hypot(cell.x - other.x, cell.y - other.y) < cellRadius * 2 &&
317
  !cellsToConvert.has(other)) {
318
- const healthyNeighbors = cellsCopy.filter(c =>
319
- c !== other &&
320
- c.type === 'healthy' &&
321
- Math.hypot(c.x - other.x, c.y - other.y) < 60
322
- );
323
- if(healthyNeighbors.length === 0) {
324
  cellsToConvert.add(other);
325
  }
326
  }
@@ -335,12 +351,16 @@
335
  function reproduceCells() {
336
  const healthyReproRate = parseInt(document.getElementById('healthyRepro').value);
337
  const healthyCells = cells.filter(c => c.type === 'healthy');
338
- const healthyCandidates = [...healthyCells].sort(() => Math.random() - 0.5).slice(0, healthyReproRate);
 
 
339
  healthyCandidates.forEach(cell => cells.push(new Cell('healthy', cell)));
340
 
341
  const cancerReproRate = parseInt(document.getElementById('cancerRepro').value);
342
  const cancerCells = cells.filter(c => c.type === 'cancer');
343
- const cancerCandidates = [...cancerCells].sort(() => Math.random() - 0.5).slice(0, cancerReproRate);
 
 
344
  cancerCandidates.forEach(cell => cells.push(new Cell('cancer', cell)));
345
  }
346
 
@@ -455,6 +475,16 @@
455
  });
456
 
457
  document.getElementById('reset').addEventListener('click', () => {
 
 
 
 
 
 
 
 
 
 
458
  cancelAnimationFrame(animationId);
459
  animationId = null;
460
  generation = 1;
 
107
  <div class="rules">
108
  <h2>Simulation Rules</h2>
109
  <ul>
110
+ <li>Cancer cells die when surrounded by 3+ cells within <span id="deathProxDisplay">25</span>px</li>
111
+ <li>Healthy cells die when near 3+ cancer cells within 25px</li>
112
+ <li>Healthy cells gain defense from neighbors and move 20% faster</li>
113
+ <li>Cancer cells become vulnerable when isolated</li>
114
+ <li>Cells reproduce with population-based adjustments</li>
115
  <li>Neural networks control movement decisions</li>
116
  </ul>
117
  </div>
 
119
  <div class="controls">
120
  <h2>Simulation Parameters</h2>
121
  <div class="param-group">
122
+ <label>Death Proximity (px): <input type="number" id="deathProximity" value="25" min="1"></label>
123
+ <label>Healthy Death Threshold: <input type="number" id="healthyDeathThreshold" value="3" min="1"></label>
124
+ <label>Healthy Death Radius: <input type="number" id="healthyDeathRadius" value="25" min="1"></label>
125
  <label>Hidden Dimension: <input type="number" id="hiddenDim" value="6" min="1"></label>
126
+ <label>Initial Healthy: <input type="number" id="initialHealthy" value="20" min="1"></label>
127
+ <label>Initial Cancer: <input type="number" id="initialCancer" value="5" min="1"></label>
128
+ <label>Mutation Rate: <input type="number" id="mutationRate" value="0.08" step="0.01" min="0"></label>
129
+ <label>Healthy Repro Rate: <input type="number" id="healthyRepro" value="3" min="0"></label>
130
  <label>Cancer Repro Rate: <input type="number" id="cancerRepro" value="1" min="0"></label>
131
  </div>
132
 
 
237
  parent.y + (Math.random() * 40 - 20) :
238
  Math.random() * canvas.height;
239
  this.speed = 0;
240
+ this.defense = type === 'healthy' ? Math.random() * 0.3 : 0;
241
  }
242
 
243
  getNearbyCells() {
 
261
 
262
  const [vx, vy] = this.brain.predict(inputs);
263
 
264
+ if(this.type === 'healthy') {
265
+ this.x += vx * 1.2;
266
+ this.y += vy * 1.2;
267
+ this.speed = Math.hypot(vx, vy) * 1.2;
268
+ } else {
269
+ this.x += vx;
270
+ this.y += vy;
271
+ this.speed = Math.hypot(vx, vy);
272
  }
273
 
274
  this.x = (this.x + canvas.width) % canvas.width;
 
276
  }
277
 
278
  draw() {
279
+ const baseColor = this.type === 'healthy' ? '#00ff00' : '#ff0000';
280
+ const defenseBoost = Math.min(this.defense * 100, 50);
281
+ ctx.fillStyle = this.type === 'healthy'
282
+ ? `hsl(120, 100%, ${50 + defenseBoost}%)`
283
+ : baseColor;
284
  ctx.beginPath();
285
  ctx.arc(this.x, this.y, cellRadius, 0, Math.PI * 2);
286
  ctx.fill();
 
298
 
299
  cellsCopy.forEach((cell) => {
300
  if(cell.type === 'healthy') {
301
+ const healthyNeighbors = cellsCopy.filter(c =>
302
+ c.type === 'healthy' &&
303
+ Math.hypot(c.x - cell.x, c.y - cell.y) < 50
304
+ );
305
+ const defenseBoost = Math.min(healthyNeighbors.length * 0.1, 0.5);
306
+
307
  const nearbyCancer = cellsCopy.filter(c =>
308
  c.type === 'cancer' &&
309
  Math.hypot(c.x - cell.x, c.y - cell.y) < healthyDeathRadius
310
  );
311
+
312
+ if(nearbyCancer.length >= healthyDeathThreshold &&
313
+ Math.random() > (cell.defense + defenseBoost)) {
314
  cellsToRemove.add(cell);
315
  }
316
  }
317
 
318
  if(cell.type === 'cancer') {
319
+ const cancerNeighbors = cellsCopy.filter(c =>
320
+ c.type === 'cancer' &&
321
+ c !== cell &&
322
+ Math.hypot(c.x - cell.x, c.y - cell.y) < 60
323
+ );
324
+
325
  const neighbors = cellsCopy.filter(c =>
326
  c !== cell &&
327
  Math.hypot(c.x - cell.x, c.y - cell.y) < deathProximity
328
  );
329
+
330
+ if((neighbors.length >= 3) || (cancerNeighbors.length === 0 && Math.random() < 0.1)) {
331
  cellsToRemove.add(cell);
332
  }
333
 
 
335
  if(other.type === 'healthy' &&
336
  Math.hypot(cell.x - other.x, cell.y - other.y) < cellRadius * 2 &&
337
  !cellsToConvert.has(other)) {
338
+ const resistance = other.defense + (Math.random() * 0.2);
339
+ if(resistance < 0.7) {
 
 
 
 
340
  cellsToConvert.add(other);
341
  }
342
  }
 
351
  function reproduceCells() {
352
  const healthyReproRate = parseInt(document.getElementById('healthyRepro').value);
353
  const healthyCells = cells.filter(c => c.type === 'healthy');
354
+ const boost = Math.max(0, 3 - Math.floor(healthyCells.length / 5));
355
+ const healthyCandidates = [...healthyCells].sort(() => Math.random() - 0.5)
356
+ .slice(0, healthyReproRate + boost);
357
  healthyCandidates.forEach(cell => cells.push(new Cell('healthy', cell)));
358
 
359
  const cancerReproRate = parseInt(document.getElementById('cancerRepro').value);
360
  const cancerCells = cells.filter(c => c.type === 'cancer');
361
+ const penalty = Math.floor(cancerCells.length / 10);
362
+ const cancerCandidates = [...cancerCells].sort(() => Math.random() - 0.5)
363
+ .slice(0, Math.max(0, cancerReproRate - penalty));
364
  cancerCandidates.forEach(cell => cells.push(new Cell('cancer', cell)));
365
  }
366
 
 
475
  });
476
 
477
  document.getElementById('reset').addEventListener('click', () => {
478
+ document.getElementById('deathProximity').value = 25;
479
+ document.getElementById('healthyDeathThreshold').value = 3;
480
+ document.getElementById('healthyDeathRadius').value = 25;
481
+ document.getElementById('hiddenDim').value = 6;
482
+ document.getElementById('initialHealthy').value = 20;
483
+ document.getElementById('initialCancer').value = 5;
484
+ document.getElementById('mutationRate').value = 0.08;
485
+ document.getElementById('healthyRepro').value = 3;
486
+ document.getElementById('cancerRepro').value = 1;
487
+
488
  cancelAnimationFrame(animationId);
489
  animationId = null;
490
  generation = 1;