From c544e7a4fb0e76692ee8805abfca24b89e936577 Mon Sep 17 00:00:00 2001 From: mdiluzio Date: Mon, 29 Dec 2014 21:59:59 +0000 Subject: [PATCH 1/6] Large refactor and addition of new features in line with 0.3.0 --- perl/randomPlayer.pl | 15 +-- perl/ttrts.pm | 223 ++++++++++++++++++++++++++++++------------- 2 files changed, 168 insertions(+), 70 deletions(-) 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); From b84c5f34ccd9614f57113b1fba924c4855947576 Mon Sep 17 00:00:00 2001 From: mdiluzio Date: Mon, 29 Dec 2014 22:12:14 +0000 Subject: [PATCH 2/6] Remove perl ttrts module, now moved to main repository --- perl/ttrts.pm | 299 -------------------------------------------------- 1 file changed, 299 deletions(-) delete mode 100644 perl/ttrts.pm diff --git a/perl/ttrts.pm b/perl/ttrts.pm deleted file mode 100644 index 6dc279e..0000000 --- a/perl/ttrts.pm +++ /dev/null @@ -1,299 +0,0 @@ -#! /usr/bin/perl -use strict; -use warnings; - -our $ttrts_perlai_versioncompat_major = 0; -our $ttrts_perlai_versioncompat_minor = 3; - -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 (shift =~ /\[(\d+),(\d+)\]/); -} - -# Get all positions -sub getPositionStringsFromLine -{ - return (shift =~ /$coordFormatter/gm ); -} - -# Get information about a unit from it's descriptor -sub getUnitInfo -{ - return (shift =~ /$unitFormatter/); -} - -# Get set of units from a string -sub GetUnitStringsFromGamestate -{ - my $gamestate = shift; - - my @units = ( $gamestate =~ /$unitFormatterNonCapture/gm ); - - foreach my $unit (@units) - { - chomp($unit); - } - - 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 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) ) - { - printf "ttrts.pm version does not match with this ttrts version\n"; - die "ttrts.pm = v$ttrts_perlai_versioncompat_minor.$ttrts_perlai_versioncompat_major ttrts = v$version_major.$version_minor"; - } -} - - -# Get information from the header for this turn -sub GetGameInfoFromFile -{ - my $turnFile = shift or die "GetGameInfoFromFile needs turnFile 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; - } - - my @info = GetGameInfoFromGamestate($text); - verifyVersion @info; - - return @info; -} - -# Get units from a specific player -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) - { - my ($unitplayer) = $unit =~ /pl:(\d+)/; - if ( $unitplayer == $thePlayer ) - { - push(@myUnits,$unit); - } - } - - return @myUnits; -} - -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 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/; - return $cmdFileName; -} - -# Output the commands file -sub OutputCommandsFile -{ - my $turn = shift; - (! defined $turn) and die "OutputCommandsFile needs turn parameter"; - my $player = shift; - (! defined $player) and die "OutputCommandsFile needs player parameter"; - my $commands = shift or die "OutputCommandsFile needs commands parameter"; - - # Get output file - our $cmdFileName = GetCommandFileName($turn,$player); - - if (! -e $cmdFileName) - { - open(my $cmdFile, '>', $cmdFileName) or die "Couldn't open '$cmdFileName' $!"; - print $cmdFile $commands; - print $cmdFile "END"; - close $cmdFile; - - $VERBOSE and printf "Outputted $cmdFileName\n"; - printf "$commands"; - } - else - { - # 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 "$text\n"; - } -} - -# Print a game map -sub PrintGameFromGamestateString -{ - 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; - - # Fill with blanks - for my $x (0 .. $gameX-1) - { - for my $y (0 .. $gameY-1) - { - $map[$x][$y] = "-"; - } - } - - # 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) = getUnitInfo($unit); - - $pl += 31; - $vs = "\e[".$pl."m".$vs."\e[0m"; - - $map[$psx][$psy] = $vs; - } - - # Print whole map bottom left is 0,0 - for my $y ( reverse 0 .. $gameY-1 ) - { - for my $x (0 .. $gameX-1) - { - printf($map[$x][$y]); - } - printf("\n"); - } -} - -# 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 = shift or die "WaitForFile needs file parameter"; - while( ! -e $file ) - { - select(undef, undef, undef, 0.01); - } -} - -return 1; \ No newline at end of file From 26f283564402d6878d744950de74de439c10dbb3 Mon Sep 17 00:00:00 2001 From: mdiluzio Date: Mon, 29 Dec 2014 22:13:32 +0000 Subject: [PATCH 3/6] No longer require ttrts to be in the same directory --- perl/randomPlayer.pl | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/perl/randomPlayer.pl b/perl/randomPlayer.pl index 11dd46f..a8362aa 100755 --- a/perl/randomPlayer.pl +++ b/perl/randomPlayer.pl @@ -3,15 +3,10 @@ use strict; use warnings; use Term::ANSIColor; -# From http://perlmaven.com/how-to-create-a-perl-module-for-code-reuse -# expect ttrts perl module in cwd -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 +# located within the main https://github.com/mdiluz/ttrts repository use ttrts; our $usage_text=< Date: Sun, 25 Jan 2015 12:14:16 +0000 Subject: [PATCH 4/6] Basic Lua player that communicates directly with the server --- lua/random_player.lua | 190 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 190 insertions(+) create mode 100755 lua/random_player.lua diff --git a/lua/random_player.lua b/lua/random_player.lua new file mode 100755 index 0000000..e1e998d --- /dev/null +++ b/lua/random_player.lua @@ -0,0 +1,190 @@ +#! /usr/bin/lua + +-- use socket to communicate with the server directly +require "socket" + +-- usage text +local USAGE = [[ +NAME + random_player.lua + +USAGE + random_player.lua --host=HOSTNAME + +SUMMARY + Random ttrts player using lua Connects directly to ttrts server + +OPTIONS + HOSTNAME - host to connect to +]] + +-- [[ Perform the handshake to connect ]] +ttrts = {} +do + +ttrts.PerformHandshake = function (sock) + + if not sock then error("Must pass PerformHandshake a socket") end + + local line = sock:receive('*l') + + local player, name = string.match(line, "player (%d+) name ([%a%d]+)") + + -- bail out if handshake information failed + assert( player and name , "Handshake failed with incorrect player and name") + + print( "Player: " .. player ) + print( "Name: " .. name ) + + -- return the handshake line with a new line (removed by the *l call to receive) and string end + sock:send( line .. "\n" .. "\0" ) + + return player, name +end + +-- [[ Recieve gamestate info ]] +ttrts.GetState = function (newLine) + + if not newLine then error("Must pass GetState a method") end + + local line = "" + local state = {} + + -- INVESTIGATE WHY THIS IS NEEDED + newLine() + + local thename = newLine() + state.name = string.match( thename, "NAME:([%a%d]+)" ) + assert( state.name, "Gamestate file format missmatch (no name)") + + state.size = {} + local sizes = newLine() + state.size.x, state.size.y = string.match( sizes, "SIZE:%[(%d+),(%d+)%]" ) + assert( state.size.x and state.size.y , "Gamestate file format missmatch (size failure)") + + state.turn = string.match( newLine(), "TURN:(%d+)" ) + assert( state.turn, "Gamestate file format missmatch (no turn)") + + -- Get the wall line + state.walls = {} + local wallline = newLine() + + assert(string.match( wallline, "WALL:"), "Gamestate file format missmatch (no wall line)") + + -- Grab all walls on the line + for wallstring in string.gmatch(wallline, "%[%d+,%d+%]") do + local wall = {} + wall.x, wall.y = string.match( wallstring, "%[(%d+),(%d+)%]" ) + table.insert(state.walls,wall) + end + + assert( newLine() == "~~~~", "Gamestate file format missmatch (missing ~~~~)" ) + + -- get the units + state.units = {} + + local unitline = newLine() + while unitline ~= "END" do + + local unit = {} + unit.pos = {} + + -- Parse the unit line + unit.id, unit.player, unit.vis, unit.dir, unit.pos.x, unit.pos.y = + string.match( unitline, "UNIT:(%d+) pl:(%d+) vs:([^%s]+) dr:(%a+) ps:%[(%d+),(%d+)%]") + + assert(unit.id and unit.player and unit.vis and unit.dir and unit.pos.x and unit.pos.y, "gamestate file format missmatch (error with unit)") + + table.insert(state.units,unit) + + unitline = newLine() + end + + assert(unitline == "END", "Gamestate file format missmatch (didn't end in END)") + + return state +end + +-- [[ Get Random Orders from gamestate for a particular player ]] +ttrts.GetRandomOrders = function( id, state ) + + local orders = "" + local possibleorders = { "F", "L", "R", "A" } + + local units = state.units + for key,unit in pairs(units) do + if unit.id == id then + local order = "F" -- TODO MAKE RANDOM + orders = orders .. "ORDER:" .. order .. " id:" .. tostring(id) .. "\n" + end + end + + orders = orders .. "END\n" + + return orders +end + +-- [[ Send the orders to the server through the socket ]] +ttrts.SendOrders = function( socket, orders ) + assert( string.match(orders,"END"), "Cannot send orders without END" ) + socket:send( orders .. "\0" ) +end + +end -- end ttrts + +-- [[ http://lua-users.org/wiki/AlternativeGetOpt ]] +function getopt( arg, options ) + local tab = {} + for k, v in ipairs(arg) do if string.sub( v, 1, 2) == "--" then local x = string.find( v, "=", 1, true ) if x then tab[ string.sub( v, 3, x-1 ) ] = string.sub( v, x+1 ) else tab[ string.sub( v, 3 ) ] = true end + elseif string.sub( v, 1, 1 ) == "-" then local y = 2 local l = string.len(v) local jopt while ( y <= l ) do jopt = string.sub( v, y, y ) if string.find( options, jopt, 1, true ) then if y < l then tab[ jopt ] = string.sub( v, y+1 ) y = l else tab[ jopt ] = arg[ k + 1 ] end + else tab[ jopt ] = true end + y = y + 1 end + end end + return tab +end + + +-- [[ =================== Program Start ======================= ]] + +-- [[ Get our options and set up state ]] +local opts = getopt(arg, "host") + +-- if no host or host not set +if not opts.host + or opts.host == true +then + print(USAGE) + return +end + +--[[ Attempt to connect to the server ]] +print( "Connecting to " .. opts.host ) + +local sock = socket.connect( opts.host, 11715 ) +if not sock then error("Failed to connect to " .. opts.host .. " on port 11715") end + +print( "Connected to " .. opts.host ) + +local function GetNewLineFromSocket() + return sock:receive('*l') +end + +--[[ Perform handshake ]] + +-- receive the handshake line +local player, name = ttrts.PerformHandshake(sock) + +--[[ Begin main loop ]] +while not gameover do + + -- Grab the current gamestate + local gamestate = ttrts.GetState( GetNewLineFromSocket ) + + -- get the orders + local orders = ttrts.GetRandomOrders( player, gamestate ) + + -- send the orders + ttrts.SendOrders( sock, orders ) + + if table.getn( gamestate.units ) == 0 then gameover = true end +end \ No newline at end of file From f278308780beb4c5bc3606e7ed46c293a3fb097b Mon Sep 17 00:00:00 2001 From: Marc Di Luzio Date: Sun, 25 Jan 2015 12:25:38 +0000 Subject: [PATCH 5/6] Refactoring to simplify interface in line with moving the ttrts module out --- lua/random_player.lua | 74 ++++++++++++++++++++----------------------- 1 file changed, 35 insertions(+), 39 deletions(-) diff --git a/lua/random_player.lua b/lua/random_player.lua index e1e998d..e06cbdc 100755 --- a/lua/random_player.lua +++ b/lua/random_player.lua @@ -22,11 +22,17 @@ OPTIONS ttrts = {} do -ttrts.PerformHandshake = function (sock) +--[[ Attempt to connect to the server ]] +ttrts.ConnectToHost = function (host) + print( "Connecting to " .. host ) - if not sock then error("Must pass PerformHandshake a socket") end + ttrts.socket = socket.connect( host, 11715 ) + if not ttrts.socket then error("Failed to connect to " .. host .. " on port 11715") end - local line = sock:receive('*l') + print( "Connected to " .. host ) + + -- Porform the hanshake + local line = ttrts.socket:receive('*l') local player, name = string.match(line, "player (%d+) name ([%a%d]+)") @@ -37,15 +43,19 @@ ttrts.PerformHandshake = function (sock) print( "Name: " .. name ) -- return the handshake line with a new line (removed by the *l call to receive) and string end - sock:send( line .. "\n" .. "\0" ) + ttrts.socket:send( line .. "\n" .. "\0" ) return player, name end -- [[ Recieve gamestate info ]] -ttrts.GetState = function (newLine) +ttrts.GetStateFromHost = function () - if not newLine then error("Must pass GetState a method") end + if not ttrts.socket then error("ttrts.socket must be set") end + + function newLine() + return ttrts.socket:receive('*l') + end local line = "" local state = {} @@ -125,15 +135,13 @@ ttrts.GetRandomOrders = function( id, state ) end -- [[ Send the orders to the server through the socket ]] -ttrts.SendOrders = function( socket, orders ) +ttrts.SendOrdersToHost = function( orders ) assert( string.match(orders,"END"), "Cannot send orders without END" ) - socket:send( orders .. "\0" ) + ttrts.socket:send( orders .. "\0" ) end -end -- end ttrts - --- [[ http://lua-users.org/wiki/AlternativeGetOpt ]] -function getopt( arg, options ) +-- [[ using method from http://lua-users.org/wiki/AlternativeGetOpt ]] +ttrts.getopt function ( arg, options ) local tab = {} for k, v in ipairs(arg) do if string.sub( v, 1, 2) == "--" then local x = string.find( v, "=", 1, true ) if x then tab[ string.sub( v, 3, x-1 ) ] = string.sub( v, x+1 ) else tab[ string.sub( v, 3 ) ] = true end elseif string.sub( v, 1, 1 ) == "-" then local y = 2 local l = string.len(v) local jopt while ( y <= l ) do jopt = string.sub( v, y, y ) if string.find( options, jopt, 1, true ) then if y < l then tab[ jopt ] = string.sub( v, y+1 ) y = l else tab[ jopt ] = arg[ k + 1 ] end @@ -143,48 +151,36 @@ function getopt( arg, options ) return tab end +end -- end ttrts + + + -- [[ =================== Program Start ======================= ]] -- [[ Get our options and set up state ]] -local opts = getopt(arg, "host") +local opts = ttrts.getopt(arg, "host") -- if no host or host not set -if not opts.host - or opts.host == true -then - print(USAGE) - return +if not opts.host or opts.host == true then + print(USAGE) return end ---[[ Attempt to connect to the server ]] -print( "Connecting to " .. opts.host ) +-- [[ Connect to the host ]] +local player, name = ttrts.ConnectToHost(opts.host) -local sock = socket.connect( opts.host, 11715 ) -if not sock then error("Failed to connect to " .. opts.host .. " on port 11715") end - -print( "Connected to " .. opts.host ) - -local function GetNewLineFromSocket() - return sock:receive('*l') -end - ---[[ Perform handshake ]] - --- receive the handshake line -local player, name = ttrts.PerformHandshake(sock) - ---[[ Begin main loop ]] -while not gameover do +--[[ Main Loop ]] +while true do -- Grab the current gamestate - local gamestate = ttrts.GetState( GetNewLineFromSocket ) + local gamestate = ttrts.GetStateFromHost() + + print("TURN " .. gamestate.turn ) -- get the orders local orders = ttrts.GetRandomOrders( player, gamestate ) -- send the orders - ttrts.SendOrders( sock, orders ) + ttrts.SendOrdersToHost( orders ) - if table.getn( gamestate.units ) == 0 then gameover = true end end \ No newline at end of file From 241fef5cc8ebcde1afbab10dfb4c5e1d3246cc5b Mon Sep 17 00:00:00 2001 From: Marc Di Luzio Date: Sun, 25 Jan 2015 13:18:20 +0000 Subject: [PATCH 6/6] Pull ttrts code out to main repo --- lua/random_player.lua | 146 ++---------------------------------------- 1 file changed, 5 insertions(+), 141 deletions(-) diff --git a/lua/random_player.lua b/lua/random_player.lua index e06cbdc..134290e 100755 --- a/lua/random_player.lua +++ b/lua/random_player.lua @@ -1,7 +1,7 @@ #! /usr/bin/lua -- use socket to communicate with the server directly -require "socket" +ttrts = require "ttrts" -- usage text local USAGE = [[ @@ -18,146 +18,6 @@ OPTIONS HOSTNAME - host to connect to ]] --- [[ Perform the handshake to connect ]] -ttrts = {} -do - ---[[ Attempt to connect to the server ]] -ttrts.ConnectToHost = function (host) - print( "Connecting to " .. host ) - - ttrts.socket = socket.connect( host, 11715 ) - if not ttrts.socket then error("Failed to connect to " .. host .. " on port 11715") end - - print( "Connected to " .. host ) - - -- Porform the hanshake - local line = ttrts.socket:receive('*l') - - local player, name = string.match(line, "player (%d+) name ([%a%d]+)") - - -- bail out if handshake information failed - assert( player and name , "Handshake failed with incorrect player and name") - - print( "Player: " .. player ) - print( "Name: " .. name ) - - -- return the handshake line with a new line (removed by the *l call to receive) and string end - ttrts.socket:send( line .. "\n" .. "\0" ) - - return player, name -end - --- [[ Recieve gamestate info ]] -ttrts.GetStateFromHost = function () - - if not ttrts.socket then error("ttrts.socket must be set") end - - function newLine() - return ttrts.socket:receive('*l') - end - - local line = "" - local state = {} - - -- INVESTIGATE WHY THIS IS NEEDED - newLine() - - local thename = newLine() - state.name = string.match( thename, "NAME:([%a%d]+)" ) - assert( state.name, "Gamestate file format missmatch (no name)") - - state.size = {} - local sizes = newLine() - state.size.x, state.size.y = string.match( sizes, "SIZE:%[(%d+),(%d+)%]" ) - assert( state.size.x and state.size.y , "Gamestate file format missmatch (size failure)") - - state.turn = string.match( newLine(), "TURN:(%d+)" ) - assert( state.turn, "Gamestate file format missmatch (no turn)") - - -- Get the wall line - state.walls = {} - local wallline = newLine() - - assert(string.match( wallline, "WALL:"), "Gamestate file format missmatch (no wall line)") - - -- Grab all walls on the line - for wallstring in string.gmatch(wallline, "%[%d+,%d+%]") do - local wall = {} - wall.x, wall.y = string.match( wallstring, "%[(%d+),(%d+)%]" ) - table.insert(state.walls,wall) - end - - assert( newLine() == "~~~~", "Gamestate file format missmatch (missing ~~~~)" ) - - -- get the units - state.units = {} - - local unitline = newLine() - while unitline ~= "END" do - - local unit = {} - unit.pos = {} - - -- Parse the unit line - unit.id, unit.player, unit.vis, unit.dir, unit.pos.x, unit.pos.y = - string.match( unitline, "UNIT:(%d+) pl:(%d+) vs:([^%s]+) dr:(%a+) ps:%[(%d+),(%d+)%]") - - assert(unit.id and unit.player and unit.vis and unit.dir and unit.pos.x and unit.pos.y, "gamestate file format missmatch (error with unit)") - - table.insert(state.units,unit) - - unitline = newLine() - end - - assert(unitline == "END", "Gamestate file format missmatch (didn't end in END)") - - return state -end - --- [[ Get Random Orders from gamestate for a particular player ]] -ttrts.GetRandomOrders = function( id, state ) - - local orders = "" - local possibleorders = { "F", "L", "R", "A" } - - local units = state.units - for key,unit in pairs(units) do - if unit.id == id then - local order = "F" -- TODO MAKE RANDOM - orders = orders .. "ORDER:" .. order .. " id:" .. tostring(id) .. "\n" - end - end - - orders = orders .. "END\n" - - return orders -end - --- [[ Send the orders to the server through the socket ]] -ttrts.SendOrdersToHost = function( orders ) - assert( string.match(orders,"END"), "Cannot send orders without END" ) - ttrts.socket:send( orders .. "\0" ) -end - --- [[ using method from http://lua-users.org/wiki/AlternativeGetOpt ]] -ttrts.getopt function ( arg, options ) - local tab = {} - for k, v in ipairs(arg) do if string.sub( v, 1, 2) == "--" then local x = string.find( v, "=", 1, true ) if x then tab[ string.sub( v, 3, x-1 ) ] = string.sub( v, x+1 ) else tab[ string.sub( v, 3 ) ] = true end - elseif string.sub( v, 1, 1 ) == "-" then local y = 2 local l = string.len(v) local jopt while ( y <= l ) do jopt = string.sub( v, y, y ) if string.find( options, jopt, 1, true ) then if y < l then tab[ jopt ] = string.sub( v, y+1 ) y = l else tab[ jopt ] = arg[ k + 1 ] end - else tab[ jopt ] = true end - y = y + 1 end - end end - return tab -end - -end -- end ttrts - - - - --- [[ =================== Program Start ======================= ]] - -- [[ Get our options and set up state ]] local opts = ttrts.getopt(arg, "host") @@ -167,8 +27,12 @@ if not opts.host or opts.host == true then end -- [[ Connect to the host ]] +print( "Connecting to " .. opts.host ) local player, name = ttrts.ConnectToHost(opts.host) +print( "Player: " .. player ) +print( "Name: " .. name ) + --[[ Main Loop ]] while true do