Robots: Difference between revisions

4,699 bytes added ,  1 year ago
m
syntax highlighting fixup automation
m (syntax highlighting fixup automation)
 
(23 intermediate revisions by 9 users not shown)
Line 1:
{{draft task|Games}}{{wikipedia|robots_Robots_(video_game1984_video_game)}}
 
<br>
The task is to implement a clone of Ken Arnold's turn-based game [[wp:Robots_(video_game)|Robots]].
The task is to implement a clone of Ken Arnold's turn-based game [[wp:Robots_(1984_video_game)|Robots]].
Simple game where its only objective is to escape from a number of robots, which have been programmed to kill the player.
 
Simple game where its only objective is to escape from a number of robots, which have been programmed to kill the player.
<br><br>
 
=={{header|C++}}==
Windows Console implementation - No safe teleport is implemeted, just the random one.
[[File:robotsCpp.png|200px|thumb|right]]
<lang cpp>
#include <windows.h>
#include <iostream>
#include <ctime>
 
See [[Robots/C++]].
const int WID = 62, HEI = 42, INC = 10;
 
=={{header|Common Lisp}}==
class coord : public COORD {
 
public:
See [[Robots/Common Lisp]].
coord( short x = 0, short y = 0 ) { set( x, y ); }
 
void set( short x, short y ) { X = x; Y = y; }
=={{header|Go}}==
};
 
class winConsole {
See [[Robots/Go]].
public:
 
static winConsole* getInstamnce() {
=={{header|J}}==
if( 0 == inst ) {
 
inst = new winConsole();
This approximately emulates the bsd robots game. There's a few differences (the game board is larger and has an explicitly displayed junk border, to quit early you close the window, ...), but the fundamental mechanics and display should be pretty close.
}
 
return inst;
We use two callbacks here: 'game_handler' to capture keyboard events, and 'sys_timer_z_' to capture timer events when the user uses the 'wait for game over' option.
 
<syntaxhighlight lang="j">require'~addons/ide/qt/gl2.ijs'
coinsert'jgl2'
 
move_handler=: {{
if. 'char'-:systype do.wd'timer 0'
select.{.tolower sysdata
case.'y'do.move _1 _1
case.'k'do.move 0 _1
case.'u'do.move 1 _1
case.'h'do.move _1 0
case.' 'do.move 0 0
case.'l'do.move 1 0
case.'b'do.move _1 1
case.'j'do.move 0 1
case.'n'do.move 1 1
case.'w'do.giveup''
case.'t'do.teleport''
end.
end.
}}
 
Directions=:({.~ i.&'0'){{)n
Directions:
 
y k u
\|/
h- -l
/|\
b j n
 
Commands:
 
w: wait for end
t: teleport
 
Legend:
 
+: robot
*: junk heap
@: you
 
Score: 0
}}
 
query_handler=: {{game_handler=: m&{{if.'char'-:systype do.x`]@.('ny'i.{.sysdata)0 end.}}}}
teleport=: {{move (dim#:?*/dim)-player}}
start=: {{initlevel 1[score=: 0}}
advance=: {{initlevel level+1}}
color=: [ gltextcolor@glrgb@{{<.0.5+255*y}}
at=: (gltext@[ [ gltextxy@])"1
dim=: 110 72
has=: +./ .=
 
showscore=: {{
t=. ];._2 LF,~Directions,":y
t at"_1] 1130,.14*2+i.#t
botrow=. I. '+' e."1 >t
'+' at 1130,14*2+botrow color 1 0 0
'*' at 1130,14*3+botrow color 1 0 1*0.5
'@' at 1130,14*4+botrow color 0 1 0.75
}}
 
initlevel=: {{
game_handler=: move_handler
junk=:(#~ has&(dim-1) +. has&0)dim#:i.*/dim
'player bots'=: ({.;}.) 1+(dim-2) #: (1+10*y) ? */dim-2
drawboard level=: y
}}
 
drawboard=: {{
glclear''
glfont '"courier" 12'
showscore score color 0 0 0
'+' at 10*bots color 1 0 0
'*' at 10*junk color 1 1 0*0.5
'@' at 10*player color 0 1 0*0.75
glpaint''
}}
 
move=: {{
player=: player+y
'hazards crashes'=.(~.;1<#/.~) (2#junk),bots-*bots-"1 player
junk=: hazards#~crashes
bots=: hazards#~crashes=0
score=: level#.5 5,-#bots
drawboard''
if.player e.junk,bots do.lose''
elseif.0=#bots do.win'' end.
}}
 
lose=: {{
wd'timer 0'
glfont '"courier" 96'
game_handler=: quit`start query_handler
'Game Over' at 320 320 color 1 0 0
glfont '"courier" 24'
'Start over? (y/n)' at 480 480 color 0 0 0
}}
 
win=: {{
glfont '"courier" 96'
game_handler=: quit`advance query_handler
'You Win' at 320 320 color 0 1 0
glfont '"courier" 24'
'Continue? (y/n)' at 480 480 color 0 0 0
}}
 
giveup=: {{
sys_timer_z_=: {{move_base_ 0 0}}
wd'timer 100'
}}
 
wd'pc game closeok; setp wh 1280 720; cc chase isidraw flush;pshow'
start''</syntaxhighlight>
 
=={{header|Java}}==
 
See [[Robots/Java]].
 
=={{header|Julia}}==
 
See [[Robots/Julia]]
 
=={{header|Kotlin}}==
 
See [[Robots/Kotlin]].
 
=={{header|Phix}}==
 
See [[Robots/Phix]].
 
=={{header|Raku}}==
(formerly Perl 6)
The bots single-mindedly chase you, taking the shortest path, ignoring obstacles. Use arrow keys to navigate your character(╂) around the board. Avoid bots(☗) and hazards(☢). "Kill" bots by causing them to crash into hazards or other bots. A dead bot creates another hazard. If you eliminate all of the bots on the board, another wave will spawn in random positions. If you touch a hazard or are touched by a bot, you die(†).
<syntaxhighlight lang="raku" line>use Term::termios;
 
constant $saved = Term::termios.new(fd => 1).getattr;
constant $termios = Term::termios.new(fd => 1).getattr;
# raw mode interferes with carriage returns, so
# set flags needed to emulate it manually
$termios.unset_iflags(<BRKINT ICRNL ISTRIP IXON>);
$termios.unset_lflags(< ECHO ICANON IEXTEN ISIG>);
$termios.setattr(:DRAIN);
 
# reset terminal to original settings and clean up on exit
END { $saved.setattr(:NOW); print "\e[?25h\n" }
 
print "\e[?25l"; # hide cursor
 
my %dir = (
"\e[A" => 'up',
"\e[B" => 'down',
"\e[C" => 'right',
"\e[D" => 'left',
);
 
my $x = 100; # nominal "board" width
my $y = 40; # nominal "board" height
 
my $human = "\e[0;92m╂\e[0m"; # various
my $robot = "\e[0;91m☗\e[0m"; # entity
my $block = "\e[0;93m☢\e[0m"; # sprite
my $dead = "\e[1;37m†\e[0m"; # characters
my $wall = "\e[1;96m█\e[0m";
my $blank = ' ';
 
my $numbots = 10; # number of bots in each round
 
# blank playing field
my @scr = flat $wall xx $x, ($wall, $blank xx $x - 2, $wall) xx $y - 2, $wall xx $x;
 
# put player on board
my $me;
loop {
$me = ($x+2 .. ($x - 1 ) * $y).roll;
last if @scr[$me] eq $blank;
}
@scr[$me] = $human;
 
# Put an assortment of hazards on board
for ^20 {
my $s = (^$x*$y).pick;
if @scr[$s] eq $blank { @scr[$s] = $block } else { redo }
}
 
my $info = 0;
my $score = 0;
 
newbots(); # populate board with a fresh wave of bots
 
loop {
print "\e[H\e[J";
print "\e[H";
print join "\n", @scr.rotor($x)».join;
print "\nSurvived " , $info , ' bots';
 
# Read up to 4 bytes from keyboard buffer.
# Page navigation keys are 3-4 bytes each.
# Specifically, arrow keys are 3.
my $key = $*IN.read(4).decode;
 
move %dir{$key} if so %dir{$key};
movebots();
last if $key eq 'q'; # (q)uit
}
 
proto sub move (|) {*};
 
multi move ('up') {
if @scr[$me - $x] ne $wall {
expire() if @scr[$me - $x] ne $blank;
@scr[$me] = $blank;
$me = $me - $x;
@scr[$me] = $human;
}
}
void showCursor( bool s ) {
multi move ('down') {
CONSOLE_CURSOR_INFO ci = { 1, s };
if @scr[$me + $x] ne $wall {
SetConsoleCursorInfo( conOut, &ci );
expire() if @scr[$me + $x] ne $blank;
@scr[$me] = $blank;
$me = $me + $x;
@scr[$me] = $human;
}
}
void setColor( WORD clr ) { SetConsoleTextAttribute( conOut, clr ); }
multi move ('left') {
void setCursor( coord p ) { SetConsoleCursorPosition( conOut, p ); }
if void@scr[$me setSize(- int1] w,ne int h )$wall {
coord crdexpire() wif +@scr[$me - 1,] hne + 1 )$blank;
SetConsoleScreenBufferSize(@scr[$me] conOut,= crd )$blank;
SMALL_RECT rc$me = {$me 0,- 0, WID, HEI }1;
SetConsoleWindowInfo(@scr[$me] conOut,= TRUE, &rc )$human;
}
}
void flush() { FlushConsoleInputBuffer( conIn ); }
 
void kill() { delete inst; }
multi move ('right') {
private:
if @scr[$me + 1] ne $wall {
winConsole() { conOut = GetStdHandle( STD_OUTPUT_HANDLE );
expire() if @scr[$me + 1] ne $blank;
conIn = GetStdHandle( STD_INPUT_HANDLE ); showCursor( false ); }
@scr[$me] = $blank;
static winConsole* inst;
$me = $me + 1;
HANDLE conOut, conIn;
@scr[$me] = $human;
};
class robots {
public:
robots() {
console = winConsole::getInstamnce();
console->setSize( WID, HEI );
}
}
~robots() { console->kill(); }
 
void play() {
sub newbots {
char g; do {
for ^$numbots {
console->showCursor( false );
my $s = (^$x*$y).pick;
robotsCount = 10; score = 0; alive = true;
if @scr[$s] eq $blank {
clearBoard(); cursor.set( rand() % ( WID - 2 ) + 1, rand() % ( HEI - 2 ) + 1 );
brd@scr[cursor.X + WID * cursor.Y$s] = '@'; createBoard()$robot;
} else do{
displayBoard(); getInput(); redo
if( !aliveRobots ) {
robotsCount += INC; clearBoard();
brd[cursor.X + WID * cursor.Y] = '@'; createBoard();
}
} while( alive );
displayBoard(); console->setCursor( coord( 0, 24 ) ); console->setColor( 0x07 );
console->setCursor( coord( 10, 8 ) );
std::cout << "+----------------------------------------+";
console->setCursor( coord( 10, 9 ) );
std::cout << "| GAME OVER |";
console->setCursor( coord( 10, 10 ) );
std::cout << "| PLAY AGAIN(Y/N)? |";
console->setCursor( coord( 10, 11 ) );
std::cout << "+----------------------------------------+";
console->setCursor( coord( 39, 10 ) ); console->showCursor( true );
console->flush(); std::cin >> g;
} while( g == 'Y' || g == 'y' );
}
private:
void clearBoard() {
for( int y = 0; y < HEI; y++ ) {
for( int x = 0; x < WID; x++ ) {
brd[x + WID * y] = 32;
if( x == 0 || x == WID - 1 || y == 0 || y == HEI - 1 )
brd[x + WID * y] = '#';
}
}
}
}
void createBoard() {
 
aliveRobots = robotsCount;
sub movebots {
int a, b; for( int x = 0; x < robotsCount; x++ ) {
my $mx = $me % do {$x;
my $my = $me div $x;
a = rand() % WID; b = rand() % HEI;
my @bots = } while( brd[a + WID@scr.grep: * b] !=eq 32$robot, ):k;
for @bots -> $b {
brd[a + WID * b] = '+';
my $bx = $b % $x;
my $by = $b div $x ;
if ($mx - $bx).abs < ($my - $by).abs {
$by += ($my - $by) < 0 ?? -1 !! 1;
} else {
$bx += ($mx - $bx) < 0 ?? -1 !! 1;
}
printScore()my $n = $by * $x + $bx;
if @scr[$n] eq $robot {
}
@scr[$b] = @scr[$n] = $block;
void displayBoard() {
char} t;elsif console->setCursor(@scr[$n] coord()eq );$block {
for( int y = 0;@scr[$b] y= < HEI$block; y++ ) {
} elsif for( int x$n == 0; x < WID; x++ )$me {
t = brd[x + WID * y];expire()
} switch( t )else {
@scr[$b] = case ' ': console->setColor( 0x00 ); break$blank;
@scr[$n] = case '#': console->setColor( 0x09 ); break$robot;
case '+': console->setColor( 0x0e ); break;
case 'Å': case '*': console->setColor( 0x0c ); break;
case '@': console->setColor( 0x0a );
}
std::cout << t;
}
std::cout << "\n";
}
}
voidunless getInput()+@bots {> 0 {
whilenewbots( 1 ) {;
$score += $numbots;
if( ( GetAsyncKeyState( 'Q' ) & 0x8000 ) && cursor.X > 1 && cursor.Y > 1 )
{ execute( -1, -1 ); break; }
if( ( GetAsyncKeyState( 'W' ) & 0x8000 ) && cursor.Y > 1 )
{ execute( 0, -1 ); break; }
if( ( GetAsyncKeyState( 'E' ) & 0x8000 ) && cursor.X < WID - 2 && cursor.Y > 1 )
{ execute( 1, -1 ); break; }
if( ( GetAsyncKeyState( 'A' ) & 0x8000 ) && cursor.X > 1 )
{ execute( -1, 0 ); break; }
if( ( GetAsyncKeyState( 'D' ) & 0x8000 ) && cursor.X < WID - 2 )
{ execute( 1, 0 ); break; }
if( ( GetAsyncKeyState( 'Y' ) & 0x8000 ) && cursor.X > 1 && cursor.Y < HEI - 2 )
{ execute( -1, 1 ); break; }
if( ( GetAsyncKeyState( 'X' ) & 0x8000 ) && cursor.Y < HEI - 2 )
{ execute( 0, 1 ); break; }
if( ( GetAsyncKeyState( 'C' ) & 0x8000 ) && cursor.X < WID - 2 && cursor.Y < HEI - 2 )
{ execute( 1, 1 ); break; }
if( ( GetAsyncKeyState( 'T' ) & 0x8000 ) )
{ teleport(); moveRobots(); break; }
if( ( GetAsyncKeyState( 'Z' ) & 0x8000 ) )
{ waitForEnd(); break; }
}
console->flush(); printScore();
}
void teleport() {
brd[cursor.X + WID * cursor.Y] = 32;
cursor.X = rand() % ( WID - 2 ) + 1;
cursor.Y = rand() % ( HEI - 2 ) + 1;
int x = cursor.X + WID * cursor.Y;
if( brd[x] == '*' || brd[x] == '+' || brd[x] == '~' ) {
alive = false; brd[x] = 'Å';
} else brd[x] = '@';
}
$info = $score + $numbots - @scr.grep: * eq $robot;
void printScore() {
console->setCursor( coord( 0, HEI ) ); console->setColor( 0x2a );
std::cout << " SCORE: " << score << " ";
}
void execute( int x, int y ) {
brd[cursor.X + WID * cursor.Y] = 32; cursor.X += x; cursor.Y += y;
brd[cursor.X + WID * cursor.Y] = '@'; moveRobots();
}
void waitForEnd() {
while( aliveRobots && alive ) {
moveRobots(); displayBoard(); Sleep( 500 );
}
}
void moveRobots() {
int tx, ty;
for( int y = 0; y < HEI; y++ ) {
for( int x = 0; x < WID; x++ ) {
if( brd[x + WID * y] != '+' ) continue;
tx = x; ty = y;
if( tx < cursor.X ) tx++; else if( tx > cursor.X ) tx--;
if( ty < cursor.Y ) ty++; else if( ty > cursor.Y ) ty--;
if( tx != x || ty != y ) {
brd[x + WID * y] = 32;
if( brd[tx + WID * ty] == 32 ) brd[tx + WID * ty] = '~';
else checkCollision( tx, ty );
}
}
}
for( int x = 0; x < WID * HEI; x++ ) {
if( brd[x] == '~') brd[x] = '+';
}
}
void checkCollision( int x, int y ) {
if( cursor.X == x && cursor.Y == y ) {
alive = false; brd[x + y * WID] = 'Å'; return;
}
x = x + y * WID;
if( brd[x] == '*' || brd[x] == '+' || brd[x] == '~' ) {
if( brd[x] != '*' ) { aliveRobots--; score++; }
brd[x] = '*'; aliveRobots--; score++;
}
}
winConsole* console; char brd[WID * HEI];
int robotsCount, score, aliveRobots;
coord cursor; bool alive;
};
winConsole* winConsole::inst = 0;
int main( int argc, char* argv[] ) {
srand( ( unsigned )time( 0 ) );
SetConsoleTitle( "Robots" );
robots g; g.play(); return 0;
}
 
</lang>
sub expire {
@scr[$me] = $dead;
print "\e[H\e[J";
print "\e[H";
print join "\n", @scr.rotor($x)».join;
print "\nSurvived " , $info , ' bots, but succumbed in the end.';
exit
}</syntaxhighlight>
{{out|Sample game}}
<pre>████████████████████████████████████████████████████████████████████████████████████████████████████
█ █
█ ☗ █
█ ☢☢ █
█ † ☢ ☢ ☢ █
█ ☢ ☢☢☢☢☢☢ █
█ ☢☢☢☢☢☢☢ ☢☢☢☢☢☢☢ █
█ ☢☢☢☢ ☢ ☢☢ ☢☢☢ █
█ ☢☢☢☢☢ ☢☢ █
█ ☢☢☢☢☢☢☢☢ ☢☢☢ ☢☢☢ █
█ ☢ ☢☢☢☢ ☢ █
█ ☢☢☢ █
█ ☗ █
█ ☢☢☢ ☢ █
█ ☢☢☢☢☢☢ █
█ ☢☢☢☢☢☢☢☢ █
█ ☢☢☢☢☢☢ ☢☢ █
█ ☢☢☢☢☢☢☢☢ ☗ █
█ ☢☢☢☢☢☢☢ ☢ ☢ █
█ ☢☢ ☢ ☢☢ █
█ ☢ ☢ ☢ ☢☢ █
█ ☢☢ ☢ █
█ ☢ ☢ █
█ ☢ █
█ ☢ █
█ █
█ ☢ ☢ █
█ █
█ █
█ █
█ ☢ █
█ ☢ ☢ █
█ ☢ █
█ █
█ █
█ ☢☢ █
█ ☢ █
█ █
█ ☢☢ █
████████████████████████████████████████████████████████████████████████████████████████████████████
Survived 117 bots, but succumbed in the end.</pre>
 
=={{header|Wren}}==
 
See [[Robots/Wren]].
10,327

edits