robot-world.lisp 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. ;;;; robot-world.lisp
  2. (in-package #:robot-impl)
  3. (defvar *robot-app-running-p* nil)
  4. (define-condition robot-app-not-running (error) ())
  5. (defclass robot ()
  6. ((active-p :accessor robot-active-p :initform t)))
  7. (defclass landscape ()
  8. ((width :reader landscape-width :initarg :width)
  9. (height :reader landscape-height :initarg :height)
  10. (hwalls :reader landscape-hwalls :initarg :hwalls)
  11. (vwalls :reader landscape-vwalls :initarg :vwalls)
  12. (dotted-cells :reader dotted-cells :initarg :dotted-cells)
  13. (temperature :reader temperature-map :initarg :temperature :initform nil)
  14. (radiation :reader radiation-map :initarg :radiation :initform nil)))
  15. (defclass world ()
  16. ((landscape :reader landscape :initarg :landscape)
  17. (robot :reader robot :initarg :robot)
  18. (robot-position :accessor robot-position :initarg :robot-position)
  19. (painted-cells :accessor painted-cells :initform '())))
  20. (defclass visible-world (world)
  21. ((wish :accessor world-wish)
  22. (robot-sprite :accessor robot-sprite)
  23. (canvas :accessor world-canvas)
  24. (cells :accessor world-cells :initform (make-hash-table :test 'equal))
  25. (yes-led :accessor yes-led)
  26. (no-led :accessor no-led)))
  27. (defclass app ()
  28. ((world :accessor robot-app-world :initarg :world)
  29. (components :accessor app-components :initform (make-hash-table :test 'equal))
  30. (callbacks :accessor app-callbacks :initform (make-hash-table :test 'equal))
  31. (wish :accessor robot-app-wish)))
  32. (defvar *app*)
  33. (defparameter *app-callbacks* '#.(loop for command in '(up down left right paint
  34. wall-up-p wall-down-p wall-left-p wall-right-p
  35. clear-up-p clear-down-p clear-left-p clear-right-p
  36. paintedp blankp
  37. temperature radiation)
  38. nconc (list (intern (symbol-name command) "KEYWORD") command)))
  39. (defparameter *robot-app-components* '(:map
  40. :yes-led
  41. :no-led
  42. :temperature-indicator
  43. :radiation-indicator))
  44. (defun make-app (world &optional (callbacks *app-callbacks*))
  45. (loop with app = (make-instance 'app :world world)
  46. for (name callback) on callbacks by #'cddr
  47. do (setf (gethash name (app-callbacks app)) callback)
  48. finally (return app)))
  49. (defun robot-app-component (component-name app)
  50. (values (gethash component-name (app-components app))))
  51. (defun (setf robot-app-component) (component component-name app)
  52. (setf (gethash component-name (app-components app)) component))
  53. (defun robot-app-callback (callback-name app)
  54. (values (gethash callback-name (app-callbacks app))))
  55. ;;; copypasted from PCL
  56. (defmacro once-only ((&rest names) &body body)
  57. (let ((gensyms (loop for n in names collect (gensym))))
  58. `(let (,@(loop for g in gensyms collect `(,g (gensym))))
  59. `(let (,,@(loop for g in gensyms for n in names collect ``(,,g ,,n)))
  60. ,(let (,@(loop for n in names for g in gensyms collect `(,n ,g)))
  61. ,@body)))))
  62. (defparameter *default-world* 'world0)
  63. (defun fresh-world (&key height width horizontal-walls vertical-walls temperature radiation dotted robot-position)
  64. (macrolet ((remdup (&rest vars)
  65. `(setf ,@(loop for var in vars
  66. append `(,var (remove-duplicates ,var :test #'equal))))))
  67. (remdup horizontal-walls vertical-walls dotted)
  68. (lambda ()
  69. (make-instance 'world
  70. :landscape (make-instance 'landscape
  71. :height height
  72. :width width
  73. :hwalls horizontal-walls
  74. :vwalls vertical-walls
  75. :dotted-cells dotted
  76. :temperature temperature
  77. :radiation radiation)
  78. :robot (make-instance 'robot)
  79. :robot-position robot-position))))
  80. (defmacro defworld (name &key height width horizontal-walls vertical-walls temperature radiation dotted robot-position)
  81. "Определить функцию без аргументов, возвращающую мир робота."
  82. (let ((temperature-array-s (gensym "TEMPERATURE-ARRAY-"))
  83. (radiation-array-s (gensym "RADIATION-ARRAY-")))
  84. (once-only (height width horizontal-walls vertical-walls temperature radiation dotted robot-position)
  85. `(let ((,temperature-array-s (and ,temperature (make-array '(,height ,width) :initial-contents ,temperature)))
  86. (,radiation-array-s (and ,radiation (make-array '(,height ,width) :initial-contents ,radiation))))
  87. (defun ,name ()
  88. (let ((world-maker (fresh-world :height ,height
  89. :width ,width
  90. :horizontal-walls ,horizontal-walls
  91. :vertical-walls ,vertical-walls
  92. :temperature ,temperature-array-s
  93. :radiation ,radiation-array-s
  94. :dotted ,dotted
  95. :robot-position ,robot-position)))
  96. (funcall world-maker)))))))
  97. (defworld world0
  98. :height 9
  99. :width 9
  100. :robot-position '(4 4))