commands.lisp 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. ;;;; commands.lisp
  2. (in-package #:robot-impl)
  3. (defparameter *motion-delay* 0.5)
  4. (defmacro defcommand (name &body body)
  5. (let ((docstring nil)
  6. (true-body body)
  7. (maybe-docstring (first body)))
  8. (when (stringp maybe-docstring)
  9. (setf docstring maybe-docstring
  10. true-body (rest body)))
  11. `(defun ,name ()
  12. ,docstring
  13. (unless *robot-app-running-p*
  14. (error "Робот не запущен."))
  15. (let ((*wish* (robot-app-wish *app*)))
  16. ,@true-body))))
  17. (defmacro defmotion (name position docstring)
  18. `(defcommand ,name
  19. ,docstring
  20. (let ((world (robot-app-world *app*)))
  21. (when (robot-active-p (robot world))
  22. (set-robot-data "" (robot-app-component :temperature *app*))
  23. (set-robot-data "" (robot-app-component :radiation *app*))
  24. (sleep *motion-delay*)
  25. (destructuring-bind (x y) (robot-position world)
  26. (destructuring-bind (new-x new-y) (list ,@position)
  27. (if (or (loop for (x-wall y-wall) in (landscape-hwalls (landscape world))
  28. thereis (and (< (min y new-y) y-wall)
  29. (>= (max y new-y) y-wall)
  30. (= x-wall x)))
  31. (loop for (x-wall y-wall) in (landscape-vwalls (landscape world))
  32. thereis (and (< (min x new-x) x-wall)
  33. (>= (max x new-x) x-wall)
  34. (= y-wall y))))
  35. (setf (robot-active-p (robot world)) nil)
  36. (when (and (<= 0 new-x (1- (landscape-width (landscape world))))
  37. (<= 0 new-y (1- (landscape-height (landscape world)))))
  38. (setf (robot-position world) (list ,@position)))))))
  39. (robot-app-update-map *app*)
  40. (if (robot-active-p (robot world))
  41. t
  42. nil))))
  43. (defmotion up (x (1- y)) "Идти на одну клетку вверх.")
  44. (defmotion down (x (1+ y)) "Идти на одну клетку вниз.")
  45. (defmotion left ((1- x) y) "Идти на одну клетку влево.")
  46. (defmotion right ((1+ x) y) "Идти на одну клетку вправо.")
  47. (defcommand paint
  48. "Закрасить клетку."
  49. (let ((world (robot-app-world *app*)))
  50. (when (robot-active-p (robot world))
  51. (sleep *motion-delay*)
  52. (pushnew (robot-position world) (painted-cells world) :test #'equal)
  53. (robot-app-update-map *app*)
  54. t)))
  55. (defun show-reply (reply app)
  56. (let ((*wish* (robot-app-wish *app*)))
  57. (set-robot-led-mode :off (robot-app-component :yes-led app))
  58. (set-robot-led-mode :off (robot-app-component :no-led app))
  59. (sleep *motion-delay*)
  60. (set-robot-led-mode :on (robot-app-component (if reply :yes-led :no-led) app)))
  61. reply)
  62. (defun %wall-up-p (world)
  63. (member (robot-position world)
  64. (landscape-hwalls (landscape world))
  65. :test #'equal))
  66. (defun %wall-left-p (world)
  67. (member (robot-position world)
  68. (landscape-vwalls (landscape world))
  69. :test #'equal))
  70. (defun %wall-down-p (world)
  71. (destructuring-bind (x y) (robot-position world)
  72. (member (list x (1+ y))
  73. (landscape-hwalls (landscape world))
  74. :test #'equal)))
  75. (defun %wall-right-p (world)
  76. (destructuring-bind (x y) (robot-position world)
  77. (member (list (1+ x) y)
  78. (landscape-vwalls (landscape world))
  79. :test #'equal)))
  80. (defun %cell-painted-p (world)
  81. (member (robot-position world) (painted-cells world)))
  82. (defmacro deftemplike (name name1 component default docstring)
  83. `(progn
  84. (defun ,name1 (world)
  85. (let ((map (temperature-map (landscape world))))
  86. (if (null map)
  87. ,default
  88. (apply #'aref map (robot-position world)))))
  89. (defcommand ,name
  90. ,docstring
  91. (let ((value (,name1 (robot-app-world *app*))))
  92. (set-robot-data value (robot-app-component ,component *app*))
  93. value))))
  94. (deftemplike temperature %temperature :temperature 20 "Температура")
  95. (deftemplike radiation %radiation :radiation 0 "Радиация")
  96. (defmacro defquery (name form docstring)
  97. `(defcommand ,name
  98. ,docstring
  99. (let ((world (robot-app-world *app*)))
  100. (if (robot-active-p (robot world))
  101. (if (show-reply ,form *app*)
  102. (values t t)
  103. (values nil t))
  104. (values nil nil)))))
  105. (defmacro def-two-queries (yes-name no-name true-name docstring1 docstring2)
  106. `(progn
  107. (defquery ,yes-name (,true-name world) ,docstring1)
  108. (defquery ,no-name (not (,true-name world)) ,docstring2)))
  109. (defmacro def-wall-queries (direction docstring1 docstring2)
  110. (let ((yes-name (intern (format nil "WALL-~A-P" direction)))
  111. (no-name (intern (format nil "CLEAR-~A-P" direction)))
  112. (true-name (intern (format nil "%WALL-~A-P" direction))))
  113. `(def-two-queries ,yes-name ,no-name ,true-name ,docstring1 ,docstring2)))
  114. (def-two-queries paintedp blankp %cell-painted-p "Клетка закрашена?" "Клетка незакрашена?")
  115. (def-wall-queries up "Есть стена сверху?" "Нет стены сверху?")
  116. (def-wall-queries down "Есть стена снизу?" "Нет стены снизу?")
  117. (def-wall-queries left "Есть стена слева?" "Нет стены слева?")
  118. (def-wall-queries right "Есть стена справа?" "Нет стены справа?")
  119. (defun start (&optional (world *default-world*))
  120. "Запустить мир робота."
  121. (if *robot-app-running-p*
  122. (progn
  123. (warn "Робот уже запущен.")
  124. nil)
  125. (progn
  126. (setf *app* (make-app (funcall world)))
  127. (show-robot-app *app*)
  128. t)))