Die Welt
Stufe 0 - der gehirn-agnostische Kern: Zustand, Wahrnehmung als Bit-Packing, Reflexe, die Schleife und der erste Aha-Moment - Stigmergie.
Bevor ein Gehirn entsteht, bauen wir die Welt. Sie ist gehirn-agnostisch: Sie weiß nie, wer entscheidet.
Zustand
Eine Ameise ist nur Position, Blickrichtung und Last. Plus etwas Buchhaltung, die erst spätere Gehirne brauchen (Q-Learning-Verlauf, LLM-Gedanke):
{ id, x, y, heading, load, // Kern
prevS, prevA, prevMarkA, rAccum, // für Q-Learning
llmAction, llmMark, llmThought, thinking } // für das LLM-Gehirn
Die Welt selbst: ein Bau (Nest) in der Mitte, ein paar Zuckerhaufen, und eine Liste
von Marken (markers) - Duftspuren, die eine Ameise hinterlässt und die andere
riechen können. Eine Marke hat einen Ort und eine Stärke, die mit der Zeit verfällt.
Was sonst noch in einer Marke steckt - Reichweite und eine kleine Nachricht - bauen
wir im nächsten Kapitel aus.
Wahrnehmung: 4 Booleans → 16 Zustände
Das ist der schlauste Teil. Die Wahrnehmung wird gebucketet, damit sie gleichzeitig (a) als endlicher Zustand für Q-Learning taugt und (b) als kurzer Text für ein LLM:
function perceive(a, world, cfg) {
const traegt = a.load > 0;
const sichtZucker = naechsterZuckerInSicht(a, world, cfg.vision);
const spur = naechsteMarkeInReichweite(a, world) !== null;
const amBau = dist(a, world.nest) < NEST_R + 18;
// Bit-Packing: 4 Booleans → eine Zahl 0..15
const s = (traegt?8:0) + (sichtZucker?4:0) + (spur?2:0) + (amBau?1:0);
return { traegt, sichtZucker, spur, amBau, s };
}
Agenten-Lektion: Wahrnehmung ist immer eine Reduktion der Welt. Die Ameise sieht nicht „alles", sondern vier Bits. Jeder Agent - auch ein LLM mit Tool-Outputs - arbeitet mit so einer reduzierten, partiellen Sicht. Wie du diese Reduktion entwirfst, entscheidet, was der Agent überhaupt lernen kann.
Aktion ausführen: Entscheidung + Reflexe
Die Welt führt aus, was das Gehirn entscheidet. Die Entscheidung hat zwei Teile: die Navigation und - optional - eine Marke, die gelegt wird. Aufnehmen und Abladen dagegen sind Reflexe: sie passieren automatisch bei Kontakt, niemand entscheidet sie.
function applyAction(a, entscheidung, world, p) {
steuere(a, entscheidung.nav, world, p); // Blickrichtung setzen
moveAnt(a, world); // einen Schritt gehen
if (entscheidung.mark) legeMarke(a, world, entscheidung.mark); // entschieden, kein Reflex
const picked = reflexAufnehmen(a, world); // Reflex bei Kontakt
const delivered = reflexAbladen(a, world); // Reflex am Bau
return { picked, delivered };
}
Agenten-Lektion: Die Trennung Entscheidung vs. Reflex ist die wichtigste Designwahl der ganzen Welt. Je kleiner der entschiedene Teil, desto leichter meistert ihn ein Gehirn - ob feste Regel, lernendes Netz oder LLM. Dass die Marke entschieden wird und nicht automatisch fällt, ist genau das, was sie im nächsten Kapitel so interessant macht.
So sieht es echt aus (TypeScript)
Die Skizzen oben zeigen die Idee. So steht der Code wirklich im Lab - in TypeScript, genau so, wie er dort läuft. Die Wahrnehmung trägt neben den vier Bits noch ein paar Felder über die gerochene Marke; was die bedeuten, ist Thema des nächsten Kapitels.
// engine/world.ts (gekürzt)
export const ACTIONS = ["ERKUNDE", "ZUM_ZUCKER", "FOLGE_SPUR", "ZUM_BAU"] as const;
export type ActionIndex = 0 | 1 | 2 | 3;
// Eine Entscheidung ist Navigation + optional eine Marke (Details: nächstes Kapitel).
export type BrainDecision = { nav: ActionIndex; mark: MarkChoice | null };
export type Percept = {
traegt: boolean; sichtZucker: boolean; spur: boolean; amBau: boolean;
s: number; // 0..15 - Bit-Packing für Q-Learning
markType: 0 | 1 | 2 | 3; markPayload: number; markDir: number; // → Kapitel 3
};
export const NEST_R = 22;
const VISION = 60;
// Wahrnehmung ist immer eine REDUKTION der Welt: vier Bits, gepackt in 0..15.
export function perceive(a: Ant, world: World): Percept {
const traegt = a.load > 0;
const sichtZucker = nearestSugarInSight(a, world) !== null;
const mark = nearestRelevantMarker(a, world);
const spur = mark !== null;
const amBau = dist(a, world.nest) < NEST_R + 18;
const s = (traegt ? 8 : 0) + (sichtZucker ? 4 : 0) + (spur ? 2 : 0) + (amBau ? 1 : 0);
return { traegt, sichtZucker, spur, amBau, s, /* mark-Felder … */ } as Percept;
}
// Aufnehmen und Abladen sind REFLEXE (passieren bei Kontakt). Die Marke dagegen
// wird ENTSCHIEDEN - die Welt legt sie nur, wenn die Entscheidung eine trägt.
export function applyAction(a: Ant, d: BrainDecision, world: World, p: Percept): StepEvent {
steer(a, d.nav, world, p);
moveAnt(a, world);
if (d.mark) addMarker(a, world, d.mark);
const picked = reflexPickup(a, world);
const delivered = reflexDrop(a, world);
return { picked, delivered };
}
Die Schleife
Ein requestAnimationFrame-Loop. Pro Frame mehrere Simulationsschritte (Tempo),
danach verfallen die Marken (Verdunstung) und es wird gerendert:
for (let step = 0; step < tempo; step++) {
for (const a of world.ants) {
const p = perceive(a, world);
const entscheidung = brain.decide(p); // ← die austauschbare Box
applyAction(a, entscheidung, world, p);
}
evaporateMarkers(world); // Marken werden schwächer und verschwinden - Vergessen
}
Lass das laufen und du siehst aus zufälligem Gewusel Ameisenstraßen entstehen - allein durch Marken, ohne zentrale Steuerung. Das ist Stigmergie, und es ist der erste „Aha"-Moment: Koordination braucht keine Allwissenheit, nur lokale Kommunikation.