641956c66398

cl-ggp: Update site.
[view raw] [browse files]
author Steve Losh <steve@stevelosh.com>
date Wed, 23 Mar 2016 21:36:48 +0000
parents 621ae61499ab
children ef26a5dd830f
branches/tags (none)
files cl-ggp/changelog/index.html cl-ggp/installation/index.html cl-ggp/overview/index.html cl-ggp/reference/index.html

Changes

--- a/cl-ggp/changelog/index.html	Wed Mar 23 16:24:01 2016 +0000
+++ b/cl-ggp/changelog/index.html	Wed Mar 23 21:36:48 2016 +0000
@@ -13,7 +13,14 @@
         <div class="wrap">
             <header><h1><a href="..">cl-ggp</a></h1></header>
                 <div class="markdown">
-<h1 id="changelog"><a href="">Changelog</a></h1></div>
+<h1 id="changelog"><a href="">Changelog</a></h1><p>Here's the list of changes in each released version.</p>
+<div class="toc">
+<ul>
+<li><a href="#v001">v0.0.1</a></li>
+</ul></div>
+<h2 id="v001">v0.0.1</h2>
+<p>Initial alpha version.  Things are going to break a lot.  Don't use this.</p>
+                </div>
             <footer><p><i>Made with Lisp and love by <a href="http://stevelosh.com/">Steve Losh</a> in Reykjavík, Iceland.</i></p>
 <script>
   (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
--- a/cl-ggp/installation/index.html	Wed Mar 23 16:24:01 2016 +0000
+++ b/cl-ggp/installation/index.html	Wed Mar 23 21:36:48 2016 +0000
@@ -13,7 +13,10 @@
         <div class="wrap">
             <header><h1><a href="..">cl-ggp</a></h1></header>
                 <div class="markdown">
-<h1 id="installation"><a href="">Installation</a></h1></div>
+<h1 id="installation"><a href="">Installation</a></h1><p><code>cl-ggp</code> is compatible with Quicklisp, but not <em>in</em> Quicklisp (yet?).  You can
+clone the repository into your <a href="https://www.quicklisp.org/beta/faq.html#local-project">Quicklisp local-projects</a> directory for
+now.</p>
+                </div>
             <footer><p><i>Made with Lisp and love by <a href="http://stevelosh.com/">Steve Losh</a> in Reykjavík, Iceland.</i></p>
 <script>
   (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
--- a/cl-ggp/overview/index.html	Wed Mar 23 16:24:01 2016 +0000
+++ b/cl-ggp/overview/index.html	Wed Mar 23 21:36:48 2016 +0000
@@ -15,6 +15,8 @@
                 <div class="markdown">
 <h1 id="overview"><a href="">Overview</a></h1><p><code>cl-ggp</code> handles the GGP protocol for you.  Players are implemented as CLOS
 objects.</p>
+<p>This document assumes you know what General Game Playing is, what GDL is, and
+how the GGP community/competitions/etc work.</p>
 <div class="toc">
 <ul>
 <li><a href="#basics">Basics</a></li>
@@ -25,24 +27,26 @@
 <li><a href="#player-stop-game">player-stop-game</a></li>
 </ul>
 </li>
+<li><a href="#timeouts">Timeouts</a></li>
+<li><a href="#symbols">Symbols</a></li>
 <li><a href="#example-player">Example Player</a></li>
 </ul></div>
 <h2 id="basics">Basics</h2>
 <p>You can create your own player by extending the <code>ggp-player</code> class, creating an
 object, and calling <code>start-player</code> on it to fire it up:</p>
-<div class="codehilite"><pre>(defclass simple-player (ggp:ggp-player)
-  ())
+<div class="codehilite"><pre><span class="p">(</span><span class="nb">defclass</span> <span class="nv">simple-player</span> <span class="p">(</span><span class="nv">ggp:ggp-player</span><span class="p">)</span>
+  <span class="p">())</span>
 
-(defvar *player* (make-instance 'simple-player
-                                :name "SimplePlayer"
-                                :port 4000))
+<span class="p">(</span><span class="nb">defvar</span> <span class="vg">*player*</span> <span class="p">(</span><span class="nb">make-instance</span> <span class="ss">'simple-player</span>
+                                <span class="ss">:name</span> <span class="s">"SimplePlayer"</span>
+                                <span class="ss">:port</span> <span class="mi">4000</span><span class="p">))</span>
 
-(ggp:start-player *player*)
+<span class="p">(</span><span class="nv">ggp:start-player</span> <span class="vg">*player*</span><span class="p">)</span>
 </pre></div>
 
 
-<p><code>ggp-player</code> takes <code>:name</code> and <code>:port</code> initargs.  It has a few other internal
-slots you shouldn't mess with.</p>
+<p><code>ggp-player</code> takes <code>:name</code> and <code>:port</code> initargs, which do what you think they
+do.  It has a few other internal slots you shouldn't mess with.</p>
 <p>You can kill a player with <code>kill-player</code>.</p>
 <h2 id="functionality">Functionality</h2>
 <p><code>cl-ggp</code> defines four generic methods that are called on players at various
@@ -51,8 +55,8 @@
 <p>At a minimum you <strong>must</strong> implement <code>player-select-move</code>.  The others are
 optional and will default to doing nothing.</p>
 <h3 id="player-start-game">player-start-game</h3>
-<div class="codehilite"><pre>(defmethod player-start-game ((player YOUR-PLAYER) rules role start-clock play-clock)
-  ...)
+<div class="codehilite"><pre><span class="p">(</span><span class="nb">defmethod</span> <span class="nv">player-start-game</span> <span class="p">((</span><span class="nv">player</span> <span class="nv">YOUR-PLAYER</span><span class="p">)</span> <span class="nv">rules</span> <span class="nv">role</span> <span class="nv">timeout</span><span class="p">)</span>
+  <span class="o">...</span><span class="p">)</span>
 </pre></div>
 
 
@@ -60,34 +64,132 @@
 <p><code>rules</code> is the GDL rules of the game, parsed into Lisp lists/symbols.  You'll
 probably want to feed this into a logic library.</p>
 <p><code>role</code> is a symbol representing which role you've been assigned.</p>
-<p><code>start-clock</code> is </p>
-<p><code>play-clock</code> is </p>
+<p><code>timeout</code> is the timestamp that the response to the server is due by, in
+internal-real time units (more on this later).</p>
 <h3 id="player-update-game">player-update-game</h3>
-<div class="codehilite"><pre>(defmethod player-update-game ((player YOUR-PLAYER) moves)
-  ...)
+<div class="codehilite"><pre><span class="p">(</span><span class="nb">defmethod</span> <span class="nv">player-update-game</span> <span class="p">((</span><span class="nv">player</span> <span class="nv">YOUR-PLAYER</span><span class="p">)</span> <span class="nv">moves</span><span class="p">)</span>
+  <span class="o">...</span><span class="p">)</span>
 </pre></div>
 
 
-<p>This is called once per turn, to update the game state with the moves each
-player selected.</p>
-<p><code>moves</code> is a list of the moves made by all players.</p>
+<p>This is called once per turn, to allow you to update the game state with the
+moves each player selected.</p>
+<p><code>moves</code> will be an association list of <code>(role . move)</code> conses representing the
+moves made by each player last turn.</p>
 <h3 id="player-select-move">player-select-move</h3>
-<div class="codehilite"><pre>(defmethod player-select-move ((player YOUR-PLAYER))
-  ...)
+<div class="codehilite"><pre><span class="p">(</span><span class="nb">defmethod</span> <span class="nv">player-select-move</span> <span class="p">((</span><span class="nv">player</span> <span class="nv">YOUR-PLAYER</span><span class="p">)</span> <span class="nv">timeout</span><span class="p">)</span>
+  <span class="o">...</span><span class="p">)</span>
 </pre></div>
 
 
-<p>This is called once per turn.  It should return the move your player wants to
+<p>This is called once per turn.  It needs to return the move your player wants to
 do.  All players <strong>must</strong> implement this function.</p>
+<p><code>timeout</code> is the timestamp that the response to the server is due by, in
+internal-real time units (more on this later).</p>
 <h3 id="player-stop-game">player-stop-game</h3>
-<div class="codehilite"><pre>(defmethod player-stop-game ((player YOUR-PLAYER))
-  ...)
+<div class="codehilite"><pre><span class="p">(</span><span class="nb">defmethod</span> <span class="nv">player-stop-game</span> <span class="p">((</span><span class="nv">player</span> <span class="nv">YOUR-PLAYER</span><span class="p">))</span>
+  <span class="o">...</span><span class="p">)</span>
 </pre></div>
 
 
 <p>This is called when the game is stopped.  You can use it for things like tearing
 down any extra data structures you've made, suggesting a GC to your Lisp, etc.</p>
+<h2 id="timeouts">Timeouts</h2>
+<p>The GGP protocol specifies time limits for players.</p>
+<p>When the initial game description is sent, players have a limited amount of time
+for "metagaming" where they might process the rules, build alternate
+representations (e.g. a propnet), start searching the game's DAG, etc.</p>
+<p>Once the initial "metagaming" phase is over, the players must each choose a move
+in every round, and there is a time limit on how long it takes them to respond.</p>
+<p><code>cl-ggp</code> mostly handles the annoying work of calculating the time your methods
+have available for work, but there are a few caveats.</p>
+<p>First: the <code>timestamp</code> arguments your methods get are timestamps of
+internal-real time.  If you're not familiar with how interal time works in
+Common Lisp, you should fix that.  Read up on <a href="http://www.lispworks.com/documentation/HyperSpec/Body/f_get_in.htm#get-internal-real-time">get-internal-real-time</a> and
+<a href="http://www.lispworks.com/documentation/HyperSpec/Body/v_intern.htm#internal-time-units-per-second">internal-time-units-per-second</a>.</p>
+<p>So you need to finish responding to the request by the internal-real timestamp
+given.  This brings us to the second caveat: "finishing responding" includes
+returning back up the call stack and sending the HTTP response back to the game
+server.  It's probably wise to bake a bit of breathing room into your player and
+not use <em>all</em> the given time in <code>timeout</code>, but <code>cl-ggp</code> doesn't try to decide
+how much time to reserve.  You should decide that based on things like:</p>
+<ul>
+<li>Your ping to the GGP server.</li>
+<li>How likely it is for your Lisp process to get descheduled by your OS, and how
+  long it might take to start running again.</li>
+<li>Worst-case duration of a GC pause right before sending the response.</li>
+<li>How brave you're feeling today.</li>
+</ul>
+<p>In a nutshell: when <code>(get-internal-real-time)</code> returns the number given to you
+in <code>timeout</code>, your message better have already reached the server.</p>
+<h2 id="symbols">Symbols</h2>
+<p>The other tricky part about <code>cl-ggp</code> is how it handles symbols.</p>
+<p>Game descriptions are written in GDL, a fragment of which might look like this:</p>
+<div class="codehilite"><pre>(role x)
+(role o)
+(init (control x))
+
+(&lt;= (legal ?role (mark ?row ?col ?role))
+  (control ?role)
+  (is-blank ?row ?col))
+</pre></div>
+
+
+<p>This is obviously pretty close to Lisp — it's just a bunch of lists of
+symbols — so reading it in is almost trivial.  The main question is which
+package the symbols get interned into.</p>
+<p><code>cl-ggp</code> interns all GDL symbols into a separate package called <code>GGP-RULES</code> to
+prevent polluting other packages.  It also clears this package between matches
+(except for a few special symbols that survive the clearing) to prevent building
+up mountains of garbage symbols from building up over time, especially when GDL
+scrambing is enabled on the server.</p>
+<p>This means that when your player's methods get symbols in their input (i.e. in
+the <code>rules</code>, <code>role</code>, and <code>moves</code> arguments) those symbols will be interned in
+<code>GGP-RULES</code>.  When your player returns a move to make from <code>player-select-move</code>,
+any symbols inside it must be interned in <code>GGP-RULES</code> for things to work
+correctly.</p>
+<p>This is kind of shitty, and the author is aware of that.  Suggestions for less
+shitty alternatives that still feel vaguely lispy are welcome.</p>
 <h2 id="example-player">Example Player</h2>
+<p><code>cl-ggp</code> is pretty bare bones, so it's tough to show an example player on its
+own without bringing in a logic library.  But we can at least sketch out
+a stupid little player that just returns the same move all the time, regardless
+of whether it's valid or not, just to show the end-to-end process of creating
+a player.</p>
+<p>First we'll define the player class and implement the required
+<code>player-select-move</code> method for it:</p>
+<div class="codehilite"><pre><span class="p">(</span><span class="nb">defclass</span> <span class="nv">simple-player</span> <span class="p">(</span><span class="nv">ggp:ggp-player</span><span class="p">)</span>
+  <span class="p">())</span>
+
+<span class="p">(</span><span class="nb">defmethod</span> <span class="nv">ggp:player-select-move</span> <span class="p">((</span><span class="nv">player</span> <span class="nv">simple-player</span><span class="p">)</span> <span class="nv">timeout</span><span class="p">)</span>
+  <span class="ss">'ggp-rules::wait</span><span class="p">)</span>
+</pre></div>
+
+
+<p>Our player doesn't store any state of its own, so it doesn't need any extra
+slots.  Notice how <code>player-select-move</code> returns a symbol from the <code>GGP-RULES</code>
+package as discussed above.</p>
+<p>The move our stupid player always returns is <code>WAIT</code>.  If the game supports that
+move we'll make it every time, otherwise the game server will reject it as
+invalid and just choose a random move for us.</p>
+<p>Now we can actually create a player:</p>
+<div class="codehilite"><pre><span class="p">(</span><span class="nb">defvar</span> <span class="vg">*player*</span>
+  <span class="p">(</span><span class="nb">make-instance</span> <span class="ss">'simple-player</span>
+                 <span class="ss">:name</span> <span class="s">"SimplePlayer"</span>
+                 <span class="ss">:port</span> <span class="mi">5000</span><span class="p">))</span>
+</pre></div>
+
+
+<p>And fire it up:</p>
+<div class="codehilite"><pre><span class="p">(</span><span class="nv">ggp:start-player</span> <span class="vg">*player*</span><span class="p">)</span>
+</pre></div>
+
+
+<p>Now we can play a few games with it.  We'll probably lose every time unless
+we're playing an unscrambled game of <a href="https://bitbucket.org/snippets/sjl/erRjL">Don't Press the Button</a>.</p>
+<p>Once we're done we can kill it to free up the port:</p>
+<div class="codehilite"><pre><span class="p">(</span><span class="nv">ggp:kill-player</span> <span class="vg">*player*</span><span class="p">)</span>
+</pre></div>
                 </div>
             <footer><p><i>Made with Lisp and love by <a href="http://stevelosh.com/">Steve Losh</a> in Reykjavík, Iceland.</i></p>
 <script>
--- a/cl-ggp/reference/index.html	Wed Mar 23 16:24:01 2016 +0000
+++ b/cl-ggp/reference/index.html	Wed Mar 23 21:36:48 2016 +0000
@@ -24,6 +24,10 @@
 <li><a href="#ggp-player-class">GGP-PLAYER (class)</a><ul>
 <li><a href="#slot-name">Slot NAME</a></li>
 <li><a href="#slot-port">Slot PORT</a></li>
+<li><a href="#slot-match-roles">Slot MATCH-ROLES</a></li>
+<li><a href="#slot-start-clock">Slot START-CLOCK</a></li>
+<li><a href="#slot-play-clock">Slot PLAY-CLOCK</a></li>
+<li><a href="#slot-message-start">Slot MESSAGE-START</a></li>
 <li><a href="#slot-current-match">Slot CURRENT-MATCH</a></li>
 <li><a href="#slot-server">Slot SERVER</a></li>
 </ul>
@@ -36,8 +40,10 @@
 <li><a href="#start-player-function">START-PLAYER (function)</a></li>
 </ul>
 </li>
+<li><a href="#package-ggp-rules">Package GGP-RULES</a></li>
 </ul></div>
 <h2 id="package-ggp">Package GGP</h2>
+<p>The main GGP package.</p>
 <h3 id="ggp-player-class">GGP-PLAYER (class)</h3>
 <p>The base class for a GGP player.  Custom players should extend this.</p>
 <h4 id="slot-name">Slot NAME</h4>
@@ -54,6 +60,31 @@
 <li>Reader: <code>PLAYER-PORT</code></li>
 </ul>
 <p>The port the HTTP server should listen on.</p>
+<h4 id="slot-match-roles">Slot MATCH-ROLES</h4>
+<ul>
+<li>Allocation: INSTANCE</li>
+<li>Type: <code>(OR NULL LIST)</code></li>
+<li>Reader: <code>PLAYER-MATCH-ROLES</code></li>
+</ul>
+<p>A list of the roles for the current match.  Feel free to read and use this if you like.  <strong>Do not modify this.</strong></p>
+<h4 id="slot-start-clock">Slot START-CLOCK</h4>
+<ul>
+<li>Allocation: INSTANCE</li>
+<li>Type: <code>(OR NULL (INTEGER 1))</code></li>
+</ul>
+<p>The start clock for the current game.  <strong>Do not touch this.</strong>  Use the <code>timeout</code> value passed to your methods instead.</p>
+<h4 id="slot-play-clock">Slot PLAY-CLOCK</h4>
+<ul>
+<li>Allocation: INSTANCE</li>
+<li>Type: <code>(OR NULL (INTEGER 1))</code></li>
+</ul>
+<p>The play clock for the current game.  <strong>Do not touch this.</strong>  Use the <code>timeout</code> value passed to your methods instead.</p>
+<h4 id="slot-message-start">Slot MESSAGE-START</h4>
+<ul>
+<li>Allocation: INSTANCE</li>
+<li>Type: <code>(OR NULL (INTEGER 0))</code></li>
+</ul>
+<p>The (internal-real) timestamp of when the current GGP message was received.  <strong>Do not touch this.</strong>  Use the <code>timeout</code> value passed to your methods instead.</p>
 <h4 id="slot-current-match">Slot CURRENT-MATCH</h4>
 <ul>
 <li>Allocation: INSTANCE</li>
@@ -73,22 +104,30 @@
 <p>This will <strong>not</strong> be done gently.  No cleanup will be performed if the player
   is in the middle of a game.  Be careful.</p>
 <h3 id="player-select-move-generic-function">PLAYER-SELECT-MOVE (generic function)</h3>
-<div class="codehilite"><pre>(PLAYER-SELECT-MOVE PLAYER)
+<div class="codehilite"><pre>(PLAYER-SELECT-MOVE PLAYER TIMEOUT)
 </pre></div>
 
 
 <p>Called when it's time for the player to select a move to play.</p>
 <p>Must return a list/symbol of the GDL move to play.  Note that any symbols in
-  the move should be ones that are interned in the <code>GGP</code> package.  The author is
-  aware that this sucks and welcomes suggestions on how to make it less awful.</p>
+  the move should be ones that are interned in the <code>GGP-RULES</code> package.  The
+  author is aware that this sucks and welcomes suggestions on how to make it
+  less awful.</p>
+<p><code>timeout</code> is the timestamp that the response to the server is due by, in
+  internal-real time units.  Basically: when <code>(get-internal-real-time)</code> returns
+  this number, your message better have reached the server.</p>
 <h3 id="player-start-game-generic-function">PLAYER-START-GAME (generic function)</h3>
-<div class="codehilite"><pre>(PLAYER-START-GAME PLAYER RULES ROLE START-CLOCK PLAY-CLOCK)
+<div class="codehilite"><pre>(PLAYER-START-GAME PLAYER RULES ROLE TIMEOUT)
 </pre></div>
 
 
 <p>Called when the game is started.</p>
 <p><code>rules</code> is a list of lists/symbols representing the GDL description of the
-  game.  Note that all symbols are interned in the <code>GGP</code> package.</p>
+  game.  Note that all symbols are interned in the <code>GGP-RULES</code> package.</p>
+<p><code>role</code> is a symbol representing the role of the player in this game.</p>
+<p><code>timeout</code> is the timestamp that the response to the server is due by, in
+  internal-real time units.  Basically: when <code>(get-internal-real-time)</code> returns
+  this number, your message better have reached the server.</p>
 <h3 id="player-stop-game-generic-function">PLAYER-STOP-GAME (generic function)</h3>
 <div class="codehilite"><pre>(PLAYER-STOP-GAME PLAYER)
 </pre></div>
@@ -102,14 +141,23 @@
 </pre></div>
 
 
-<p>Called after all player have made their moves.</p>
-<p><code>moves</code> will be a list of moves made by the players.</p>
+<p>Called after all players have made their moves.</p>
+<p><code>moves</code> will be a list of <code>(role . move)</code> conses representing moves made by
+  each player last turn.</p>
 <h3 id="start-player-function">START-PLAYER (function)</h3>
 <div class="codehilite"><pre>(START-PLAYER PLAYER)
 </pre></div>
 
 
 <p>Start the HTTP server for the given player.</p>
+<h2 id="package-ggp-rules">Package GGP-RULES</h2>
+<p>Symbol storage package.</p>
+<p>The GGP-RULES package is used to hold all the symbols in the GDL game
+  descriptions, as well as some special symbols in the GGP protocol.  It is
+  cleared between game runs to avoid a buildup of garbage symbols (especially
+  when GDL scrambling is turned on), though certain special symbols are allowed
+  to survive the clearing.</p>
+<p>This is ugly.  I'm sorry.  I'm open to suggestions on better ways to do this.</p>
                 </div>
             <footer><p><i>Made with Lisp and love by <a href="http://stevelosh.com/">Steve Losh</a> in Reykjavík, Iceland.</i></p>
 <script>