Jump to content

Robots

From Rosetta Code
Robots is a draft programming task. It is not yet considered ready to be promoted as a complete task, for reasons that should be found in its talk page.
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

Translation of: C++
#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.

Cookies help us deliver our services. By using our services, you agree to our use of cookies.