I have been making this FSM today. However, as this is probably the biggest practical program I have ever written in CL, I don't know if there are some things that could be improved, or if using a closure is the best thing here.
Any feedback is appreciated.
;;; States: -- EnterMineAndDigForNugget
;;; -- QuenchThirst
;;; -- GoHomeAndSleepTillRested
;;; -- VisitBankAndDepositGold
(defmacro while (test &rest body)
`(do ()
((not ,test))
,@body))
(defmacro enter (state)
`(setf state ,state))
(defun make-miner ()
(let ((wealth 0)
(thirst 0)
(rested 0)
(state 'EnterMineAndDigForNugget))
(list
(defun EnterMineAndDigForNugget ()
; (setf location 'mine)
(format t "~&Diggin' up gold!")
(incf wealth)
(incf thirst)
(cond ((>= thirst 7) (enter 'QuenchThirst))
(t (enter 'VisitBankAndDepositGold))))
(defun QuenchThirst ()
(format t "~&Drinkin' old good whiskey")
(setf thirst 0)
(enter 'EnterMineAndDigForNugget))
(defun VisitBankAndDepositGold ()
(format t "~&All this gold ought to be stored somewhere!")
(incf wealth)
(cond ((>= wealth 5) (progn
(format t "~&Too much gold for today, let's sleep!")
(enter 'GoHomeAndSleepTillRested)
(setf wealth 0)))
(t (EnterMineAndDigForNugget))))
(defun GoHomeAndSleepTillRested ()
(while (<= rested 3)
(format t "~&Sleepin'")
(incf rested))
(enter 'EnterMineAndDigForNugget)
(setf rested 0))
(defun controller ()
(dotimes (n 30)
(cond ((equal state 'QuenchThirst) (QuenchThirst))
((equal state 'VisitBankAndDepositGold) (VisitBankAndDepositGold))
((equal state 'GoHomeAndSleepTillRested) (GoHomeAndSleepTillRested))
((equal state 'EnterMineAndDigForNugget) (EnterMineAndDigForNugget))))))))
EDIT
I have applied all the suggested changes but for the flet/labels one. Everything worked fine until I changed the one of "set the state to the next function". Now, the macro enter
doesn't seem to be ever called.
This is the current state of the code, with the required code to make it work
;;; States: -- enter-mine-and-dig-for-nugget
;;; -- quench-thirst
;;; -- go-home-and-sleep-till-rested
;;; -- visit-bank-and-deposit-gold
(defmacro enter (state)
`(setf state ,state))
(defun make-miner ()
(let ((wealth 0)
(thirst 0)
(rested 0)
(state #'enter-mine-and-dig-for-nugget))
(list
(defun enter-mine-and-dig-for-nugget ()
(format t "~&Diggin' up gold!")
(incf wealth)
(incf thirst)
(if (>= thirst 7)
(enter #'quench-thirst)
(enter #'visit-bank-and-deposit-gold)))
(defun quench-thirst ()
(format t "~&Drinkin' old good whiskey")
(setf thirst 0)
(enter #'enter-mine-and-dig-for-nugget))
(defun visit-bank-and-deposit-gold ()
(format t "~&All this gold ought to be stored somewhere!")
(incf wealth)
(if (>= wealth 5)
(progn
(format t "~&Too much gold for today, let's sleep!")
(enter #'go-home-and-sleep-till-rested)
(setf wealth 0))
(enter #'enter-mine-and-dig-for-nugget)))
(defun go-home-and-sleep-till-rested ()
(dotimes (i 4)
(format t "~&Sleepin'"))
(enter #'enter-mine-and-dig-for-nugget))
(defun controller ()
(dotimes (n 30)
(funcall state))))))
(let ((a (make-miner)))
(funcall (fifth a)))