--- a/Makefile Wed Mar 23 15:22:05 2016 +0000
+++ b/Makefile Wed Mar 23 16:23:52 2016 +0000
@@ -12,7 +12,7 @@
docs: docs/build/index.html
-docs/build/index.html: $(docfiles) docs/title
+docs/build/index.html: $(docfiles) $(apidoc) docs/title
cd docs && ~/.virtualenvs/d/bin/d
pubdocs: docs
--- a/docs/03-reference.markdown Wed Mar 23 15:22:05 2016 +0000
+++ b/docs/03-reference.markdown Wed Mar 23 16:23:52 2016 +0000
@@ -12,3 +12,96 @@
## Package GGP
+### GGP-PLAYER (class)
+
+The base class for a GGP player. Custom players should extend this.
+
+#### Slot NAME
+
+* Allocation: INSTANCE
+* Type: `STRING`
+* Reader: `PLAYER-NAME`
+
+The name of the player.
+
+#### Slot PORT
+
+* Allocation: INSTANCE
+* Type: `(INTEGER 0)`
+* Reader: `PLAYER-PORT`
+
+The port the HTTP server should listen on.
+
+#### Slot CURRENT-MATCH
+
+* Allocation: INSTANCE
+
+The ID of the current match the player is playing, or `nil` if it is waiting. **Do not touch this.**
+
+#### Slot SERVER
+
+* Allocation: INSTANCE
+
+The Clack server object of the player. **Do not touch this.** Use `start-player` and `kill-player` to start/stop the server safely.
+
+### KILL-PLAYER (function)
+
+ (KILL-PLAYER PLAYER)
+
+Kill the HTTP server for the given player.
+
+ This will **not** be done gently. No cleanup will be performed if the player
+ is in the middle of a game. Be careful.
+
+
+
+### PLAYER-SELECT-MOVE (generic function)
+
+ (PLAYER-SELECT-MOVE PLAYER)
+
+Called when it's time for the player to select a move to play.
+
+ 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 `GGP` package. The author is
+ aware that this sucks and welcomes suggestions on how to make it less awful.
+
+
+
+### PLAYER-START-GAME (generic function)
+
+ (PLAYER-START-GAME PLAYER RULES ROLE START-CLOCK PLAY-CLOCK)
+
+Called when the game is started.
+
+ `rules` is a list of lists/symbols representing the GDL description of the
+ game. Note that all symbols are interned in the `GGP` package.
+
+
+
+### PLAYER-STOP-GAME (generic function)
+
+ (PLAYER-STOP-GAME PLAYER)
+
+Called when the game is stopped.
+
+ This is a good place to do any teardown stuff your player might need, or maybe
+ to suggest a GC to your Lisp implementation.
+
+
+
+### PLAYER-UPDATE-GAME (generic function)
+
+ (PLAYER-UPDATE-GAME PLAYER MOVES)
+
+Called after all player have made their moves.
+
+ `moves` will be a list of moves made by the players.
+
+
+
+### START-PLAYER (function)
+
+ (START-PLAYER PLAYER)
+
+Start the HTTP server for the given player.
+
--- a/docs/api.lisp Wed Mar 23 15:22:05 2016 +0000
+++ b/docs/api.lisp Wed Mar 23 16:23:52 2016 +0000
@@ -1,6 +1,8 @@
(let ((*standard-output* (make-broadcast-stream)))
(ql:quickload "docparser"))
+(declaim (optimize (debug 3))) ; dammit sbcl
+
(defparameter *index*
(docparser:parse :cl-ggp))
@@ -38,10 +40,12 @@
;;;; Documentation Utils
(defun get-doc (package-name symbol-name)
- (elt (docparser:query *index*
- :package-name package-name
- :symbol-name symbol-name)
- 0))
+ (let ((results (docparser:query *index*
+ :package-name package-name
+ :symbol-name symbol-name)))
+ (when (> (length results) 0)
+ (elt results 0))))
+
(defun get-package-doc (package-name)
;; good god, lemon
(docparser::find-package-index *index* package-name))
@@ -75,6 +79,26 @@
(defgeneric render-documentation (node symbol-name))
+(defun render-class-slot (node)
+ (let ((name (docparser:node-name node))
+ (type (docparser:slot-type node))
+ (readers (docparser:slot-readers node))
+ (writers (docparser:slot-writers node))
+ (accessors (docparser:slot-accessors node)))
+ (format t "#### Slot ~A~%~%" name )
+ (format t "* Allocation: ~A~%" (docparser:slot-allocation node))
+ (when type (format t "* Type: `~A`~%" type))
+ (when readers (format t "* Reader~p: ~{`~A`~^, ~}~%" (length readers) readers))
+ (when writers (format t "* Writer~p: ~{`~A`~^, ~}~%" (length writers) writers))
+ (when accessors (format t "* Accessor~p: ~{`~A`~^, ~}~%" (length accessors) accessors))
+ (format t "~%")
+ (render-docstring node)))
+
+
+(defmethod render-documentation ((node docparser:class-node) symbol-name)
+ (render-symbol-header symbol-name " (class)")
+ (render-docstring node)
+ (mapc #'render-class-slot (docparser:record-slots node)))
(defmethod render-documentation ((node docparser:documentation-node) symbol-name)
(render-symbol-header symbol-name "")
@@ -90,6 +114,11 @@
(render-lambda-list node)
(render-docstring node))
+(defmethod render-documentation ((node docparser:generic-function-node) symbol-name)
+ (render-symbol-header symbol-name " (generic function)")
+ (render-lambda-list node)
+ (render-docstring node))
+
(defmethod render-documentation ((node docparser:macro-node) symbol-name)
(render-symbol-header symbol-name " (macro)")
(render-lambda-list node)
@@ -100,7 +129,7 @@
(defun document-symbol (package-name symbol)
(let* ((symbol-name (symbol-name symbol))
(doc-node (get-doc package-name symbol-name)))
- (render-documentation doc-node symbol-name)))
+ (when doc-node (render-documentation doc-node symbol-name))))
(defun document-package (package-name)
(render-package-header package-name)
--- a/src/ggp.lisp Wed Mar 23 15:22:05 2016 +0000
+++ b/src/ggp.lisp Wed Mar 23 16:23:52 2016 +0000
@@ -10,15 +10,57 @@
;;;; GGP Player
(defclass ggp-player ()
- ((name :initarg :name :initform "CL-GGP" :reader player-name)
- (port :initarg :port :initform 9999 :reader player-port)
- (current-match :initform nil)
- (server)))
+ ((name
+ :initarg :name
+ :initform "CL-GGP"
+ :reader player-name
+ :type string
+ :documentation "The name of the player.")
+ (port
+ :initarg :port
+ :initform 9999
+ :reader player-port
+ :type (integer 0)
+ :documentation "The port the HTTP server should listen on.")
+ (current-match
+ :initform nil
+ :documentation "The ID of the current match the player is playing, or `nil` if it is waiting. **Do not touch this.**")
+ (server
+ :documentation "The Clack server object of the player. **Do not touch this.** Use `start-player` and `kill-player` to start/stop the server safely."))
+ (:documentation "The base class for a GGP player. Custom players should extend this."))
+
+
+(defgeneric player-start-game (player rules role start-clock play-clock)
+ (:documentation "Called when the game is started.
+
+ `rules` is a list of lists/symbols representing the GDL description of the
+ game. Note that all symbols are interned in the `GGP` package.
-(defgeneric player-start-game (player rules role start-clock play-clock))
-(defgeneric player-update-game (player moves))
-(defgeneric player-select-move (player))
-(defgeneric player-stop-game (player))
+ "))
+
+(defgeneric player-update-game (player moves)
+ (:documentation "Called after all player have made their moves.
+
+ `moves` will be a list of moves made by the players.
+
+ "))
+
+(defgeneric player-select-move (player)
+ (:documentation "Called when it's time for the player to select a move to play.
+
+ 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 `GGP` package. The author is
+ aware that this sucks and welcomes suggestions on how to make it less awful.
+
+ "))
+
+(defgeneric player-stop-game (player)
+ (:documentation "Called when the game is stopped.
+
+ This is a good place to do any teardown stuff your player might need, or maybe
+ to suggest a GC to your Lisp implementation.
+
+ "))
(defmethod player-start-game ((player ggp-player) rules role start-clock play-clock)
@@ -109,12 +151,13 @@
(l "UNKNOWN REQUEST: ~S~%~%" unknown-request)
'what)))
+
+;;;; Boilerplate
(defun should-log-p (request)
(match request
(`(info) nil)
(_ t)))
-;;;; Boilerplate
(defun app (player env)
(let* ((body (get-body env))
(request (safe-read-from-string body))
@@ -134,6 +177,7 @@
;;;; Spinup/spindown
(defun start-player (player)
+ "Start the HTTP server for the given player."
(let* ((player-handler #'(lambda (env) (app player env)))
(server (clack:clackup player-handler
:port (player-port player))))
@@ -141,4 +185,10 @@
player))
(defun kill-player (player)
+ "Kill the HTTP server for the given player.
+
+ This will **not** be done gently. No cleanup will be performed if the player
+ is in the middle of a game. Be careful.
+
+ "
(clack.handler:stop (slot-value player 'server)))