diamond.scm 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  1. ;;; This requires SRFI-23
  2. ;;; We create an amphibious vehicle which inherits from a car - which
  3. ;;; can only drive on ground - and from a ship - which can only drive
  4. ;;; on water. Roads have a type of terrain. The amphibious vehicle
  5. ;;; drives along the road, using either the drive method of the car or
  6. ;;; of the ship.
  7. ;;; First, let's build a road.
  8. (define-object road-segment (*the-root-object*)
  9. (next set-next! #f)
  10. (type set-type! 'ground)
  11. ((clone self resend next type)
  12. (let ((o (resend #f 'clone)))
  13. (o 'set-next! next)
  14. (o 'set-type! type)
  15. o)))
  16. ;;; Create a road with the environment types in the ENVIRONMENTS list.
  17. (define (make-road environments)
  18. (if (null? (cdr environments))
  19. (road-segment 'clone
  20. #f
  21. (car environments))
  22. (road-segment 'clone
  23. (make-road (cdr environments))
  24. (car environments))))
  25. ;;; Now, we need a vehicle - the base class.
  26. (define-object vehicle (*the-root-object*)
  27. (location set-location! #f)
  28. ((drive self resend)
  29. #f)
  30. ((clone self resend . location)
  31. (let ((o (resend #f 'clone)))
  32. (if (not (null? location))
  33. (o 'set-location! (car location)))
  34. o)))
  35. ;;; All vehicles have to drive quite similarily - no one stops us from
  36. ;;; using a normal helper procedure here.
  37. (define (handle-drive self handlers)
  38. (let ((next ((self 'location) 'next)))
  39. (cond
  40. ((not next)
  41. (display "Yay, we're at the goal!")
  42. (newline))
  43. ((assq (next 'type) handlers)
  44. => (lambda (handler)
  45. ((cdr handler) next)))
  46. (else
  47. (error "Your vehicle crashed on a road segment of type"
  48. (next 'type))))))
  49. ;;; And a car. Hm. Wait. A CAR is something pretty specific in Scheme,
  50. ;;; make an automobile instead.
  51. (define-object automobile (vehicle)
  52. ((drive self resend)
  53. (resend #f 'drive)
  54. (handle-drive self `((ground . ,(lambda (next)
  55. (display "*wrooom*")
  56. (newline)
  57. (self 'set-location! next)))))))
  58. ;;; And now a ship, for waterways.
  59. (define-object ship (vehicle)
  60. ((drive self resend)
  61. (resend #f 'drive)
  62. (handle-drive self `((water . ,(lambda (next)
  63. (display "*whoosh*")
  64. (newline)
  65. (self 'set-location! next)))))))
  66. ;;; And an amphibious vehicle for good measure!
  67. (define-object amphibious (ship (ground-parent automobile))
  68. ((drive self resend)
  69. (handle-drive self `((water . ,(lambda (next)
  70. (resend 'parent 'drive)))
  71. (ground . ,(lambda (next)
  72. (resend 'ground-parent 'drive)))))))
  73. ;;; The code above works already. We can clone ships, automobiles and
  74. ;;; amphibious vehicles as much as we want, and they drive happily on
  75. ;;; roads. But we could extend this, and add gas consumption. This
  76. ;;; will even modify already existing vehicles, because they inherit
  77. ;;; from the vehicle object we extend:
  78. (vehicle 'add-value-slot! 'gas 'set-gas! 0)
  79. (vehicle 'add-value-slot! 'needed-gas 'set-needed-gas! 0)
  80. (define-method (vehicle 'drive self resend)
  81. (let ((current-gas (self 'gas))
  82. (needed-gas (self 'needed-gas)))
  83. (if (>= current-gas needed-gas)
  84. (self 'set-gas! (- current-gas needed-gas))
  85. (error "Out of gas!"))))
  86. ;;; If you want to test the speed of the implementation:
  87. (define (make-infinite-road)
  88. (let* ((ground (road-segment 'clone #f 'ground))
  89. (water (road-segment 'clone ground 'water)))
  90. (ground 'set-next! water)
  91. ground))
  92. (define (test n)
  93. (let ((o (amphibious 'clone (make-infinite-road))))
  94. (do ((i 0 (+ i 1)))
  95. ((= i n) #t)
  96. (o 'drive))))