Robots
This page uses content from Wikipedia. The original article was at Robots_(1984_video_game). The list of authors can be seen in the page history. As with Rosetta Code, the text of Wikipedia is available under the GNU FDL. (See links for details on variance) |
The task is to implement a clone of Ken Arnold's turn-based game Robots.
Simple game where its only objective is to escape from a number of robots, which have been programmed to kill the player.
C++
See Robots/C++.
Common Lisp
See Robots/Common Lisp.
FreeBASIC
#include "windows.bi"
Const WID = 62, HEI = 42, INC = 10
Type coordenada
As Short x, y
Declare Constructor (x As Short = 0, y As Short = 0)
Declare Sub set (x As Short, y As Short)
End Type
Constructor coordenada (x As Short, y As Short)
this.set(x, y)
End Constructor
Sub coordenada.set (x As Short, y As Short)
this.x = x
this.y = y
End Sub
Type winConsole
As HANDLE conOut, conIn
Declare Static Function getInstance() As winConsole Ptr
Declare Sub showCursor (s As Boolean)
Declare Sub setColor (clr As Ushort)
Declare Sub setCursor (p As coordenada)
Declare Sub setSize (w As Integer, h As Integer)
Declare Sub flush ()
Declare Sub Kill ()
Private:
Declare Constructor ()
End Type
Constructor winConsole ()
conOut = GetStdHandle(STD_OUTPUT_HANDLE)
conIn = GetStdHandle(STD_INPUT_HANDLE)
showCursor(False)
End Constructor
Dim Shared As winConsole Ptr inst = 0
Function winConsole.getInstance() As winConsole Ptr
If inst = 0 Then inst = New winConsole()
Return inst
End Function
Sub winConsole.showCursor (s As Boolean)
Dim As CONSOLE_CURSOR_INFO ci = (1, s)
SetConsoleCursorInfo(conOut, @ci)
End Sub
Sub winConsole.setColor (clr As Ushort)
SetConsoleTextAttribute(conOut, clr)
End Sub
Sub winConsole.setCursor (p As coordenada)
Dim As COORD Pos = (p.x, p.y)
SetConsoleCursorPosition(conOut, Pos)
End Sub
Sub winConsole.setSize (w As Integer, h As Integer)
Dim As COORD crd = (w + 1, h + 1)
SetConsoleScreenBufferSize(conOut, crd)
Dim As SMALL_RECT rc = (0, 0, WID, HEI)
SetConsoleWindowInfo(conOut, True, @rc)
End Sub
Sub winConsole.flush ()
FlushConsoleInputBuffer(conIn)
End Sub
Sub winConsole.kill ()
Delete inst
End Sub
Type robots
As winConsole Ptr console
As Ubyte brd(WID * HEI)
As Integer robotsCount, score, aliveRobots
As coordenada cursor
As Boolean alive
Declare Constructor ()
Declare Destructor ()
Declare Sub play ()
Private:
Declare Sub clearBoard ()
Declare Sub createBoard ()
Declare Sub displayBoard ()
Declare Sub getInput ()
Declare Sub teleport ()
Declare Sub printScore ()
Declare Sub execute (x As Integer, y As Integer)
Declare Sub waitForEnd ()
Declare Sub moveRobots ()
Declare Sub checkCollision (x As Integer, y As Integer)
End Type
Constructor robots ()
console = winConsole.getInstance()
console->setSize(WID, HEI)
End Constructor
Destructor robots ()
console->Kill()
End Destructor
Sub robots.play ()
Dim As String*1 KBD
Do
console->showCursor(False)
robotsCount = 10
score = 0
alive = True
clearBoard()
cursor.set(Rnd * (WID - 2) + 1, Rnd * (HEI - 2) + 1)
brd(cursor.x + WID * cursor.y) = Asc("@")
createBoard()
Do
displayBoard()
getInput()
If aliveRobots = 0 Then
robotsCount += INC
clearBoard()
brd(cursor.x + WID * cursor.y) = Asc("@")
createBoard()
End If
Loop While alive
displayBoard()
console->setCursor(coordenada(0, 24))
console->setColor(&h07)
console->setCursor(coordenada(10, 8))
Print "+----------------------------------------+"
console->setCursor(coordenada(10, 9))
Print "| GAME OVER |"
console->setCursor(coordenada(10, 10))
Print "| PLAY AGAIN(Y/N) ? |"
console->setCursor(coordenada(10, 11))
Print "+----------------------------------------+"
console->setCursor(coordenada(39, 10))
console->showCursor(True)
console->flush()
Input " ", KBD
Loop Until Ucase(KBD) = "N"
End Sub
Sub robots.clearBoard ()
For y As Integer = 0 To HEI - 1
For x As Integer = 0 To WID - 1
brd(x + WID * y) = 32
If x = 0 Or x = WID - 1 Or y = 0 Or y = HEI - 1 Then
brd(x + WID * y) = Asc("#")
End If
Next
Next
End Sub
Sub robots.createBoard ()
aliveRobots = robotsCount
Dim As Integer a, b, x
For x = 0 To robotsCount - 1
Do
a = Rnd * WID
b = Rnd * HEI
Loop While brd(a + WID * b) <> 32
brd(a + WID * b) = Asc("+")
Next
printScore()
End Sub
Sub robots.displayBoard ()
Dim As Ubyte t
console->setCursor(coordenada())
For y As Integer = 0 To HEI - 1
For x As Integer = 0 To WID - 1
t = brd(x + WID * y)
Select Case As Const t
Case 32: console->setColor(&h00)
Case Asc("#"): console->setColor(&h09)
Case Asc("+"): console->setColor(&h0e)
Case Asc("Å"), Asc("*"): console->setColor(&h0c)
Case Asc("@"): console->setColor(&h0a)
End Select
Print Chr(t);
Next
Print
Next
End Sub
Sub robots.getInput ()
Do
If (GetAsyncKeyState(Asc("Q")) And &h8000) And cursor.x > 1 And cursor.y > 1 Then
execute(-1, -1)
Exit Do
End If
If (GetAsyncKeyState(Asc("W")) And &h8000) And cursor.y > 1 Then
execute(0, -1)
Exit Do
End If
If (GetAsyncKeyState(Asc("E")) And &h8000) And cursor.x < WID - 2 And cursor.y > 1 Then
execute(1, -1)
Exit Do
End If
If (GetAsyncKeyState(Asc("A")) And &h8000) And cursor.x > 1 Then
execute(-1, 0)
Exit Do
End If
If (GetAsyncKeyState(Asc("D")) And &h8000) And cursor.x < WID - 2 Then
execute(1, 0)
Exit Do
End If
If (GetAsyncKeyState(Asc("Y")) And &h8000) And cursor.x > 1 And cursor.y < HEI - 2 Then
execute(-1, 1)
Exit Do
End If
If (GetAsyncKeyState(Asc("X")) And &h8000) And cursor.y < HEI - 2 Then
execute(0, 1)
Exit Do
End If
If (GetAsyncKeyState(Asc("C")) And &h8000) And cursor.x < WID - 2 And cursor.y < HEI - 2 Then
execute(1, 1)
Exit Do
End If
If (GetAsyncKeyState(Asc("T")) And &h8000) Then
teleport()
moveRobots()
Exit Do
End If
If (GetAsyncKeyState(Asc("Z")) And &h8000) Then
waitForEnd()
Exit Do
End If
Loop
console->flush()
printScore()
End Sub
Sub robots.teleport ()
brd(cursor.x + WID * cursor.y) = 32
cursor.x = Rnd * (WID - 2) + 1
cursor.y = Rnd * (HEI - 2) + 1
Dim As Integer x = cursor.x + WID * cursor.y
If brd(x) = Asc("*") Or brd(x) = Asc("+") Or brd(x) = Asc("~") Then
alive = False
brd(x) = Asc("Å")
Else
brd(x) = Asc("@")
End If
End Sub
Sub robots.printScore ()
console->setCursor(coordenada(0, HEI))
console->setColor(&h2a)
Print " SCORE: "; score; " "
End Sub
Sub robots.execute (x As Integer, y As Integer)
brd(cursor.x + WID * cursor.y) = 32
cursor.x += x
cursor.y += y
brd(cursor.x + WID * cursor.y) = Asc("@")
moveRobots()
End Sub
Sub robots.waitForEnd ()
While aliveRobots And alive
moveRobots()
displayBoard()
Sleep(500)
Wend
End Sub
Sub robots.moveRobots ()
Dim As Integer x, y, tx, ty
For y = 0 To HEI - 1
For x = 0 To WID - 1
If brd(x + WID * y) <> Asc("+") Then Continue For
tx = x
ty = y
If tx < cursor.x Then tx += 1 Else If tx > cursor.x Then tx -= 1
If ty < cursor.y Then ty += 1 Else If ty > cursor.y Then ty -= 1
If tx <> x Or ty <> y Then
brd(x + WID * y) = 32
If brd(tx + WID * ty) = 32 Then
brd(tx + WID * ty) = Asc("~")
Else
checkCollision(tx, ty)
End If
End If
Next
Next
For x = 0 To WID * HEI - 1
If brd(x) = Asc("~") Then brd(x) = Asc("+")
Next
End Sub
Sub robots.checkCollision (x As Integer, y As Integer)
If cursor.x = x And cursor.y = y Then
alive = False
brd(x + y * WID) = Asc("Å")
Return
End If
x = x + y * WID
If brd(x) = Asc("*") Or brd(x) = Asc("+") Or brd(x) = Asc("~") Then
If brd(x) <> Asc("*") Then
aliveRobots -= 1
score += 1
End If
brd(x) = Asc("*")
aliveRobots -= 1
score += 1
End If
End Sub
'--- Programa Principal ---
Randomize Timer
SetConsoleTitle("Robots")
Dim As robots g
g.play()
'--------------------------
Go
See Robots/Go.
J
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.
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.
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''
Java
See Robots/Java.
Julia
See Robots/Julia
Kotlin
See Robots/Kotlin.
Phix
See Robots/Phix.
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(†).
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;
}
}
multi move ('down') {
if @scr[$me + $x] ne $wall {
expire() if @scr[$me + $x] ne $blank;
@scr[$me] = $blank;
$me = $me + $x;
@scr[$me] = $human;
}
}
multi move ('left') {
if @scr[$me - 1] ne $wall {
expire() if @scr[$me - 1] ne $blank;
@scr[$me] = $blank;
$me = $me - 1;
@scr[$me] = $human;
}
}
multi move ('right') {
if @scr[$me + 1] ne $wall {
expire() if @scr[$me + 1] ne $blank;
@scr[$me] = $blank;
$me = $me + 1;
@scr[$me] = $human;
}
}
sub newbots {
for ^$numbots {
my $s = (^$x*$y).pick;
if @scr[$s] eq $blank {
@scr[$s] = $robot;
} else {
redo
}
}
}
sub movebots {
my $mx = $me % $x;
my $my = $me div $x;
my @bots = @scr.grep: * eq $robot, :k;
for @bots -> $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;
}
my $n = $by * $x + $bx;
if @scr[$n] eq $robot {
@scr[$b] = @scr[$n] = $block;
} elsif @scr[$n] eq $block {
@scr[$b] = $block;
} elsif $n == $me {
expire()
} else {
@scr[$b] = $blank;
@scr[$n] = $robot;
}
}
unless +@bots > 0 {
newbots();
$score += $numbots;
}
$info = $score + $numbots - @scr.grep: * eq $robot;
}
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
}
- Sample game:
████████████████████████████████████████████████████████████████████████████████████████████████████ █ █ █ ☗ █ █ ☢☢ █ █ † ☢ ☢ ☢ █ █ ☢ ☢☢☢☢☢☢ █ █ ☢☢☢☢☢☢☢ ☢☢☢☢☢☢☢ █ █ ☢☢☢☢ ☢ ☢☢ ☢☢☢ █ █ ☢☢☢☢☢ ☢☢ █ █ ☢☢☢☢☢☢☢☢ ☢☢☢ ☢☢☢ █ █ ☢ ☢☢☢☢ ☢ █ █ ☢☢☢ █ █ ☗ █ █ ☢☢☢ ☢ █ █ ☢☢☢☢☢☢ █ █ ☢☢☢☢☢☢☢☢ █ █ ☢☢☢☢☢☢ ☢☢ █ █ ☢☢☢☢☢☢☢☢ ☗ █ █ ☢☢☢☢☢☢☢ ☢ ☢ █ █ ☢☢ ☢ ☢☢ █ █ ☢ ☢ ☢ ☢☢ █ █ ☢☢ ☢ █ █ ☢ ☢ █ █ ☢ █ █ ☢ █ █ █ █ ☢ ☢ █ █ █ █ █ █ █ █ ☢ █ █ ☢ ☢ █ █ ☢ █ █ █ █ █ █ ☢☢ █ █ ☢ █ █ █ █ ☢☢ █ ████████████████████████████████████████████████████████████████████████████████████████████████████ Survived 117 bots, but succumbed in the end.
Wren
See Robots/Wren.