diff --git a/perl/randomPlayer.pl b/perl/randomPlayer.pl index b24beb8..11dd46f 100755 --- a/perl/randomPlayer.pl +++ b/perl/randomPlayer.pl @@ -9,6 +9,8 @@ use File::Basename qw(dirname); use Cwd qw(abs_path); use lib dirname(abs_path($0)); +our $VERBOSE = $ENV{"VERBOSE"}; + # Use our ttrts perl library use ttrts; @@ -62,24 +64,24 @@ printf("Launching with player %i\n",$player); while ( 1 ) { # Wait for turn file - our $turnFile = GetTurnFile($turn); + our $turnFile = GetTurnFileName($turn); # Wait for the turn file - printf("Waiting for %s\n", $turnFile); + $VERBOSE and printf("Waiting for %s\n", $turnFile); WaitForFile $turnFile; # Read in the game state from turnFile - my @units = GetUnitsForTurn($turnFile); - my ($gameName,$gameX,$gameY) = GetHeaderForTurn($turnFile); + my @units = GetUnitStringsFromFile($turnFile); + my ($major,$minor,$patch,$gameName,$gameX,$gameY) = GetGameInfoFromFile($turnFile); # Get units on my player - my @myUnits = getUnitsOnPlayer($player,@units); + my @myUnits = GetPlayerUnits($player,@units); # Generate some commands my $commands = OrderEverythingRandom(@myUnits); # At this point, print the game map - PrintGameMap($gameX,$gameY,@units); + PrintGameMapForTurn($turn); if( scalar(@units) == 0 ) { @@ -96,6 +98,7 @@ while ( 1 ) printf "Game over, you lose!\n"; exit 0; } + # TODO: Detect lack of possible movement OutputCommandsFile $turn,$player,$commands; diff --git a/perl/ttrts.pm b/perl/ttrts.pm index 8acdf17..6dc279e 100644 --- a/perl/ttrts.pm +++ b/perl/ttrts.pm @@ -3,50 +3,97 @@ use strict; use warnings; our $ttrts_perlai_versioncompat_major = 0; -our $ttrts_perlai_versioncompat_minor = 2; +our $ttrts_perlai_versioncompat_minor = 3; -# Get information about a unit from it's descriptor -sub getUnit +our $headerDelimiter="~~~~"; + +our $VERBOSE = $ENV{"VERBOSE"}; + +# Format of the a gamestate header +our $headerFormatter = qr/==== ttrts v(\d+)\.(\d+)\.(\d+)+ ==== +NAME:(.+) +SIZE:\[(\d+),(\d+)\] +TURN:(\d+) +(WALL:.*?) +$headerDelimiter/; + +# Formatter for coords +our $coordFormatter = qr/\[\d+,\d+\]/; + +# Format of a unit descriptor +our $unitFormatterNonCapture = qr/UNIT:\d+ pl:\d+ vs:[^ ]+ dr:[^ ]+ ps:\[\d+,\d+\]\n?/; + +# Format of a unit descriptor +our $unitFormatter = qr/UNIT:(\d+) pl:(\d+) vs:([^ ]+) dr:([^ ]+) ps:\[(\d+),(\d+)\]\n?/; + +# Get x and y +sub getPositionsXandYString { - return ($_[0] =~ /UNIT:(\d+) pl:(\d+) vs:([^ ]+) dr:([^ ]+) ps:\[(\d+),(\d+)\]/); + return (shift =~ /\[(\d+),(\d+)\]/); } -# Get the units from a turn file -sub GetUnitsForTurn +# Get all positions +sub getPositionStringsFromLine { - my $turnFile = shift; + return (shift =~ /$coordFormatter/gm ); +} - # Open the turn file - open (my $TURNHANDLE, '<', $turnFile) or die "Could not open '$turnFile' $!"; - - # Skip the header information - my $num = 0; - while( !( <$TURNHANDLE> =~ /~~~~/ ) ) - { - $num++; - $num > 20 and die "gamestate file did not reach ~~~~ line within 10 lines"; - } +# Get information about a unit from it's descriptor +sub getUnitInfo +{ + return (shift =~ /$unitFormatter/); +} - my @units; - while( my $unitLine = <$TURNHANDLE> ) +# Get set of units from a string +sub GetUnitStringsFromGamestate +{ + my $gamestate = shift; + + my @units = ( $gamestate =~ /$unitFormatterNonCapture/gm ); + + foreach my $unit (@units) { - chomp $unitLine; - if( !($unitLine eq "END") ) - { - push(@units,$unitLine); - } + chomp($unit); } - close $TURNHANDLE; - return @units; } +# in the format $major,$minor,$patch,$name,$sizex,$sizey,$turn,$invalidpositions+ +sub GetGameInfoFromGamestate +{ + my $header = shift; + (! defined $header) and die "GetGameInfoFromGamestate was not passed valid header parameter"; + + my @info = ($header =~ /$headerFormatter/ ); + + return @info; +} + +# Get the units from a turn file +sub GetUnitStringsFromFile +{ + my $turnFile = shift or die "GetUnitStringsFromFile needs file parameter"; + + # Read in the whole file method from http://www.perlmonks.org/?node_id=1952 + my $text; + { + local $/=undef; + open FILE, $turnFile or die "Couldn't open file: $!"; + $text = ; + close FILE; + } + + return GetUnitStringsFromGamestate($text); +} + # Check version numbers against ttrts.pm version -sub checkVersion +sub verifyVersion { my $version_major = shift; + (! defined $version_major) and die "verifyVersion needs version_major parameter"; my $version_minor = shift; + (! defined $version_minor) and die "verifyVersion needs version_minor parameter"; if( ($version_major != $ttrts_perlai_versioncompat_major) or ($version_minor != $ttrts_perlai_versioncompat_minor) ) { @@ -55,40 +102,34 @@ sub checkVersion } } + # Get information from the header for this turn -sub GetHeaderForTurn +sub GetGameInfoFromFile { - my $turnFile = shift; + my $turnFile = shift or die "GetGameInfoFromFile needs turnFile parameter"; - # Open the turn file - open (my $TURNHANDLE, '<', $turnFile) or die "Could not open '$turnFile' $!"; - - # Pull in the header information - my $headerLine = <$TURNHANDLE>; - chomp $headerLine; - my $nameLine = <$TURNHANDLE>; - chomp $nameLine; - my $sizeLine = <$TURNHANDLE>; - chomp $sizeLine; - my $turnLine = <$TURNHANDLE>; - chomp $turnLine; + # Read in the whole file method from http://www.perlmonks.org/?node_id=1952 + my $text; + { + local $/=undef; + open FILE, $turnFile or die "Couldn't open file: $!"; + $text = ; + close FILE; + } - my ($version_major,$version_minor) = ( $headerLine =~ /==== ttrts v(\d+)\.(\d+)\.\d+ ====/ ); - checkVersion $version_major,$version_minor; + my @info = GetGameInfoFromGamestate($text); + verifyVersion @info; - my ($gameName) = ( $nameLine =~ /NAME:(.+)/ ); - my ($gameX,$gameY) = ( $sizeLine =~ /SIZE:\[(\d+),(\d+)\]/ ); - - close $TURNHANDLE; - - return ($gameName,$gameX,$gameY); + return @info; } # Get units from a specific player -sub getUnitsOnPlayer +sub GetPlayerUnits { my $thePlayer = shift; + (! defined $thePlayer) and die "GetPlayerUnits needs player parameter"; my @allUnits = @_; + (! @allUnits) and die "GetPlayerUnits needs units parameters"; my @myUnits; for my $unit (@allUnits) @@ -103,18 +144,21 @@ sub getUnitsOnPlayer return @myUnits; } -sub GetTurnFile +sub GetTurnFileName { my $turn = shift; + (! defined $turn) and die "GetTurnFileName needs turn parameter"; my $turnFile = "Turn_TURN.txt"; $turnFile =~ s/TURN/$turn/; return $turnFile; } -sub GetCommandFile +sub GetCommandFileName { my $turn = shift; + (! defined $turn) and die "GetCommandFileName needs turn parameter"; my $player = shift; + (! defined $player) and die "GetCommandFileName needs player parameter"; my $cmdFileName = "Player_PLAYER_Turn_TURN.txt"; $cmdFileName =~ s/TURN/$turn/; $cmdFileName =~ s/PLAYER/$player/; @@ -125,11 +169,13 @@ sub GetCommandFile sub OutputCommandsFile { my $turn = shift; + (! defined $turn) and die "OutputCommandsFile needs turn parameter"; my $player = shift; - my $commands = shift; + (! defined $player) and die "OutputCommandsFile needs player parameter"; + my $commands = shift or die "OutputCommandsFile needs commands parameter"; # Get output file - our $cmdFileName = GetCommandFile($turn,$player); + our $cmdFileName = GetCommandFileName($turn,$player); if (! -e $cmdFileName) { @@ -138,25 +184,41 @@ sub OutputCommandsFile print $cmdFile "END"; close $cmdFile; - printf "Outputted $cmdFileName\n"; + $VERBOSE and printf "Outputted $cmdFileName\n"; printf "$commands"; } else { - open(my $cmdFile, '<', $cmdFileName) or die "Couldn't open '$cmdFileName' $!"; - my $old_commands = do { <$cmdFile> }; + # Read in the whole file method from http://www.perlmonks.org/?node_id=1952 + my $text; + { + local $/=undef; + open FILE, $cmdFileName or die "Couldn't open file: $!"; + $text = ; + close FILE; + } + + $text =~ s/\nEND//; printf "Replaying $cmdFileName\n"; - printf "$old_commands"; + printf "$text\n"; } } # Print a game map -sub PrintGameMap +sub PrintGameFromGamestateString { - my $gameX = shift; - my $gameY = shift; - my @units = @_; + my $gamestateString = shift or die "PrintGameFromGamestateString needs string parameter"; + + my @info = GetGameInfoFromGamestate($gamestateString); + my @units = GetUnitStringsFromGamestate($gamestateString); + + # $major,$minor,$patch,$name,$sizex,$sizey,$turn,$invalidpositions+ + my $gameX = $info[4]; + my $gameY = $info[5]; + + # Shift into info to where the invalid positions are stored + my @invalids = getPositionStringsFromLine($info[7]); my @map; @@ -169,10 +231,17 @@ sub PrintGameMap } } + # Fill in all invalid coordinates + foreach my $coord (@invalids) + { + my @invalidPos = getPositionsXandYString($coord); + $map[$invalidPos[0]][$invalidPos[1]] = "~"; + } + # Fill with units for my $unit (@units) { - my ($id,$pl,$vs,$dr,$psx,$psy) = getUnit($unit); + my ($id,$pl,$vs,$dr,$psx,$psy) = getUnitInfo($unit); $pl += 31; $vs = "\e[".$pl."m".$vs."\e[0m"; @@ -191,10 +260,36 @@ sub PrintGameMap } } +# Print a game map +sub PrintGameFromFile +{ + my $turnFile = shift or die "PrintGameFromFile needs file parameter"; + + # Read in the whole file method from http://www.perlmonks.org/?node_id=1952 + my $text; + { + local $/=undef; + open FILE, $turnFile or die "Couldn't open file: $!"; + $text = ; + close FILE; + } + + PrintGameFromGamestateString($text); +} + +# Print a turn +sub PrintGameMapForTurn +{ + my $turn = shift; + (! defined $turn) and die "PrintGameMapForTurn needs turn parameter"; + $turn = GetTurnFileName($turn); + PrintGameFromFile( $turn ); +} + # Wait for a file to exist sub WaitForFile { - my $file = $_[0]; + my $file = shift or die "WaitForFile needs file parameter"; while( ! -e $file ) { select(undef, undef, undef, 0.01);