Index of /~thor/ravt

      Name                              Last modified       Size  Description

[DIR] Parent Directory 19-Jul-2007 16:51 - [   ] animate-ascii.el 11-Sep-2002 23:18 3k [DIR] bot-battle-recordings/ 12-Sep-2002 16:29 - [DIR] docs/ 15-Sep-2002 02:15 - [DIR] examples/ 12-Sep-2002 16:29 - [   ] ravt-0.1.tar.gz 04-Sep-2002 17:41 11k [   ] ravt-0.2.tar.gz 05-Sep-2002 02:25 12k [   ] ravt-0.3.tar.gz 05-Sep-2002 17:45 20k [   ] ravt-0.4.tar.gz 06-Sep-2002 00:50 22k [DIR] ravt-0.4/ 06-Sep-2002 00:50 - [   ] ravt-0.5.tar.gz 06-Sep-2002 14:08 22k [DIR] ravt-0.5/ 06-Sep-2002 14:08 - [   ] ravt-0.6.tar.gz 09-Sep-2002 08:21 23k [DIR] ravt-0.6/ 09-Sep-2002 08:21 - [   ] ravt-0.7-linux-i686.tar.gz 10-Sep-2002 16:49 748k [DIR] ravt-0.7-linux-i686/ 10-Sep-2002 16:49 - [   ] ravt-0.7.5-linux-i686.tar.gz 10-Sep-2002 21:34 778k [DIR] ravt-0.7.5-linux-i686/ 10-Sep-2002 21:34 - [   ] ravt-0.7.5.tar.gz 10-Sep-2002 22:51 25k [DIR] ravt-0.7.5/ 10-Sep-2002 22:51 - [   ] ravt-0.7.tar.gz 10-Sep-2002 16:19 25k [DIR] ravt-0.7/ 10-Sep-2002 16:19 - [   ] ravt-0.8-linux-i686.tar.gz 11-Sep-2002 03:30 778k [DIR] ravt-0.8-linux-i686/ 11-Sep-2002 03:30 - [   ] ravt-0.8-static-linux-i686.tar.gz 11-Sep-2002 04:05 1.7M [DIR] ravt-0.8-static-linux-i686/ 11-Sep-2002 04:04 - [   ] ravt-0.8.tar.gz 11-Sep-2002 03:30 26k [DIR] ravt-0.8/ 11-Sep-2002 03:30 - [   ] ravt-0.9-linux-i686.tar.gz 12-Sep-2002 00:25 714k [DIR] ravt-0.9-linux-i686/ 12-Sep-2002 00:25 - [   ] ravt-0.9-static-linux-i686.tar.gz 12-Sep-2002 00:02 1.7M [DIR] ravt-0.9-static-linux-i686/ 12-Sep-2002 00:01 - [   ] ravt-0.9.tar.gz 12-Sep-2002 00:25 28k [DIR] ravt-0.9/ 12-Sep-2002 00:25 -


                                README

          ICFP 2002 Robot Analysis and Visualization Toolkit
                    Tom Moertel <tom@moertel.com>

     CVS $Id: README,v 1.13 2002/09/12 03:17:15 thor Exp $


* WHAT'S NEW

  2002-09-15

  - Added example Perl code to README that shows how to process the
    output of DumpGameAnalysis. (See "Example visualizer in Perl".)

  2002-09-11

  - Explained how to use RobotProxy to record the names of your
    robots.  The names are used by the analysis tools to generate
    titles automatically.

  - Web-based visualization is on the way!  Tomas Rokicki of Team
    Radical Too is building a Javascript visualizer on top of
    DumpGameAnalysis.  It's way cool.  Stay tuned for more.

  - DumpGameAnalysis makes it easy to write visualizers in other
    languages.  It does all of the game-state analysis for you and
    dumps an easy-to-parse stream to standard output.

  - There is now an Emacs mode for playing back ASCII visualizations
    (animate-ascii.el).  To use:

      M-x load-file RET animate-ascii.el RET

      (switch to a buffer containing an ASCII visualization)

      M-x animate-ascii RET
      -- or, if the buffer contains ANSI color codes --
      M-x animate-ascii-color RET



* CONTENTS

   WHAT'S NEW
   CONTENTS
   WHAT IS THE ROBOT ANALYSIS AND VISUALIZATION TOOLKIT?
   VERY QUICK START
   BUILDING THE TOOLKIT
   WHAT'S IN THE TOOLKIT?
   MONITORING AND RECORDING GAMES
      Using RobotProxy
      One robot, one perspective
   ANALYSIS TOOLS
      ReadGameLog
      MergeGames
   VISUALIZATION TOOLS
      VisualizeGameASCII
   BUILDING YOUR OWN VISUALIZERS
      Sample DumpGameAnalysis output
      Example visualizer in Perl
   REFERENCES
   LICENSE


* WHAT IS THE ROBOT ANALYSIS AND VISUALIZATION TOOLKIT?

The Challenge Task for the 2002 ICFP Programming Contest required
contestants to program robots that would attempt to deliver packages
in a fictional game world.  The robots compete alone and against other
robots in games played on game servers, and the winner is determined
based upon the best cumulative score.

Because these games might be interesting to watch, I created the Robot
Analysis and Visualization Toolkit (RAVT for short).  RAVT provides
the following:

  - tools for monitoring and recording live games

  - programming libraries for reading and analyzing recorded games

  - visualization tools that allow games to be replayed, stepped
    through, and otherwise scrutinized by human observers

RAVT is written in Haskell using GHC 5.04 and relies upon some GHC
extensions to the Haskell 98 standard.


* VERY QUICK START

For those of you who want to jump right in, this is the section for
you.  It presents the bare essentials, nothing more.  You can read
the following sections if you want to learn more.

Here's how to use RAVT:

  0. Build the toolkit: make.

  1. Set up per-robot proxies to to record a game. (RobotProxy)

  2. Convert the resulting logs into Game format (ReadGameLog) and
     merge the per-robot Games into a composite Game.  (MergeGames)

  3. Visualize the Games.  (VisualizeGameASCII, VisualizeGamePS)

  4. Write your own visualizers.  (DumpGameAnalysis)

The following subsections explain in slightly more detail by way of
example.

** Set up per-robot proxies to record a game.

Let's say that a robot battle simulator is running on port 12000 of
gamehost.example.com and is configured for battles among three
robots at a time.  You want to record a three-way battle.

Here's how to do it. First, set up three RobotProxy instances, each on
a separate port and running in the background:

    RobotProxy 15001 gamehost.example.com 12000 > bot1.log &
    RobotProxy 15002 gamehost.example.com 12000 > bot2.log &
    RobotProxy 15003 gamehost.example.com 12000 > bot3.log &

(See the RobotProxy section for information on how to add your
robot's names to the log so that they can be used for automatic
title generation.)

Second, run your bots, telling each to connect to its respective
RobotProxy instance:

    /path/to/mybot/runme localhost 15001
    /path/to/myotherbot/runme localhost 15002
    /path/to/anotherbot/runme localhost 15003

Finally, wait for the battle to end.  The RobotProxy instances will
exit automatically.

**  Convert the resulting logs into a merged Game file.

You have recorded a single game from the perspective from three
robots.  Each robot may see only a portion of the overall game.  To
see the complete picture, you must combine their individual
perspectives:

    ReadGameLog bot1.log > bot1.game
    ReadGameLog bot2.log > bot2.game
    ReadGameLog bot3.log > bot3.game
    MergeGames bot1.game bot2.game bot3.game > complete.game

If you are using the bash shell, you can simplify the procedure as
follows:

    for f in bot?.log; do ReadGameLog $f; done \
    | MergeGames > complete.game

**  Visualize the Games.

Now it's time to watch the battle!  First, render the game as an
ASCII-art visualization:

    VisualizeGameASCII --colorize complete.game > complete.txt

(If your terminal doesn't support ANSI color codes, omit the --colorize
option.)

Then, view the animation in an ASCII-art viewer, or use a simple
Perl one-liner like this:

    perl -pe 'sleep 1 if /^\f/' complete.txt

The examples/ section of the RAVT web site provides example
visualizations and provides more-sophisticated viewers.

    http://tea.moertel.com/~thor/ravt/examples/

** Read on

If you want to know more about about RAVT, including how to create
your own visualizers, read the following sections.


* BUILDING THE TOOLKIT

If you have GHC 5.04 installed, you should be able to build all of the
tools by typing

    make

from within the root of the project directory.  If you have the
Haddock documentation generator installed, you may also want to

    make docs

to generate reference documentation.


* WHAT'S IN THE TOOLKIT?

The toolkit includes the following tools:

    RobotProxy -- Proxy server that records a game from a robot's
        perspective.

    ReadGameLog -- Converts a RobotProxy log file into a Game, which
        is more suitable representation of a game for analysis and
        visualization purposes.

    MergeGames -- Merges Games captured by different robots into a
        composite Game value that combines the individual robots'
        knowledge.

    VisualizeGameASCII -- Converts a game into a text file that shows
        each turn in the game as ASCII art.  Turns are separated by
        ^L page breaks.

    VisualizeGameCurses -- Plays back the game on a curses-based
        viewer (terminal screen) that allows forward and backward
        playback and single stepping. *

    VisualizeGamePS -- Converts a game into a series of Postscript
        pages, each of which represents a turn of the game.  This
        format more suitable for analyzing and viewing games played on
        very large maps. *

    * = not finished yet

The toolkit also provides a number of Haskell modules for reading,
analyzing, and visualizing games.  These modules make it easy to
create new analysis and visualization tools.


* MONITORING AND RECORDING GAMES

Games are monitored using RobotProxy, a proxy server that can be
inserted between a robot and real game server.  The proxy records
transactions between the server and the robot, writing the
transactions to standard output in a format that both humans and
computers can read (although the computer may have the easier job).

RobotProxy also allows you to connect to a server manually via telnet,
should you desire to "play robot."  Normally you can't do this because
telnet sends CRLF pairs that the game server considers illegal, but
RobotProxy converts these pairs to acceptable Unix-style line endings.

** Using RobotProxy

Using RobotProxy is simple.  You provide it with a local port to
listen on and tell it where the real game server is:

    RobotProxy <localport> <realserver> <realserverport> [<robotname>]

RobotProxy listens on <localport> for a single robot to connect.  It
then connects to the real game server at <realserver>:<realserverport>
and relays communications between the robot and the server, recording
the events of the game in passing.  Usually, you should redirect
RobotProxy's output to a log file, but if you want to watch in real
time, go right ahead.

The <robotname> parameter is optional.  If you know the name of the
robot that will be connecting to a particular instance of RobotProxy,
use the <robotname> parameter to tell RobotProxy to append the name
to the recordings.  That way the analysis tools can automatically
generate battle titles.

    Example

    A game server is running on port 12000 of gamehost.example.com,
    and you want to record a game in which your robot SmartyBot
    participates.

    (1) Start RobotProxy on local port 15000:

        RobotProxy 15000 gamehost.example.com 12000 SmartyBot > game1.log &

    (2) Start your robot, directing it to RobotProxy:

        /path/to/SmartyBot/runme localhost 15000

    (3) That's it!  When SmartyBot is finished, you can examine
        the game1.log to review the game.

** One robot, one perspective

It's important to note that RobotProxy captures the events of the game
from the perspective of the robot being monitored.  Since the game
protocol, by design, provides different information to different robots,
the game recording won't include information known only to other
robots.  The analysis tools provide a means of merging recordings from
several robots in order to yield a more complete understanding of a
game. (See MergeGames for more.)


* ANALYSIS TOOLS

Once you have made recordings of a game, you will want to convert
the recording logs into a format more suitable for analysis and
visualization.  The ReadGameLog program does this.  It converts
a single game recording into a Game value, which represents the
history of the game in sensible parts:

    PlayerHandshakes -- The handshakes that the robots used to
        announce themselves to the server.  Typically, each
        robot will use the "Player" handshake, but others are
        legal (e.g., "Login <X> <Y>").

    Board -- The game board provided by the server.

    RobotConfigs -- The information provided to each robot by the
        server at the start of the game.  Each robot is assigned a
        unique identifier, a maximum carrying capacity, and an
        allotment of money.

    InitialResponse -- The information provided to all robots before
        the game begins.  The information is in the same format that
        the sever uses at the end of each turn to tell the robots the
        outcome of the turn.  Here, the response serves mainly to
        inform each robot about its starting position as well as let
        it know about all of the other robots on the playing field.

    Turns -- A list of the turns in the game.  The format of each turn
        is as follows:

        PackageInfo -- The information provided to each robot about
            the packages in the cell it occupies at the start of the
            turn.

        PlayerCommands -- The bid and command each robot tried to
            perform.

        ServerResponse -- The response from the server to all robots
            that describes the outcome the turn.

    Epilogues -- The information provided to each robot when it dies
        or when the game ends.  Each robot may receive a different
        epilogue at a different time.  A typical epilogue looks like
        this:

                       **** Reason: Game over
                       **** Score : 242
                       **** Money : 883

The format of Game values is described in the Game.hs file and in the
accompanying Haddock documentation.

The ReadGameLog tool converts a game log, as captured by RobotProxy,
into a Game and writes the Game to standard output.  The MergeGames
tool merges any number of Game values captured from the same
game into a single composite Game.  The following sections explain
these tools in more detail.

** ReadGameLog

ReadGameLog is a filter that converts a RobotProxy game log into
Game format:

    ReadGameLog game1.log > game1.game

If you don't care about real-time monitoring of the log, you can
record directly into Game format using RobotProxy and ReadGameLog in a
pipeline:

    RobotProxy 15000 gamehost.example.com 12000  \
       | ReadGameLog > game1.game &

** MergeGames

If you record a game from the perspective of several robots, you can
combine their respective Games into a unified Game that captures their
combined knowledge.  You will almost always want to merge all the
Games you have recorded from a single game before application of a
visualization tool.  Otherwise, the visualizer may have to accommodate
knowledge gaps, which lead to less informative visualizations.

MergeGames does this merging.  For example, if you have game1.game and
game2.game, you can combine them as follows:

    MergeGames game1.game game2.game > games1and2.game

games1and2.game captures all of the knowledge from both game1.game and
game2.game.  You can merge any number of Games, provided that they
all were originally recorded from the same game.


* VISUALIZATION TOOLS

RAVT provides a number of tools to visualize Games.  The following
sections describe them in detail.

** VisualizeGameASCII

VisualizeGameASCII converts a Game into a series of ASCII-art pages,
one page for each turn.  Usage is simple:

    VisualizeGameASCII [--colorize] mygame.game > mygame.txt

The --colorize option causes the output to include ANSI color codes.
If your terminal supports ANSI color codes, you probably ought to
use this option because it makes the visualization more effective.

You can view the visualization in any page-based text viewer, or you
can use the following Perl one-liner to animate it:

    perl -pe 'sleep 1 if /^\f/' mygame.txt

A C version of the above concept allows for finer-grained control over
the playback speed.

I have also provided an emacs mode (animate-ascii.el) for playing back
the ASCII-based visualizations.  You can find both the C "view2" player
and animate-ascii.el in the examples/ directory of the RAVT web site.


* BUILDING YOUR OWN VISUALIZERS

It is easy to write your own game visualizers.  DumpGameAnalysis can
be used by your visualizer to read a game, analyze it, and hand you
the turn-by-turn analysis in an easy-to-parse format.  Then you simply
convert each turn into an appropriate visualization.

The output format of DumpGameAnalysis is as follows:

    <board-cols> <board-rows>
    <board, one line per row, right side up>
    <count of robots>

and then, for each robot, a row of the following format:

    I <robot's ID> <robot's name (names may contain spaces)>

and then, for each turn and for each still-alive robot, a row of the
following format:

    R <turn> <robot's ID> <x> <y> <score> <money> <#pkgs> <bid> <cmd>

Note: <cmd> may contain spaces (that's why it's last in the list).

Note: When a robot dies (or otherwise is removed from the game during
a turn), the reason for its death/removal is appended to the <cmd>,
field, separated from the rest by a pipe symbol ("|"):

    R ... <bid> <cmd> | <reason for death>

The example, below, shows actual output.


** Sample DumpGameAnalysis output

Here's a sample of DumpGameAnalysis's output, taken from a battle
between Skipperdee and #Haskell's Postman on venice.map:

    60 15
    ~~~~~~~~~......#.#@......@#.#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    ~~~~~~~........#.####..####.#.~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    ~~~~~..........#..............~~~~~~~~~~~~~~~~~~~~~~~~~~~~~.
    ~~~~...~.......######~~######.~~~~~~~~~~~~~~~~~.............
    ~.....~~~......................~~~~~~~~~~~~~~...............
    ~.....~~~~~~~~~~~~~..~~~~~.........~~~~~~..........~~~~~~~~~
    ~.....~~~~~~~~~~~~~..~~~~~.....~~~~~~~~.........~~~~~~~~~~~~
    ~.....~~~~~~~~~~~~~..~~~~~....~~~~~~~~~...#..#..~~~~~~~~~~~~
    ~.....~~~~~~~~~~~~~..~~~~~...~~.......#####..###############
    ~.....~~~~~~~~~~~~~..~~~~~~~~~~.......#....................#
    ~.............~~~~~~.~~~~~~~.........####...####...#######.#
    ~~~~##..........~~~~........................#......#..@....#
    #~~~##...........~~~~~...............####...####...#.#####.#
    ##.###................~~~~~~~~~.......#....................#
    ......................................######################
    2
    I 1 Skipperdee
    I 2 #Haskell Postman
    R 0 1 1 1 0 5000 0 ?
    R 0 2 1 1 0 5000 0 ?
    R 1 1 2 1 0 4999 0 1 Move E
    R 1 2 3 1 0 4999 0 1 Move E
    R 2 1 3 1 0 4997 0 2 Move E
    R 2 2 4 1 0 4998 0 1 Move E
    R 3 1 4 1 0 4995 0 2 Move E
    R 3 2 5 1 0 4997 0 1 Move E
    R 4 1 5 1 0 4993 0 2 Move E
    R 4 2 6 1 0 4996 0 1 Move E
        (turns 5--19 omitted)
    R 20 1 7 13 0 4466 0 497 Move E
    R 20 2 6 13 0 4980 0 1 Move N
    R 21 1 6 13 0 4241 0 225 Move W
    R 21 2 5 13 0 4979 0 1 Move E | Robot 2 died. *** Reason: Water
    R 22 1 7 13 0 4239 0 2 Move E
    R 23 1 8 13 0 4238 0 1 Move E
        (turns 24--167 omitted)
    R 168 1 44 6 30 4093 1 1 Move N
    R 169 1 45 6 30 4092 1 1 Move E
    R 170 1 46 6 30 4091 1 1 Move E | (Finished.)

Note that after Robot 2 died, no more rows are output for it.

** Example visualizer in Perl

Here is a simple Perl-based visualizer viz-distance.pl that I wrote to
summarize the distance that each robot traveled during a battle.  First,
to show what it does, here is its output when run on the battle whose
analysis dump was provided in the previous subsection:

    $ ./viz-distance.pl examples/skipperdee-vs-postman-venice.game

    Skipperdee (robot 1) traveled 168 blocks.
    #Haskell Postman (robot 2) traveled 22 blocks.

Here's the code:

    #!/usr/bin/perl -wl

    use strict;
    use File::Basename;
    use File::Spec;

    # determine where DumpGameAnalysis tool is (assume it's in the
    # same directory as this tool)

    my $tool_dir = dirname($0);
    my $dump_game_tool = File::Spec->catfile($tool_dir, "DumpGameAnalysis");

    # pass DumpGameAnalysis our arguments, let it analyze the game,
    # and read its output from a pipe so that we can parse it below

    open(PIPE, "-|") || exec($dump_game_tool, @ARGV)
        or die "Can't open pipe to $dump_game_tool: $!";

    # initialize hashes in which we'll track robot names, positions,
    # and distances traveled

    my (%robot_names, %positions, %distances);

    # parse the output from DumpGameAnalysis

    while (<PIPE>) {

        # handle robot-identification lines (I <id> <name>)
        if (/^I (\S+) (.*)/) {$robot_names{$1} = $2 ; next}

        # handle robot turn-status lines (R <turn> <id> <x> <y> ...)
        if (/^R \S+ (\S+) (\S+) (\S+)/) {
            my ($robot, $x, $y) = ($1, $2, $3);
            my ($lastx, $lasty) = @{$positions{$robot} ||= [$x, $y]};
            $distances{$robot} += abs($x - $lastx) + abs($y - $lasty);
            $positions{$robot} = [$x, $y];
        }
    }

    close PIPE;

    # print the results

    foreach my $robot (sort keys %robot_names) {
        my ($name, $distance) = ($robot_names{$robot}, $distances{$robot});
        print "$name (robot $robot) traveled $distance blocks.";
    }


* REFERENCES

Robot Analysis and Visualization Toolkit Home Page
    http://tea.moertel.com/~thor/ravt/

ICFP 2002 Programming Contest
    http://icfpcontest.cse.ogi.edu/

GHC, the Glasgow Haskell Compiler
    http://www.haskell.org/ghc/

Haddock: A Haskell documentation tool
    http://www.haskell.org/haddock/


* LICENSE

Copyright (C) 2002 Thomas Moertel.

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.

The text of the GNU GPL may be found in the LICENSE file,
included with this software, or online at the following URL:

    http://www.gnu.org/copyleft/gpl.html

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.

Except as provided for under the terms of the GNU GPL, all rights
are reserved worldwide.




Local Variables:
mode:outline
End: