(setenv "CATBIRD_DEV_MODE" "1") (use-modules (catbird) (catbird asset) (catbird camera) (catbird kernel) (catbird node) (catbird node-2d) (catbird region) ((catbird scene) #:select ()) (chickadee config) (chickadee graphics color) (chickadee graphics path) (chickadee graphics text) (chickadee graphics texture) (chickadee math vector) (chickadee scripting) (goblins) (goblins actor-lib cell) (goblins actor-lib methods) (goblins utils simple-sealers) (goblins vrun) (ice-9 atomic) (ice-9 match) (oop goops) (srfi srfi-1) (srfi srfi-9) (srfi srfi-43)) (define garden-vat (spawn-vat)) (define catbird-vat (spawn-vat)) (define alice-vat (spawn-vat)) (define-vat-run garden-run garden-vat) (define-vat-run catbird-run catbird-vat) (define-vat-run alice-run alice-vat) (define-record-type (make-plant name char) plant? (name plant-name) (char plant-char)) (define sunflower (make-plant "Sunflower" #\S)) (define cabbage (make-plant "Cabbage" #\C)) (define winter-squash (make-plant "Winter Squash" #\W)) (define (list-replace lst i o) (let loop ((j 0) (lst lst)) (match lst ((head . rest) (if (= i j) (cons o rest) (cons head (loop (+ j 1) rest))))))) (define (make-empty-row width) (make-list width #f)) (define (make-empty-bed width height) (list-tabulate height (lambda (_i) (make-empty-row width)))) (define (bed-ref bed x y) (list-ref (list-ref bed y) x)) (define (bed-set bed x y o) (list-replace bed y (list-replace (list-ref bed y) x o))) (define-record-type (%make-garden-bed width height tiles) garden-bed? (width garden-bed-width) (height garden-bed-height) (tiles garden-bed-tiles)) (define (make-garden-bed width height) (%make-garden-bed width height (make-empty-bed width height))) (define (bounds-check garden x y) (unless (and (>= x 0) (>= y 0) (< x (garden-bed-width garden)) (< y (garden-bed-height garden))) (error "garden tile out of bounds" x y))) (define (garden-bed-ref garden x y) (bounds-check garden x y) (bed-ref (garden-bed-tiles garden) x y)) (define (garden-bed-set garden x y o) (bounds-check garden x y) (%make-garden-bed (garden-bed-width garden) (garden-bed-height garden) (bed-set (garden-bed-tiles garden) x y o))) (define (display-garden-bed garden) (for-each (lambda (row) (for-each (lambda (tile) (display (if (plant? tile) (plant-char tile) ".")) (display " ")) row) (newline)) (garden-bed-tiles garden))) (define (^botanist bcom) (define-values (seal-plant unseal-plant approved-plant?) (make-sealer-triplet)) (methods ((approve-plant plant) (seal-plant plant)) ((check-plant plant) (if (approved-plant? plant) (unseal-plant plant) (error "plant is not allowed" plant))))) (define (^garden-guard bcom botanist) (methods ((check-plant plant) ($ botanist 'check-plant plant)))) (define (^garden bcom name garden-bed garden-guard) (define (ensure-empty x y) (when (garden-bed-ref garden-bed x y) (error "tile already has something planted in it" x y))) (methods ((get-name) name) ((get-bed) garden-bed) ((plant x y sealed-plant) (ensure-empty x y) (let* ((plant ($ garden-guard 'check-plant sealed-plant)) (new-bed (garden-bed-set garden-bed x y plant))) (bcom (^garden bcom name new-bed garden-guard)))) ((dig-up x y) (let ((new-bed (garden-bed-set garden-bed x y #f))) (bcom (^garden bcom name new-bed garden-guard)))))) (define (^visitor bcom name garden) (methods ((get-name) name) ((get-garden-name) (<- garden 'get-name)) ((inspect-garden) (<- garden 'get-bed)))) (define (^gardener bcom name garden) (methods ((get-name) name) ((get-garden-name) (<- garden 'get-name)) ((inspect-garden) (<- garden 'get-bed)) ((plant x y plant) (<- garden 'plant x y plant)) ((dig-up x y) (<- garden 'dig-up x y)))) (define the-botanist (garden-run (spawn ^botanist))) (define the-garden-guard (garden-run (spawn ^garden-guard the-botanist))) (define sunflower/approved (garden-run ($ the-botanist 'approve-plant sunflower))) (define cabbage/approved (garden-run ($ the-botanist 'approve-plant cabbage))) (define our-garden (garden-run (spawn ^garden "Spritely Institute Community Garden" (make-garden-bed 8 8) the-garden-guard))) (define alice (alice-run (spawn ^gardener "Alice" our-garden))) (alice-run ($ alice 'plant 1 1 sunflower/approved)) (alice-run ($ alice 'plant 2 1 sunflower/approved)) (alice-run ($ alice 'plant 1 2 sunflower/approved)) (alice-run ($ alice 'plant 2 2 sunflower/approved)) (alice-run ($ alice 'plant 5 1 cabbage/approved)) (alice-run ($ alice 'plant 6 1 cabbage/approved)) (alice-run ($ alice 'plant 5 2 cabbage/approved)) (alice-run ($ alice 'plant 6 2 cabbage/approved)) (define catbird-visitor (catbird-run (spawn ^visitor "Catbird UI" our-garden))) (define catbird-garden-bed (make-atomic-box #f)) (define catbird-garden-name (make-atomic-box #f)) (catbird-run (on ($ catbird-visitor 'get-garden-name) (lambda (name) (atomic-box-set! catbird-garden-name name)))) (catbird-run (on ($ catbird-visitor 'inspect-garden) (lambda (garden-bed) (atomic-box-set! catbird-garden-bed garden-bed)))) (define %window-width 1024) (define %window-height 768) (define %tile-width 64.0) (define %tile-height 64.0) (define font-file (scope-datadir "fonts/Inconsolata-Regular.otf")) (define-asset (title-font (f font-file)) (load-font f 24)) (define-asset (plant-tile-font (f font-file)) (load-font f 32)) (define-asset (sunflower-texture (f "assets/images/sunflower.png")) (load-image f)) (define-asset (cabbage-texture (f "assets/images/cabbage.png")) (load-image f)) (define-class () (vat #:getter vat #:init-keyword #:vat) (visitor #:getter visitor #:init-keyword #:visitor) (name-box #:getter name-box #:init-keyword #:name-box) (garden-bed-box #:getter garden-bed-box #:init-keyword #:garden-bed-box) (prev-garden #:accessor prev-garden #:init-value #f) (tiles #:accessor tiles #:init-value #())) (define (make-garden-view) (make #:rank 1 #:vat catbird-vat #:visitor catbird-visitor #:name-box catbird-garden-name #:garden-bed-box catbird-garden-bed)) (define-method (garden-bed (garden )) (atomic-box-ref (garden-bed-box garden))) (define-method (garden-name (garden )) (atomic-box-ref (name-box garden))) (define-method (on-boot (garden )) (define title (make