java-topology/tests/workbench/Friend.java
russell@unturf.com 0a580b313d undefect. CWE-407 — 63 sites patched across 27 ecosystems
Authors: russell@unturf.com · brackishbert@gmail.com · foxhop.net · TimeHexOn.com

Patches, unit tests, benchmarks, whitepaper, and outreach briefs.
Public domain — no copyright claimed. Use freely.
2026-03-26 17:11:57 -04:00

95 lines
2.9 KiB
Java

package workbench;
import java.util.List;
import java.util.Random;
/**
* Agent that walks the manifold adjacency graph, injecting heat.
*
* Walk policy: 85% greedy (hottest neighbor), 15% random exploration.
* Injects injectAmt heat at current vertex each step.
* Life decays 0.05/step; respawns at random vertex when life <= 0.
*/
public class Friend {
public static final String[] IDS = {"G","R","C","Y","V"};
public static final int[] COLORS = {0x68ff9a, 0xff3232, 0x00eeff, 0xffd700, 0x9400d3};
public final int idx;
public final String id;
public float life = 1000f;
public float sap = 0f;
public int blooms = 0;
public int vIdx; // current vertex index on manifold
// position in 3D (copied from manifold vertex each step)
public float x, y, z;
private final float injectAmt;
private final float explorePct;
private final Random rng;
private final Manifold manifold;
// callback for PCB log lines (set by Workbench)
public Runnable onRespawn;
public Runnable onBloom;
public Friend(int idx, Manifold manifold) {
this.idx = idx;
this.id = IDS[idx];
this.manifold = manifold;
this.injectAmt = 8.0f;
this.explorePct = 0.15f;
this.rng = new Random();
this.vIdx = rng.nextInt(Math.max(1, manifold.vertexCount));
syncPosition();
}
public void compute() {
List<Integer> neighbors = manifold.adjacency.get(vIdx);
if (!neighbors.isEmpty()) {
int best = neighbors.get(0);
for (int n : neighbors) {
if (manifold.heat[n] > manifold.heat[best]) best = n;
}
vIdx = (rng.nextFloat() < explorePct)
? neighbors.get(rng.nextInt(neighbors.size()))
: best;
}
syncPosition();
life -= 0.05f;
sap += 0.02f;
if (vIdx < manifold.heat.length) manifold.heat[vIdx] += injectAmt;
if (life <= 0) {
vIdx = rng.nextInt(Math.max(1, manifold.vertexCount));
life = 1000f; sap = 0f;
if (onRespawn != null) onRespawn.run();
}
if (sap > 20) {
blooms++; sap = 0f;
if (onBloom != null) onBloom.run();
}
}
private void syncPosition() {
if (manifold.built && vIdx < manifold.vertexCount) {
// x/y from originalPositions — avoids per-frame wobble noise jitter
// z from positions — includes oracle heat displacement
x = manifold.originalPositions[vIdx*3];
y = manifold.originalPositions[vIdx*3+1];
z = manifold.positions[vIdx*3+2];
}
}
/** Relocate to random vertex (call after manifold rebuild). */
public void relocate() {
if (manifold.vertexCount > 0)
vIdx = rng.nextInt(manifold.vertexCount);
life = 1000f; sap = 0f;
syncPosition();
}
}