Get RobotChase at SourceForge.net. Fast, secure and Free Open Source software downloads

RobotChase v1.0.7 API

Welcome to Robot Chase!

See:
          Description

Packages
org.gcs.robot  

 

Welcome to Robot Chase!

RobotChase is a game in which the player moves about on a rectangular grid, while trying to escape advancing robots. The player accumulates points by killing robots and advancing to the next level. Robots die when they collide with each other or with one of several obstructions. The project is hosted on SourceForge.

Java Web Start: Launch RobotChase by clicking here.

Download: Click here to download the jar or Mac application files.

screenshot

History

The game was implemented in UCSD Pascal in the early eighties, as seen in Listing 1. The original may be found on Volume 1 of the USUS Software Library hosted in the west wing of the Jefferson Computer Museum.

Features

Although based on the classic version, the game includes several modern features:

Design

The design of RobotChase is an example of the Model-View-Controller pattern. The main class (RobotChase) instantiates a model of the game (RCModel) and three views of that model (RCView, RCStatus, and RCInfo).

The interaction between the model and its views uses the Observer pattern. The model extends the class Observable, and each of the views implements the Observer interface. In this way, each view can update itself whenever the model signals a change in state.

RCView, in turn, delegates the drawing of each game tile to RCTile. The class RCImage is a factory that supplies one of several sets of images to RCView. The class RCPrefs provides static methods that maintain a persistent user state. RCHelp is a modal dialog that displays game instructions.

The game is played with the keyboard or mouse. By implementing KeyListener, the controller accepts the user's input and conducts game play. The main view implements MouseListener and MouseMotionListener as an alternate means of play.

The keys used to control the game are managed in the Key enumeration. The modal dialog RCKeys provides an interface for editing the corresponding key bindings.

Internally, the game model uses numeric virtual keycodes (96-105) to control movement. The numbers represent the eight (semi-) cardinal directions. The number five signifies no movement:

NW 7 North
8
9 NE
West 4 5 6 East
SW 1 2
South
3 SE
0 Jump

Implementation

The present implementation uses Java. The latest source code is available on SourceForge. The ant build target compiles the source and creates a jar file of the required classes and images. The jar file is then copied to a Mac application bundle. The file Info.plist is edited and copied. Diagnostic output from the launch process may be obtained as follows:

$ export JAVA_LAUNCHER_VERBOSE
$ ./RobotChase.app/Contents/MacOS/JavaApplicationStub
Revision history

1.0.7 Assorted bug fixes; new certificate.

1.0.6 Update logo; show window dimensions during resize.

1.0.5 Stop timer if won; sign jars; allow shift-tab navigation.

1.0.4 Improve help; leaner distribututions; fix mouse bug.

1.0.3 Animate player on mouse up; add editor for key bindings.

1.0.2 Resume previous game and screen size; preserve jumps.

1.0.1 Add jump convenience; move to SourceForge.

1.0.0 Add resize message; initial public release.

0.9.9 Refactor main view and tiles; normalize player position.

0.9.8 Normalize Observer pattern; handle minimum game board size.

0.9.7 Better mouse support; add high level; preserve game on resize.

0.9.6 Add mouse support; better on-line help.

0.9.5 Add preferences; normalize package name; third beta release.

0.9.4 Add high score; normalize layout usage; second beta release.

0.9.3 Initial beta release.

Listing 1.

PROGRAM CHASE;
USES APPLESTUFF;
CONST   PLAYER     = 'O';                     {SYMBOL FOR THE PLAYER}
        EDGE       = 'I';                     {SYMBOL FOR THE FENCE}
        OBST       = '*';                     {SYMBOL FOR AN OBSTRUCTION}
        ROBOT      = 'R';                     {SYMBOL FOR A ROBOT}
        BLANK      = ' ';                     {AN ASCII BLANK}
       
        DROB       =   3;                     {STARTING NO OF ROBOTS}
        ROBMAX     =  19;                     {MAX NO OF ROBOTS ALLOWED}
        XMAX       =  39;                     {MAX HORIZONTAL FIELD DIMENSION}
        YMAX       =  14;                     {MAX VERTICAL FIELD DIMENSION}
        
        TOP        =   2;                     {SPACE ABOVE FIELD}
        SIDE       =   5;                     {SPACE TO LEFT OF FIELD}
        
        CLRSCRN    =  12;                     {CLEAR SCREEN CODE}


VAR     FIELD      : PACKED ARRAY[0..XMAX,0..YMAX] OF CHAR;
        AGAIN,PLAY : BOOLEAN;
        WIN        : BOOLEAN;
        MI,MJ      : INTEGER;                 {COORDINATES OF PLAYER}
        R          : INTEGER;                 {NUMBER OF ROBOTS LEFT}
        RI,RJ      : ARRAY[1..ROBMAX] OF INTEGER; {ROBOT COORDINATES}
        DIFF       : INTEGER;                 {DIFFICULTY}
        IDIFF      : 0..10;                   {INITIAL DIFFICULTY}
        GAMENU     : INTEGER;                 {GAME NUMBER}
        M          : CHAR;
        NROB       : INTEGER;                 {NUMBER OF ROBOTS}
        WINS       : INTEGER;                 {NUMBER OF GAMES WON}
        GOODCHAR   : SET OF CHAR;             {GOOD CHARACTERS}
        MOVES      : INTEGER;                 {COUNT OF MOVES}
        CRASH      : INTEGER;                 {NO OF ROBOTS "CRASHED"}


FUNCTION RND(LO,HI:INTEGER):INTEGER;          {CALL APPLESTUFF}
BEGIN
  RND := LO + RANDOM MOD (HI - LO + 1);
END;
    

PROCEDURE DOMOVE(COL,ROW:INTEGER;SYMBOL:CHAR); {DISPLAY SYMBOL AT I,J}
BEGIN
  GOTOXY(COL,ROW);         {POSITION CURSOR}
  WRITE(SYMBOL)
END;            {END OF DOMOVE PROCEDURE}


PROCEDURE CLEARSCREEN;         {FOR AN ADM3-A CHANGE IT FOR OTHER TERMINAL}
BEGIN
  WRITE(CHR(CLRSCRN),CHR(0),CHR(0),CHR(0),CHR(0),CHR(0))
END;


PROCEDURE INSTRUCTIONS;                 {DISPLAY INSTRUCTIONS}
VAR M:CHAR;
BEGIN
  CLEARSCREEN;
  WRITELN('WELCOME TO THE EXCITING GAME OF CHASE');
  GOTOXY(0,4);
  WRITE('WOULD YOU LIKE INSTRUCTIONS ? (Y OR N) ');
  READ(M);
  IF M IN ['Y','y'] THEN
  BEGIN
    WRITELN;WRITELN;
    WRITELN('INSTRUCTIONS:');
    WRITELN('YOU,"O",ARE IN A HIGH VOLTAGE MAZE.');
    WRITELN('THE ROBOT COMPUTERS,"R",ARE TRYING TO DESTROY YOU.');
    WRITELN('TO WIN, YOU MUST DESTROY THE COMPUTERS.');
    WRITELN('THIS IS DONE BY RUNNING THEM INTO FENCE POSTS,"*",');
    WRITELN('OR BY RUNNING THEM INTO EACH OTHER.');
    WRITELN('THE DIAGRAM BELOW THE MAZE SHOWS HOW YOU CAN MOVE');
    WRITELN('THE ROBOTS WILL TRY TO FOLLOW YOU.');
    WRITELN('THERE ARE 3 ROBOTS TO START FOR A BEGINNER.');
    WRITELN('THE NUMBER WILL INCREASE AS YOU WIN GAMES !');
    WRITELN;
    WRITELN('GOOD LUCK!!!!!');
    WriteLn; Write('Press any key: '); READ(M)
  END
END;                                    {END OF INSTRUCTIONS}


PROCEDURE STARTGAME;
VAR    SK: CHAR;
BEGIN
WRITELN;WRITELN;WRITELN;
  CLEARSCREEN;
  WRITELN('      HOW GOOD A PLAYER ARE YOU ?');
  WRITELN;
  WRITELN('        BEGINNER     - B');
  WRITELN('        INTERMEDIATE - I');
  WRITELN('        EXPERT       - E');
  WRITELN('        OLD PRO      - P');
  WRITELN;
  WRITE('              TYPE IN YOUR SKILL ');
  READ (SK);
  WRITELN;
  WHILE NOT (SK IN ['B','b','I','i','E','e','P','p']) DO
  BEGIN
    GOTOXY(10,10);
    WRITE('    WHAT WAS THAT AGAIN PLEASE ? ',CHR(7));
    READ (SK);
    WRITELN
  END;
  CASE SK OF
    'B','b': IDIFF:=0;
    'I','i': IDIFF:=1;
    'E','e': IDIFF:=3;
    'P','p': IDIFF:=5;
  END;
END;


PROCEDURE INITIALIZE;   {SET UP BLANK FIELD SURROUNDED BY FENCE}
VAR I,J:INTEGER;
BEGIN
  FOR I:=0 TO XMAX DO
  BEGIN
    FOR J:=0 TO YMAX DO
    IF((I=0) OR (I=XMAX) OR (J=0) OR (J=YMAX)) THEN FIELD[I,J]:=EDGE
      ELSE FIELD[I,J]:=BLANK
   END;
END;    {END OF INITIALIZE}


PROCEDURE INNERFIELD;   {SET UP PLAYER, ROBOTS AND OBSTRUCTIONS}
VAR I,J,L,POSTS:INTEGER;
BEGIN
  MI:=RND(1,XMAX-1); MJ:=RND(1,YMAX-1); {PLAYER AT A RANDOM POSITION}
  FIELD[MI,MJ]:=PLAYER;
  R:=NROB;
  FOR L:=1 TO R DO                      {NOW DO R ROBOTS}
  BEGIN
    REPEAT
      I:=RND(0,XMAX);J:=RND(0,YMAX);
    UNTIL FIELD[I,J]=BLANK;
    FIELD[I,J]:=ROBOT;
    RI[L]:=I;
    RJ[L]:=J
  END;
  POSTS:=RND(25,35);                    {NOW SET UP 25 TO 35 POSTS}
  FOR L:=1 TO POSTS DO
  BEGIN
    REPEAT
      IF DIFF>3 THEN
      BEGIN
        I:=RND(0,XMAX);
        J:=RND(0,YMAX)
      END ELSE
      BEGIN
        I:=RND(1,XMAX-1);
        J:=RND(1,YMAX-1)
      END;
    UNTIL FIELD[I,J]=BLANK;
    FIELD[I,J]:=OBST
    END; 
END;                                    {END OF INNERFIELD}


PROCEDURE MAP;                          {DISPLAY PLAYING FIELD}
VAR I,J:INTEGER;
BEGIN
  CLEARSCREEN;
  WRITELN('GAME  DIFF   ROBOTS    WINS    MOVE':79);
  WRITE(' ':44,GAMENU:3,DIFF:5,R:8,WINS:10,MOVES:8);
  GOTOXY(0,0);
  FOR J:=0 TO YMAX DO
  BEGIN
    FOR I:=0 TO XMAX DO WRITE(FIELD[I,J]);
    WRITELN
  END;
  WRITELN;
  WRITELN('7 8 9      Q = QUIT');
  WRITELN('4 X 6      5 = NO MOVE'); 
  WRITE(  '1 2 3                  MOVE => ');
END;                                    {END OF MAP}

PROCEDURE MOVE;                         {ENTER YOUR MOVE FROM KEYBOARD}
VAR     M : INTEGER;
        C : CHAR;
      BAD : BOOLEAN;
BEGIN
  BAD:=FALSE;
  REPEAT
    WRITE(' ',CHR(8));
    READ (C);
    IF NOT (C IN GOODCHAR) THEN
    BEGIN
      GOTOXY(4,21);
      BAD:=TRUE;
      WRITE('BAD MOVE, PLEASE TRY AGAIN ':33,CHR(7))
    END;
  UNTIL (C IN GOODCHAR);
  IF BAD THEN
    BEGIN
      GOTOXY(4,21);
      WRITE(' ':40);
      GOTOXY(10,22);
    END;
  IF C IN ['Q','q'] THEN
    BEGIN
     PLAY:=FALSE;
     WIN:=FALSE
    END;
  M:=ORD(C)-48;
  FIELD[MI,MJ]:=BLANK;
  DOMOVE(MI,MJ,BLANK);
  CASE M OF
    1: BEGIN MI:=MI-1; MJ:=MJ+1 END;
    2: MJ:=MJ+1;
    3: BEGIN MI:=MI+1; MJ:=MJ+1 END;
    4: MI:=MI-1;
    5: ;
    6: MI:=MI+1;
    7: BEGIN MI:=MI-1; MJ:=MJ-1 END;
    8: MJ:=MJ-1;
    9: BEGIN MI:=MI+1; MJ:=MJ-1 END
  END;
  MOVES:=MOVES+1;
  IF FIELD[MI,MJ] = BLANK THEN
    BEGIN
      DOMOVE(MI,MJ,PLAYER);
      FIELD[MI,MJ]:=PLAYER 
    END ELSE
  BEGIN
    IF FIELD[MI,MJ] = EDGE THEN
    BEGIN
      WIN:=FALSE;
      PLAY:=FALSE;
      WRITELN('OUCH, YOU GOT ELECTROCUTED!')
    END ELSE
    BEGIN
      IF FIELD[MI,MJ] = ROBOT THEN 
      WRITELN('THWACK! YOU RAN INTO A ROBOT (TURKEY!)') ELSE
      WRITELN('ZZAP! YOU RAN INTO AN ELECTIFIED POST');
      WIN:=FALSE;
      PLAY:=FALSE
    END;
  END;
END;                    {END OF MOVE PROCEDURE}


PROCEDURE ROBOTMOVE;    {COMPUTE MOVE FOR R OR FEWER ROBOTS}
VAR M,L,I,J:INTEGER;
BEGIN
  FOR L:=1 TO NROB DO
  BEGIN
    IF((RI[L]<>0) AND (WIN)) THEN
    BEGIN
      FIELD[RI[L],RJ[L]]:=BLANK;
      DOMOVE(RI[L],RJ[L],BLANK);
      IF MI>RI[L] THEN RI[L]:=RI[L]+1;
      IF MI<RI[L] THEN RI[L]:=RI[L]-1;
      IF MJ>RJ[L] THEN RJ[L]:=RJ[L]+1;
      IF MJ<RJ[L] THEN RJ[L]:=RJ[L]-1;
      I:=RI[L];J:=RJ[L];
      IF FIELD[I,J]=BLANK THEN
      BEGIN
        FIELD[RI[L],RJ[L]]:=ROBOT;
        DOMOVE(I,J,ROBOT)
      END
      ELSE
      BEGIN
        IF ((FIELD[I,J]=OBST) OR (FIELD[I,J]=ROBOT))  THEN 
        BEGIN
          GOTOXY(XMAX+8,CRASH+3);
          CRASH:=CRASH+1;
          WRITELN('CRASH!! ',R-1:2,' OF ',NROB,' ROBOTS REMAIN');
          R:=R-1;
          GOTOXY(53,1);                 {CHANGE NO OF ROBOTS}
          WRITE(R:8);
          RI[L]:=0;
          IF R=0 THEN
          BEGIN
            GOTOXY(XMAX+8,CRASH+3);
            {WRITELN('CONGRATULATIONS! GOOD WORK!');}
            {GOTOXY(XMAX+8,CRASH+4);}
            WRITELN('YOU HAVE DESTROYED THEM ALL!!!');
            WIN:=TRUE;
            PLAY:=FALSE
          END;
        END;
      END;
      IF FIELD[RI[L],RJ[L]]=FIELD[MI,MJ] THEN
      BEGIN
        WRITELN('ZAP! A ROBOT GOT YOU!!!');
        WIN:=FALSE;
        PLAY:=FALSE
      END;
    END;
 END;
END;                                    {END OF ROBOTMOVE PROCEDURE}

BEGIN                 {START OF MAIN PROGRAM}
  RANDOMIZE;
  GOODCHAR:=['1'..'9','Q','q'];
  GAMENU:=1;
  WINS:=0;
  AGAIN:=TRUE;
  PLAY:=TRUE;          {INITIALIZE QUIT}
  INSTRUCTIONS;        {DISPLAY INSTRUCTIONS}
  STARTGAME;           {INPUT STARTING POSITION AND SKILL LEVEL}
  DIFF:=IDIFF;         {INITIAL DIFFICULTY LEVEL}
  NROB:=DROB+DIFF*2;   {INITIAL NUMBER OF ROBOTS}
  WHILE AGAIN DO
  BEGIN
    MOVES:=1;WIN:=TRUE;CRASH:=0;
    INITIALIZE;        {CLEARS FIELD[X,Y]}
    INNERFIELD;        {SETS UP PLAYING FIELD}
    WHILE PLAY DO
    BEGIN
      IF MOVES=1 THEN MAP ELSE
      BEGIN
        GOTOXY(70,1);
        WRITELN(MOVES:8);
        DOMOVE(30,18,BLANK)    {INPUT NEXT MOVE}
      END;
      MOVE;                    {LETS YOU MOVE}
      IF(PLAY) THEN ROBOTMOVE  {MOVES THE ROBOTS}
    END;
    GOTOXY(0,21);
    UnitClear(1); { Empty keyboard buffer }
    WRITE('WOULD YOU LIKE TO PLAY AGAIN (Y OR N) ');
    READ(M);
    IF M IN ['N','n'] THEN AGAIN:=FALSE ELSE
    BEGIN
      PLAY:=TRUE;
      GAMENU:=GAMENU+1;
      IF WIN THEN
      BEGIN
        WINS:=WINS+1;
        IF WINS>2 THEN DIFF:=IDIFF+1;
        IF WINS>5 THEN DIFF:=IDIFF+2;
        IF WINS>8 THEN DIFF:=IDIFF+3;
        IF WINS>11 THEN DIFF:=IDIFF+4;
        IF WINS>15 THEN DIFF:=IDIFF+6;
        IF WINS>20 THEN DIFF:=IDIFF+8;
        IF WINS>30 THEN DIFF:=IDIFF+12;
        NROB:=DROB+2*DIFF;
        IF NROB>ROBMAX THEN NROB:=ROBMAX
      END;
    END;
  END;
END.

RobotChase is an open-source project, distributed under the terms of the GPL.

Author:
John B. Matthews

Get RobotChase at SourceForge.net. Fast, secure and Free Open Source software downloads

Copyright © 2007 Gem City Software. Distributed under the terms of the GPL