ASCII Interface for Games

May 16, 2011 / By Yanick Champoux

Tags: , ,

Although the quantity of tuits I have for them are measured in Planck time, I still think about games I would like to hack together. One of them I already discussed last year, and another would be a cross between Space Hulk, nethack and the X-Com series.

Since I have so little time to devote to those pet projects, and because I’m no graphical interface ninja (I dabbled with perl/tk, true, but that was many moons ago), I’ve looked for ways to ease off the burden of the UI. In the blog entry about the spaceships battle game, I’ve mentioned leveraging browsers, SVG and good ol’ AJAX, but lately I thought of another alternative. Why not try an ASCII interface? Obviously, it served nethack and its ilk very well, and Dwarf Fortress is proof that new insane things can still be done with nothing but colors and character sets. Although, to be perfectly honest, DF is a wee bit too hardcore for me. But then, a long, long time ago, I said the same thing about vim, and look at me now. Anyway…

So, that thought make me look into possible ASCII modules on CPAN. Term::Caca, an interface to the regrettably-named but quite excellent libcaca, seemed to have a lot of potential, so I tried to install it and, oh darn, found it wasn’t compatible with the latest versions of the library. Nothing that a small patch couldn’t solve. Happy about it, I sent the patch to its maintainer, John Beppu. What happened next ties nicely to my blog entry about the consequences of contributing to other peeps’s modules, and is an excellent example of the harsh, strict, cold, hard-ball playing, process-oriented ways CPAN authors usually adopt. To wit, not 24 hours after submitting the patch, John and I had an exchange that wasn’t too far from:

John: Thanks for the patch! Hey, I haven't had much time to devote
        to Term::Caca lately, wanna become its prime maintainer?
Me:   Uh, sure.
John: There you go. Have fun.

Indeed, there I went. On my journey to get my UIs done in a quick and dirty way, I ended up the maintainer of yet another module. One more proof that Fate works in mysterious ways. :-)

As the best way to get a feel for a module is to work with it, I decided to try my hand at a small, unassuming maze game. For the maze creation itself, I used Games::Maze, and with that out of the way, the resulting program turned out to be quite simple:

#!/usr/bin/perl

use 5.12.0;

use Games::Maze;
use Term::Caca;
use Term::Caca::Constants qw/ :all /;

my $term = Term::Caca->new;

$term->set_window_title( 'maze' );

my $w = $term->get_width;
my $h = $term->get_height;

# generate the maze
my $maze = Games::Maze->new(
    dimensions => [ ($w-1)/3, ($h-1)/2 , 1 ],
    entry => [1,1,1]
);
$maze->make;
my @maze = map { [ split '' ] }  split "\n", $maze->to_ascii;

# display the maze itself
$term->set_color( CACA_COLOR_LIGHTBLUE, CACA_COLOR_BLACK );
for my $x ( 0..$w ) {
    for my $y ( 0..$h ) {
        $term->putchar( $x, $y, $maze[$y][$x] );
    }
}

$term->set_color( CACA_COLOR_RED, CACA_COLOR_BLACK );

my @pos = (1,0);

while (1) {
    $term->putchar( @pos, '@' );
    $term->refresh;
    $term->putchar( @pos, '.' );

    # move using the keypad (2, 4, 6, 8)
    given ( chr( $term->wait_event( CACA_EVENT_KEY_PRESS )
                    ^ CACA_EVENT_KEY_PRESS ) ) {
        when ( 2 ) {
            if ( $pos[1] < $w and $maze[$pos[1]+1][$pos[0]] eq ' ' ) {
                $pos[1]++;
            }
        }
        when ( 8 ) {
            if ( $pos[1] > 0 and $maze[$pos[1]-1][$pos[0]] eq ' ' ) {
                $pos[1]--;
            }
        }
        when ( 4 ) {
            if ( $pos[0] > 0 and $maze[$pos[1]][$pos[0]-1] eq ' ' ) {
                $pos[0]--;
            }
        }
        when ( 6 ) {
            if ( $pos[0] < $w and $maze[$pos[1]][$pos[0]+1] eq ' ' ) {
                $pos[0]++;
            }
        }
    }
    $term->putchar( @pos, '@' );
}

The result is basic (and Games::Maze seems to fail to create a maze from time to time), but quite playable:

maze screenshot

2 Responses to “ASCII Interface for Games”

  • Gwen Shapira says:

    No good did ever goes unpunished.

    Congrats on adopting a new module :)

    • > No good did ever goes unpunished.

      Some would even argue that a good deed is its own punishment. ;-)

      > Congrats on adopting a new module :)

      Thanks. Which reminds me that I have to get crackin’ on DBD::Oracle. I’ll probably poke the list on an item or two later today. >:-)

Leave a Reply

  • (will not be published)

XHTML: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>