Snake: Difference between revisions

From Rosetta Code
Content added Content deleted
m (→‎{{header|Sidef}}: simpler code)
(→‎{{header|Java}}: added Java)
Line 6: Line 6:


Implement a variant of the Snake game, in any interactive environment, in which a sole player attempts to eat items by running into them with the head of the snake. Each item eaten makes the snake longer and a new item is randomly generated somewhere else on the plane. The game ends when the snake attempts to eat himself.
Implement a variant of the Snake game, in any interactive environment, in which a sole player attempts to eat items by running into them with the head of the snake. Each item eaten makes the snake longer and a new item is randomly generated somewhere else on the plane. The game ends when the snake attempts to eat himself.

=={{header|Java}}==

See [[Snake/Java]].


=={{header|Perl}}==
=={{header|Perl}}==

Revision as of 22:49, 30 March 2016

Snake 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 Snake_(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)

Snake is a game where the player maneuvers a line which grows in length every time the snake reaches a food source.

Task

Implement a variant of the Snake game, in any interactive environment, in which a sole player attempts to eat items by running into them with the head of the snake. Each item eaten makes the snake longer and a new item is randomly generated somewhere else on the plane. The game ends when the snake attempts to eat himself.

Java

See Snake/Java.

Perl

<lang perl>use utf8; use Time::HiRes qw(sleep); use Term::ANSIColor qw(colored); use Term::ReadKey qw(ReadMode ReadLine);

binmode(STDOUT, ':utf8');

use constant {

             VOID => 0,
             HEAD => 1,
             BODY => 2,
             TAIL => 3,
             FOOD => 4,
            };

use constant {

             LEFT  => [+0, -1],
             RIGHT => [+0, +1],
             UP    => [-1, +0],
             DOWN  => [+1, +0],
            };

use constant {

             BG_COLOR  => "on_black",
             SLEEP_SEC => 0.05,
            };

use constant {

             SNAKE_COLOR => ('bold green' . ' ' . BG_COLOR),
             FOOD_COLOR  => ('red'        . ' ' . BG_COLOR),
            };

use constant {

   U_HEAD => colored('▲', SNAKE_COLOR),
   D_HEAD => colored('▼', SNAKE_COLOR),
   L_HEAD => colored('◀', SNAKE_COLOR),
   R_HEAD => colored('▶', SNAKE_COLOR),
   U_BODY => colored('╹', SNAKE_COLOR),
   D_BODY => colored('╻', SNAKE_COLOR),
   L_BODY => colored('╴', SNAKE_COLOR),
   R_BODY => colored('╶', SNAKE_COLOR),
   U_TAIL => colored('╽', SNAKE_COLOR),
   D_TAIL => colored('╿', SNAKE_COLOR),
   L_TAIL => colored('╼', SNAKE_COLOR),
   R_TAIL => colored('╾', SNAKE_COLOR),
   A_VOID => colored(' ',   BG_COLOR),
   A_FOOD => colored('❇', FOOD_COLOR),
            };

local $| = 1;

my $w = eval { `tput cols` } || 80; my $h = eval { `tput lines` } || 24; my $r = "\033[H";

my @grid = map {

   [map { [VOID] } 1 .. $w]

} 1 .. $h;

my $dir = LEFT; my @head_pos = ($h / 2, $w / 2); my @tail_pos = ($head_pos[0], $head_pos[1] + 1);

$grid[$head_pos[0]][$head_pos[1]] = [HEAD, $dir]; # head $grid[$tail_pos[0]][$tail_pos[1]] = [TAIL, $dir]; # tail

sub create_food {

   my ($food_x, $food_y);
   do {
       $food_x = rand($w);
       $food_y = rand($h);
   } while ($grid[$food_y][$food_x][0] != VOID);
   $grid[$food_y][$food_x][0] = FOOD;

}

create_food();

sub display {

   my $i = 0;
   print $r, join("\n",
       map {
           join("",
               map {
                   my $t = $_->[0];
                   if ($t != FOOD and $t != VOID) {
                       my $p = $_->[1];
                       $i =
                           $p eq UP   ? 0
                         : $p eq DOWN ? 1
                         : $p eq LEFT ? 2
                         :              3;
                   }
                       $t == HEAD ? (U_HEAD, D_HEAD, L_HEAD, R_HEAD)[$i]
                     : $t == BODY ? (U_BODY, D_BODY, L_BODY, R_BODY)[$i]
                     : $t == TAIL ? (U_TAIL, D_TAIL, L_TAIL, R_TAIL)[$i]
                     : $t == FOOD ? (A_FOOD)
                     :              (A_VOID);
                 } @{$_}
               )
         } @grid
   );

}

sub move {

   my $grew = 0;
   # Move the head
   {
       my ($y, $x) = @head_pos;
       my $new_y = ($y + $dir->[0]) % $h;
       my $new_x = ($x + $dir->[1]) % $w;
       my $cell = $grid[$new_y][$new_x];
       my $t    = $cell->[0];
       if ($t == BODY or $t == TAIL) {
           die "Game over!\n";
       }
       elsif ($t == FOOD) {
           create_food();
           $grew = 1;
       }
       # Create a new head
       $grid[$new_y][$new_x] = [HEAD, $dir];
       # Replace the current head with body
       $grid[$y][$x] = [BODY, $dir];
       # Save the position of the head
       @head_pos = ($new_y, $new_x);
   }
   # Move the tail
   if (not $grew) {
       my ($y, $x) = @tail_pos;
       my $pos   = $grid[$y][$x][1];
       my $new_y = ($y + $pos->[0]) % $h;
       my $new_x = ($x + $pos->[1]) % $w;
       $grid[$y][$x][0]         = VOID;    # erase the current tail
       $grid[$new_y][$new_x][0] = TAIL;    # create a new tail
       # Save the position of the tail
       @tail_pos = ($new_y, $new_x);
   }

}

ReadMode(3); while (1) {

   my $key;
   until (defined($key = ReadLine(-1))) {
       move();
       display();
       sleep(SLEEP_SEC);
   }
   # up
   if ($key eq "\e[A") {
       $dir = UP;
   }
   # down
   elsif ($key eq "\e[B") {
       $dir = DOWN;
   }
   # right
   elsif ($key eq "\e[C") {
       $dir = RIGHT;
   }
   # left
   elsif ($key eq "\e[D") {
       $dir = LEFT;
   }

}</lang>

Sidef

<lang ruby>class SnakeGame(w, h) {

   const readkey = frequire('Term::ReadKey')
   const ansi    = frequire('Term::ANSIColor')
   enum (VOID, HEAD, BODY, TAIL, FOOD)
   define (
       LEFT  = [+0, -1],
       RIGHT = [+0, +1],
       UP    = [-1, +0],
       DOWN  = [+1, +0],
   )
   define BG_COLOR    = "on_black"
   define FOOD_COLOR  = ("red"        + " " + BG_COLOR)
   define SNAKE_COLOR = ("bold green" + " " + BG_COLOR)
   define SLEEP_SEC   = 0.02
   const (
       A_VOID  = ansi.colored(' ', BG_COLOR),
       A_FOOD  = ansi.colored('❇', FOOD_COLOR),
       A_BLOCK = ansi.colored('■', SNAKE_COLOR),
   )
   has dir = LEFT
   has grid = [[]]
   has head_pos = [0, 0]
   has tail_pos = [0, 0]
   method init {
       grid = h.of { w.of { [VOID] } }
       head_pos = [h//2, w//2]
       tail_pos = [head_pos[0], head_pos[1]+1]
       grid[head_pos[0]][head_pos[1]] = [HEAD, dir]    # head
       grid[tail_pos[0]][tail_pos[1]] = [TAIL, dir]    # tail
       self.make_food()
   }
   method make_food {
       var (food_x, food_y)
       do {
           food_x = w.rand.int
           food_y = h.rand.int
       } while (grid[food_y][food_x][0] != VOID)
       grid[food_y][food_x][0] = FOOD
   }
   method display {
       print("\033[H", grid.map { |row|
           row.map { |cell|
               given (cell[0]) {
                   when (VOID) { A_VOID }
                   when (FOOD) { A_FOOD }
                   default     { A_BLOCK }
               }
             }.join()
           }.join("\n")
       )
   }
   method move {
       var grew = false
       # Move the head
       var (y, x) = head_pos...
       var new_y = (y+dir[0] % h)
       var new_x = (x+dir[1] % w)
       var cell = grid[new_y][new_x]
       given (cell[0]) {
           when (BODY) { die "\nYou just bit your own body!\n" }
           when (TAIL) { die "\nYou just bit your own tail!\n" }
           when (FOOD) { grew = true; self.make_food()         }
       }
       # Create a new head
       grid[new_y][new_x] = [HEAD, dir]
       # Replace the current head with body
       grid[y][x] = [BODY, dir]
       # Update the head position
       head_pos = [new_y, new_x]
       # Move the tail
       if (!grew) {
           var (y, x) = tail_pos...
           var pos   = grid[y][x][1]
           var new_y = (y+pos[0] % h)
           var new_x = (x+pos[1] % w)
           grid[y][x][0]         = VOID    # erase the current tail
           grid[new_y][new_x][0] = TAIL    # create a new tail
           tail_pos = [new_y, new_x]
       }
   }
   method play {
       STDOUT.autoflush(true)
       readkey.ReadMode(3)
       try {
           loop {
               var key
               while (!defined(key = readkey.ReadLine(-1))) {
                   self.move()
                   self.display()
                   Sys.sleep(SLEEP_SEC)
               }
               given (key) {
                   when ("\e[A") { dir = UP    }
                   when ("\e[B") { dir = DOWN  }
                   when ("\e[C") { dir = RIGHT }
                   when ("\e[D") { dir = LEFT  }
               }
           }
       }
       catch {
           readkey.ReadMode(0)
       }
   }

}

var w = `tput cols`.to_i var h = `tput lines`.to_i

SnakeGame(w || 80, h || 24).play</lang>