#!/usr/local/bin/perl
#
#############################################################################
# this program generates mazes on a text terminal and allows you to traverse 
# them. it requires the Term::ReadKey module (available from www.cpan.org) 
# to automatically size the mazes (-m flag).
#
# the current version of this program is available at:
#
# http://www.robobunny.com/projects/textmaze
#
# run textmaze -h for usage information
#
#############################################################################
# Author:
#   Kirk Baucom <kbaucom@schizoid.com>
#
# Contributors:
#   Kyle Guilbert <kguilber@coe.neu.edu>: maze solve code
#   Juan Orlandini <jorlandini@DATALINK.com>: move count, additional move keys
#
# License:
#
# Copyright (C) 2001 Kirk Baucom (kbaucom@schizoid.com)
# 
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
# 
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
#############################################################################

$SIG{'INT'} = 'quit';
$SIG{'KILL'} = 'quit';

require Term::Cap;

# 9600 bps is fast enough for anybody!
$terminal = Tgetent Term::Cap {TERM => undef, OSPEED => 9600};
$| = 1;
$VERSION = "1.0";

######## CONFIGURATION #########
# don't edit this stuff, edit your config file!
# you will have one generated for you the first time you run the program

$config_file = "$ENV{'HOME'}/.textmaze";

# our global config variable
%c = ();

# ANSI color values
%bg = (
	black	=> "40",
	red	=> "41",
	green	=> "42",
	yellow	=> "43",
	blue	=> "44",
	magenta	=> "45",
	cyan	=> "46",
	white	=> "47"
);

%fg = (
	black	=> "30",	BLACK	=> "30m",
	red	=> "31",	RED	=> "31m",
	green	=> "32",	GREEN	=> "32m",
	yellow	=> "33",	YELLOW	=> "33m",
	blue	=> "34",	BLUE	=> "34m",
	magenta	=> "35",	MAGENTA	=> "35m",
	cyan	=> "36",	CYAN	=> "36m",
	white	=> "37",	WHITE	=> "37m"
);

read_config($config_file);

# set the colors
$c{'trail'} =  "\e[" . $bg{"$c{'trail_bg'}"}  . ";" . $fg{"$c{'trail_fg'}"};
$c{'cursor'} = "\e[" . $bg{"$c{'cursor_bg'}"} . ";" . $fg{"$c{'cursor_fg'}"};
$c{'finish'} = "\e[" . $bg{"$c{'finish_bg'}"} . ";" . $fg{"$c{'finish_fg'}"};
$c{'unseen'} = "\e[" . $bg{"$c{'unseen_bg'}"} . ";" . $fg{"$c{'unseen_fg'}"};

# we want the arrow keys to always work, regardless of config file
# yes, i know these shouldn't be hard coded, but i can't get the Term::Cap
# values to work right...
# $up = $terminal->{_ku};      # up arrow
push(@{$c{'up'}}, "\e[A");      # up arrow
push(@{$c{'down'}}, "\e[B");    # down arrow
push(@{$c{'left'}}, "\e[D");    # left arrow
push(@{$c{'right'}}, "\e[C");   # right arrow

# always make ctrl-l redraw the screen
push(@{$c{'redraw'}}, chr(12));

######### END CONFIGURATION ###########

######## BEGIN INITIALIZATION #########
# what each array element is
$north = 0;
$south = 1;
$east = 2;
$west = 3;
$set = 4;
$setlist = 5;

# set values after generating maze:
$empty = 0;
$cursor_pos = -1;
$maze_end = -2;
$trail = -3;

# find the width and height of the terminal
if(-t STDOUT && eval "require Term::ReadKey") {
  import Term::ReadKey;
  ($c{'screen_width'}, $c{'screen_height'}, $junk, $junk) = GetTerminalSize('STDOUT');
  $c{'autosize'} = 1; # so we know if we can limit the max size or not
}
else {
  $c{'screen_width'} = 80;
  $c{'screen_height'} = 24;
}

if(($c{'screen_width'} < 11) || ($c{'screen_height'} < 5)) {
  help("Your terminal screen must be at least 11 x 5");
}

if(($c{'default_width'} * 2) > $c{'screen_width'}) { $c{'default_width'} = int($c{'screen_width'} / 2); }
if($c{'default_height'} +1 > $c{'screen_height'}) { $c{'default_height'} = $c{'screen_height'} - 1; }

# get the width, height, and random seed from the command line
($c{'width'}, $c{'height'}, $c{'seed'}) = getinput();

$c{'size'} = $c{'width'} * $c{'height'};

system("clear");

unless($c{'dissolve'}) { print "Initializing maze...\n"; }
initialize();  

if($c{'dissolve'}) { tty_display(); }
else { print "Generating maze...\n"; }
generate_maze();
unless($c{'dissolve'}) { system("clear"); }

tty_display();

######### END INITIALIZATION ##########


#### MAIN LOOP ####
system("stty raw -echo");
while(1) {

  $input = getc(STDIN);

  # deal with arrow keys
  if($input eq "\e") { $input .= getc(STDIN) . getc(STDIN); }

  # process the input
  move($input);    
}

############ SUBROUTINES ###############

## create the grid (although it is stored as a flat list)
sub initialize {
  my $size = $c{'size'};
  for ($i=0; $i<$size; $i++) {
      $maze[$i][$set] = $i;
      @{$maze[$i][$setlist]} = ("$i");
      $maze[$i][$north] = $maze[$i][$south] = $maze[$i][$west]
        = $maze[$i][$east] = "NULL";
  }
}

## yank walls out until we have a real maze
sub generate_maze { 
  srand($c{'seed'});
  my $cell_num;     # current cell that is being looked at
  my $dir; 	    # direction to check
  my $entry;        # where the maze starts
  my $exit;         # where the maze ends

  my $unified = 0;  # maze is finished when this is equal to the # of cells
                    # in the maze

  $c{'starttime'} = time();

  my $dissolve = $c{'dissolve'};
  my $size = $c{'size'};
  my $w = $c{'width'}; my $h = $c{'height'};

  while($unified < $size -1) {
    $cell_num = int(rand($size)); #pick a cell
    $dir= int(rand(4));             #pick a direction
    if($dir == $north) {
      if(($cell_num >= $w) && 
           ($maze[$cell_num][$set] != $maze[$cell_num-$w][$set])) {
        $maze[$cell_num][$north] = $cell_num - $w;
        $maze[$cell_num - $w][$south] = $cell_num;
        $unified = unify($maze[$cell_num][$set], $maze[$cell_num - $w][$set], $unified);
        if($dissolve) { clearwall($cell_num - $w, $south); }
      }
    }

    elsif($dir == $south) {
      if( ($cell_num<($w*($h-1)) ) && 
           ($maze[$cell_num][$set] != $maze[$cell_num+$w][$set]) ) {
        $maze[$cell_num][$south] = $cell_num + $w;
        $maze[$cell_num + $w][$north] = $cell_num;
        $unified = unify($maze[$cell_num][$set], $maze[$cell_num + $w][$set], $unified);
        if($dissolve) { clearwall($cell_num, $dir); }
      }
    }

    elsif($dir == $east) {
      if( ($cell_num % $w) != ($w - 1) && 
              ($maze[$cell_num][$set] != $maze[$cell_num+1][$set])) {
        $maze[$cell_num][$east] = $cell_num + 1;
        $maze[$cell_num + 1][$west] = $cell_num;
        $unified = unify($maze[$cell_num][$set], $maze[$cell_num +1][$set], $unified);
        if($dissolve) { clearwall($cell_num, $dir); }
      }
    }

    elsif($dir == $west) {
      if( (($cell_num % $w) != 0) &&
               ($maze[$cell_num][$set] != $maze[$cell_num-1][$set])) {
        $maze[$cell_num][$west] = $cell_num - 1;
        $maze[$cell_num - 1][$east] = $cell_num;
        $unified = unify($maze[$cell_num][$set], $maze[$cell_num-1][$set], $unified);
        if($dissolve) { clearwall($cell_num, $dir); }
      }
    }
  }
  $entry = ( int(rand($h)) * $w ) + ($w - 1);  # beginning of maze
  $exit = int(rand($h)) * $w;		   # end of maze
  $maze[$entry][$east] = $entry;           # entry and exit point to themselves
  $maze[$exit][$west] = $exit;             #   so that you can't leave the maze
  $maze[$exit][$set] = $maze_end;
  $cursor = $entry;                        # put the cursor at the entry point
  $maze[$cursor][$set] = $cursor_pos;
  $c{'endtime'} = time();
  $c{'dissolve'} = 0;			# don't want to dissolve twice...
}


# puts two cells in the same set, used when generating the maze
sub unify {
  my ($a, $b, $unified) = @_;  # set numbers for the two sets to combine
  $unified++;

  if($a < $b) { $x = $a; $y = $b; }
  else        { $y = $a; $x = $b; }

  for(@{$maze[$y][$setlist]}) {
    $maze[$_][$set] = $x;
  }
  push(@{$maze[$x][$setlist]}, @{$maze[$y][$setlist]});
  @{$maze[$y][$setlist]} = ();

  return($unified);
}


# redraw current and last cursor positions
sub update { 
  
  my $size = $c{'size'};
  my $w = $c{'width'}; my $h = $c{'height'};

  foreach $i (@_) {
    $c = 2 * ($i % $w);
    $r = int($i / $w);
    $terminal->Tgoto('cm', $c+1, $r+1, STDOUT);

    # use this to mark the path you have traveled
    if($c{'color'} && $maze[$i][$set] == $trail) {
      print $c{'trail'};
    }

    # cursor position
    if ( $maze[$i][$set] == $cursor_pos) {
      if($c{'color'}) { print $c{'cursor'}, "*", $c{'trail'}; }
      else { print "\e[7m\e[4m*\e[0m"; }
    }
    elsif($maze[$i][$south] eq "NULL") {
      print "_";
    }
    else {
      print " ";
    }

    if($maze[$i][$east] eq "NULL") {
      if($c{'color'}) { print $c{'unseen'}; }
      print "|";
    }
    elsif($maze[$i][$set] != $trail) {
      print "_";
    }
    if( $maze[$i][$set] == $cursor_pos || $maze[$i][$set] == $trail ) {
      print "\e[0m";
    }    
  }
  $terminal->Tgoto('cm', 0, 79, STDOUT);
}

# this routine is used in "dissolve" (-d) mode to remove walls
sub clearwall {
  my ($cell, $dir) = @_;

  my $w = $c{'width'}; my $h = $c{'height'};

  next if(($cell < 0) || ($cell >= ($w * $h))); # shouldn't happen...
  $c = 2 * ($cell % $w);
  $r = int($cell / $w) +1;

  if($dir eq $west) {
    $terminal->Tgoto('cm', $c, $r, STDOUT);
    if($maze[$i][$west] eq "NULL") {
      print "|";
    }
    else {
      print "_";
    }
  }
  elsif($dir eq $south) {
    $terminal->Tgoto('cm', $c+1, $r, STDOUT);
    if($maze[$i][$south] eq "NULL") {
      print "_";
    }
    else {
      print " ";
    }
  }
  elsif($dir eq $east) {
    $terminal->Tgoto('cm', $c+2, $r, STDOUT);
    if($maze[$i][$east] eq "NULL") {
      print "|";
    }
    else {
      print "_";    
    }
  }

  # now that we have updated, we might need to sleep some
  select(undef,undef,undef,$c{'dissolve_delay'});
}

## display the maze
sub tty_display { 

  my $size = $c{'size'};
  my $w = $c{'width'}; my $h = $c{'height'};

  $terminal->Tgoto('cm', 0, 0, STDOUT);
  if($c{'color'}) { print $c{'unseen'}; }
  print " ";  

  # row across the top
  for($i=0; $i<(2*$w); $i++) { print "_"; }

  for($i=0; $i<$size; $i++) {
    $c = 2 * ($i % $w);
    $r = int($i / $w);
    if(($i%$w) == 0) {
      $terminal->Tgoto('cm', $c, $r+1, STDOUT);
      if($c{'color'}) { print $c{'unseen'}; }
      print "|";
      if($c{'color'}) { print "\e[0m"; }
    }
    else { $terminal->Tgoto('cm', $c+1, $r+1, STDOUT); }
    
    if($c{'color'} && $maze[$i][$set] == $trail) { print $c{'trail'}; }

    if($maze[$i][$set] == $maze_end) {
      if($c{'color'}) { print $c{'finish'}, "%", "\e[0m"; }
      else { print "%"; }
    }
    elsif ( $maze[$i][$set] == $cursor_pos) {
      if($c{'color'}) { print $c{'cursor'}, "*", "\e[0m"; }
      else { print "\e[7m\e[4m*\e[0m" };
    }
    elsif($maze[$i][$south] eq "NULL") {
      if($c{'color'}) {
        if($maze[$i][$set] == $trail) { print $c{'trail'}; }
        else { print $c{'unseen'}; }
      }
      print "_";
    }
    else {
      if($c{'color'}) {
        if($maze[$i][$set] == $trail) { print $c{'trail'}; }
        else { print $c{'unseen'}; }
      }
      print " ";
    }

    if($maze[$i][$east] eq "NULL") {
      if($c{'color'}) { print $c{'unseen'}; }
      print "|";
    }
    else {
      if($c{'color'}) {
        if($maze[$i][$set] == $trail) { print $c{'trail'}; }
        else { print $c{'unseen'}; }
      }
      print "_";    
    }
  }
}

## take input, mostly for moving your little dude around in the maze
sub move {
  my $key = shift;
  my $moved = 0;
  $prev_cursor = $cursor;

  if (compare_key($key, $c{'up'}) && $maze[$cursor][$north] ne "NULL") {
    $maze[$cursor][$set] = $trail;
    $cursor = $maze[$cursor][$north];
    $moved = 1;
  } 
  elsif (compare_key($key, $c{'left'}) && $maze[$cursor][$west] ne "NULL") {
    $maze[$cursor][$set] = $trail;
    $cursor = $maze[$cursor][$west];
    $moved = 1;
  }
  elsif (compare_key($key, $c{'right'}) && $maze[$cursor][$east] ne "NULL") {
    $maze[$cursor][$set] = $trail;
    $cursor = $maze[$cursor][$east];
    $moved = 1;
  }
  elsif (compare_key($key, $c{'down'}) && $maze[$cursor][$south] ne "NULL") {
    $maze[$cursor][$set] = $trail;
    $cursor = $maze[$cursor][$south];
    $moved = 1;
  }
  elsif(compare_key($key, $c{'toggle_color'})) { # toggle the color
    $c{'color'} = 1 - $c{'color'};
    tty_display(@maze);
  }
  elsif (compare_key($key, $c{'redraw'})) { 
    system("clear");
    tty_display(@maze);
  }
  elsif (compare_key($key, $c{'quit'})) { 
    quit();
  }
  elsif (compare_key($key, $c{'solve'})) { 
    solve();
  }

  if($moved == 1) {
    if( $maze[$cursor][$set] == $maze_end ) { 
      win($c{'seed'});
    }
    $c{'movesdone'}++;
    $maze[$cursor][$set] = $cursor_pos;
  }
  update($prev_cursor, $cursor);
}

################## BEGIN MAZE SOLVING FUNCTIONS ##########################
## count the number of exits. used by solve().
sub numExits {
  my $exits = 0;
  for ($i=0; $i<4; $i++) {
    if ( $maze[$cursor][$i] ne "NULL" ) {
      $exits++;
    }
  }
  return $exits;
}

## whether or not a given path from an intersection has been tried already
sub beenThere {
  my $pos = shift;
  my $found = 0;
  foreach $ele (@tried) {
    if( $ele == $pos ) {
      $found = 1;
    }
  }
  return $found;
}

## figure out if we've got nowhere new to go from the current intersection
sub noMoreOptions {
  # if a new path still exists, return 0 (i.e. "more options")
  for($i=0; $i<4; $i++) {
    if( $maze[$cursor][$i] ne "NULL" &&
    $maze[$maze[$cursor][$i]][$set] != $trail &&
    !beenThere($maze[$cursor][$i]) ) {
      return 0;
    }
  }
  return 1;
}

## back-track to the last intersection
sub gotoLastIntersect {
  do {
    for($i=0; $i<4; $i++) {      
      if( $maze[$maze[$cursor][$i]][$set] == $trail ) {
        $prev_cursor = $cursor;
        $maze[$cursor][$set] = $empty;
        $cursor = $maze[$cursor][$i];
        update($prev_cursor, $cursor);
        last;
      }
    }
  } while( numExits() < 3 );
}

## solve the maze
sub solve {
  # reset the maze
  initialize();
  generate_maze();
  tty_display(@maze);
  $c{'solvestart'} = time();
  while(1) {
    # are we at a dead end?
    if( numExits() == 1 ) {
      gotoLastIntersect();
    }
    # pick a random direction
    $dir = int(rand(4));

    # don't try moving into a wall
    if( $maze[$cursor][$dir] eq "NULL") {
      next;
    }
    # don't go where we just came from
    if( $maze[$maze[$cursor][$dir]][$set] == $trail ) {
      next;
    }
    # are we at an intersection?
    if( numExits() > 2 ) {
      # have we been in that direction already?
      if( beenThere($maze[$cursor][$dir]) ) {
        # if we've been to all the exits, go to the last intersection
        if( noMoreOptions() ) {
          gotoLastIntersect();
        }
        next;
      }
      else {
        # add on to the list of exits we've taken
        push(@tried, $maze[$cursor][$dir]);
      }
    }

    # make the move
    $maze[$cursor][$set] = $trail;
    $prev_cursor = $cursor;
    $cursor = $maze[$cursor][$dir];
    # did we win?
    if( $maze[$cursor][$set] == $maze_end ) {
      $c{'solveend'} = time();
      $maze[$cursor][$set] = $cursor_pos;
      return;
    }
    $maze[$cursor][$set] = $cursor_pos;
    update($prev_cursor, $cursor);
  }
}
#################### END MAZE SOLVING FUNCTIONS ########################## 


sub quit {
  system("stty -raw echo");
  print "\n\nQuitting...\n\n";
  print "\nYou just played: -r $c{'height'} -c $c{'width'} -s $c{'seed'}\n";
  print "Maze generated in ", $c{'endtime'} - $c{'starttime'}, " seconds.\n";
  if($c{'solvestart'}) {
    print "Maze solved in ", $c{'solveend'} - $c{'solvestart'}, " seconds.\n";
  }
  elsif($c{'movesdone'}) {
    print "You performed $c{'movesdone'} moves.\n" 
  }
  exit(0);
}

## read the command line arguments
sub getinput {
  while($arg = shift @ARGV) {
    if($arg eq "--help" || $arg eq "-h") {
      help();
    }
    elsif($arg eq "-d") { $c{'dissolve'} = 1 - $c{'dissolve'}; }
    elsif($arg eq "-a") { $c{'color'} = 1 - $c{'color'}; }
    elsif($arg eq "-m") {
      $width = int(($c{'screen_width'}-1)/2);
      $height = $c{'screen_height'}-1;
    }
    elsif($arg eq "-c") {
      $width = shift @ARGV;
      if($width < 1) { help("Maze width must be at least 1"); }
      elsif($c{'autosize'} && ($width > $c{'screen_width'})) { help("Maze width must be less than half of the screen width (Max: $c{'screen_width'})\n"); }
    }
    elsif($arg eq "-r") {
      $height = shift @ARGV; 
      if($height < 1) { help("Maze height must be at least 1"); }
      elsif($c{'autosize'} && ($height > $c{'screen_height'})) { help("Maze height must be one less than the screen height (Max: $c{'screen_height'})\n"); }
    }
    elsif($arg eq "-s") { $random_seed = shift @ARGV; }
  }
  unless($width) { $width = $c{'default_width'}; }
  unless($height) { $height = $c{'default_height'}; }
  if(($width + $height) < 3) { help("A 1 x 1 maze is too small."); } 
  unless($random_seed) { $random_seed = (time); }

  return($width, $height, $random_seed);
}


## hot dog! you won! ##
sub win {
  
  system("stty -raw echo");

  print <<EOF;
             _                                     |###|
            ( )                                    \\###/
            |H|              YOU                   (o^o)
           _|=|_                   WON!             / \\
         =|/:M:\\|=                                  \\_/
         U{ :W: }U    TOM and CROW                ___=___
           \\___/                                [|=======|]
         TOM SERVO        congratulate you      | CROOOOW |
         /___8___\\                              |   / \\   |
        (_________)                                 L_J
EOF


  quit();
}

sub help {
  my $msg = shift;
  if($msg) { print "\n$msg\n\n"; }
  $max_height = $c{'screen_height'} -1;
  $max_width = int(($c{'screen_width'}-1)/2);
  print <<END;
Usage: $0 [-h] [-m] [-d] [-r <rows>] [-c <columns>] [-s <seed>]
     -m           set maze size to the maximum allowed by your screen
     -d           generate in \"dissolve\" mode, slower but fun to watch
     -h           print this help text
     -r <num>     set the number of rows in the maze
     -c <num>     set the number of columns in the maze
     -s <num>     provide a seed value for generating a maze
     -a           use ANSI color

Default Keys:
    Movement:            Arrow keys, or vi movement keys (h,j,k,l)
    Redraw:              r
    Solve Maze:          S
    Quit:                q
    Toggle ANSI color:   c

END

printf "Default height: %3d   Max height: %3d\n", $c{'default_height'}, $max_height;
printf "Default width:  %3d   Max Width:  %3d\n", $c{'default_width'}, $max_width;


  print "\nTextMaze v$VERSION by Kirk Baucom <kbaucom\@schizoid.com>\n";

  unless(eval "require Term::ReadKey") {
    print "\nWARNING: You do not have the Term::ReadKey module. You will not be able to\n";
    print "         use the -m option properly. Term::ReadKey is available at:\n";
    print "         http://www.cpan.org\n";
  } 

  exit;
}

# read in the configuration file
sub read_config {
  my $conf = shift;

  my $pos = tell(DATA);
  parse_config(DATA);

  # generate a default config file if one doesn't exist.
  if(-f "$conf") {
    if(-r "$conf") { open(C, "<$conf"); parse_config(C); }
  }
  else {
    open(C, ">$conf") || return; # can't create config file
    print C "# This is a config file for textmaze version $VERSION\n";
    print C "# Automatically generated ", `date`;

    seek(DATA,$pos,0);

    while(<DATA>) {
      print C;
    }
    close(C);
  }
}

sub parse_config {
  my $config = shift;
  while(<$config>) {
    chomp($line = $_); $line =~ s/\s//g; $line =~ s/\#.*$//;
    if(!$line) { next; }
    elsif($line =~ /^up:(.*)$/) { @{$c{'up'}} = split(",", $1); }
    elsif($line =~ /^down:(.*)$/) { @{$c{'down'}} = split(",", $1); }
    elsif($line =~ /^left:(.*)$/) { @{$c{'left'}} = split(",", $1); }
    elsif($line =~ /^right:(.*)$/) { @{$c{'right'}} = split(",", $1); }
    elsif($line =~ /^redraw:(.*)$/) { @{$c{'redraw'}} = split(",", $1); }
    elsif($line =~ /^quit:(.*)$/) { @{$c{'quit'}} = split(",", $1); }
    elsif($line =~ /^solve:(.*)$/) { @{$c{'solve'}} = split(",", $1); }
    elsif($line =~ /^toggle_color:(.*)$/) { @{$c{'toggle_color'}} = split(",", $1); }

    elsif($line =~ /^color:(.*)$/) { $c{'color'} = boolstring($1); }
    elsif($line =~ /^dissolve:(.*)$/) { $c{'dissolve'} = boolstring($1); }

#    elsif($line =~ /^default_height:(\d+)$/) { $c{'default_height'} = $1; }
#    elsif($line =~ /^default_width:(\d+)$/) { $c{'default_width'} = $1; }
    elsif($line =~ /^(\w+):(.*)$/) { $c{$1} = $2; }
    else { print "Malformed config file line:\n$_"; }
  }
  close(C);
}

sub boolstring {
  my $string = shift;
  if($string eq "on" || $string eq "ON" || $string eq "yes" || $string eq "YES") {
    return 1;
  }
  else { return 0; }
}

# check the key that was pressed against a list to see what we should do
sub compare_key {
  my ($key, $set) = @_;
  for(@$set) { if($key eq $_) { return 1; } }
  return 0;
}

# dump our state
sub debug {
  if(eval "require Dumpvalue") {
    import Dumpvalue;
    my $dumper = new Dumpvalue;
    $dumper->dumpValue(\%c);
  }
  else { return; }
}

# i decided this would be the easiest way to distribute a default config file
# don't edit this stuff! edit your own config file after you run textmaze
# the first time! it will be ~/.textmaze
__DATA__

# key values are case sensitive. arguments should be comma separated lists.
up: k, w
down: j, s
left: h, a
right: l, d
redraw: r
quit: q
solve: S
toggle_color: c

# some default behavior
default_height: 20
default_width: 20
color: off
dissolve: on
# higher = slower
dissolve_delay: .025

## colors to use, if the maze is in color
#
# the color name in all caps (ie "BLACK" instead of "black") for a foreground
# implies that it should be bold.
#
# available colors:      
#
# black
# red
# green
# yellow
# blue
# magenta
# cyan
# white

trail_bg: green
trail_fg: WHITE

cursor_bg: yellow
cursor_fg: BLACK

finish_bg: black
finish_fg: RED

unseen_bg: black
unseen_fg: WHITE
