4520c6449f48

Add Towers of Hanoi GDL example
[view raw] [browse files]
author Steve Losh <steve@stevelosh.com>
date Thu, 30 Jun 2016 17:53:20 +0000
parents 13136d4b4761
children 802872f9505a
branches/tags (none)
files examples/ggp-wam-hanoi.lisp

Changes

--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/ggp-wam-hanoi.lisp	Thu Jun 30 17:53:20 2016 +0000
@@ -0,0 +1,272 @@
+(in-package #:bones.wam)
+
+(declaim (optimize (speed 3) (debug 0) (safety 0)))
+
+(defparameter *d* (make-database))
+
+(with-database *d*
+  (rules ((member :thing (list* :thing :rest)))
+         ((member :thing (list* :other :rest))
+          (member :thing :rest)))
+
+  (rule (true :state :thing)
+    (member :thing :state))
+
+  (rule (does :performed :role :move)
+    (member (does :role :move) :performed))
+
+  (rules ((not :x) (call :x) ! fail)
+         ((not :x)))
+
+  (fact (role player))
+
+  (facts (init (on disc7 pillar1))
+         (init (on disc6 disc7))
+         (init (on disc5 disc6))
+         (init (on disc4 disc5))
+         (init (on disc3 disc4))
+         (init (on disc2 disc3))
+         (init (on disc1 disc2))
+         (init (clear disc1))
+         (init (clear pillar2))
+         (init (clear pillar3))
+         (init (step s0)))
+
+  (rule (legal :state player (puton :x :y))
+    (true :state (clear :x))
+    (true :state (clear :y))
+    (smallerdisc :x :y))
+
+  (rules ((next :state :performed (step :y))
+          (true :state (step :x))
+          (successor :x :y))
+         ((next :state :performed (on :x :y))
+          (does :performed player (puton :x :y)))
+         ((next :state :performed (on :x :y))
+          (true :state (on :x :y))
+          (not (put_on_any :performed :x)))
+         ((next :state :performed (clear :y))
+          (true :state (on :x :y))
+          (put_on_any :performed :x))
+         ((next :state :performed (clear :y))
+          (true :state (clear :y))
+          (not (put_any_on :performed :y))))
+
+  (rule (put_on_any :performed :x)
+    (does :performed player (puton :x :y)))
+
+  (rule (put_any_on :performed :y)
+    (does :performed player (puton :x :y)))
+
+  (rules ((goal :state player num100)
+          (tower :state pillar3 s7))
+         ((goal :state player num80)
+          (tower :state pillar3 s6))
+         ((goal :state player num60)
+          (tower :state pillar3 s5))
+         ((goal :state player num40)
+          (tower :state pillar3 s4))
+         ((goal :state player num0)
+          (tower :state pillar3 :height)
+          (smaller :height s4)))
+
+  (rule (terminal :state)
+    (true :state (step s127)))
+
+  (rules ((tower :state :x s0)
+          (true :state (clear :x)))
+         ((tower :state :x :height)
+          (true :state (on :y :x))
+          (disc_or_pillar :y)
+          (tower :state :y :height1)
+          (successor :height1 :height)))
+
+  (facts (pillar pillar1)
+         (pillar pillar2)
+         (pillar pillar3))
+
+  (rules ((nextsize disc1 disc2))
+         ((nextsize disc2 disc3))
+         ((nextsize disc3 disc4))
+         ((nextsize disc4 disc5))
+         ((nextsize disc5 disc6))
+         ((nextsize disc6 disc7))
+         ((nextsize disc7 :pillar)
+          (pillar :pillar)))
+
+  (rules ((disc_or_pillar :p) (pillar :p))
+         ((disc_or_pillar disc1))
+         ((disc_or_pillar disc2))
+         ((disc_or_pillar disc3))
+         ((disc_or_pillar disc4))
+         ((disc_or_pillar disc5))
+         ((disc_or_pillar disc6))
+         ((disc_or_pillar disc7)))
+
+  (rules ((smallerdisc :a :b)
+          (nextsize :a :b))
+         ((smallerdisc :a :b)
+          (nextsize :a :c)
+          (smallerdisc :c :b)))
+
+  (facts (successor s0 s1) (successor s1 s2) (successor s2 s3)
+         (successor s3 s4) (successor s4 s5) (successor s5 s6)
+         (successor s6 s7) (successor s7 s8) (successor s8 s9)
+         (successor s9 s10) (successor s10 s11) (successor s11 s12)
+         (successor s12 s13) (successor s13 s14) (successor s14 s15)
+         (successor s15 s16) (successor s16 s17) (successor s17 s18)
+         (successor s18 s19) (successor s19 s20) (successor s20 s21)
+         (successor s21 s22) (successor s22 s23) (successor s23 s24)
+         (successor s24 s25) (successor s25 s26) (successor s26 s27)
+         (successor s27 s28) (successor s28 s29) (successor s29 s30)
+         (successor s30 s31) (successor s31 s32) (successor s32 s33)
+         (successor s33 s34) (successor s34 s35) (successor s35 s36)
+         (successor s36 s37) (successor s37 s38) (successor s38 s39)
+         (successor s39 s40) (successor s40 s41) (successor s41 s42)
+         (successor s42 s43) (successor s43 s44) (successor s44 s45)
+         (successor s45 s46) (successor s46 s47) (successor s47 s48)
+         (successor s48 s49) (successor s49 s50) (successor s50 s51)
+         (successor s51 s52) (successor s52 s53) (successor s53 s54)
+         (successor s54 s55) (successor s55 s56) (successor s56 s57)
+         (successor s57 s58) (successor s58 s59) (successor s59 s60)
+         (successor s60 s61) (successor s61 s62) (successor s62 s63)
+         (successor s63 s64) (successor s64 s65) (successor s65 s66)
+         (successor s66 s67) (successor s67 s68) (successor s68 s69)
+         (successor s69 s70) (successor s70 s71) (successor s71 s72)
+         (successor s72 s73) (successor s73 s74) (successor s74 s75)
+         (successor s75 s76) (successor s76 s77) (successor s77 s78)
+         (successor s78 s79) (successor s79 s80) (successor s80 s81)
+         (successor s81 s82) (successor s82 s83) (successor s83 s84)
+         (successor s84 s85) (successor s85 s86) (successor s86 s87)
+         (successor s87 s88) (successor s88 s89) (successor s89 s90)
+         (successor s90 s91) (successor s91 s92) (successor s92 s93)
+         (successor s93 s94) (successor s94 s95) (successor s95 s96)
+         (successor s96 s97) (successor s97 s98) (successor s98 s99)
+         (successor s99 s100) (successor s100 s101) (successor s101 s102)
+         (successor s102 s103) (successor s103 s104) (successor s104 s105)
+         (successor s105 s106) (successor s106 s107) (successor s107 s108)
+         (successor s108 s109) (successor s109 s110) (successor s110 s111)
+         (successor s111 s112) (successor s112 s113) (successor s113 s114)
+         (successor s114 s115) (successor s115 s116) (successor s116 s117)
+         (successor s117 s118) (successor s118 s119) (successor s119 s120)
+         (successor s120 s121) (successor s121 s122) (successor s122 s123)
+         (successor s123 s124) (successor s124 s125) (successor s125 s126)
+         (successor s126 s127))
+
+  (rules ((smaller :x :y)
+          (successor :x :y))
+         ((smaller :x :y)
+          (successor :x :z)
+          (smaller :z :y))))
+
+
+(defun extract (key results)
+  (mapcar (lambda (result) (getf result key)) results))
+
+(defun to-prolog-list (l)
+  (if (null l)
+    nil
+    (list* 'list l)))
+
+(defun initial-state ()
+  (to-prolog-list
+    (with-database *d*
+      (extract :what (return-all (init :what))))))
+
+(defun terminalp (state)
+  (with-database *d*
+    (perform-prove `((terminal ,state)))))
+
+(defun legal-moves (state)
+  (with-database *d*
+    (perform-return `((legal ,state :role :move)) :all)))
+
+(defun roles ()
+  (with-database *d*
+    (extract :role (return-all (role :role)))))
+
+(defun goal-value (state role)
+  (with-database *d*
+    (getf (perform-return `((goal ,state ,role :goal)) :one) :goal)))
+
+(defun goal-values (state)
+  (with-database *d*
+    (perform-return `((goal ,state :role :goal)) :all)))
+
+(defun next-state (current-state move)
+  (let ((does `(list (does
+                       ,(getf move :role)
+                       ,(getf move :move)))))
+    (with-database *d*
+      (to-prolog-list
+        (extract :what
+                 (perform-return `((next ,current-state ,does :what)) :all))))))
+
+
+
+(defvar *count* 0)
+
+(defstruct search-path state (path nil) (previous nil))
+
+(defun tree-search (states goal-p children combine)
+  (labels
+      ((recur (states)
+         (if (null states)
+           nil
+           (destructuring-bind (state . remaining) states
+             (incf *count*)
+             (when (zerop (rem *count* 1000))
+               (format t "~D...~%" *count*))
+             ; (format t "Searching: ~S (~D remaining)~%"
+             ;         state
+             ;         (length remaining))
+             (if (funcall goal-p state)
+               state
+               (recur (funcall combine
+                               (funcall children state)
+                               remaining)))))))
+    (let ((result (recur states)))
+      (when result
+        (reverse (search-path-path result))))))
+
+
+(defun game-goal-p (search-path)
+  (let ((state (search-path-state search-path)))
+    (and (terminalp state)
+         (eql (goal-value state 'player) 'num100))))
+
+(defun game-children (search-path)
+  (let ((state (search-path-state search-path))
+        (path (search-path-path search-path)))
+    (when (not (terminalp state))
+      (loop :for move :in (legal-moves state)
+            :collect (make-search-path :state (next-state state move)
+                                       :path (cons move path)
+                                       :previous search-path)))))
+
+(defun never (&rest args)
+  (declare (ignore args))
+  nil)
+
+(defun dfs ()
+  (let ((*count* 0))
+    (tree-search (list (make-search-path :state (initial-state)))
+               #'game-goal-p
+               #'game-children
+               #'append)))
+
+(defun dfs-exhaust ()
+  (let ((*count* 0))
+    (prog1
+        (tree-search (list (make-search-path :state (initial-state)))
+                     #'never
+                     #'game-children
+                     #'append)
+      (format t "Searched ~D nodes.~%" *count*))))
+
+(defun bfs ()
+  (tree-search (list (make-search-path :state (initial-state)))
+               #'game-goal-p
+               #'game-children
+               (lambda (x y)
+                 (append y x))))