http://www.perlmonks.org?node_id=93745
Category: Fun Stuff
Author/Contact Info Ben Jacobs <dooberwah@crosswinds.net>
Description: Plibbles is ment to be much like the clasic worm(6) game, but written in Perl. You control a worm that moves about the screent trying to eat numbers. Whenever you eat a number you grow as many segments longer as the number you ate. The object of the game is to get the hishest score by eating the most numbers without running into something.

Todo:

  • Make worm move forward every 0.25 seconds or so.
  • Document the code
  • Clean up the code

    I'm sure that this isn't the only way to do this, (hey, TMTOWTDI after all) and I'm sure the way I thought up isn't the most efficient way, but it's what I could come up with. Any comments/improvments/questions would be very welcome.

  • #!/usr/bin/perl -w
    
    use strict; 
    use Curses; 
    
    srand( time() ^ ($$ + ($$ << 15)) );
    
    my $score = 0;
    my @worm;
    for (my $i=0; $i < 8; $i++) {
        push @worm, { y => 12,
                      x => 9-$i };
    }
    
    my $w = Curses->new();
    
    noecho();
    
    my $maxy;
    my $maxx;
    $w->getmaxyx($maxy, $maxx);
    $w->clear;
    my $t = $w->subwin(1, $maxx, 0, 0);
    my $o = $w->subwin($maxy-1, $maxx, 1, 0);
    my $growing;
    my %prize;
    
    $t->addstr(0, 1, "Plibbles: A worm game in Perl");
    $t->addstr(0, $maxx-8-length($score), "Score: $score");
    $t->refresh;
    
    $o->box('|', '-');
    
    draw_worm(@worm);
    $o->move($worm[0]{y}, $worm[0]{x});
    prize();
    $o->addstr($prize{y}, $prize{x}, $prize{prize});
    $o->refresh();
    
    while(1) 
    {
        my @oldworm;
        for (my $wormlen = @worm - 1; $wormlen >= 0; $wormlen--) {
            $oldworm[$wormlen]{y} = $worm[$wormlen]{y};
            $oldworm[$wormlen]{x} = $worm[$wormlen]{x};
        }
        for (my $wormlen = @worm - 1; $wormlen > 0; $wormlen--) {
            $worm[$wormlen]{y} = $worm[$wormlen-1]{y};
            $worm[$wormlen]{x} = $worm[$wormlen-1]{x};
        }
        my $key = $o->getch();
        if ($key eq 'h') { 
            $worm[0]{x}--;
        } elsif ($key eq 'j') {
            $worm[0]{y}++;
        } elsif ($key eq 'k') {
            $worm[0]{y}--;
        } elsif ($key eq 'l') {
            $worm[0]{x}++;
        } else {
            @worm = @oldworm;
            $o->clear();
            $o->box('|', '-');
            draw_worm(@worm);
            $o->move($worm[0]{y}, $worm[0]{x});
            next;
        }
        if ($growing != 0) {
            push @worm, $oldworm[scalar(@oldworm)];
            $growing--;
        }
        $o->move($worm[0]{y}, $worm[0]{x});
        my $char = $o->inch();
        if ($char =~ /\d/) {
            $growing += $char;
            $score += $char;
            $t->addstr(0, $maxx-8-length($score), "Score: $score");
            $t->refresh();
            prize();
        }
        elsif ($char ne ' ') { 
            crash(); 
        } 
        $o->clear();
        $o->box('|', '-');
        $o->addstr($prize{y}, $prize{x}, $prize{prize});
        draw_worm(@worm);
        $o->move($worm[0]{y}, $worm[0]{x});
        $o->refresh();
    }
    endwin();
    
    sub draw_worm {
        my @worm = @_;
        my $head = shift @worm;
        $o->addstr($head->{y}, $head->{x}, '@');
        foreach my $segment (@worm) {
            $o->addstr($segment->{y}, $segment->{x}, 'o');
        }
    }
    
    sub crash {
        endwin;
        print "\nWell, you ran into something and the game is over.\n";
        print "Your final score was $score\n\n";
        exit;
    }
    
    sub prize {
        my ($a, $b);
        do {
            $a = rand($maxy-3) + 2;
            $b = rand($maxx-2) + 1;
            $o->move($a, $b);
        } while($o->inch ne ' ');
        my $v = int(rand(9) + 1);
        %prize = ( y => $a, x => $b, prize => $v );
    }
    

    Edit by tye to replace tabs with spaces

    Replies are listed 'Best First'.
    Re: Plibbles
    by agoth (Chaplain) on Jul 12, 2001 at 15:05 UTC
      I like it, but any reason you dont indent past one level?
      Is that for perlmonks formatting reasons? otherwise it just makes your code harder to follow? just curious....
      sub draw_worm { my @worm = @_; my $head = shift @worm; $o->addstr($head->{y}, $head->{x}, '@'); foreach my $segment (@worm) { $o->addstr($segment->{y}, $segment->{x}, 'o'); if ($bleh) { #stuff } } }

        FYI (where Y=y'all's), each tab in code becomes 4 spaces in my testing. I'm guessing that The Monastery does that translation.

        I've updated the root node to have spaces instead of tabs.

                - tye (but my friends call me "Tye")