/usr/local/CPAN/Games-Perlwar/Games/Perlwar/Shell.pm
package Games::Perlwar::Shell;
use strict;
use warnings;
our $VERSION = '0.03';
use Cwd;
use Games::Perlwar;
use XML::Simple;
use File::Copy;
use IO::Prompt;
use Term::ShellUI;
use IO::Prompt;
my $pw;
# TODO: add color entry for players and default colors
my @colors = qw( pink lightblue yellow lime maroon purple
olive pink gold red aqua );
my $shell = Term::ShellUI->new(
commands => {
load => {
desc => "load a Perlwar game",
maxargs => 2,
proc => \&do_load,
},
save => {
desc => "save the current Perlwar game",
maxargs => 1,
proc => \&do_save,
},
quit => {
desc => "exit the shell",
method => sub { shift->exit_requested(1) },
},
q => { syn => 'quit', exclude_from_completion => 1 },
}
);
### help
$shell->add_commands({
help => {
desc => "print list of commands",
args => sub { shift->help_args(undef, @_); },
method => sub { shift->help_call(undef, @_); },
},
h => { syn => "help", exclude_from_completion=>1},
});
### create
$shell->add_commands({
create => {
desc => "create a new game",
proc => \&do_create,
},
});
### cd, pwd
$shell->add_commands({
cd => {
desc => "change working directory",
proc => \&do_cd,
},
pwd => {
desc => "print current working directory",
proc => \&do_pwd,
},
});
### run
$shell->add_commands({
run => {
desc => 'run iterations of the game',
proc => \&do_run,
}
});
### exec, info
$shell->add_commands({
eval => {
desc => 'execute arbitrary perl code',
proc => sub { print eval( join ' ', @_ ), "\n" },
},
e => { syn => 'eval', exclude_from_completion => 1 },
info => {
desc => 'game stats',
proc => \&do_info,
},
});
$shell->prompt( 'pw> ' );
sub run { $shell->run; }
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
sub do_info {
die "no game loaded\n" unless $pw;
print 'iteration ', $pw->{round}, ' of ', $pw->{conf}{gameLength}, "\n",
'game status: ', ( $pw->get_game_status || 'ongoing' ), "\n",
'players', "\n";
for my $p ( keys %{$pw->{conf}{player}} ) {
print "\t$p : ", $pw->{conf}{player}{$p}{agents}, "\n";
}
}
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
sub do_create {
if ( $pw ) {
my $r = prompt -yes, -d => 'y',
"creating a new game will discard any unsaved information to "
."the currently loaded game. do it? [Yn] ";
return unless $r;
}
my $game_name = shift || 'perlwar';
my $game_dir = "./$game_name";
print "creating game directories $game_dir..\n";
mkdir $game_dir or die "couldn't create directory $game_dir: $!\n";
chdir $game_dir or die "can't chdir to $game_dir: $!\n";
mkdir "history" or die "couldn't create directory history:$!\n";
mkdir 'mobil' or die "couldn't create directory mobil:$!\n";
print "\n\ngame configuration\n";
my $config_file = IO::File->new( '>configuration.xml' )
or die "can't create configuration file: $!\n";
my $conf = XML::Writer->new( OUTPUT => $config_file,
NEWLINES => 1 );
$conf->startTag( 'configuration' );
$game_name =~ s#^.*/##; # remove path if any
$conf->dataElement( title =>
prompt "game title [$game_name]: ", -d => $game_name );
$conf->dataElement( gameLength =>
my $gameLength = prompt -integer,
"game length (0 = open-ended game) [100]: ",
-d => 100 );
$conf->dataElement( theArraySize =>
prompt -integer, "size of the Array [100]: ", -d => 100 );
$conf->dataElement( agentMaxSize =>
prompt -integer, "agent max. size [100]: ", -d => 100 );
if ( prompt -y => "blitzkrieg? [yN]: ", -d => 0 ) {
$conf->dataElement( 'gameVariant', 'blitzkrieg' );
}
if( prompt -y => "mambo war? [n]: ", -d => 0 ) {
$conf->emptyTag( 'mambo', decrement =>
prompt "decrement per iteration [1]: ", -d => 1
);
}
my $player_list_type =
prompt -menu => [ qw/ adhoc predefined / ], "type of player list: ";
if ( $player_list_type eq 'adhoc' ) {
$conf->emptyTag( 'players',
list => $player_list_type,
community =>
prompt "community file [h4x00rs.xml]: ",
-d => 'h4x00rs.xml'
);
}
else {
$conf->startTag( 'players', list => $player_list_type );
while(1) {
my $line = prompt "enter a player (name password [color]), or nothing if done: ";
my( $name, $password, $color ) = split ' ', $line, 3;
last unless $name;
$color ||= shift @colors;
$conf->emptyTag( 'player', name => $name,
password => $password,
color => $color );
}
$conf->endTag( 'players' );
}
print "notes (CTL-D to terminate):\n";
my $note;
$note .= $_ while <>;
$conf->dataElement( notes => $note ) if $note;
$conf->endTag( 'configuration' );
$conf->end;
$config_file->close;
print "creating round 0.. \n";
for my $filename ( qw/ round_current.xml round_00000.xml / )
{
my $fh;
open $fh, ">$filename" or die "can't create file $game_dir/$filename: $!\n";
print $fh "<iteration nbr='0'>",
"<summary><status>not started yet</status></summary><theArray/><log/></iteration>\n";
close $fh;
}
print "\ngame '$game_name' created\n";
$pw = Games::Perlwar->new( '.' );
$pw->load;
}
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
sub do_load {
my $dir = shift || '.';
my $iteration = shift;
if ( $pw ) {
my $r = prompt -yes, -d => 'y',
"loading a new game will discard any unsaved information to "
."the currently loaded game. do it? [Yn] ";
return unless $r;
}
$pw = Games::Perlwar->new( $dir );
$pw->load( $iteration );
}
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
sub do_save {
die "no game to save" unless $pw;
$pw->save;
print "game saved\n";
}
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
sub do_run {
die "no game loaded" unless $pw;
return print "game is already over\n" if $pw->get_game_status eq 'over';
if ( my $turns = shift ) {
$pw->play_round while $turns-- and $pw->get_game_status ne 'over';
}
else {
$pw->play_round until $pw->get_game_status eq 'over';
}
}
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
sub do_cd {
my $dir = shift;
unless( -d $dir ) {
print "ERROR: can't change directory, $dir doesn't exist\n";
return;
}
chdir $dir or print "ERROR: couldn't change to directory: $!\n";
}
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
sub do_pwd {
print "current directory: ", getcwd, "\n";
}
__END__