Syntax10.Scn.Fnt MODULE Swarm; (* MB 25.1.90 *) IMPORT Oberon, Display, Viewers, Input, Texts, Display1; CONST Border = 50; BeeVel = 11; WaspVel = 12; MaxWasps = 10; MaxBees = 500; TYPE Point = RECORD x, y: INTEGER END; Insect = RECORD pos: ARRAY 3 OF Point; vx, vy: INTEGER END; VAR Wasps: ARRAY MaxWasps OF Insect; Bees: ARRAY MaxBees OF Insect; seed: LONGINT; NrWasps, NrBees, Delay, WaspAcc, BeeAcc: INTEGER; firstTime: BOOLEAN; F: Display.Frame; PROCEDURE random(): INTEGER; BEGIN seed := (seed + 773)*13 MOD 99991; RETURN SHORT(seed MOD 32749) END random; PROCEDURE Rand(x: INTEGER): INTEGER; BEGIN RETURN random() MOD x - x DIV 2 END Rand; PROCEDURE Wait(d: LONGINT); VAR t, t1: LONGINT; BEGIN t := Oberon.Time(); REPEAT t1 := Oberon.Time() UNTIL t+d <= t1 END Wait; PROCEDURE InitWasp(VAR Wasp: Insect); BEGIN Wasp.pos[0].x := Border + random() MOD (Display.Width-2*Border); Wasp.pos[0].y := Border + random() MOD (Display.Height-2*Border); Wasp.pos[1] := Wasp.pos[0]; Wasp.vx := 0; Wasp.vy := 0 END InitWasp; PROCEDURE InitBee(VAR Bee: Insect); VAR j: INTEGER; BEGIN j := random() MOD Display.Width; Bee.pos[0].x := j; Bee.pos[1].x := j; j := random() MOD Display.Height; Bee.pos[0].y := j; Bee.pos[1].y := j; Bee.vx := Rand(7); Bee.vy := Rand(7) END InitBee; PROCEDURE InitSwarm; VAR i: INTEGER; BEGIN seed := Oberon.Time() MOD 231; (*DIM(Wasps, NrWasps); DIM(Bees, NrBees);*) NEW(F); F.X := 0; F.Y := 0; F.W := Display.Width; F.H := Display.Height; firstTime := TRUE; i := 0; WHILE i < NrWasps DO InitWasp(Wasps[i]); INC(i) END; i := 0; WHILE i < NrBees DO InitBee(Bees[i]); INC(i) END END InitSwarm; PROCEDURE Age(VAR i: Insect); BEGIN i.pos[2] := i.pos[1]; i.pos[1] := i.pos[0] END Age; PROCEDURE BoundSpeed(VAR i: Insect; limit: INTEGER); BEGIN IF i.vx > limit THEN i.vx := limit ELSIF i.vx < -limit THEN i.vx := -limit END; IF i.vy > limit THEN i.vy := limit ELSIF i.vy < -limit THEN i.vy := -limit END END BoundSpeed; PROCEDURE AccelerateWasp(VAR Wasp: Insect); BEGIN Wasp.vx := Wasp.vx+Rand(WaspAcc); Wasp.vy := Wasp.vy+Rand(WaspAcc); BoundSpeed(Wasp, WaspVel) END AccelerateWasp; PROCEDURE ReflectWasp(VAR Wasp: Insect); BEGIN IF (Wasp.pos[0].x < Border) OR (Wasp.pos[0].x > Display.Width-Border-1) THEN Wasp.vx := -Wasp.vx; INC(Wasp.pos[0].x, Wasp.vx) END; IF (Wasp.pos[0].y < Border) OR (Wasp.pos[0].y > Display.Height-Border-1) THEN Wasp.vy := -Wasp.vy; INC(Wasp.pos[0].y, Wasp.vy) END END ReflectWasp; PROCEDURE AccelerateBee(VAR Bee: Insect); VAR dx, dy, distance, dx1, dy1, distance1, i: INTEGER; BEGIN i := 0; distance := 10000; WHILE i < NrWasps DO dx1 := Wasps[i].pos[1].x-Bee.pos[1].x; dy1 := Wasps[i].pos[1].y-Bee.pos[1].y; distance1 := ABS(dx1)+ABS(dy1); IF distance1 < distance THEN dx := dx1; dy := dy1; distance := distance1 END; INC(i) END; IF distance = 0 THEN distance := 1 END; Bee.vx := Bee.vx + (dx*BeeAcc) DIV distance; Bee.vy := Bee.vy + (dy*BeeAcc) DIV distance; BoundSpeed(Bee, BeeVel) END AccelerateBee; PROCEDURE Move(VAR i: Insect); BEGIN i.pos[0].x := i.pos[1].x + i.vx; i.pos[0].y := i.pos[1].y + i.vy END Move; PROCEDURE Draw(VAR i: Insect); BEGIN IF ~firstTime THEN Display1.Line(F, Display.white, i.pos[1].x, i.pos[1].y, i.pos[2].x, i.pos[2].y, Display.invert) END; Display1.Line(F, Display.white, i.pos[0].x, i.pos[0].y, i.pos[1].x, i.pos[1].y, Display.invert) END Draw; PROCEDURE DrawSwarm; VAR i: INTEGER; BEGIN i := 0; WHILE i < NrWasps DO Age(Wasps[i]); AccelerateWasp(Wasps[i]); Move(Wasps[i]); ReflectWasp(Wasps[i]); Draw(Wasps[i]); INC(i) END; i := random() MOD NrBees; Bees[i].vx := Bees[i].vx + Rand(3); (* change a random bee *) i := random() MOD NrBees; Bees[i].vy := Bees[i].vy + Rand(3); i := 0; WHILE i < NrBees DO Age(Bees[i]); AccelerateBee(Bees[i]); Move(Bees[i]); Draw(Bees[i]); INC(i) END END DrawSwarm; PROCEDURE GetPar(VAR S: Texts.Scanner; lbound, ubound, default: INTEGER; VAR val: INTEGER; VAR list: BOOLEAN); BEGIN IF list THEN IF S.class = Texts.Int THEN IF S.i < lbound THEN val := lbound ELSIF S.i < ubound THEN val := SHORT(S.i) ELSE val := ubound END ELSE list := FALSE; val := default END; Texts.Scan(S) ELSE val := default END END GetPar; PROCEDURE Start*; VAR msg: Viewers.ViewerMsg; S: Texts.Scanner; T: Texts.Text; pos, t, dummy: LONGINT; list: BOOLEAN; BEGIN Texts.OpenScanner(S, Oberon.Par.text, Oberon.Par.pos); Texts.Scan(S); IF (S.class = Texts.Char) & (S.c = "^") THEN Oberon.GetSelection(T, pos, dummy, t); IF t >= 0 THEN Texts.OpenScanner(S, T, pos); Texts.Scan(S) END END; list := TRUE; GetPar(S, 1, MaxWasps, 2, NrWasps, list); GetPar(S, 1, MaxBees, 100, NrBees, list); GetPar(S, 2, 20, 5, WaspAcc, list); GetPar(S, 1, 19, 3, BeeAcc, list); GetPar(S, 0, 20, 5, Delay, list); InitSwarm; msg.id := Viewers.suspend; Viewers.Broadcast(msg); Display.ReplConst(Display.black, 0, 0, Display.Width, Display.Height, Display.replace); WHILE Input.Available() = 0 DO DrawSwarm; Wait(Delay); firstTime := FALSE END; msg.id := Viewers.restore; Viewers.Broadcast(msg) END Start; END Swarm.Start 5 200 5 3 20 (* Parameters: number of wasps, number of bees, wasp acceleration, bee acceleration, delay between steps (Input.Tick's) *) Swarm.Start System.State Swarm