RosettaCodeData/Task/Snake/XPL0/snake.xpl0

110 lines
4.5 KiB
Plaintext

def Width=40, Height=25-1, \playing area including border
StartLength = 10, \starting length of snake including head
Morsels = 10; \number of food items constantly offered
int Heading; \direction snake is heading
def Up, Down, Left, Right;
int Length, \current length of snake including head
Score; \number of food items eaten
char SnakeX(10000), \location of each segment including head
SnakeY(10000), \ample room to grow
FoodX(Morsels), FoodY(Morsels); \location of each food item
def Black, Blue, Green, Cyan, Red, Magenta, Brown, White, \attribute colors
Gray, LBlue, LGreen, LCyan, LRed, LMagenta, Yellow, BWhite; \EGA palette
proc PlaceFood(N); \Place Nth food item in playing area
int N;
[FoodX(N):= Ran(Width-3) + 1; \pick random location inside borders
FoodY(N):= Ran(Height-3) + 1;
Cursor(FoodX(N), FoodY(N)); \show food
Attrib(Red<<4+LRed);
ChOut(6, ^@);
]; \PlaceFood
int X, Y, I, C;
[SetVid($01); \set 40x25 text mode
ShowCursor(false); \turn off flashing cursor
Attrib(Blue<<4+LBlue); \show borders
Cursor(0, 0);
for X:= 0 to Width-1 do ChOut(6, ^+);
Cursor(0, Height-1);
for X:= 0 to Width-1 do ChOut(6, ^+);
for Y:= 0 to Height-1 do
[Cursor(0, Y); ChOut(6, ^+);
Cursor(Width-1, Y); ChOut(6, ^+);
];
Attrib(Black<<4+White); \show initial score
Cursor(0, 24);
Text(6, "Score: 0");
Score:= 0;
SnakeX(0):= Width/2; \start snake head at center
SnakeY(0):= Height/2;
Heading:= Left;
Length:= StartLength;
for I:= 1 to Length-1 do \segments follow head to the right
[SnakeX(I):= SnakeX(I-1) + 1;
SnakeY(I):= SnakeY(I-1);
];
for I:= 0 to Morsels-1 do PlaceFood(I); \sow some tasty food
\Continuously move snake
loop \--------------------------------------------------------------------------
[Attrib(Black<<4+White); \remove tail-end segment
Cursor(SnakeX(Length-1), SnakeY(Length-1));
ChOut(6, ^ );
Attrib(Green<<4+Yellow); \add segment at head location
Cursor(SnakeX(0), SnakeY(0));
ChOut(6, ^#);
\Shift coordinates toward tail (+1 in case a segment gets added)
for I:= Length downto 1 do \segment behind head gets head's coords
[SnakeX(I):= SnakeX(I-1);
SnakeY(I):= SnakeY(I-1);
];
if ChkKey then \key hit--get new movement direction
[repeat C:= ChIn(1) until C # 0; \remove arrow keys' prefix byte
case C of
$1B: exit; \Escape, and scan codes for arrow keys
$48: if Heading # Down then Heading:= Up;
$50: if Heading # Up then Heading:= Down;
$4B: if Heading # Right then Heading:= Left;
$4D: if Heading # Left then Heading:= Right
other []; \ignore any other keystrokes
];
case Heading of \move head to its new location
Up: SnakeY(0):= SnakeY(0)-1;
Down: SnakeY(0):= SnakeY(0)+1;
Left: SnakeX(0):= SnakeX(0)-1;
Right:SnakeX(0):= SnakeX(0)+1
other [];
Cursor(SnakeX(0), SnakeY(0)); \show head at its new location
ChOut(6, ^8);
for I:= 0 to Morsels-1 do
if SnakeX(0)=FoodX(I) & SnakeY(0)=FoodY(I) then
[Score:= Score+1; \ate a morsel
Attrib(Black<<4+White);
Cursor(7, 24);
IntOut(6, Score*10);
PlaceFood(I); \replenish morsel
Length:= Length+1; \grow snake one segment
I:= Morsels; \over eating can be bad--quit for loop
Sound(1, 1, 1500); \BURP!
Sound(1, 1, 1000);
];
if I = Morsels then Sound(0, 2, 1); \no sound adds delay of 2/18th second
if SnakeX(0)=0 or SnakeX(0)=Width-1 or
SnakeY(0)=0 or SnakeY(0)=Height-1 then
quit; \snake hit border--game over
for I:= 1 to Length-1 do
if SnakeX(0)=SnakeX(I) & SnakeY(0)=SnakeY(I) then
quit; \snake bit itself--game over
]; \loop -----------------------------------------------------------------------
for I:= 1 to 8 do Sound(1, 1, 4000*I); \death dirge
Sound(0, 36, 1); \pause 2 seconds to see result
OpenI(1); \flush any pending keystrokes
]