Exercise: Another Game, Maze

Previous Table of Contents Next

Exercise: Another Game, Maze

After learning so many newand strange concepts—references and structures—you deserve a little diversion. The following exercise demonstrates a structure and a few references by allowing you to play a simple game.

In the manner of classic games such as Adventure, Zork, and Hunt the Wumpus, you will be placed in a maze from which you must find your way out. The maze is featureless, consisting of only rooms with at least one doorway. The doorways lead to adjacent rooms to the north, south, east, or west. The object is to find the secret room. You'll soon learn, however, that only a couple of paths actually lead to that room; there are many dead-end paths.

To get started, type Listing 13.1 and save it as Maze. Running the program gives output similar to Listing 13.2.

Listing 13.1. The Complete Listing for Maze

1:   #!/usr/bin/perl -w

2:   use strict;


4:   my @maze=(

5:        [ qw( e   swe we ws  ) ],

6:        [ qw( se new sw ns ) ],

7:        [ qw( ns  -      ns n  ) ],

8:        [ qw( ne w     ne w   ) ],

9:   );

10:  my %direction=( n=> [ -1, 0], s=> [1,  0],

11:      e=> [  0, 1], w=> [0, -1]);


13:  my %full=( e => 'East', n => 'North', w=>'West', s=>'South');

14:  my($curr_x, $curr_y, $x, $y)=(0,0,3,3);

15:  my $move;


17:  sub disp_location {

18:      my($cx, $cy)=@_;

19:      print "You may move ";

20:      while($maze[$cx][$cy]=~/([nsew])/g) {

21:           print "$full{$1} ";

22:      }

23:      print "($maze[$cx][$cy])\n";

24:  }

25:  sub move_to {

26:      my($new, $xref, $yref)=@_;


28:      $new=substr(lc($new),0,1);

29:      if ($maze[$$xref][$$yref]!~/$new/) {

30:          print "Invalid direction, $new.\n";

31:          return;

32:      }

33:      $$xref += $direction{$new}[0];

34:      $$yref += $direction{$new}[1];

35:  }


37:  until ( $curr_x == $x and $curr_y == $y ) {

38:      disp_location($curr_x, $curr_y);

39:      print "Which way? ";

40:      $move=<STDIN>; chomp $move;

41:      exit if ($move=~/^q/);

42:      move_to($move, \$curr_x, \$curr_y);

43:  }


45:  print "You made it through the maze!\n";

Lines 1–2: These lines are a normal beginning to a Perl program. Warnings are enabled with -w, and use strict is used to catch mistakes and bad programming practices.

Lines 4–9: The structure that describes the maze, @maze, is defined. The maze shown is a 4x4 grid, represented by a list of lists. Each element of the list describes which doors are available in any room in the maze, so if you redesign this maze, make sure you leave a path out! The current maze looks like this:

One room is inaccessible (2,1) and is designated by a - in the structure; actually, any string not matching n, s, e, or w would work as well.

Lines 10–11: As the player moves north, south, and so on, the current position in the maze needs to be changed. The hash %direction is used to calculate the player's new position, given the old position and direction. Moving "north" changes the player's x coordinate by –1 (going up), and the y coordinate remains unchanged. Moving "east" leaves the player's x coordinate where it is but increases the y coordinate by 1. You'll see how this is used in lines 33–34.

Lines 13–15: The variables used in the program are declared with my to make use strict happy. The player's current position—stored in $curr_x and $curr_y—is set to 0,0. The final destination—$x and $y—is set to 3,3.

Line 17: Given an x,y coordinate pair in the grid, this function displays the directions the player is allowed to move in each room.

Line 20: The letters n, s, e, and w are picked out of the room description in $maze[$cx][$cy] one letter at a time. The appropriate description for the nsew directions is displayed from the hash %full. This hash is used only for translating the short name (n) into the long name (North) for display.

Line 25: This function takes a direction (stored in $new) and references to the player's current coordinates.

Line 28: The direction is shifted to lowercase with lc, and substr takes just the first letter and assigns it to $new. Thus, East becomes e, West becomes w, and s remains s.

Line 29: The current room—$maze[$$xref][$$yref]—is searched for the direction given (n, s, e, or w). If it doesn't exist, it's not valid for this room, and a message is printed.

Lines 33–34: The player's x and y coordinates are changed. If the direction is e, then $direction{e} is a two-element array reference to (0, 1). The x coordinate would be increased by 0—$direction{e}[0]. The y coordinate would be increased by 1—$direction{e}[1].

Line 37: The main body of the program starts here. The loop will continue until the player's x and y coordinates ($curr_x, $curr_y) match the hidden room's coordinates ($x, $y).

Line 38: The "map" of the current room is displayed.

Lines 39–41: The desired direction is read into $move, and the newline character is removed with chomp. If the player types anything beginning with a q, the game ends.

Line 42: The move_to() subroutine is called with the player's current desired move and references to the player's coordinates. The move_to() subroutine moves the player appropriately by adjusting $curr_x and $curr_y.

Listing 13.2. Sample Output from Maze

You may move East (e)

Which way? e

You may move South West East (swe)

Which way? e


Which way? e

You made it through the maze!

To change the maze to have a different layout, simply change the grid stored in @maze. The maze doesn't necessarily need to be square, nor does each room need to be mapped, nor does a valid path need to exist. Remember, though, not to provide a door that would lead off the edge of the maze; the program does not check the validity of the maze, although Perl does emit warnings if you construct an invalid maze. You can move the secret room by altering the values of $x and $y.

    Previous Table of Contents Next
    © 2000- NIV