cdlaforc has asked for the wisdom of the Perl Monks concerning the following question:

Hello, I'm new to perl, and am trying to write an ascii game. The game will basically be a third person view of a character, and will accept users input to move the character. Basically I need a little input designing the flow of the game. I can't wait for user input by doing a blocking read, but my current code eats up memory almost right away.
#!/usr/bin/perl use Term::Info; use Term::ReadKey; use Term::Size 'chars'; ($cols, $rows) = chars; ReadMode 4; # Turn off controls keys sub userInput { $key = ReadKey(-1); if (not defined($key)) { #do nothing } elsif ($key eq "\e") { $key = ReadKey(-1); if ($key eq "[") { $key = ReadKey(-1); if ($key eq "A") { print "Forward\n"; } elsif ($key eq "B") { print "Backward\n"; } elsif ($key eq "C") { print "Right\n"; } elsif ($key eq "D") { print "Left\n"; } } } elsif ($key eq "q" or $key eq "Q") { #Change to exit function exit 0 } else { print "Get key $key\n"; } updateScreen(); } sub updateScreen { #add code to refresh screen userInput(); } #Accept user input userInput(); ReadMode 0;
Not much code because I just started, but any help on the most efficient design would be greatly appreciated. Thanks, Chris.

Replies are listed 'Best First'.
Re: Most efficient design
by almut (Canon) on May 11, 2009 at 20:42 UTC
    ...but my current code eats up memory almost right away.

    As it is, you have an endless recursion, i.e. UserInput() calls updateScreen(), which then calls userInput(), etc...  Every stack frame needs memory, which quickly adds up. And as the functions never return, the memory won't be freed.

    You probably want one main loop that's checking for user input, simply calling updateScreen() from there whenever needed  (without updateScreen() calling userInput() again...).

    Something like this  (renaming userInput to mainLoop, letting userInput just get the keys... — this is not essential, of course):

    ... sub mainLoop { while (1) { $key = userInput(); if ($key eq "...") { # do something } ... updateScreen(); } } sub userInput { #... } sub updateScreen { #add code to refresh screen } mainLoop(); ...
Re: Most efficient design
by John M. Dlugosz (Monsignor) on May 11, 2009 at 21:23 UTC
    Someone else pointed out that you have a recursion loop.

    Reading the code, I think you would benefit from given/when instead of a cascade of elsif statements.

    But... maybe you should make a hash as a keyboard mapping. This will not only make your loop simple as all the logic is elsewhere, but allow you to remap the keyboard.

    my $key = ReadKey(-1); next unless defined $key; #next or return depending on your code stru +cture if ($key eq "\e") { #expecting more $key .= ReadKey(-1); # should be a '[' $key .= ReadKey(-1); } my $callback= $keymap{$key}; if (defined $callback) { $callback->($key); } else { beep(); } #no such key is meaningful here
    That is, the gathering is centralized, and separate from the code dispatched to. The $key is passed as an argument in case you have common subs for several keys and need to distinguish between them.

    —John

Re: Most efficient design
by CountZero (Bishop) on May 12, 2009 at 06:24 UTC
    This is code which would benefit from:
    1. use strict; use warnings;
    2. Using a dispatch table: have a look at: Higher Order Perl - Dispatch Tables

    CountZero

    A program should be light and agile, its subroutines connected like a string of pearls. The spirit and intent of the program should be retained throughout. There should be neither too little or too much, neither needless loops nor useless variables, neither lack of structure nor overwhelming rigidity." - The Tao of Programming, 4.1 - Geoffrey James

Re: Most efficient design
by salva (Canon) on May 11, 2009 at 21:51 UTC
    Not Perl related, but if you want to create a conversational game, check Inform.