lattice.scm 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551
  1. #!/usr/bin/guile
  2. !#
  3. ; A Lattice Game of Cosmic Insignificance:
  4. ; A small game about mathematical lattices and tribes.
  5. ; Copyright (C) 2019 <houkime at protonmail.com>
  6. ; This program is free software: you can redistribute it and/or modify
  7. ; it under the terms of the GNU General Public License as published by
  8. ; the Free Software Foundation, either version 3 of the License, or
  9. ; (at your option) any later version.
  10. ;
  11. ; This program is distributed in the hope that it will be useful,
  12. ; but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. ; GNU General Public License for more details.
  15. ; You should have received a copy of the GNU General Public License
  16. ; along with this program. If not, see <https://www.gnu.org/licenses/>.
  17. (use-modules (chickadee)
  18. (chickadee math vector)
  19. (chickadee math rect)
  20. (chickadee render font)
  21. (chickadee render sprite)
  22. (chickadee render texture)
  23. (oop goops)
  24. (oop goops describe)
  25. (srfi srfi-1)
  26. (ice-9 format)
  27. )
  28. (define-class <node> ()
  29. (name #:init-keyword #:name)
  30. (more #:init-keyword #:more #:init-value '())
  31. (less #:init-keyword #:less #:init-value '())
  32. (init_type #:init-keyword #:init_type #:init-value "mammalian");
  33. (type_changed #:init-keyword #:type_changed #:init-value #f))
  34. (define list_interrow_dist 15)
  35. (define action "join"); can be join or meet
  36. (define target #f) ; these 2 are specified at load time
  37. (define current #f)
  38. (define imbalance 0)
  39. (define turns-taken 0)
  40. (define (bump_turns)
  41. (set! turns-taken (+ turns-taken 1))
  42. (update-turns-label))
  43. (define (update-turns-label)
  44. (slot-set! turns-taken-label 'str (simple-format #f "~A Turns Taken" turns-taken)))
  45. (define (typestat type)
  46. (fold + 0 (map (lambda (node)
  47. (if (eqv? (get-node-type node) type) 1 0)) lattice)))
  48. (define (calculate-imbalance)
  49. (set! imbalance (- (typestat "mammalian") (typestat "bird")))
  50. (slot-set! imbalance-label 'str (simple-format #f "Cosmic imbalance is ~A" imbalance))
  51. (if (eqv? imbalance 0) (display-term "Balance is restored. you sorta won")))
  52. (define-class <tree_node> ()
  53. (position #:init-keyword #:position #:init-value #v(0 0))
  54. (visible #:init-value #t #:init-keyword #:visible)
  55. (parent #:init-value #f #:init-keyword #:parent)
  56. (children #:init-value '())
  57. )
  58. (define-class <clickable> (<tree_node>)
  59. (rect #:init-keyword #:rect #:init-value (make-rect 0 0 100 15))
  60. (click-enabled #:init-keyword #:click-enabled #:init-value #t)
  61. (on_click #:init-keyword #:on_click #:init-value (lambda (self)
  62. (display "click!")))
  63. )
  64. (define-class <button> (<clickable>)
  65. (str #:init-keyword #:str))
  66. (define-class <terminal_widget> (<tree_node>)
  67. (item_height #:init-value 15)
  68. (max_lines #:init-value 20)
  69. (width #:init-value 300)
  70. (lines #:init-value '())
  71. )
  72. (define-method (add-entry (term <terminal_widget>) str)
  73. (add-child term (make <label> #:str str))
  74. (if (> (length (slot-ref term 'children)) (slot-ref term 'max_lines))
  75. (begin
  76. (display "unparenting excessive stuff")
  77. (unparent (list-ref (slot-ref term 'children) 0))
  78. ))
  79. )
  80. (define-method (clear-children (node <tree_node>))
  81. (let ((children-list (slot-ref node 'children)))
  82. (slot-set! node 'children '())
  83. (for-each unparent children-list)))
  84. (define (display-term str)
  85. (add-entry terminal str))
  86. (define-class <label> (<tree_node>)
  87. (str #:init-value "label" #:init-keyword #:str))
  88. (define-class <list_widget> (<tree_node>)
  89. (item_height #:init-value 15)
  90. (on_selected #:init-keyword #:on_selected #:init-value (lambda (self key)
  91. (display "list clicked"))))
  92. (define-class <list_entry> (<button>)
  93. (key #:init-keyword #:key)
  94. (on_click #:init-keyword #:on_click
  95. #:init-value (lambda (self)
  96. ((slot-ref (slot-ref self 'parent) 'on_selected)
  97. (slot-ref self 'parent) (slot-ref self 'key))))
  98. )
  99. (define-method (activate (lw <list_widget>))
  100. (for-each (lambda (x)
  101. (slot-set! x 'visible #t)
  102. (slot-set! x 'click-enabled #t))
  103. (slot-ref lw 'children)))
  104. (define-method (inactivate (lw <list_widget>))
  105. (for-each (lambda (x)
  106. (slot-set! x 'visible #f)
  107. (slot-set! x 'click-enabled #f))
  108. (slot-ref lw 'children)))
  109. (define-method (toggle_active (lw <list_widget>))
  110. (for-each (lambda (x)
  111. (slot-set! x 'visible (not (slot-ref x 'visible)))
  112. (slot-set! x 'click-enabled (not (slot-ref x 'click-enabled))))
  113. (slot-ref lw 'children)))
  114. (define-class <folding_list> (<button>)
  115. lw
  116. (on_click #:init-keyword #:on_click
  117. #:init-value (lambda (self)
  118. (for-each (lambda (x) (toggle_active x))
  119. (slot-ref self 'children) ))))
  120. (define-method (initialize (instance <folding_list>) . initargs)
  121. (next-method)
  122. (let ((lw (make <list_widget> #:position #v(0 15))))
  123. (slot-set! instance 'lw lw)
  124. (add-child instance lw))
  125. (display "initializing a folding list mutafuka\n")
  126. )
  127. (define-method (tree-node-self-draw (button <button>))
  128. (let ((pos (get_global_position button)))
  129. (draw-nine-patch list_background_patch (rect-move-vec2
  130. (make-rect 0 0 100 list_interrow_dist)
  131. pos)
  132. #:margin 6)
  133. (draw-text (slot-ref button 'str) pos)))
  134. (define-method (tree-node-self-draw (label <label>))
  135. (let ((pos (get_global_position label)))
  136. (draw-text (slot-ref label 'str) pos)))
  137. (define-method (draw-tree (node <tree_node>))
  138. (if (slot-ref node 'visible)
  139. (begin
  140. (tree-node-self-draw node)
  141. (for-each draw-tree (slot-ref node 'children))
  142. )))
  143. (define-method (add-child (node <tree_node>) (child <tree_node>))
  144. ;(describe child)
  145. (slot-set! node 'children (append (slot-ref node 'children) (list child)))
  146. ;(display (slot-ref node 'children))
  147. (slot-set! child 'parent node))
  148. (define-method (unparent (child <tree_node>))
  149. (let ((parent (slot-ref child 'parent)))
  150. (slot-set! parent 'children (delq child (slot-ref parent 'children))))
  151. (slot-set! child 'parent #f))
  152. (define-method (tree-node-self-draw (node <tree_node>)))
  153. (define scene (make <tree_node>)); the scene root
  154. (define list_background_patch #f)
  155. (define-method (tree-node-self-draw (lst <list_widget>))
  156. ;(display "drawing list\n")
  157. (let ((offset 0))
  158. (for-each (lambda (child)
  159. (slot-set! child 'position
  160. #v(0 offset))
  161. (set! offset (+ offset list_interrow_dist)))
  162. (slot-ref lst 'children))))
  163. (define-method (tree-node-self-draw (term <terminal_widget>))
  164. (let* ((offset 0)
  165. (pos (get_global_position term))
  166. (overall_height (* list_interrow_dist (slot-ref term 'max_lines)))
  167. (term_bg_rect (rect-move-vec2
  168. (make-rect 0 0 (slot-ref term 'width) overall_height)
  169. (vec2+ pos
  170. #v(0 (- (- overall_height list_interrow_dist))))))
  171. )
  172. (draw-nine-patch list_background_patch term_bg_rect #:margin 6)
  173. (for-each (lambda (child)
  174. (slot-set! child 'position
  175. #v(0 offset))
  176. (set! offset (- offset list_interrow_dist)))
  177. (slot-ref term 'children))
  178. ))
  179. (define-method (clickable-click (clickable <clickable>) x y)
  180. ;(display (in_bound? clickable x y))
  181. ;(newline)
  182. (if (and (in_bound? clickable x y) (slot-ref clickable 'click-enabled))
  183. ((slot-ref clickable 'on_click) clickable)))
  184. (define-method (clickable-click clickable x y))
  185. (define-method (in_bound? (clickable <clickable>) x y)
  186. ;(display (list "clickable" clickable x y))
  187. ;(newline)
  188. (let ((global_rect (rect-move-vec2 (slot-ref clickable 'rect)
  189. (get_global_position clickable))))
  190. ;(display global_rect)
  191. ;(newline)
  192. (rect-contains? global_rect x y)))
  193. (define-method (get_global_position (node <tree_node>))
  194. (if (slot-ref node 'parent)
  195. (vec2+ (slot-ref node 'position) (get_global_position
  196. (slot-ref node 'parent)))
  197. (slot-ref node 'position)))
  198. (define-method (add-entry (lst <folding_list>) str key)
  199. (add-child (slot-ref lst 'lw) (make <list_entry> #:str str #:key key
  200. #:visible #f #:click-enabled #f)))
  201. (define-method (clear-entries (lst <folding_list>))
  202. (for-each unparent (slot-ref (slot-ref lst 'lw) 'children)))
  203. #!
  204. (define lattice
  205. (list
  206. (make <node> #:name "Raven" #:init_type "divine")
  207. (make <node> #:name "Coyote" #:init_type "divine" #:more '("Falcon" "Jay" "Gnu"))
  208. (make <node> #:name "Bear" #:init_type "mammalian" #:more '("Raven"))
  209. (make <node> #:name "Eagle" #:init_type "bird" #:more '("Bear"))
  210. (make <node> #:name "Gnu" #:init_type "mammalian" #:more '("Eagle"))
  211. (make <node> #:name "Jay" #:init_type "bird" #:more '("Raven"))
  212. (make <node> #:name "Tit" #:init_type "bird" #:more '("Bear"))
  213. (make <node> #:name "Falcon" #:init_type "bird" #:more '("Tit"))
  214. ))
  215. !#
  216. (define lattice
  217. (list
  218. (make <node> #:name "Raven" #:init_type "divine")
  219. (make <node> #:name "Coyote" #:init_type "divine" #:more '("Tit" "Gnu"))
  220. (make <node> #:name "Gnu" #:init_type "mammalian" #:more '("Dodo" "Jay"))
  221. (make <node> #:name "Jay" #:init_type "bird" #:more '("Tit"))
  222. (make <node> #:name "Dodo" #:init_type "bird" #:more '("Cuckoo" "Falcon" "Owl"))
  223. (make <node> #:name "Falcon" #:init_type "bird" #:more '("Beaver"))
  224. (make <node> #:name "Cuckoo" #:init_type "bird" #:more '("Bear"))
  225. (make <node> #:name "Beaver" #:init_type "mammalian" #:more '("Raven"))
  226. (make <node> #:name "Bear" #:init_type "mammalian" #:more '("Eagle"))
  227. (make <node> #:name "Owl" #:init_type "bird" #:more '("Eagle"))
  228. (make <node> #:name "Tit" #:init_type "bird" #:more '("Plover" "Heron"))
  229. (make <node> #:name "Plover" #:init_type "bird" #:more '("Eagle"))
  230. (make <node> #:name "Eagle" #:init_type "bird" #:more '("Raven"))
  231. (make <node> #:name "Heron" #:init_type "bird" #:more '("Raven"))
  232. ))
  233. (define (add-less lat)
  234. (for-each (lambda (node)
  235. (for-each (lambda (more-node-name)
  236. (let ((target-node (get-node more-node-name)))
  237. (slot-set! target-node 'less (append
  238. (list (slot-ref node 'name))
  239. (slot-ref target-node 'less)))))
  240. (slot-ref node 'more)))
  241. lat))
  242. (define (get-node name)
  243. (let ((lst (filter (lambda (node) (eqv? (slot-ref node 'name) name)) lattice)))
  244. (list-ref lst 0)))
  245. (define (get-rel-tree node symbol)
  246. (append (list node)
  247. (delete-duplicates
  248. (concatenate (map (lambda (n)
  249. (get-rel-tree n symbol))
  250. (map get-node (slot-ref node symbol)))))))
  251. (define-method (get-name (node <node>))
  252. (slot-ref node 'name))
  253. (define (find-join lst)
  254. (find-rel lst 'more #f))
  255. (define (find-meet lst)
  256. (find-rel lst 'less #f))
  257. (define (anti-rel symbol)
  258. (if (eq? 'more symbol) 'less 'more))
  259. (define (find-rel lst symbol restricted)
  260. (display (list "trying to rel with symbol" symbol))
  261. (newline)
  262. (display (map get-name lst))
  263. (newline)
  264. (let ((intersec (apply lset-intersection
  265. (append (list eqv?)
  266. (map (lambda (n) (get-rel-tree n symbol))
  267. lst)))))
  268. (display "intersection\n")
  269. (display (map get-name intersec))
  270. (if restricted
  271. (list-ref (lset-intersection eqv? intersec lst) 0)
  272. (find-rel intersec (anti-rel symbol) #t))
  273. )
  274. )
  275. (define-method (get-node-type (node <node>))
  276. (if (not (slot-ref node 'type_changed)); "divine" never changes type
  277. (slot-ref node 'init_type)
  278. (if (eqv? (slot-ref node 'init_type) "mammalian") "bird" "mammalian")))
  279. (define (list-valid-nodes current)
  280. (let* ((current (get-node current))
  281. (faction (get-node-type current)))
  282. (if (not (string=? (get-node-type current) "divine"))
  283. (if (eqv? action "join")
  284. (filter (lambda (node)
  285. (and
  286. (not (eqv? (get-node-type node) faction))
  287. (not (eqv? (get-node-type node) "divine"))))
  288. lattice)
  289. (filter (lambda (node)
  290. (and
  291. (eqv? (get-node-type node) faction)
  292. (not (eqv? (get-node-type node) "divine"))
  293. (not (eqv? node current))))
  294. lattice))
  295. (filter (lambda (node) (not (eqv? (get-node-type node) "divine"))) lattice)
  296. )))
  297. (define action_list
  298. (begin
  299. (let ((lst (make <folding_list> #:str "action_list" #:position #v(0 0))))
  300. (add-entry lst "join" "join")
  301. (add-entry lst "meet" "meet")
  302. (slot-set! (slot-ref lst 'lw)
  303. 'on_selected
  304. (lambda (self key)
  305. (display (list "selected" key))
  306. (set! action key)
  307. (slot-set! (slot-ref self 'parent) 'str key)
  308. (inactivate self)
  309. (fill_with_choices node_list)
  310. ))
  311. (slot-set! lst 'str action)
  312. lst
  313. )))
  314. (define node_list
  315. (make <folding_list> #:str "node_list" #:position #v(100 0)))
  316. (define (fill_with_choices node_list)
  317. (clear-entries node_list)
  318. (let ((nodes (list-valid-nodes current)))
  319. (for-each (lambda (node)
  320. (add-entry node_list
  321. (get-full-name (slot-ref node 'name))
  322. (slot-ref node 'name)))
  323. nodes)
  324. (set! target (slot-ref (list-ref nodes 0) 'name))
  325. (slot-set! node_list 'str (get-full-name target))))
  326. (define (get-full-name node-name)
  327. (let ((node (get-node node-name)))
  328. (if (slot-ref node 'type_changed); divine never changes type
  329. (if (eqv? (get-node-type node) "mammalian"); new type, not old
  330. (string-append node-name "-With-Tits")
  331. (string-append "Feathered " node-name))
  332. node-name)))
  333. (define (take_action self)
  334. (display "taking a decisive action\n")
  335. (let ((target-node (get-node target))
  336. (current-node (get-node current)))
  337. (if (eqv? action "join")
  338. (begin
  339. (if (not (eqv? (get-node-type current-node) "divine"))
  340. (begin
  341. (slot-set! current-node 'type_changed
  342. (not (slot-ref current-node 'type_changed)))
  343. (display-term (simple-format #f "~A helps you overcome your past" (get-full-name target)))
  344. (display-term "You transform.")
  345. (display-term (simple-format #f "you are now known as ~A" (get-full-name current))))
  346. (begin
  347. (display-term (simple-format #f "You come to ~A in his dreams" (get-full-name target)))))
  348. (calculate-imbalance)
  349. (set! current (slot-ref (find-join (map get-node (list current target))) 'name))
  350. )
  351. (begin
  352. (if (not (eqv? (get-node-type current-node) "divine"))
  353. (begin
  354. (display-term (simple-format #f "Meeting with The ~A" (get-full-name target)))
  355. (display-term "You eat pretzels and discuss clanly matters"))
  356. (begin
  357. (display-term (simple-format #f "You come to ~A in his dreams" (get-full-name target)))))
  358. (set! current (slot-ref (find-meet (map get-node (list current target))) 'name))
  359. )))
  360. (bump_turns)
  361. (fill_with_choices node_list)
  362. (morning-message)
  363. )
  364. (define (morning-message)
  365. (display-term "* * *")
  366. (display-term "Sun rises and you wake up.")
  367. (display-term (simple-format #f "You are The ~A." (get-full-name current)))
  368. (if (eqv? (get-node-type (get-node current)) "divine")
  369. (display-term "... a supposedly divine being."))
  370. )
  371. (define terminal
  372. (make <terminal_widget> #:position #v(0 400)))
  373. (define imbalance-label
  374. (make <label> #:position #v(0 450)))
  375. (define turns-taken-label
  376. (make <label> #:position #v(0 435)))
  377. (define (reset-lattice)
  378. (for-each (lambda (n)
  379. (slot-set! n 'type_changed #f))
  380. lattice))
  381. (define (reset-scene)
  382. (set! scene (make <tree_node>)))
  383. (define (load)
  384. (set! current "Bear")
  385. (add-less lattice)
  386. (add-child scene imbalance-label)
  387. (add-child scene turns-taken-label)
  388. (calculate-imbalance)
  389. (update-turns-label)
  390. (display (list "imbalance is " imbalance))
  391. ;(for-each describe lattice)
  392. ;(display (map (lambda (node) (list (slot-ref node 'name) (get-node-type node))) lattice))
  393. (set! list_background_patch (load-image "images/dialog-box.png"))
  394. (add-child scene terminal)
  395. (morning-message)
  396. (display-term "You brush your beary teeth.")
  397. (display-term "Annoyingly, you feel like cosmic balance is off")
  398. (display-term "However that might be just your stomache.")
  399. (add-child scene action_list)
  400. (fill_with_choices node_list)
  401. (add-child scene node_list)
  402. (slot-set! (slot-ref node_list 'lw)
  403. 'on_selected
  404. (lambda (self key)
  405. (display (list "selected" key))
  406. (set! target key)
  407. (slot-set! (slot-ref self 'parent) 'str (get-full-name key))
  408. (inactivate self)))
  409. (add-child scene (make <button>
  410. #:str "make turn"
  411. #:position #v(200 0)
  412. #:on_click take_action))
  413. (add-child scene (make <button>
  414. #:str "reset"
  415. #:position #v(200 465)
  416. #:on_click reset))
  417. (describe scene))
  418. (define (reset self)
  419. (display "reset called\n")
  420. (reset-lattice)
  421. (display "lattice cleared\n")
  422. (reset-scene)
  423. (clear-children terminal)
  424. (display "scene cleared\n")
  425. (load)
  426. (display "scene reloaded\n")
  427. (set! turns-taken 0)
  428. (update-turns-label)
  429. )
  430. (define (draw alpha)
  431. (draw-tree scene))
  432. (define-method (click-rec (node <tree_node>) x y)
  433. ;(display (list node x y))
  434. ;(newline)
  435. (clickable-click node x y)
  436. (for-each (lambda (child) (click-rec child x y)) (slot-ref node 'children)))
  437. (define (mouse-release button x y)
  438. (click-rec scene x y)
  439. ;(newline)
  440. )
  441. (run-game #:draw draw #:load load #:mouse-release mouse-release
  442. #:window-width 300 #:window-title "A Lattice Game of Cosmic Insignificance")