(require (file "../prometheus.ss"))
(define-object road-segment (*the-root-object*)
(next set-next! #f)
(type set-type! 'ground)
((clone self resend next type)
(let ((o (resend #f 'clone)))
(o 'set-next! next)
(o 'set-type! type)
o)))
(define (make-road environments)
(if (null? (cdr environments))
(road-segment 'clone
#f
(car environments))
(road-segment 'clone
(make-road (cdr environments))
(car environments))))
(define-object vehicle (*the-root-object*)
(location set-location! #f)
((drive self resend)
#f)
((clone self resend . location)
(let ((o (resend #f 'clone)))
(if (not (null? location))
(o 'set-location! (car location)))
o)))
(define (handle-drive self handlers)
(let ((next ((self 'location) 'next)))
(cond
((not next)
(display "Yay, we're at the goal!")
(newline))
((assq (next 'type) handlers)
=> (lambda (handler)
((cdr handler) next)))
(else
(error "Your vehicle crashed on a road segment of type"
(next 'type))))))
(define-object automobile (vehicle)
((drive self resend)
(resend #f 'drive)
(handle-drive self `((ground . ,(lambda (next)
(display "*wrooom*")
(newline)
(self 'set-location! next)))))))
(define-object ship (vehicle)
((drive self resend)
(resend #f 'drive)
(handle-drive self `((water . ,(lambda (next)
(display "*whoosh*")
(newline)
(self 'set-location! next)))))))
(define-object amphibious (ship (ground-parent automobile))
((drive self resend)
(handle-drive self `((water . ,(lambda (next)
(resend 'parent 'drive)))
(ground . ,(lambda (next)
(resend 'ground-parent 'drive)))))))
(vehicle 'add-value-slot! 'gas 'set-gas! 0)
(vehicle 'add-value-slot! 'needed-gas 'set-needed-gas! 0)
(define-method (vehicle 'drive self resend)
(let ((current-gas (self 'gas))
(needed-gas (self 'needed-gas)))
(if (>= current-gas needed-gas)
(self 'set-gas! (- current-gas needed-gas))
(error "Out of gas!"))))
(define (make-infinite-road)
(let* ((ground (road-segment 'clone #f 'ground))
(water (road-segment 'clone ground 'water)))
(ground 'set-next! water)
ground))
(define (test n)
(let ((o (amphibious 'clone (make-infinite-road))))
(do ((i 0 (+ i 1)))
((= i n) #t)
(o 'drive))))