<> <> <> <<>> DIRECTORY Buttons USING [ButtonProc, Button, Create], Commander USING [CommandProc, Handle, Register], Containers USING [Container, Create], IO USING [CreateStream, CreateStreamProcs, PutF, PutRope, STREAM, StreamProcs, int, rope], Process USING [MsecToTicks, Pause, Ticks], ProcessProps USING [GetProp], Random USING [RandomStream, Create, ChooseInt], Real USING [FixI, RoundLI], RealFns USING [ArcTan, Cos, Sin], RobotArena USING [Arena, Create, SetRobot, SetRobotColor], RobotDefs USING [MemoryMap, Robot, RobotIndex, RobotState, RobotStateRec], RobotIO USING [AssembleRobot, ReadRobot], RobotHardware USING [direct, fire, hdmg, hx, hy, InitialMemory, mdmg, mx, my, ProcessRobot, speed], Rope USING [Length, ROPE], TypeScript USING [ChangeLooks, Create, PutChar, TS], ViewerClasses USING [Viewer], ViewerOps USING [OpenIcon, PaintViewer, SetOpenHeight], ViewerTools USING [GetContents, MakeNewTextViewer]; RobotTool: CEDAR MONITOR IMPORTS Buttons, Commander, Containers, IO, Process, ProcessProps, Random, Real, RealFns, RobotArena, RobotHardware, RobotIO, Rope, TypeScript, ViewerOps, ViewerTools ~ { OPEN V: ViewerClasses, R: Real, RF: RealFns, RH: RobotHardware; ROPE: TYPE ~ Rope.ROPE; maxTurn: CARDINAL _ 5000; waitTurn: CARDINAL _ 0; hMargin: INT ~ 5; --Spacing between buttons on a line vMargin: INT ~ 5; --Spacing between rows of buttons vHeight: INT ~ 18; --Height of each row hTextWidth: INT ~ 100; --Default width of a text box arenaHeight, arenaWidth: INT ~ 400; --Size of the battle arena robotDeath: INT _ 5; --Death count for robots robotRadius: INT _ 1; --Robot fatness failTemperature: INT _ 20; --Laser failure delay: Process.Ticks _ Process.MsecToTicks[1000/10]; accuracy: REAL _ 100.0; --Legal locations/reading along arena MemoryMap: TYPE ~ RobotDefs.MemoryMap; RobotIndex: TYPE ~ RobotDefs.RobotIndex; RobotTool: TYPE ~ REF RobotToolRec; RobotToolRec: TYPE ~ RECORD [ robots: ARRAY RobotIndex OF ViewerClasses.Viewer _ ALL[NIL], arena: ViewerClasses.Viewer _ NIL, ts: TypeScript.TS, wDir: ROPE, pleaseStop: BOOLEAN ]; MakeRobotTool: Commander.CommandProc ~ { robotTool: RobotTool _ NEW[RobotToolRec]; viewer: Containers.Container _ Containers.Create[[ name: "Robot War", iconic: TRUE, scrollable: FALSE ]]; thisX: INT _ hMargin; thisY: INT _ vMargin; prev: ViewerClasses.Viewer; <> WITH ProcessProps.GetProp[$WorkingDirectory] SELECT FROM wd: ROPE => robotTool.wDir _ wd; ENDCASE => ERROR; <> prev _ Buttons.Create[ info: [ name: "Go! ", wx: thisX, wy: thisY, wh: vHeight, parent: viewer, border: TRUE ], proc: RobotBattle, fork: TRUE, clientData: robotTool ]; thisX _ thisX + prev.ww + hMargin; <> prev _ Buttons.Create[ info: [ name: "Stop! ", wx: thisX, wy: thisY, wh: vHeight, parent: viewer, border: TRUE ], proc: RobotStop, fork: TRUE, clientData: robotTool ]; thisX _ thisX + prev.ww + hMargin; <> FOR i: RobotIndex IN RobotIndex DO IF thisX+hTextWidth > arenaWidth THEN { --Go to next line thisX _ hMargin; thisY _ thisY + vHeight + vMargin; }; prev _ robotTool.robots[i] _ ViewerTools.MakeNewTextViewer[ info: [ wx: thisX, wy: thisY, wh: vHeight, parent: viewer, ww: hTextWidth, border: TRUE, scrollable: FALSE ] ]; thisX _ thisX + prev.ww + hMargin; ENDLOOP; thisX _ hMargin; thisY _ thisY + vHeight + vMargin; <> prev _ robotTool.ts _ TypeScript.Create[[ wx: thisX, wy: thisY, wh: 5*vHeight, ww: arenaWidth, parent: viewer, border: TRUE ]]; thisY _ thisY + prev.wh + vMargin; thisX _ vMargin; <> prev _ robotTool.arena _ RobotArena.Create[[ parent: viewer, wx: thisX, wy: thisY, ww: arenaWidth, wh: arenaHeight, border: TRUE, scrollable: FALSE ]]; thisX _ hMargin; thisY _ thisY + prev.wh + vMargin; <> ViewerOps.SetOpenHeight[viewer, thisY + vMargin]; ViewerOps.OpenIcon[icon: viewer, bottom: FALSE]; result _ viewer; }; RobotStop: Buttons.ButtonProc ~ { robotTool: RobotTool _ NARROW[clientData]; robotTool.pleaseStop _ TRUE; --He'll stop eventually }; colorName: ARRAY RobotIndex OF ROPE ~ ["Black", "Gray", "Red", "Green", "Blue"]; deadRobot: INT ~ LAST[INT]; --Used to mark dead robots RobotBattle: Buttons.ButtonProc ~ { Alive: PROC [i: RobotIndex] RETURNS [BOOLEAN] ~ INLINE { RETURN [state[i].damage # deadRobot AND robot[i] # NIL] }; names: ARRAY RobotIndex OF ROPE; robot: ARRAY RobotIndex OF RobotDefs.Robot; state: ARRAY RobotIndex OF RobotDefs.RobotState; robotTool: RobotTool _ NARROW[clientData]; tsLog: IO.STREAM ~ TSToLog[robotTool.ts]; active: CARDINAL _ 0; valid, fight: BOOLEAN _ TRUE; robotTool.pleaseStop _ FALSE; --So he can request a stop TypeScript.ChangeLooks[robotTool.ts, 'b]; FOR i: RobotIndex IN RobotIndex DO names[i] _ ViewerTools.GetContents[robotTool.robots[i]]; IF Rope.Length[names[i]]=0 THEN names[i] _ NIL ELSE { active _ active+1; --Keep track of the robots left in IO.PutF[tsLog, IF active=1 THEN "%g (%g)" ELSE "vs. %g (%g) ", IO.rope[names[i]], IO.rope[colorName[i]]]; }; ENDLOOP; IO.PutRope[tsLog, "\n"]; TypeScript.ChangeLooks[robotTool.ts, ' ]; FOR i: RobotIndex IN RobotIndex DO IF names[i]=NIL THEN robot[i] _ NIL ELSE { IF RobotIO.AssembleRobot[r: names[i], log: tsLog, wDir: robotTool.wDir] THEN { robot[i] _ RobotIO.ReadRobot[names[i], robotTool.wDir]; } ELSE fight _ FALSE; }; ENDLOOP; IF fight THEN { FOR i: RobotIndex IN RobotIndex DO Loc: PROC RETURNS [REAL] ~ INLINE {RETURN[Random.ChooseInt[rs, 1, 99]]}; state[i] _ NEW[RobotDefs.RobotStateRec]; IF Alive[i] THEN { state[i].x _ Random.ChooseInt[rs, 1, 99]; state[i].y _ Random.ChooseInt[rs, 1, 99]; state[i].memory _ RobotHardware.InitialMemory[robot[i].code]; --Get ready to run } ELSE { state[i].x _ state[i].y _ 200; --Out of sight }; RobotArena.SetRobot[robotTool.arena, i, [ x: state[i].x, y: state[i].y, hit: FALSE, fire: FALSE ]]; ENDLOOP; ViewerOps.PaintViewer[robotTool.arena, client]; { <> FOR turn: CARDINAL IN [0 .. maxTurn] UNTIL active<2 OR robotTool.pleaseStop DO fired: ARRAY RobotIndex OF BOOLEAN _ ALL[FALSE]; --Who fires this turn? hit: ARRAY RobotIndex OF BOOLEAN _ ALL[FALSE]; --Who got hit? Process.Pause[delay]; FOR i: RobotIndex IN RobotIndex DO FindEnemy: PROC RETURNS [nme: RobotIndex] ~ { offset: CARDINAL _ FIRST[RobotIndex]; modulo: CARDINAL _ LAST[RobotIndex]-FIRST[RobotIndex]+1; nme _ i; UNTIL Alive[nme _ ((nme+1-offset) MOD modulo) + offset] DO ENDLOOP; }; map: MemoryMap; nme: RobotIndex _ FindEnemy[]; --To have somebody to shoot at <> IF ~Alive[i] THEN LOOP; <> state[i].memory[RH.mx] _ R.FixI[state[i].x]; state[i].memory[RH.my] _ R.FixI[state[i].y]; state[i].memory[RH.mdmg] _ R.FixI[state[i].damage]; state[i].memory[RH.hx] _ R.FixI[state[nme].x]; state[i].memory[RH.hy] _ R.FixI[state[nme].y]; state[i].memory[RH.hdmg] _ R.FixI[state[nme].damage]; <> map _ RobotHardware.ProcessRobot[state[i].memory]; <> IF state[i].memory[RH.speed] # 0 THEN { mx: REAL _ state[i].x; my: REAL _ state[i].y; direction: REAL _ ToRad[state[i].memory[RH.direct]]; speed: INTEGER _ MIN[3, MAX[-3, state[i].memory[RH.speed]]]; mx _ Real.RoundLI[accuracy*(mx + speed*RF.Cos[direction])]/accuracy; my _ Real.RoundLI[accuracy*(my + speed*RF.Sin[direction])]/accuracy; <> IF mx # (MIN[100.0, MAX[0.0, mx]]) OR my # (MIN[100.0, MAX[0.0, my]]) THEN { IO.PutF[stream: tsLog, format: "%g hits wall (%g)...", v1: IO.rope[names[i]], v2: IO.int[turn]]; state[i].damage _ state[i].damage+2; hit[i] _ TRUE; }; state[i].x _ MIN[100.0, MAX[0.0, mx]]; state[i].y _ MIN[100.0, MAX[0.0, my]]; }; <<>> <
> state[i].temperature _ MAX[state[i].temperature-1, 0]; IF turn>waitTurn AND map[RH.fire] AND (state[i].temperature _ MAX[state[i].temperature-1, 0])> IF RF.Cos[direction - RF.ArcTan[hy-my, hx-mx]]<0 THEN LOOP; <> IF ABS[(hx-mx)*sin IO.PutF[stream: tsLog, format: "%g hits %g (%g)...", v1: IO.rope[names[gunman]], v2: IO.rope[names[target]], v3: IO.int[turn]]; state[target].damage _ MIN[robotDeath, state[target].damage+1]; hit[target] _ TRUE; }; ENDLOOP; }; ENDLOOP; <> FOR i: RobotIndex IN RobotIndex DO IF Alive[i] AND state[i].damage>=robotDeath THEN { TypeScript.ChangeLooks[robotTool.ts, 'b]; IO.PutF[stream: tsLog, format: "%g dies...", v1: IO.rope[names[i]]]; TypeScript.ChangeLooks[robotTool.ts, ' ]; active _ active - 1; state[i].damage _ deadRobot; }; ENDLOOP; <> FOR i: RobotIndex IN RobotIndex DO IF robot[i]#NIL THEN RobotArena.SetRobot[robotTool.arena, i, [ x: state[i].x, y: state[i].y, hit: hit[i], fire: fired[i], fireAngle: state[i].memory[RH.fire] ]]; ENDLOOP; ViewerOps.PaintViewer[robotTool.arena, client, FALSE, $MoveRobots]; ENDLOOP; IO.PutRope[tsLog, "\nRound over.\n"]; }; }; }; ToRad: PROC [bytians: INT] RETURNS [radians: REAL] ~ { RETURN [ }; rs: Random.RandomStream ~ Random.Create[]; TSToLog: PROC [ts: TypeScript.TS] RETURNS [s: IO.STREAM] ~ { RETURN [IO.CreateStream[streamProcs: TSLogProcs, streamData: ts]]; }; PutTSChar: PROC [self: IO.STREAM, char: CHAR] ~ { ts: TypeScript.TS ~ NARROW[self.streamData]; TypeScript.PutChar[ts, char]; }; TSLogProcs: REF IO.StreamProcs ~ IO.CreateStreamProcs[ variety: output, class: $TSLog, putChar: PutTSChar ]; Init: PROC ~ { Commander.Register[key: "RobotTool", proc: MakeRobotTool, doc: "Make an instance of a Robot Tool" ]; FOR index: RobotIndex IN RobotIndex DO RobotArena.SetRobotColor[index, colorName[index]]; ENDLOOP; }; Init[]; }.