e5a300df7d49

cl-ggp: Update site.
[view raw] [browse files]
author Steve Losh <steve@stevelosh.com>
date Fri, 10 Feb 2017 16:22:16 +0000
parents f5a0fcf62e5e
children 6a37936a2df4
branches/tags (none)
files cl-ggp/changelog/index.html cl-ggp/index.html cl-ggp/overview/index.html cl-ggp/reference-reasoner/index.html

Changes

--- a/cl-ggp/changelog/index.html	Sun Jan 29 22:07:43 2017 +0000
+++ b/cl-ggp/changelog/index.html	Fri Feb 10 16:22:16 2017 +0000
@@ -15,14 +15,16 @@
 <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="#pending">Pending</a></li>
+<li><a href="#v100">v1.0.0</a></li>
 <li><a href="#v001">v0.0.1</a></li>
 </ul></div>
-<h2 id="pending">Pending</h2>
+<h2 id="v100">v1.0.0</h2>
 <ul>
 <li><code>start-player</code> now takes <code>:server</code> and <code>:use-thread</code> options which it passes
   along to Clack.</li>
 <li>Added rudimentary support for writing GDL-II players.</li>
+<li>Added <code>cl-ggp.reasoner</code> to reduce the friction for new folks wanting to get
+  started with general game playing.</li>
 </ul>
 <h2 id="v001">v0.0.1</h2>
 <p>Initial alpha version.  Things are going to break a lot.  Don't use this.</p>
--- a/cl-ggp/index.html	Sun Jan 29 22:07:43 2017 +0000
+++ b/cl-ggp/index.html	Fri Feb 10 16:22:16 2017 +0000
@@ -14,9 +14,9 @@
                 <div class="markdown">
 <p><code>cl-ggp</code> is a tiny framework for writing <a href="http://www.ggp.org/">general game players</a> in Common
 Lisp.</p>
-<p>The <code>cl-ggp</code> system handles the GGP protocol for you and <em>nothing else</em>.  If you
+<p>The <code>ggp</code> system handles the GGP protocol for you and <em>nothing else</em>.  If you
 plan on doing your own GDL reasoning, this is all you need.</p>
-<p>The <code>cl-ggp.reasoner</code> system contains a simple Prolog-based reasoner using the
+<p>The <code>ggp.reasoner</code> system contains a simple Prolog-based reasoner using the
 <a href="https://sjl.bitbucket.io/temperance/">Temperance</a> logic programming library.  It's useful as a starting point for
 when writing players.</p>
 <ul>
--- a/cl-ggp/overview/index.html	Sun Jan 29 22:07:43 2017 +0000
+++ b/cl-ggp/overview/index.html	Fri Feb 10 16:22:16 2017 +0000
@@ -12,14 +12,13 @@
         <div class="wrap">
             <header><h1><a href="..">cl-ggp</a></h1></header>
                 <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>
+<h1 id="overview"><a href="">Overview</a></h1><p>This document assumes you know what <a href="http://ggp.org/">General Game Playing</a> is, what <a href="https://en.wikipedia.org/wiki/Game_Description_Language">GDL</a>
+is, and how the GGP community/competitions/etc work.</p>
 <div class="toc">
 <ul>
+<li><a href="#ggp-protocol">GGP Protocol</a><ul>
 <li><a href="#basics">Basics</a></li>
-<li><a href="#functionality">Functionality</a><ul>
+<li><a href="#game-functionality">Game Functionality</a><ul>
 <li><a href="#player-start-game">player-start-game</a></li>
 <li><a href="#player-update-game">player-update-game</a></li>
 <li><a href="#player-select-move">player-select-move</a></li>
@@ -28,9 +27,15 @@
 </li>
 <li><a href="#timeouts">Timeouts</a></li>
 <li><a href="#symbols">Symbols</a></li>
+</ul>
+</li>
+<li><a href="#reasoning">Reasoning</a></li>
 <li><a href="#example-player">Example Player</a></li>
 </ul></div>
-<h2 id="basics">Basics</h2>
+<h2 id="ggp-protocol">GGP Protocol</h2>
+<p>The <code>ggp</code> system handles the GGP network protocol and game flow for you.
+Players are implemented as CLOS objects.</p>
+<h3 id="basics">Basics</h3>
 <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><span/><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>
@@ -47,13 +52,13 @@
 <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>
+<h3 id="game-functionality">Game Functionality</h3>
 <p><code>cl-ggp</code> defines four generic methods that are called on players at various
 points in each game.  You can provide method definitions for some or all of
 these to let your player do whatever it needs to do.</p>
 <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>
+<h4 id="player-start-game">player-start-game</h4>
 <div class="codehilite"><pre><span/><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>
@@ -65,7 +70,7 @@
 <p><code>role</code> is a symbol representing which role you've been assigned.</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>
+<h4 id="player-update-game">player-update-game</h4>
 <div class="codehilite"><pre><span/><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>
@@ -75,7 +80,7 @@
 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>
+<h4 id="player-select-move">player-select-move</h4>
 <div class="codehilite"><pre><span/><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>
@@ -85,7 +90,7 @@
 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>
+<h4 id="player-stop-game">player-stop-game</h4>
 <div class="codehilite"><pre><span/><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>
@@ -93,7 +98,7 @@
 
 <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>
+<h3 id="timeouts">Timeouts</h3>
 <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
@@ -121,7 +126,7 @@
 </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>
+<h3 id="symbols">Symbols</h3>
 <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><span/>(role x)
@@ -149,45 +154,91 @@
 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="reasoning">Reasoning</h2>
+<p>The <code>ggp.reasoner</code> system contains a Prolog-based GDL reasoner based on the
+<a href="https://sjl.bitbucket.io/temperance/">Temperance</a> logic programming library.</p>
+<p>It's useful as a starting point if you just want to get a bot up and running
+quickly.  If you want more speed or control over the reasoning process you'll
+probably want to replace it with your own implementation.</p>
+<p>You can make a reasoner for a set of GDL rules (e.g. the rules given to you by
+<code>player-start-game</code>) with <code>(make-reasoner rules)</code>.</p>
+<p>Once you've got a reasoner you can ask it for the initial state of the game with
+<code>(initial-state reasoner)</code>.  This will give you back a state object -- it's
+currently just a list, but this may change in the future, so you should just
+treat it as an opaque object.</p>
+<p>Once you've got a state and a set of moves you can compute the next state with
+<code>(next-state reasoner current-state moves)</code>.</p>
+<p>States can be queried for their terminality, goal values, and legal moves with
+<code>terminalp</code>, <code>goal-values-for</code>, and <code>legal-moves-for</code> respectively.</p>
+<p>See the <a href="../reference-reasoner/">Reasoner API Reference</a> for more details.</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/><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>
+<p>Let's create a small example player that uses the reasoner to play any GGP game
+legally.  We'll start by creating a class for the player, with three slots to
+keep track of the data we need to play a game:</p>
+<div class="codehilite"><pre><span/><span class="p">(</span><span class="nb">defclass</span> <span class="nv">random-player</span> <span class="p">(</span><span class="nv">ggp:ggp-player</span><span class="p">)</span>
+  <span class="p">((</span><span class="nv">role</span>          <span class="ss">:accessor</span> <span class="nv">p-role</span><span class="p">)</span>
+   <span class="p">(</span><span class="nv">current-state</span> <span class="ss">:accessor</span> <span class="nv">p-current-state</span><span class="p">)</span>
+   <span class="p">(</span><span class="nv">reasoner</span>      <span class="ss">:accessor</span> <span class="nv">p-reasoner</span><span class="p">)))</span>
+</pre></div>
 
-<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>
+
+<p>Now we can implement <code>player-start-game</code>.  We'll store the role we've been
+assigned, and create a reasoner so we can compute our legal moves later.  We'll
+ignore the deadline because we're not doing any extensive processing:</p>
+<div class="codehilite"><pre><span/><span class="p">(</span><span class="nb">defmethod</span> <span class="nv">ggp:player-start-game</span>
+    <span class="p">((</span><span class="nv">player</span> <span class="nv">random-player</span><span class="p">)</span> <span class="nv">rules</span> <span class="nv">role</span> <span class="nv">deadline</span><span class="p">)</span>
+  <span class="p">(</span><span class="k">declare</span> <span class="p">(</span><span class="k">ignore</span> <span class="nv">deadline</span><span class="p">))</span>
+  <span class="p">(</span><span class="nb">setf</span> <span class="p">(</span><span class="nv">p-role</span> <span class="nv">player</span><span class="p">)</span> <span class="nv">role</span>
+        <span class="p">(</span><span class="nv">p-reasoner</span> <span class="nv">player</span><span class="p">)</span> <span class="p">(</span><span class="nv">ggp.reasoner:make-reasoner</span> <span class="nv">rules</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/><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>
+<p>Next we'll implement <code>player-update-game</code>, which will compute the current state
+of the game and store it in the <code>current-state</code> slot:</p>
+<div class="codehilite"><pre><span/><span class="p">(</span><span class="nb">defmethod</span> <span class="nv">ggp:player-update-game</span>
+    <span class="p">((</span><span class="nv">player</span> <span class="nv">random-player</span><span class="p">)</span> <span class="nv">moves</span><span class="p">)</span>
+  <span class="p">(</span><span class="nb">setf</span> <span class="p">(</span><span class="nv">p-current-state</span> <span class="nv">player</span><span class="p">)</span>
+        <span class="p">(</span><span class="k">if</span> <span class="p">(</span><span class="nb">null</span> <span class="nv">moves</span><span class="p">)</span>
+          <span class="p">(</span><span class="nv">ggp.reasoner:initial-state</span> <span class="p">(</span><span class="nv">p-reasoner</span> <span class="nv">player</span><span class="p">))</span>
+          <span class="p">(</span><span class="nv">ggp.reasoner:next-state</span> <span class="p">(</span><span class="nv">p-reasoner</span> <span class="nv">player</span><span class="p">)</span>
+                                   <span class="p">(</span><span class="nv">p-current-state</span> <span class="nv">player</span><span class="p">)</span>
+                                   <span class="nv">moves</span><span class="p">))))</span>
 </pre></div>
 
 
-<p>And fire it up:</p>
-<div class="codehilite"><pre><span/><span class="p">(</span><span class="nv">ggp:start-player</span> <span class="vg">*player*</span><span class="p">)</span>
+<p>If <code>moves</code> is null we ask the reasoner for the initial state, otherwise we
+compute the next state from the current one and the moves that were made.</p>
+<p>Now we can implement <code>player-select-move</code>.  We'll just ask the reasoner for all
+our legal moves and choose one at random.  If we wanted to make a smarter
+player, this is where we would search the game tree to find a good move:</p>
+<div class="codehilite"><pre><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">random-player</span><span class="p">)</span> <span class="nv">deadline</span><span class="p">)</span>
+  <span class="p">(</span><span class="k">declare</span> <span class="p">(</span><span class="k">ignore</span> <span class="nv">deadline</span><span class="p">))</span>
+  <span class="p">(</span><span class="k">let</span> <span class="p">((</span><span class="nv">moves</span> <span class="p">(</span><span class="nv">ggp.reasoner:legal-moves-for</span>
+                 <span class="p">(</span><span class="nv">p-reasoner</span> <span class="nv">player</span><span class="p">)</span>
+                 <span class="p">(</span><span class="nv">p-current-state</span> <span class="nv">player</span><span class="p">)</span>
+                 <span class="p">(</span><span class="nv">p-role</span> <span class="nv">player</span><span class="p">))))</span>
+    <span class="p">(</span><span class="nb">nth</span> <span class="p">(</span><span class="nb">random</span> <span class="p">(</span><span class="nb">length</span> <span class="nv">moves</span><span class="p">))</span> <span class="nv">moves</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/><span class="p">(</span><span class="nv">ggp:kill-player</span> <span class="vg">*player*</span><span class="p">)</span>
+<p>Finally we can implement <code>player-stop-game</code>.  We'll just clear out the player's
+slots so the data can be garbage collected:</p>
+<div class="codehilite"><pre><span/><span class="p">(</span><span class="nb">defmethod</span> <span class="nv">ggp:player-stop-game</span>
+    <span class="p">((</span><span class="nv">player</span> <span class="nv">random-player</span><span class="p">))</span>
+  <span class="p">(</span><span class="nb">setf</span> <span class="p">(</span><span class="nv">p-current-state</span> <span class="nv">player</span><span class="p">)</span> <span class="no">nil</span>
+        <span class="p">(</span><span class="nv">p-reasoner</span> <span class="nv">player</span><span class="p">)</span> <span class="no">nil</span>
+        <span class="p">(</span><span class="nv">p-role</span> <span class="nv">player</span><span class="p">)</span> <span class="no">nil</span><span class="p">))</span>
+</pre></div>
+
+
+<p>Now we can make an instance of our player and start it up!</p>
+<div class="codehilite"><pre><span/><span class="p">(</span><span class="nb">defvar</span> <span class="vg">*random-player*</span>
+  <span class="p">(</span><span class="nb">make-instance</span> <span class="ss">'random-player</span>
+                 <span class="ss">:name</span> <span class="s">"RandomPlayer"</span>
+                 <span class="ss">:port</span> <span class="mi">4000</span><span class="p">))</span>
+
+<span class="p">(</span><span class="nv">ggp:start-player</span> <span class="vg">*random-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>
--- a/cl-ggp/reference-reasoner/index.html	Sun Jan 29 22:07:43 2017 +0000
+++ b/cl-ggp/reference-reasoner/index.html	Fri Feb 10 16:22:16 2017 +0000
@@ -12,7 +12,7 @@
         <div class="wrap">
             <header><h1><a href="..">cl-ggp</a></h1></header>
                 <div class="markdown">
-<h1 id="reasoner-api-reference"><a href="">Reasoner API Reference</a></h1><p>cl-ggp includes a simple Prolog-based reasoner you can use as a starting point when writing general game players in the <code>cl-ggp.reasoner</code> system.</p>
+<h1 id="reasoner-api-reference"><a href="">Reasoner API Reference</a></h1><p>cl-ggp includes a simple Prolog-based reasoner you can use as a starting point when writing general game players in the <code>ggp.reasoner</code> system.</p>
 <div class="toc">
 <ul>
 <li><a href="#package-ggpreasoner">Package GGP.REASONER</a><ul>