home *** CD-ROM | disk | FTP | other *** search
- #include:util.g
- #include:crt.g
-
- /*
- * WATOR - simulation of the torus world of Wa-Tor, with a population of
- * sharks and fish. Size of display = 23 lines x 80 columns.
- *
- * Idea from: "Computer Recreations" by A. K. Dewdney in December 1984
- * Scientific American.
- *
- * Programmed: December 10, 1984, by Chris Gray.
- * Language: Draco
- */
-
- ushort
- NLINES = 23, /* number of lines displayed and run */
- NCOLUMNS = 80; /* number of columns displayed and run */
-
- /* footer line with statistics:
-
- NSharks: xxxx NFish: xxxx Time: xxxxx SBreed: xx FBreed: xx Starve: xx
-
- */
-
- ushort
- NSHARKSCOLUMN = 9,
- NFISHCOLUMN = 22,
- TIMECOLUMN = 34,
- SBREEDCOLUMN = 49,
- FBREEDCOLUMN = 61,
- STARVECOLUMN = 73;
-
- byte
- SHARK = 0x01, /* shark is present in this ocean cell */
- FISH = 0x02, /* fish is present in this ocean cell */
- NEWSHARK = 0x04, /* shark has moved here this cronon */
- NEWFISH = 0x08; /* fish has moved here this cronon */
-
- type
- CELL = struct {
- byte f_flags;
- ushort f_age;
- ushort s_age;
- ushort s_eat;
- };
-
- uint
- NSharks, /* number of sharks currently alive */
- NFish, /* number of fish currently alive */
- Time; /* the current time */
-
- ushort
- SBreed, /* breeding time for sharks */
- FBreed, /* breeding time for fish */
- Starve; /* starvation time for sharks */
-
- [NLINES, NCOLUMNS] CELL Ocean; /* the ocean of Wa-Tor */
-
- channel output text
- CRTOut, /* formatted output to screen */
- LogOut; /* statistics logging */
-
- bool Logging; /* true if logging is enabled */
-
- file() File; /* file for save, restore and logging */
-
- /*
- * initialize - set up the screen and the various data structures.
- */
-
- proc initialize()void:
- *CELL p;
- uint i;
- ushort l, c;
-
- p := &Ocean[0, 0];
- for i from 0 upto NLINES * NCOLUMNS - 1 do
- p*.f_flags := 0x00;
- p := p + sizeof(CELL);
- od;
- Time := 0;
- corp;
-
- /*
- * beep - beep to indicate an error (send BEL to terminal).
- */
-
- proc beep()void:
-
- CRT_PutChar('\(0x07)');
- corp;
-
- /*
- * findCell - find a random cell meeting the given mask requirements.
- * Return 'false' if no neighbouring cell is satisfactory.
- */
-
- proc findCell(byte mask, value; **CELL pp; ushort l, c)bool:
- *CELL p, p1;
- ushort count;
- [4] *CELL neighbour;
-
- p1 := pp*;
- count := 0;
- p :=
- if l = NLINES - 1 then
- p1 - ((NLINES - 1) * NCOLUMNS * sizeof(CELL))
- else
- p1 + (NCOLUMNS * sizeof(CELL))
- fi;
- if p*.f_flags & mask = value then
- neighbour[count] := p;
- count := count + 1;
- fi;
- p :=
- if l = 0 then
- p1 + ((NLINES - 1) * NCOLUMNS * sizeof(CELL))
- else
- p1 - (NCOLUMNS * sizeof(CELL))
- fi;
- if p*.f_flags & mask = value then
- neighbour[count] := p;
- count := count + 1;
- fi;
- p :=
- if c = NCOLUMNS - 1 then
- p1 - ((NCOLUMNS - 1) * sizeof(CELL))
- else
- p1 + sizeof(CELL)
- fi;
- if p*.f_flags & mask = value then
- neighbour[count] := p;
- count := count + 1;
- fi;
- p :=
- if c = 0 then
- p1 + ((NCOLUMNS - 1) * sizeof(CELL))
- else
- p1 - sizeof(CELL)
- fi;
- if p*.f_flags & mask = value then
- neighbour[count] := p;
- count := count + 1;
- fi;
- if count = 0 then
- false
- else
- count := CRT_Random(count);
- pp* := neighbour[count];
- true
- fi
- corp;
-
- /*
- * updateFish - update and regenerate the fish.
- */
-
- proc updateFish()void:
- *CELL p, p1;
- ushort l, c;
-
- p := &Ocean[0, 0];
- for l from 0 upto NLINES - 1 do
- for c from 0 upto NCOLUMNS - 1 do
- if p*.f_flags & FISH ~= 0x00 then
- p1 := p;
- if findCell(NEWFISH | FISH, 0x00, &p1, l, c) then
- p1*.f_flags := p1*.f_flags | NEWFISH;
- p1*.f_age := p*.f_age + 1;
- if p1*.f_age = FBreed then
- /*
- * it's giving birth to a new fish at old position.
- */
- p1*.f_age := 0;
- p*.f_flags := p*.f_flags | NEWFISH;
- p*.f_age := CRT_Random((FBreed + 1) / 2);
- NFish := NFish + 1;
- fi;
- else
- p*.f_flags := p*.f_flags | NEWFISH;
- fi;
- fi;
- p := p + sizeof(CELL);
- od;
- od;
- corp;
-
- /*
- * updateSharks - update and regenerate the sharks and eat the fish.
- */
-
- proc updateSharks()void:
- *CELL p, p1;
- ushort l, c;
- bool moved;
-
- p := &Ocean[0, 0];
- for l from 0 upto NLINES - 1 do
- for c from 0 upto NCOLUMNS - 1 do
- if p*.f_flags & SHARK ~= 0x00 then
- moved := false;
- p1 := p;
- if findCell(NEWFISH|NEWSHARK|SHARK, NEWFISH, &p1, l, c) then
- /*
- * this shark is eating a fish.
- */
- p1*.f_flags := p1*.f_flags | NEWSHARK;
- p1*.s_eat := 0;
- NFish := NFish - 1;
- moved := true;
- else
- p*.s_eat := p*.s_eat + 1;
- if p*.s_eat = Starve then
- /*
- * this shark has starved to death
- */
- NSharks := NSharks - 1;
- else
- if findCell(FISH|NEWSHARK|SHARK,FISH, &p1, l, c) or
- findCell(NEWSHARK|SHARK,0x00, &p1, l, c) then
- /*
- * shark will chase a fish if one WAS nearby,
- * otherwise it just wanders.
- */
- p1*.f_flags := p1*.f_flags | NEWSHARK;
- p1*.s_eat := p*.s_eat;
- moved := true;
- else
- p*.f_flags := p*.f_flags | NEWSHARK;
- if p*.f_flags & NEWFISH ~= 0x00 then
- /*
- * poor fish swam right to him!
- */
- p*.s_eat := 0;
- NFish := NFish - 1;
- fi;
- fi;
- fi;
- fi;
- if moved then
- p1*.s_age := p*.s_age + 1;
- if p1*.s_age = SBreed then
- /*
- * it's giving birth to a new shark at old position.
- */
- p1*.s_age := 0;
- if p*.f_flags & NEWFISH ~= 0x00 then
- /*
- * unlucky fish there is eaten by newborn!
- */
- NFish := NFish - 1;
- fi;
- p*.f_flags := p*.f_flags | NEWSHARK;
- p*.s_age := CRT_Random((SBreed + 1) / 2);
- p*.s_eat := 0;
- NSharks := NSharks + 1;
- fi;
- fi;
- fi;
- p := p + sizeof(CELL);
- od;
- od;
- corp;
-
- /*
- * updateDisplay - redraw the changes to the screen and reset Ocean.
- */
-
- proc updateDisplay()void:
- *CELL p;
- ushort l, c;
- byte b;
-
- p := &Ocean[0, 0];
- for l from 0 upto NLINES - 1 do
- for c from 0 upto NCOLUMNS - 1 do
- b := p*.f_flags;
- if b & NEWSHARK ~= 0x00 then
- if b & SHARK = 0x00 then
- CRT_Move(l, c);
- CRT_PutChar('0');
- fi;
- p*.f_flags := SHARK;
- elif b & NEWFISH ~= 0x00 then
- if b & FISH = 0x00 then
- CRT_Move(l, c);
- CRT_PutChar('.');
- fi;
- p*.f_flags := FISH;
- elif b ~= 0x00 then
- CRT_Move(l, c);
- CRT_PutChar(' ');
- p*.f_flags := 0x00;
- fi;
- p := p + sizeof(CELL);
- od;
- od;
- Time := Time + 1;
- CRT_Move(NLINES, NSHARKSCOLUMN);
- write(CRTOut; NSharks : 4);
- CRT_Move(NLINES, NFISHCOLUMN);
- write(CRTOut; NFish : 4);
- CRT_Move(NLINES, TIMECOLUMN);
- write(CRTOut; Time : 5);
- if Logging then
- writeln(LogOut; NSharks, ' ', NFish);
- fi;
- corp;
-
- /*
- * readNumber - read a number in CRT mode from the status line.
- */
-
- proc readNumber(ushort c, digits)uint:
- *char p;
- uint n;
- [6] char buffer;
-
- while
- CRT_Move(NLINES, c);
- for n from 1 upto digits do
- CRT_PutChar(' ');
- od;
- CRT_Move(NLINES, c);
- CRT_GetLine(&buffer[0], digits + 1);
- p := &buffer[0];
- while p* = ' ' do
- p := p + 1;
- od;
- if p* = '\e' then
- true
- else
- n := 0;
- while p* >= '0' and p* <= '9' do
- n := n * 10 + (p* - '0');
- p := p + 1;
- od;
- p* ~= '\e' or n = 0
- fi
- do
- beep(); /* beep to indicate error */
- od;
- CRT_Move(NLINES, c);
- write(CRTOut; n : digits);
- n
- corp;
-
- /*
- * getParameters - read in the five operating parameters.
- */
-
- proc getParameters()void:
-
- CRT_Move(NLINES, 0);
- CRT_PutChars("NSharks:");
- NSharks := readNumber(NSHARKSCOLUMN, 4);
- CRT_Move(NLINES, NSHARKSCOLUMN + 6);
- CRT_PutChars("NFish:");
- NFish := readNumber(NFISHCOLUMN, 4);
- CRT_Move(NLINES, NFISHCOLUMN + 6);
- CRT_PutChars("Time: 0 SBreed:");
- SBreed := readNumber(SBREEDCOLUMN, 2);
- CRT_Move(NLINES, SBREEDCOLUMN + 4);
- CRT_PutChars("FBreed:");
- FBreed := readNumber(FBREEDCOLUMN, 2);
- CRT_Move(NLINES, FBREEDCOLUMN + 4);
- CRT_PutChars("Starve:");
- Starve := readNumber(STARVECOLUMN, 2);
- corp;
-
- /*
- * initializeOcean - initialize the populations and Ocean.
- * Note: if NFish and/or NSharks are too large, this
- * routine will go into an infinite loop.
- */
-
- proc initializeOcean()void:
- *CELL p;
- uint i;
- ushort l, c;
-
- for i from 1 upto NFish do
- while
- l := CRT_Random(NLINES);
- c := CRT_Random(NCOLUMNS);
- p := &Ocean[l, c];
- p*.f_flags ~= 0x00
- do
- od;
- p*.f_flags := FISH;
- p*.f_age := CRT_Random(FBreed);
- CRT_Move(l, c);
- CRT_PutChar('.');
- od;
- for i from 1 upto NSharks do
- while
- l := CRT_Random(NLINES);
- c := CRT_Random(NCOLUMNS);
- p := &Ocean[l, c];
- p*.f_flags ~= 0x00
- do
- od;
- p*.f_flags := SHARK;
- p*.s_age := CRT_Random(SBreed);
- p*.s_eat := CRT_Random(Starve);
- CRT_Move(l, c);
- CRT_PutChar('0');
- od;
- corp;
-
- /*
- * restoreOcean - restore the state from a file and write screen.
- */
-
- proc restoreOcean()void:
- *CELL p;
- uint i;
-
- CRT_ClearScreen();
- p := &Ocean[0, 0];
- for i from 0 upto NLINES * NCOLUMNS - 1 do
- CRT_PutChar(
- if p*.f_flags & SHARK ~= 0x00 then
- '0'
- elif p*.f_flags & FISH ~= 0x00 then
- '.'
- else
- ' '
- fi
- );
- p := p + sizeof(CELL);
- od;
- write(CRTOut;
- "NSharks: ", NSharks : 4,
- " NFish: ", NFish : 4,
- " Time: ", Time : 5,
- " SBreed: ", SBreed : 2,
- " FBreed: ", FBreed : 2,
- " Starve: ", Starve : 2
- );
- corp;
-
- /*
- * main - main program - handles setup, restore, save and running.
- */
-
- proc main()void:
- *char p;
- channel input binary restore;
- channel output binary save;
- [100] char buffer;
-
- Logging := false;
- p := GetPar();
- if p ~= nil and p* = '-' then
- case (p + 1)*
- incase 'l':
- incase 'L':
- Logging := true;
- default:
- writeln("*** Invalid flag '", (p + 1)*, "' - aborting. ***");
- exit(1);
- esac;
- p := GetPar();
- fi;
- CRT_Initialize("Wator", NLINES + 1, NCOLUMNS);
- open(CRTOut, CRT_PutChar);
- if p = nil then
- /*
- * start a new run.
- */
- initialize();
- getParameters();
- initializeOcean();
- else
- /*
- * restore a run from a save file.
- */
- if not open(restore, File, p) then
- writeln("*** Can't open restore file ",
- p, " - aborting. ***");
- CRT_Abort();
- fi;
- read(restore; NFish, NSharks, SBreed, FBreed, Starve, Ocean, Time);
- close(restore);
- restoreOcean();
- fi;
- if Logging then
- if not FileDestroy("wator.log") then fi;
- if not FileCreate("wator.log") then
- writeln("*** Can't create log file wator.log - aborting. ***");
- CRT_Abort();
- fi;
- open(LogOut, File, "WATOR.LOG");
- writeln(LogOut; NSharks, ' ', NFish);
- fi;
- while (NFish ~= 0 or NSharks ~= 0) and not CRT_GotChar() do
- updateFish();
- updateSharks();
- updateDisplay();
- od;
- if Logging then
- close(LogOut);
- fi;
- while
- CRT_ClearLine(NLINES);
- CRT_PutChars("File to save to (<CR> to abandon run): ");
- CRT_GetLine(&buffer[0], 15);
- p := &buffer[0];
- while p* = ' ' do
- p := p + 1;
- od;
- CRT_ClearLine(NLINES - 1);
- if p* = '\e' then
- CRT_PutChars("Run abandoned.");
- false
- else
- if FileDestroy(p) then fi;
- if FileCreate(p) then
- open(save, File, p);
- write(save; NFish, NSharks, SBreed, FBreed, Starve,
- Ocean, Time);
- close(save);
- CRT_PutChars("Run saved.");
- false
- else
- write(CRTOut; "*** Can't create save file ", p, ". ***");
- true
- fi
- fi
- do
- od;
- CRT_Terminate();
- corp;
-