;;==============================================================================
;;; ggp-test.el -- Test Suite for ggp.el
;;
;;; Copyright (C) 2014 Kyle W T Sherman
;;
;; Author:   Kyle W T Sherman <kylewsherman at gmail dot com>
;; Created:  2014-04-07
;; Version:  0.1
;; Keywords: general game playing client ggp
;;
;; This file is not part of GNU Emacs.
;;
;; This 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, or (at your option) any later version.
;;
;; This 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.
;;
;; You should have received a copy of the GNU General Public License along
;; with GNU Emacs; see the file COPYING.  If not, write to the Free Software
;; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
;;
;;; Commentary:
;;
;; Tests `ggp.el' functionality.
;;
;;; Installation:
;;
;; Load `ggp-test.el':
;;
;;   (load "ggp-test.el")
;;
;;; Usage:
;;
;; Run tests:
;;
;;   (eval-buffer)
;;==============================================================================

;;==============================================================================
;;; Code:
;;==============================================================================

;; ggp
(require 'ggp)

;; test output buffer
(defconst ggp-test-output-buffer-name "*ggp-test-output*")

;; ;; assert
;; (defun ggp-test (input output &rest responses)
;;   "Run INPUT through the GGP compiler and compare its output to OUTPUT."
;;   (let ((ggp-debug-log t))
;;     (save-excursion
;;       (with-temp-buffer
;;         (insert input)
;;         (ggp-run-test responses))
;;       (set-buffer "*ggp-output*")
;;       (let ((buffer-str (buffer-substring-no-properties (point-min) (point-max))))
;;         (when (> (length buffer-str) (length output))
;;           (setq output (concat output "\n")))
;;         (assert (string= buffer-str output)))
;;       )))
;;     ;; (switch-to-buffer "*ggp-debug*")
;;     ;; (goto-char (point-min))))

;;------------------------------------------------------------------------------
;;; Unit Tests
;;------------------------------------------------------------------------------

;; match tests
(let ((match
       '((:rules (:role "white" "black")
                 (:relation
                  (:base (
                          (((:function . "cell") (:variable . "M") (:variable . "N") (:variable . "Z")) ((:function . "index") (:variable . "M")) ((:function . "index") (:variable . "N")) ((:function . "filter") (:variable . "Z")))
                          (((:function . "control") (:variable . "W")) ((:role) (:variable . "W")))
                          ))
                  (:input (
                           (((:variable . "W") (:function . "mark") (:variable . "X") (:variable . "Y")) ((:role) (:variable . "W")) ((:function . "index") (:variable . "X")) ((:function . "index") (:variable . "Y")))
                           (((:variable . "W") (:constant . "noop")) ((:role) (:variable . "W")))
                           ))
                  (:init (
                          (((:function . "cell") (:variable . "X") (:variable . "Y") (:constant . "b")) ((:function . "index") (:variable . "X")) ((:function . "index") (:variable . "Y")))
                          ))
                  (:legal (
                           (((:variable . "P") (:function . "mark") (:variable . "X") (:variable . "Y")) ((:true) (:function . "cell") (:variable . "X") (:variable . "Y") (:constant . "b")) ((:true) (:function . "control") (:variable . "P")))
                           (((:constant . "x") (:constant . "noop")) ((:function . "control") (:constant . "black")))
                           (((:constant . "o") (:constant . "noop")) ((:function . "control") (:constant . "white")))
                           ))
                  (:next (
                          (((:function . "cell") (:variable . "M") (:variable . "N") (:constant . "x")) ((:does) (:constant . "white") (:function . "mark") (:variable . "M") (:variable . "N")))
                          (((:function . "cell") (:variable . "M") (:variable . "N") (:constant . "o")) ((:does) (:constant . "black") (:function . "mark") (:variable . "M") (:variable . "N")))
                          (((:function . "cell") (:variable . "M") (:variable . "N") (:variable . "Z")) ((:does) (:constant . "P") (:function . "mark") (:variable . "M") (:variable . "N")) ((:true) (:function . "cell") (:variable . "M") (:variable . "N") (:variable . "Z")) ((:distinct) (:variable . "Z") (:constant . "b")))
                          (((:function . "cell") (:variable . "M") (:variable . "N") (:constant . "b")) ((:does) (:constant . "P") (:function . "mark") (:variable . "J") (:variable . "K")) ((:true) (:function . "cell") (:variable . "M") (:variable . "N") (:constant . "b")) ((:distinct) (:variable . "M") (:variable . "J")))
                          (((:function . "cell") (:variable . "M") (:variable . "N") (:constant . "b")) ((:does) (:constant . "P") (:function . "mark") (:variable . "J") (:variable . "K")) ((:true) (:function . "cell") (:variable . "M") (:variable . "N") (:constant . "b")) ((:distinct) (:variable . "N") (:variable . "K")))
                          (((:function . "control") (:constant . "white")) ((:true) (:function . "control") (:constant . "black")))
                          (((:function . "control") (:constant . "black")) ((:true) (:function . "control") (:constant . "white")))
                          ))
                  (:goal (
                          (((:constant . "white") (:number . 100)) ((:function . "line") (:constant . "x")) ((:not) (:function . "line") (:constant . "o")))
                          (((:constant . "white") (:number . 50)) ((:not) (:function . "line") (:constant . "x")) ((:not) (:function . "line") (:constant . "o")))
                          (((:constant . "white") (:number . 0)) ((:not) (:function . "line") (:constant . "x")) ((:function . "line") (:constant . "o")))
                          (((:constant . "black") (:number . 100)) ((:not) (:function . "line") (:constant . "x")) ((:function . "line") (:constant . "o")))
                          (((:constant . "black") (:number . 50)) ((:not) (:function . "line") (:constant . "x")) ((:not) (:function . "line") (:constant . "o")))
                          (((:constant . "black") (:number . 0)) ((:function . "line") (:constant . "x")) ((:not) (:function . "line") (:constant . "o")))
                          ))
                  (:terminal (
                              (((:function . "line") (:constant . "P")))
                              (((:not) (:constant . "open")))
                              ))
                  (:custom (
                            (((:function . "row") (:variable . "M") (:variable . "P")) ((:true) (:function . "cell") (:variable . "M") (:number . 1) (:variable . "P")) ((:true) (:function . "cell") (:variable . "M") (:number . 2) (:variable . "P")) ((:true) (:function . "cell") (:variable . "M") (:number . 3) (:variable . "P")))
                            (((:function . "column") (:variable . "N") (:variable . "P")) ((:true) (:function . "cell") (:number . 1) (:variable . "N") (:variable . "P")) ((:true) (:function . "cell") (:number . 2) (:variable . "N") (:variable . "P")) ((:true) (:function . "cell") (:number . 3) (:variable . "N") (:variable . "P")))
                            (((:function . "diagonal") (:variable . "P")) ((:true) (:function . "cell") (:number . 1) (:number . 1) (:variable . "P") (:true) (:function . "cell") (:number . 2) (:number . 2) (:variable . "P") (:true) (:function . "cell") (:number . 3) (:number . 3) (:variable . "P")))
                            (((:function . "diagonal") (:variable . "P")) ((:true) (:function . "cell") (:number . 1) (:number . 3) (:variable . "P") (:true) (:function . "cell") (:number . 2) (:number . 2) (:variable . "P") (:true) (:function . "cell") (:number . 3) (:number . 1) (:variable . "P")))
                            (((:function . "line") (:variable . "P")) ((:function . "row") (:variable . "M") (:variable . "P")))
                            (((:function . "line") (:variable . "P")) ((:function . "column") (:variable . "N") (:variable . "P")))
                            (((:function . "line") (:variable . "P")) ((:function . "diagonal") (:variable . "P")))
                            (((:function . "open")) ((:true) (:function . "cell") (:variable . "M") (:variable . "N") (:constant . "b")))
                            )))
                 (:data
                  (:init (
                          (((:function . "control") (:constant . "white")))
                          ))
                  (:custom (
                            (((:function . "index")) ((:number . 1)))
                            (((:function . "index")) ((:number . 2)))
                            (((:function . "index")) ((:number . 3)))
                            (((:function . "filter")) ((:constant . "x")))
                            (((:function . "filter")) ((:constant . "o")))
                            (((:function . "filter")) ((:constant . "b")))
                            ))))
         (:role . "white")
         (:roles "white" "black")
         (:state ((((:function . "control") (:constant . "white"))))))))
  (let ((rules (cdr (assq :rules match)))
        (role (cdr (assq :role match)))
        (roles (cdr (assq :roles match)))
        (state (cdr (assq :state match))))
    (assert (let ((r (ggp-find-roles rules)))
              (and (string= (car r) "white")
                   (string= (cadr r) "black"))))
    ))

;; tic-tac-toe (from GDL spec)
(progn
  (clrhash ggp-match-hash)
  (assert (string= (ggp-handle-request (ggp-parse-request "(INFO)")) (concat "((name " ggp-name ") (status available))")))
  (assert (string= (ggp-handle-request (ggp-parse-request "(START TEST.TIC.TAC.TOE X (
    (ROLE X)
    (ROLE O)
    (INIT (CELL 1 1 B))
    (INIT (CELL 1 2 B))
    (INIT (CELL 1 3 B))
    (INIT (CELL 2 1 B))
    (INIT (CELL 2 2 B))
    (INIT (CELL 2 3 B))
    (INIT (CELL 3 1 B))
    (INIT (CELL 3 2 B))
    (INIT (CELL 3 3 B))
    (INIT (CONTROL X))
    (<= (NEXT (CELL ?X ?Y ?PLAYER)) (DOES ?PLAYER (MARK ?X ?Y)))
    (<= (NEXT (CELL ?X ?Y ?MARK)) (TRUE (CELL ?X ?Y ?MARK)) (DOES ?PLAYER (MARK ?M ?N)) (DISTINCTCELL ?X ?Y ?M ?N))
    (<= (NEXT (CONTROL X)) (TRUE (CONTROL O)))
    (<= (NEXT (CONTROL O)) (TRUE (CONTROL X)))
    (<= (ROW ?X ?PLAYER) (TRUE (CELL ?X 1 ?PLAYER)) (TRUE (CELL ?X 2 ?PLAYER)) (TRUE (CELL ?X 3 ?PLAYER)))
    (<= (COLUMN ?Y ?PLAYER) (TRUE (CELL 1 ?Y ?PLAYER)) (TRUE (CELL 2 ?Y ?PLAYER)) (TRUE (CELL 3 ?Y ?PLAYER)))
    (<= (DIAGONAL ?PLAYER) (TRUE (CELL 1 1 ?PLAYER)) (TRUE (CELL 2 2 ?PLAYER)) (TRUE (CELL 3 3 ?PLAYER)))
    (<= (DIAGONAL ?PLAYER) (TRUE (CELL 1 3 ?PLAYER)) (TRUE (CELL 2 2 ?PLAYER)) (TRUE (CELL 3 1 ?PLAYER)))
    (<= (LINE ?PLAYER) (ROW ?X ?PLAYER))
    (<= (LINE ?PLAYER) (COLUMN ?Y ?PLAYER))
    (<= (LINE ?PLAYER) (DIAGONAL ?PLAYER))
    (<= OPEN (TRUE (CELL ?X ?Y B)))
    (<= (DISTINCTCELL ?X ?Y ?M ?N) (DISTINCT ?X ?M))
    (<= (DISTINCTCELL ?X ?Y ?M ?N) (DISTINCT ?Y ?N))
    (<= (LEGAL ?PLAYER (MARK ?X ?Y)) (TRUE (CELL ?X ?Y B)) (TRUE (CONTROL ?PLAYER)))
    (<= (LEGAL ?PLAYER NOOP) (NOT (TRUE (CONTROL ?PLAYER))))
    (<= (GOAL ?PLAYER 100) (LINE ?PLAYER))
    (<= (GOAL ?PLAYER 50) (NOT (LINE X)) (NOT (LINE O)) (NOT OPEN))
    (<= (GOAL ?PLAYER1 0) (LINE ?PLAYER2) (DISTINCT ?PLAYER1 ?PLAYER2))
    (<= (GOAL ?PLAYER 0) (NOT (LINE X)) (NOT (LINE O)) OPEN)
    (<= TERMINAL (LINE ?PLAYER))
    (<= TERMINAL (NOT OPEN)))
    30 30)")) "ready")))

;; tick-tac-toe
(progn
  (clrhash ggp-match-hash)
  (assert (string= (ggp-handle-request (ggp-parse-request "(info)")) (concat "((name " ggp-name ") (status available))")))
  (assert (string= (ggp-handle-request (ggp-parse-request "(start test.tic.tac.toe white (
    (role white)
    (role black)
    (<= (base (cell ?M ?N ?Z)) (index ?M) (index ?N) (filter ?Z))
    (<= (base (control ?W)) (role ?W))
    (<= (input ?W (mark ?X ?Y)) (role ?W) (index ?X) (index ?Y))
    (<= (input ?W noop) (role ?W))
    (<= (init (cell ?X ?Y b)) (index ?X) (index ?Y))
    (init (control white))
    (<= (legal ?P (mark ?X ?Y)) (true (cell ?X ?Y b)) (true (control ?P)))
    (<= (legal x noop) (control black))
    (<= (legal o noop) (control white))
    (<= (next (cell ?M ?N x)) (does white (mark ?M ?N)))
    (<= (next (cell ?M ?N o)) (does black (mark ?M ?N)))
    (<= (next (cell ?M ?N ?Z)) (does P (mark ?M ?N)) (true (cell ?M ?N ?Z)) (distinct ?Z b))
    (<= (next (cell ?M ?N b)) (does P (mark ?J ?K)) (true (cell ?M ?N b)) (distinct ?M ?J))
    (<= (next (cell ?M ?N b)) (does P (mark ?J ?K)) (true (cell ?M ?N b)) (distinct ?N ?K))
    (<= (next (control white)) (true (control black)))
    (<= (next (control black)) (true (control white)))
    (<= (goal white 100) (line x) (not (line o)))
    (<= (goal white 50) (not (line x)) (not (line o)))
    (<= (goal white 0) (not (line x)) (line o))
    (<= (goal black 100) (not (line x)) (line o))
    (<= (goal black 50) (not (line x)) (not (line o)))
    (<= (goal black 0) (line x) (not (line o)))
    (<= terminal (line P))
    (<= terminal (not open))
    (<= (row ?M ?P) (true (cell ?M 1 ?P)) (true (cell ?M 2 ?P)) (true (cell ?M 3 ?P)))
    (<= (column ?N ?P) (true (cell 1 ?N ?P)) (true (cell 2 ?N ?P)) (true (cell 3 ?N ?P)))
    (<= (diagonal ?P) (true (cell 1 1 ?P) (true (cell 2 2 ?P) (true (cell 3 3 ?P)))))
    (<= (diagonal ?P) (true (cell 1 3 ?P) (true (cell 2 2 ?P) (true (cell 3 1 ?P)))))
    (<= (line ?P) (row ?M ?P))
    (<= (line ?P) (column ?N ?P))
    (<= (line ?P) (diagonal ?P))
    (<= open (true (cell ?M ?N b)))
    (index 1)
    (index 2)
    (index 3)
    (filter x)
    (filter o)
    (filter b))
    10 10)")) "ready")))

;; 3-puzzle
;; http://ggp.stanford.edu/applications/050201.php
(progn
  (clrhash ggp-match-hash)
  (assert (string= (ggp-handle-request (ggp-parse-request "(info)")) (concat "((name " ggp-name ") (status available))")))
  (assert (string= (ggp-handle-request (ggp-parse-request "(start test.x050201 robot (
    (role robot)
    (<= (base (cell ?m ?n ?t)) (index ?m) (index ?n) (tile ?t))
    (base (step 1))
    (<= (base (step ?n)) (successor ?m ?n))
    (index 1)
    (index 2)
    (tile 1)
    (tile 2)
    (tile 3)
    (tile b)
    (input robot left)
    (input robot right)
    (input robot up)
    (input robot down)
    (init (cell 1 1 b))
    (init (cell 1 2 3))
    (init (cell 2 1 2))
    (init (cell 2 2 1))
    (init (step 1))
    (<= (legal robot left)  (true (cell ?m 2 b)))
    (<= (legal robot right) (true (cell ?m 1 b)))
    (<= (legal robot up)    (true (cell 2 ?n b)))
    (<= (legal robot down)  (true (cell 1 ?n b)))
    (<= (next (cell 1 ?n b)) (does robot up) (true (cell 2 ?n b)))
    (<= (next (cell 2 ?n b)) (does robot down) (true (cell 1 ?n b)))
    (<= (next (cell ?m 1 b)) (does robot left) (true (cell ?m 2 b)))
    (<= (next (cell ?m 2 b)) (does robot right) (true (cell ?m 1 b)))
    (<= (next (cell 2 ?n ?x)) (does robot up) (true (cell 2 ?n b)) (true (cell 1 ?n ?x)))
    (<= (next (cell 1 ?n ?x)) (does robot down) (true (cell 1 ?n b)) (true (cell 2 ?n ?x)))
    (<= (next (cell ?m 2 ?x)) (does robot left) (true (cell ?m 2 b)) (true (cell ?m 1 ?x)))
    (<= (next (cell ?m 1 ?x)) (does robot right) (true (cell ?m 1 b)) (true (cell ?m 2 ?x)))
    (<= (next (cell ?m ?n ?w)) (does robot up) (true (cell ?x ?y b)) (true (cell ?m ?n ?w)) (distinct ?y ?n))
    (<= (next (cell ?m ?n ?w)) (does robot down) (true (cell ?x ?y b)) (true (cell ?m ?n ?w)) (distinct ?y ?n))
    (<= (next (cell ?m ?n ?w)) (does robot left) (true (cell ?x ?y b)) (true (cell ?m ?n ?w)) (distinct ?x ?m))
    (<= (next (cell ?m ?n ?w)) (does robot right) (true (cell ?x ?y b)) (true (cell ?m ?n ?w)) (distinct ?x ?m))
    (<= (next (step ?n)) (true (step ?m)) (successor ?m ?n))
    (<= (goal robot 100) (true (cell 1 1 1)) (true (cell 1 2 2)) (true (cell 2 1 3)))
    (<= (goal robot 0) (not (true (cell 1 1 1))))
    (<= (goal robot 0) (not (true (cell 1 2 2))))
    (<= (goal robot 0) (not (true (cell 2 1 3))))
    (<= terminal (true (step 7)))
    (successor 1 2)
    (successor 2 3)
    (successor 3 4)
    (successor 4 5)
    (successor 5 6)
    (successor 6 7))
    10 10)")) "ready")))

;; hunter
;; http://ggp.stanford.edu/applications/040100.php
(progn
  (clrhash ggp-match-hash)
  (assert (string= (ggp-handle-request (ggp-parse-request "(info)")) (concat "((name " ggp-name ") (status available))")))
  (assert (string= (ggp-handle-request (ggp-parse-request "(start test.x040100 robot (
    (role robot)
    (<= (base (cell ?M ?N ?P)) (row ?M) (col ?N) (piece ?P))
    (<= (base (captures ?M)) (scoremap ?M ?N))
    (<= (base (step ?N)) (succ ?M ?N))
    (<= (input robot (move ?M1 ?N1 ?M2 ?N2)) (row ?M1) (col ?N1) (knightmove ?M1 ?N1 ?M2 ?N2))
    (row 1)
    (row 2)
    (row 3)
    (row 4)
    (row 5)
    (col 1)
    (col 2)
    (col 3)
    (piece knight)
    (piece pawn)
    (piece blank)
    (init (cell 1 1 knight))
    (init (cell 1 2 pawn))
    (init (cell 1 3 pawn))
    (init (cell 2 1 pawn))
    (init (cell 2 2 pawn))
    (init (cell 2 3 pawn))
    (init (cell 3 1 pawn))
    (init (cell 3 2 pawn))
    (init (cell 3 3 pawn))
    (init (cell 4 1 pawn))
    (init (cell 4 2 pawn))
    (init (cell 4 3 pawn))
    (init (cell 5 1 pawn))
    (init (cell 5 2 pawn))
    (init (cell 5 3 pawn))
    (init (captures 0))
    (init (step 1))
    (<= (legal robot (move ?M1 ?N1 ?M2 ?N2)) (true (cell ?M1 ?N1 knight)) (knightmove ?M1 ?N1 ?M2 ?N2))
    (<= (next (cell ?M2 ?N2 knight)) (does robot (move ?M1 ?N1 ?M2 ?N2)))
    (<= (next (cell ?M1 ?N1 blank)) (does robot (move ?M1 ?N1 ?M2 ?N2)))
    (<= (next (cell ?U ?V pawn)) (true (cell ?U ?V pawn)) (does robot (move ?M1 ?N1 ?M2 ?N2)) (distinct ?U ?M2))
    (<= (next (cell ?U ?V pawn)) (true (cell ?U ?V pawn)) (does robot (move ?M1 ?N1 ?M2 ?N2)) (distinct ?V ?N2))
    (<= (next (cell ?U ?V blank)) (true (cell ?U ?V blank)) (does robot (move ?M1 ?N1 ?M2 ?N2)) (distinct ?U ?M2))
    (<= (next (cell ?U ?V blank)) (true (cell ?U ?V blank)) (does robot (move ?M1 ?N1 ?M2 ?N2)) (distinct ?V ?N2))
    (<= (next (captures ?Old)) (does robot (move ?M1 ?N1 ?M2 ?N2)) (true (cell ?M2 ?N2 blank)) (true (captures ?Old)))
    (<= (next (captures ?New)) (does robot (move ?M1 ?N1 ?M2 ?N2)) (true (cell ?M2 ?N2 pawn)) (true (captures ?Old)) (succ ?Old ?New))
    (<= (next (step ?New)) (true (step ?Old)) (succ ?Old ?New))
    (<= (goal robot ?Goal) (true (captures ?Count)) (scoremap ?Count ?Goal))
    (<= terminal (true (step 15)))
    (<= (knightmove ?M1 ?N1 ?M2 ?N2) (add1row ?M1 ?M2) (add2col ?N1 ?N2))
    (<= (knightmove ?M1 ?N1 ?M2 ?N2) (add1row ?M1 ?M2) (add2col ?N2 ?N1))
    (<= (knightmove ?M1 ?N1 ?M2 ?N2) (add1row ?M2 ?M1) (add2col ?N1 ?N2))
    (<= (knightmove ?M1 ?N1 ?M2 ?N2) (add1row ?M2 ?M1) (add2col ?N2 ?N1))
    (<= (knightmove ?M1 ?N1 ?M2 ?N2) (add2row ?M1 ?M2) (add1col ?N1 ?N2))
    (<= (knightmove ?M1 ?N1 ?M2 ?N2) (add2row ?M1 ?M2) (add1col ?N2 ?N1))
    (<= (knightmove ?M1 ?N1 ?M2 ?N2) (add2row ?M2 ?M1) (add1col ?N1 ?N2))
    (<= (knightmove ?M1 ?N1 ?M2 ?N2) (add2row ?M2 ?M1) (add1col ?N2 ?N1))
    (succ 0 1)
    (succ 1 2)
    (succ 2 3)
    (succ 3 4)
    (succ 4 5)
    (succ 5 6)
    (succ 6 7)
    (succ 7 8)
    (succ 8 9)
    (succ 9 10)
    (succ 10 11)
    (succ 11 12)
    (succ 12 13)
    (succ 13 14)
    (succ 14 15)
    (add1row 1 2)
    (add1row 2 3)
    (add1row 3 4)
    (add1row 4 5)
    (add2row 1 3)
    (add2row 2 4)
    (add2row 3 5)
    (add1col 1 2)
    (add1col 2 3)
    (add2col 1 3)
    (scoremap 0 0)
    (scoremap 1 1)
    (scoremap 2 3)
    (scoremap 3 7)
    (scoremap 4 11)
    (scoremap 5 16)
    (scoremap 6 22)
    (scoremap 7 29)
    (scoremap 8 37)
    (scoremap 9 45)
    (scoremap 10 54)
    (scoremap 11 64)
    (scoremap 12 75)
    (scoremap 13 87)
    (scoremap 14 100))
    10 10)")) "ready"))
  (let* ((match (gethash "test.x040100" ggp-match-hash))
         (rules (cdr (assoc :rules match)))
         (role (cdr (assoc :role match)))
         (roles (ggp-find-roles rules))
         (state (ggp-find-inits rules)))
    (message "Roles: %s" roles)
    (message "State: %s" state))
  (assert (string= (ggp-handle-request (ggp-parse-request "(play test.x040100 (move 1 1 2 3))")) "(move 1 1 2 3)"))
  (assert (string= (ggp-handle-request (ggp-parse-request "(play test.x040100 (move 2 3 3 1))")) "(move 2 3 3 1)"))
  (assert (string= (ggp-handle-request (ggp-parse-request "(play test.x040100 (move 3 1 4 3))")) "(move 3 1 4 3)"))
  (assert (string= (ggp-handle-request (ggp-parse-request "(play test.x040100 (move 4 3 5 1))")) "(move 4 3 5 1)"))
  (assert (string= (ggp-handle-request (ggp-parse-request "(play test.x040100 (move 5 1 4 3))")) "(move 5 1 4 3)"))
  (assert (string= (ggp-handle-request (ggp-parse-request "(play test.x040100 (move 4 3 5 1))")) "(move 4 3 5 1)"))
  (assert (string= (ggp-handle-request (ggp-parse-request "(play test.x040100 (move 5 1 4 3))")) "(move 5 1 4 3)"))
  (assert (string= (ggp-handle-request (ggp-parse-request "(play test.x040100 (move 4 3 5 1))")) "(move 4 3 5 1)"))
  (assert (string= (ggp-handle-request (ggp-parse-request "(play test.x040100 (move 5 1 4 3))")) "(move 5 1 4 3)"))
  (assert (string= (ggp-handle-request (ggp-parse-request "(play test.x040100 (move 4 3 5 1))")) "(move 4 3 5 1)"))
  (assert (string= (ggp-handle-request (ggp-parse-request "(play test.x040100 (move 5 1 4 3))")) "(move 5 1 4 3)"))
  (assert (string= (ggp-handle-request (ggp-parse-request "(play test.x040100 (move 4 3 5 1))")) "(move 4 3 5 1)"))
  (assert (string= (ggp-handle-request (ggp-parse-request "(play test.x040100 (move 5 1 4 3))")) "(move 5 1 4 3)"))
  (assert (string= (ggp-handle-request (ggp-parse-request "(stop test.x040100 (move 4 3 5 1))")) "done")))


(progn
  (get-buffer-create ggp-test-output-buffer-name)
  (set-buffer ggp-test-output-buffer-name)
  (switch-to-buffer ggp-test-output-buffer-name)
  (setq buffer-read-only nil)
  (erase-buffer)
  (insert (format "%S" (ggp-parse-request "(start test.x040100 robot (
    (role robot)
    (<= (base (cell ?M ?N ?P)) (row ?M) (col ?N) (piece ?P))
    (<= (base (captures ?M)) (scoremap ?M ?N))
    (<= (base (step ?N)) (succ ?M ?N))
    (<= (input robot (move ?M1 ?N1 ?M2 ?N2)) (row ?M1) (col ?N1) (knightmove ?M1 ?N1 ?M2 ?N2))
    (row 1)
    (row 2)
    (row 3)
    (row 4)
    (row 5)
    (col 1)
    (col 2)
    (col 3)
    (piece knight)
    (piece pawn)
    (piece blank)
    (init (cell 1 1 knight))
    (init (cell 1 2 pawn))
    (init (cell 1 3 pawn))
    (init (cell 2 1 pawn))
    (init (cell 2 2 pawn))
    (init (cell 2 3 pawn))
    (init (cell 3 1 pawn))
    (init (cell 3 2 pawn))
    (init (cell 3 3 pawn))
    (init (cell 4 1 pawn))
    (init (cell 4 2 pawn))
    (init (cell 4 3 pawn))
    (init (cell 5 1 pawn))
    (init (cell 5 2 pawn))
    (init (cell 5 3 pawn))
    (init (captures 0))
    (init (step 1))
    (<= (legal robot (move ?M1 ?N1 ?M2 ?N2)) (true (cell ?M1 ?N1 knight)) (knightmove ?M1 ?N1 ?M2 ?N2))
    (<= (next (cell ?M2 ?N2 knight)) (does robot (move ?M1 ?N1 ?M2 ?N2)))
    (<= (next (cell ?M1 ?N1 blank)) (does robot (move ?M1 ?N1 ?M2 ?N2)))
    (<= (next (cell ?U ?V pawn)) (true (cell ?U ?V pawn)) (does robot (move ?M1 ?N1 ?M2 ?N2)) (distinct ?U ?M2))
    (<= (next (cell ?U ?V pawn)) (true (cell ?U ?V pawn)) (does robot (move ?M1 ?N1 ?M2 ?N2)) (distinct ?V ?N2))
    (<= (next (cell ?U ?V blank)) (true (cell ?U ?V blank)) (does robot (move ?M1 ?N1 ?M2 ?N2)) (distinct ?U ?M2))
    (<= (next (cell ?U ?V blank)) (true (cell ?U ?V blank)) (does robot (move ?M1 ?N1 ?M2 ?N2)) (distinct ?V ?N2))
    (<= (next (captures ?Old)) (does robot (move ?M1 ?N1 ?M2 ?N2)) (true (cell ?M2 ?N2 blank)) (true (captures ?Old)))
    (<= (next (captures ?New)) (does robot (move ?M1 ?N1 ?M2 ?N2)) (true (cell ?M2 ?N2 pawn)) (true (captures ?Old)) (succ ?Old ?New))
    (<= (next (step ?New)) (true (step ?Old)) (succ ?Old ?New))
    (<= (goal robot ?Goal) (true (captures ?Count)) (scoremap ?Count ?Goal))
    (<= terminal (true (step 15)))
    (<= (knightmove ?M1 ?N1 ?M2 ?N2) (add1row ?M1 ?M2) (add2col ?N1 ?N2))
    (<= (knightmove ?M1 ?N1 ?M2 ?N2) (add1row ?M1 ?M2) (add2col ?N2 ?N1))
    (<= (knightmove ?M1 ?N1 ?M2 ?N2) (add1row ?M2 ?M1) (add2col ?N1 ?N2))
    (<= (knightmove ?M1 ?N1 ?M2 ?N2) (add1row ?M2 ?M1) (add2col ?N2 ?N1))
    (<= (knightmove ?M1 ?N1 ?M2 ?N2) (add2row ?M1 ?M2) (add1col ?N1 ?N2))
    (<= (knightmove ?M1 ?N1 ?M2 ?N2) (add2row ?M1 ?M2) (add1col ?N2 ?N1))
    (<= (knightmove ?M1 ?N1 ?M2 ?N2) (add2row ?M2 ?M1) (add1col ?N1 ?N2))
    (<= (knightmove ?M1 ?N1 ?M2 ?N2) (add2row ?M2 ?M1) (add1col ?N2 ?N1))
    (succ 0 1)
    (succ 1 2)
    (succ 2 3)
    (succ 3 4)
    (succ 4 5)
    (succ 5 6)
    (succ 6 7)
    (succ 7 8)
    (succ 8 9)
    (succ 9 10)
    (succ 10 11)
    (succ 11 12)
    (succ 12 13)
    (succ 13 14)
    (succ 14 15)
    (add1row 1 2)
    (add1row 2 3)
    (add1row 3 4)
    (add1row 4 5)
    (add2row 1 3)
    (add2row 2 4)
    (add2row 3 5)
    (add1col 1 2)
    (add1col 2 3)
    (add2col 1 3)
    (scoremap 0 0)
    (scoremap 1 1)
    (scoremap 2 3)
    (scoremap 3 7)
    (scoremap 4 11)
    (scoremap 5 16)
    (scoremap 6 22)
    (scoremap 7 29)
    (scoremap 8 37)
    (scoremap 9 45)
    (scoremap 10 54)
    (scoremap 11 64)
    (scoremap 12 75)
    (scoremap 13 87)
    (scoremap 14 100))
    10 10)"))))

(progn
  (get-buffer-create ggp-test-output-buffer-name)
  (set-buffer ggp-test-output-buffer-name)
  (switch-to-buffer ggp-test-output-buffer-name)
  (setq buffer-read-only nil)
  (erase-buffer)
  (let ((parsed-request (ggp-parse-request "(start test.x040100 robot (
    (role robot)
    (<= (base (cell ?M ?N ?P)) (row ?M) (col ?N) (piece ?P))
    (<= (base (captures ?M)) (scoremap ?M ?N))
    (<= (base (step ?N)) (succ ?M ?N))
    (<= (input robot (move ?M1 ?N1 ?M2 ?N2)) (row ?M1) (col ?N1) (knightmove ?M1 ?N1 ?M2 ?N2))
    (row 1)
    (row 2)
    (row 3)
    (row 4)
    (row 5)
    (col 1)
    (col 2)
    (col 3)
    (piece knight)
    (piece pawn)
    (piece blank)
    (init (cell 1 1 knight))
    (init (cell 1 2 pawn))
    (init (cell 1 3 pawn))
    (init (cell 2 1 pawn))
    (init (cell 2 2 pawn))
    (init (cell 2 3 pawn))
    (init (cell 3 1 pawn))
    (init (cell 3 2 pawn))
    (init (cell 3 3 pawn))
    (init (cell 4 1 pawn))
    (init (cell 4 2 pawn))
    (init (cell 4 3 pawn))
    (init (cell 5 1 pawn))
    (init (cell 5 2 pawn))
    (init (cell 5 3 pawn))
    (init (captures 0))
    (init (step 1))
    (<= (legal robot (move ?M1 ?N1 ?M2 ?N2)) (true (cell ?M1 ?N1 knight)) (knightmove ?M1 ?N1 ?M2 ?N2))
    (<= (next (cell ?M2 ?N2 knight)) (does robot (move ?M1 ?N1 ?M2 ?N2)))
    (<= (next (cell ?M1 ?N1 blank)) (does robot (move ?M1 ?N1 ?M2 ?N2)))
    (<= (next (cell ?U ?V pawn)) (true (cell ?U ?V pawn)) (does robot (move ?M1 ?N1 ?M2 ?N2)) (distinct ?U ?M2))
    (<= (next (cell ?U ?V pawn)) (true (cell ?U ?V pawn)) (does robot (move ?M1 ?N1 ?M2 ?N2)) (distinct ?V ?N2))
    (<= (next (cell ?U ?V blank)) (true (cell ?U ?V blank)) (does robot (move ?M1 ?N1 ?M2 ?N2)) (distinct ?U ?M2))
    (<= (next (cell ?U ?V blank)) (true (cell ?U ?V blank)) (does robot (move ?M1 ?N1 ?M2 ?N2)) (distinct ?V ?N2))
    (<= (next (captures ?Old)) (does robot (move ?M1 ?N1 ?M2 ?N2)) (true (cell ?M2 ?N2 blank)) (true (captures ?Old)))
    (<= (next (captures ?New)) (does robot (move ?M1 ?N1 ?M2 ?N2)) (true (cell ?M2 ?N2 pawn)) (true (captures ?Old)) (succ ?Old ?New))
    (<= (next (step ?New)) (true (step ?Old)) (succ ?Old ?New))
    (<= (goal robot ?Goal) (true (captures ?Count)) (scoremap ?Count ?Goal))
    (<= terminal (true (step 15)))
    (<= (knightmove ?M1 ?N1 ?M2 ?N2) (add1row ?M1 ?M2) (add2col ?N1 ?N2))
    (<= (knightmove ?M1 ?N1 ?M2 ?N2) (add1row ?M1 ?M2) (add2col ?N2 ?N1))
    (<= (knightmove ?M1 ?N1 ?M2 ?N2) (add1row ?M2 ?M1) (add2col ?N1 ?N2))
    (<= (knightmove ?M1 ?N1 ?M2 ?N2) (add1row ?M2 ?M1) (add2col ?N2 ?N1))
    (<= (knightmove ?M1 ?N1 ?M2 ?N2) (add2row ?M1 ?M2) (add1col ?N1 ?N2))
    (<= (knightmove ?M1 ?N1 ?M2 ?N2) (add2row ?M1 ?M2) (add1col ?N2 ?N1))
    (<= (knightmove ?M1 ?N1 ?M2 ?N2) (add2row ?M2 ?M1) (add1col ?N1 ?N2))
    (<= (knightmove ?M1 ?N1 ?M2 ?N2) (add2row ?M2 ?M1) (add1col ?N2 ?N1))
    (succ 0 1)
    (succ 1 2)
    (succ 2 3)
    (succ 3 4)
    (succ 4 5)
    (succ 5 6)
    (succ 6 7)
    (succ 7 8)
    (succ 8 9)
    (succ 9 10)
    (succ 10 11)
    (succ 11 12)
    (succ 12 13)
    (succ 13 14)
    (succ 14 15)
    (add1row 1 2)
    (add1row 2 3)
    (add1row 3 4)
    (add1row 4 5)
    (add2row 1 3)
    (add2row 2 4)
    (add2row 3 5)
    (add1col 1 2)
    (add1col 2 3)
    (add2col 1 3)
    (scoremap 0 0)
    (scoremap 1 1)
    (scoremap 2 3)
    (scoremap 3 7)
    (scoremap 4 11)
    (scoremap 5 16)
    (scoremap 6 22)
    (scoremap 7 29)
    (scoremap 8 37)
    (scoremap 9 45)
    (scoremap 10 54)
    (scoremap 11 64)
    (scoremap 12 75)
    (scoremap 13 87)
    (scoremap 14 100))
    10 10)")))
    (insert (format "%S" (ggp-extract-rule-set (substring parsed-request 4 -3))))))

;;------------------------------------------------------------------------------
;;; Functional Tests
;;------------------------------------------------------------------------------

;; ;; test 1
;; (ggp-test
;;  "
;; 10 REM GGP Test 1
;; 20 PRINT \"GGP Test 1\": PRINT
;; 30 PRINT \"Hello World\"
;; 40 END
;; "
;;  "GGP Test 1

;; Hello World
;; ")

;;==============================================================================
;;; ggp-test.el ends here
;;==============================================================================