123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185 |
- #!/usr/bin/perl
- # Author: Daniel "Trizen" Șuteu
- # License: GPLv3
- # Date: 25 June 2015
- # Website: https://github.com/trizen
- # The snake game. (with colors + Unicode)
- use utf8;
- use 5.010;
- use strict;
- use warnings;
- 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'};
- 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),
- };
- my $sleep = 0.05; # sleep duration between displays
- my $food_num = 1; # number of initial food sources
- 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() for (1 .. $food_num);
- sub display {
- print $r, join(
- "\n",
- map {
- join(
- "",
- map {
- my $t = $_->[0];
- my $p = $_->[1] // '';
- my $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);
- }
- if ($key eq "\e[A" and $dir ne DOWN ) { $dir = UP }
- elsif ($key eq "\e[B" and $dir ne UP ) { $dir = DOWN }
- elsif ($key eq "\e[C" and $dir ne LEFT ) { $dir = RIGHT }
- elsif ($key eq "\e[D" and $dir ne RIGHT) { $dir = LEFT }
- }
|