123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148 |
- ;;;; commands.lisp
- (in-package #:robot-impl)
- (defparameter *motion-delay* 0.5)
- (defmacro defcommand (name &body body)
- (let ((docstring nil)
- (true-body body)
- (maybe-docstring (first body)))
- (when (stringp maybe-docstring)
- (setf docstring maybe-docstring
- true-body (rest body)))
- `(defun ,name ()
- ,docstring
- (unless *robot-app-running-p*
- (error "Робот не запущен."))
- (let ((*wish* (robot-app-wish *app*)))
- ,@true-body))))
- (defmacro defmotion (name position docstring)
- `(defcommand ,name
- ,docstring
- (let ((world (robot-app-world *app*)))
- (when (robot-active-p (robot world))
- (set-robot-data "" (robot-app-component :temperature *app*))
- (set-robot-data "" (robot-app-component :radiation *app*))
- (sleep *motion-delay*)
- (destructuring-bind (x y) (robot-position world)
- (destructuring-bind (new-x new-y) (list ,@position)
- (if (or (loop for (x-wall y-wall) in (landscape-hwalls (landscape world))
- thereis (and (< (min y new-y) y-wall)
- (>= (max y new-y) y-wall)
- (= x-wall x)))
- (loop for (x-wall y-wall) in (landscape-vwalls (landscape world))
- thereis (and (< (min x new-x) x-wall)
- (>= (max x new-x) x-wall)
- (= y-wall y))))
- (setf (robot-active-p (robot world)) nil)
- (when (and (<= 0 new-x (1- (landscape-width (landscape world))))
- (<= 0 new-y (1- (landscape-height (landscape world)))))
- (setf (robot-position world) (list ,@position)))))))
- (robot-app-update-map *app*)
- (if (robot-active-p (robot world))
- t
- nil))))
- (defmotion up (x (1- y)) "Идти на одну клетку вверх.")
- (defmotion down (x (1+ y)) "Идти на одну клетку вниз.")
- (defmotion left ((1- x) y) "Идти на одну клетку влево.")
- (defmotion right ((1+ x) y) "Идти на одну клетку вправо.")
- (defcommand paint
- "Закрасить клетку."
- (let ((world (robot-app-world *app*)))
- (when (robot-active-p (robot world))
- (sleep *motion-delay*)
- (pushnew (robot-position world) (painted-cells world) :test #'equal)
- (robot-app-update-map *app*)
- t)))
- (defun show-reply (reply app)
- (let ((*wish* (robot-app-wish *app*)))
- (set-robot-led-mode :off (robot-app-component :yes-led app))
- (set-robot-led-mode :off (robot-app-component :no-led app))
- (sleep *motion-delay*)
- (set-robot-led-mode :on (robot-app-component (if reply :yes-led :no-led) app)))
- reply)
- (defun %wall-up-p (world)
- (member (robot-position world)
- (landscape-hwalls (landscape world))
- :test #'equal))
- (defun %wall-left-p (world)
- (member (robot-position world)
- (landscape-vwalls (landscape world))
- :test #'equal))
- (defun %wall-down-p (world)
- (destructuring-bind (x y) (robot-position world)
- (member (list x (1+ y))
- (landscape-hwalls (landscape world))
- :test #'equal)))
- (defun %wall-right-p (world)
- (destructuring-bind (x y) (robot-position world)
- (member (list (1+ x) y)
- (landscape-vwalls (landscape world))
- :test #'equal)))
- (defun %cell-painted-p (world)
- (member (robot-position world) (painted-cells world)))
- (defmacro deftemplike (name name1 component default docstring)
- `(progn
- (defun ,name1 (world)
- (let ((map (temperature-map (landscape world))))
- (if (null map)
- ,default
- (apply #'aref map (robot-position world)))))
- (defcommand ,name
- ,docstring
- (let ((value (,name1 (robot-app-world *app*))))
- (set-robot-data value (robot-app-component ,component *app*))
- value))))
- (deftemplike temperature %temperature :temperature 20 "Температура")
- (deftemplike radiation %radiation :radiation 0 "Радиация")
- (defmacro defquery (name form docstring)
- `(defcommand ,name
- ,docstring
- (let ((world (robot-app-world *app*)))
- (if (robot-active-p (robot world))
- (if (show-reply ,form *app*)
- (values t t)
- (values nil t))
- (values nil nil)))))
- (defmacro def-two-queries (yes-name no-name true-name docstring1 docstring2)
- `(progn
- (defquery ,yes-name (,true-name world) ,docstring1)
- (defquery ,no-name (not (,true-name world)) ,docstring2)))
- (defmacro def-wall-queries (direction docstring1 docstring2)
- (let ((yes-name (intern (format nil "WALL-~A-P" direction)))
- (no-name (intern (format nil "CLEAR-~A-P" direction)))
- (true-name (intern (format nil "%WALL-~A-P" direction))))
- `(def-two-queries ,yes-name ,no-name ,true-name ,docstring1 ,docstring2)))
- (def-two-queries paintedp blankp %cell-painted-p "Клетка закрашена?" "Клетка незакрашена?")
- (def-wall-queries up "Есть стена сверху?" "Нет стены сверху?")
- (def-wall-queries down "Есть стена снизу?" "Нет стены снизу?")
- (def-wall-queries left "Есть стена слева?" "Нет стены слева?")
- (def-wall-queries right "Есть стена справа?" "Нет стены справа?")
- (defun start (&optional (world *default-world*))
- "Запустить мир робота."
- (if *robot-app-running-p*
- (progn
- (warn "Робот уже запущен.")
- nil)
- (progn
- (setf *app* (make-app (funcall world)))
- (show-robot-app *app*)
- t)))
|