Robots

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
}

Output:

████████████████████████████████████████████████████████████████████████████████████████████████████
█                                                                                                  █
█                                               ☗                                                  █
█                                 ☢☢                                                               █
█                             †    ☢       ☢                                  ☢                    █
█          ☢                  ☢☢☢☢☢☢                                                               █
█       ☢☢☢☢☢☢☢                ☢☢☢☢☢☢☢                                                             █
█               ☢☢☢☢           ☢  ☢☢                              ☢☢☢                              █
█             ☢☢☢☢☢               ☢☢                                                               █
█            ☢☢☢☢☢☢☢☢             ☢☢☢                        ☢☢☢                                   █
█             ☢ ☢☢☢☢                ☢                                                              █
█              ☢☢☢                                                                                 █
█                                              ☗                                                   █
█               ☢☢☢ ☢                                                                              █
█               ☢☢☢☢☢☢                                                                             █
█                ☢☢☢☢☢☢☢☢                                                                          █
█               ☢☢☢☢☢☢ ☢☢                                                                          █
█               ☢☢☢☢☢☢☢☢                   ☗                                                       █
█               ☢☢☢☢☢☢☢      ☢                                 ☢                                   █
█                 ☢☢ ☢       ☢☢                                                                    █
█                  ☢ ☢       ☢         ☢☢                                                          █
█                 ☢☢                   ☢                                                           █
█           ☢                          ☢                                                           █
█           ☢                                                                                      █
█           ☢                                                                                      █
█                                                                                                  █
█                                                                        ☢                      ☢  █
█                                                                                                  █
█                                                                                                  █
█                                                                                                  █
█                                                                                             ☢    █
█                                                                             ☢             ☢      █
█                                                        ☢                                         █
█                                                                                                  █
█                                                                                                  █
█                                           ☢☢                                                     █
█                                           ☢                                                      █
█                                                                                                  █
█            ☢☢                                                                                    █
████████████████████████████████████████████████████████████████████████████████████████████████████
Survived 117 bots, but succumbed in the end.