/roguelikes/grid.rkt

http://github.com/VincentToups/racket-lib · Racket · 206 lines · 178 code · 28 blank · 0 comment · 8 complexity · f3e10d0a4809136e5851ec42a63415d8 MD5 · raw file

  1. #lang racket
  2. (require utilities/proletariat
  3. (rename-in roguelikes/white-whale-data3 [floor dungeon-floor] [exit dungeon-exit])
  4. functional/better-monads
  5. utilities/rmatch-let
  6. functional/point-free)
  7. (define/class grid (object) 'data '() 'min-x +inf.0 'max-x -inf.0 'min-y +inf.0 'max-y -inf.0)
  8. (define-method (at grid pos) :: #(grid list)
  9. (match grid
  10. [(hash-table grid ('data data) (_ _) ...)
  11. (dict-ref data pos #f)]))
  12. (define-method (at grid s) :: #(grid symbol)
  13. (match s
  14. ['count (with-slots grid (data) (dict-count data))]
  15. ['keys (sort (dict-keys grid) pos<)]
  16. [_ (call-next-method)]))
  17. (define (pos< p1 p2)
  18. (match (list p1 p2)
  19. [(list
  20. (list (? number? i1)
  21. (? number? j1))
  22. (list (? number? i2)
  23. (? number? j2)))
  24. (if (= i1 i2) (< j1 j2)
  25. (< i1 i2))]))
  26. (define (pos-cons p pl . acc)
  27. (match acc
  28. [(list) (pos-cons p pl '())]
  29. [(list acc)
  30. (match pl
  31. [(list) (reverse (cons p acc))]
  32. [(cons h rest)
  33. (cond
  34. ((pos< p h) (append (reverse (cons p acc)) pl))
  35. ((equal? p h) (append (reverse acc) pl))
  36. (else (pos-cons p rest (cons h acc))))])]))
  37. (define (pos-remove p pl . acc)
  38. (match acc
  39. [(list) (pos-remove p pl '())]
  40. [(list acc)
  41. (match pl
  42. [(list) (reverse acc)]
  43. [(cons h rest)
  44. (cond
  45. ((equal? p h) (append (reverse acc) rest))
  46. (else (pos-remove p rest (cons h acc))))])]))
  47. (define (empty-grid? g)
  48. (empty? (dict-keys g)))
  49. (define (update-grid-min/max grid)
  50. (let* ((positions (at grid 'keys)))
  51. (if (empty? positions)
  52. (adjust grid 'min-x +inf.0 'max-x -inf.0 'min-y +inf.0 'max-y -inf.0)
  53. (let*
  54. ((first (car positions))
  55. (init (list (car first) (cadr first)
  56. (car first) (cadr first))))
  57. (match
  58. (foldl
  59. (lambda (it ac)
  60. (match it
  61. [(list minx miny maxx maxy)
  62. (match ac
  63. [(list cx cy)
  64. (list
  65. (min minx cx)
  66. (min miny cy)
  67. (max maxx cx)
  68. (max maxy cy))])]))
  69. init
  70. (cdr positions))
  71. [(list minx miny maxx maxy)
  72. (adjust grid
  73. 'min-x minx
  74. 'max-x maxx
  75. 'min-y miny
  76. 'max-y maxy)])))))
  77. (define-multimethod (set-at gr p val) :: (vector-immutable (class-name gr) (class-name p)))
  78. (define-method (set-at gr p val) :: #(grid list)
  79. (adjust gr 'data
  80. (depending-on (data) (dict-set data p val))
  81. 'min-x (depending-on (min-x)
  82. (min min-x (car p)))
  83. 'min-y (depending-on (min-y)
  84. (min min-y (cadr p)))
  85. 'max-x (depending-on (max-x)
  86. (max max-x (car p)))
  87. 'max-y (depending-on (max-y)
  88. (max max-y (cadr p)))))
  89. (define-multimethod (unset-at grid pos) :: (vector-immutable (class-name grid)
  90. (class-name pos)))
  91. (define-method (unset-at grid pos) :: #(grid list)
  92. (update-grid-min/max
  93. (adjust grid
  94. 'data
  95. (depending-on (data)
  96. (dict-remove data pos)))))
  97. (define-multimethod (dip-at gr p dip) :: (vector-immutable (class-name gr) (class-name p)))
  98. (define-method (dip-at gr p dip) :: #(grid list)
  99. (let ((val (at gr p)))
  100. (set-at gr p (dip val))))
  101. (define-multimethod (square-extent o) :: (class-name o))
  102. (define-method (square-extent g) :: grid
  103. (cond
  104. ((= 0 (at g 'count)) '())
  105. (else
  106. (with-slots g (min-x max-x min-y max-y)
  107. (list
  108. (list min-x min-y)
  109. (list max-x max-y))))))
  110. (define pos-i car)
  111. (define pos-j cadr)
  112. (define-match-expander pos
  113. (syntax-rules ()
  114. [(pos x y) (list x y)]))
  115. (define (set-horizontal-line grid x-start x-stop y what)
  116. (match-let ([(list x-start x-stop) (sort (list x-start x-stop) <)])
  117. (let loop [(acc grid)
  118. (i x-start)]
  119. (if (> i x-stop) acc
  120. (loop (set-at acc (list i y) what)
  121. (+ i 1))))))
  122. (define (set-vertical-line grid y-start y-stop x what)
  123. (match-let ([(list y-start y-stop) (sort (list y-start y-stop) <)])
  124. (let loop [(acc grid)
  125. (j y-start)]
  126. (if (> j y-stop) acc
  127. (loop (set-at acc (list x j) what)
  128. (+ j 1))))))
  129. (define (set-rectangle grid . args)
  130. (match args
  131. [(list (pos min-x min-y) (pos max-x max-y) thing)
  132. (set-rectangle grid min-x min-y max-x max-y thing)]
  133. [(list min-x min-y max-x max-y thing)
  134. ((compose
  135. (partial< set-horizontal-line min-x max-x min-y thing)
  136. (partial< set-horizontal-line min-x max-x max-y thing)
  137. (partial< set-vertical-line (+ min-y 1) (- max-y 1) min-x thing)
  138. (partial< set-vertical-line (+ min-y 1) (- max-y 1) max-x thing))
  139. grid)]))
  140. (define (set-filled-rectangle grid . args)
  141. (match args
  142. [(list (pos min-x min-y) (pos max-x max-y) thing)
  143. (set-filled-rectangle grid min-x min-y max-x max-y thing)]
  144. [(list min-x min-y max-x max-y thing)
  145. (let loop ((x min-x)
  146. (grid grid))
  147. (if (> x max-x) grid
  148. (loop (+ x 1)
  149. (set-vertical-line grid min-y max-y x thing))))]))
  150. (define (set-room grid . args)
  151. (match args
  152. [(list (pos min-x min-y) (pos max-x max-y))
  153. (set-rectangle grid min-x min-y max-x max-y)]
  154. [(list min-x min-y max-x max-y)
  155. ((compose
  156. (partial< set-filled-rectangle
  157. (+ min-x 1) (+ min-y 1)
  158. (- max-x 1) (- max-y 1)
  159. dungeon-floor)
  160. (partial< set-rectangle
  161. min-x min-y
  162. max-x max-y
  163. wall))
  164. grid)]))
  165. (define wall-grid (set-filled-rectangle grid (list 0 0) (list 60 30) wall))
  166. (define floor-grid (set-filled-rectangle grid (list 0 0) (list 60 30) dungeon-floor))
  167. (define (grid-extent g)
  168. (match g
  169. [(obj
  170. ['min-x min-x]
  171. ['max-x max-x]
  172. ['min-y min-y]
  173. ['max-y max-y])
  174. (list (list min-x min-y)
  175. (list max-x max-y))]))
  176. (provide grid grid? dip-at unset-at set-at square-extent pos-i pos-j
  177. set-rectangle set-vertical-line set-horizontal-line wall-grid floor-grid
  178. set-filled-rectangle set-room empty-grid? grid-extent)