Starter code for Sharks
Fall 2010, David Matuszek
The Clojure Shark assignment is not intended to be terribly difficult, and I don't think it is. However, there are a lot of pieces to put together, and I had to constantly refer back to my slides while I was doing even this much. Since I just wrote those slides, it's probably even harder for other people. I therefore thought it might be helpful to supply some "starter" code for you to build on.
Use of this code is totally optional. If it helps you get started, use it. If it gets in your way, ignore it. I am reasonably confident that the code I'm supplying is correct, as far as it goes--I do not know how much it will need to be modified in order to complete the assignment.
(x... occurs, you are calling function x. ((x y z) u v... occurs, you are calling function x with parameters y and z, and getting back a function X which you are then calling with parameters u and v.| Returning a single value |
|---|
(defn my-function [lst]
(cond
(empty? lst) ()
:else (some-op (first lst) (my-function (rest lst))) ) ) |
| Returning a list of values |
(defn my-function [lst]
(cond
(empty? lst) ()
:else (cons (some-op (first lst)) (my-function (rest lst))) ) ) |
map, filter, etc.) can often be used in place of recursion.A defstruct is something like a class definition, something like a map.
(defstruct shark :id :direction :weight :hunger :status)You can create a struct with the struct-map function.
(def my-shark (struct-map shark
:id 3
:direction
:left ... ))You can use (assoc struct key value ... key value) to get a new struct based on the given struct, but with different values for the keys.
You can make a reference to a struct (or anything else); this lets you replace the value of the reference with a different value.
(def my-ref (ref my-shark))
(ref-set my-ref
(assoc my-ref :id 4)) ; not yet legalYou can only change a reference within a dosync.
(dosync (ref-set my-ref
(assoc @my-ref :id 4)) ; here it's legaldosync takes any number of expressions as arguments, so you can make multiple changes at once.
I said "Use an agent, whose value is a struct, to represent a shark." That seems to make sense--an agent, like an actor in Erlang, is a concurrent process, and each shark should be able to move concurrently with other sharks. I do want concurrency in this program, so that STM actually has some meaning, but this may not be the best way to introduce the concurrency. If you find some way to introduce concurrency that seems to work better, feel free to use it.
(defstruct shark :id :direction :weight :hunger :status)
(defn make-shark
"Defines a shark with :id = n and various attributes."
[n]
(struct-map shark
:id n
:direction (if (< (rand) 0.5)
:left
:right )
:weight (+ 90 (* 20 (rand)))
:hunger 0
:status :alive) )
(defn str-shark
"Returns a string representation of a shark (or () for an empty list)."
[shark]
(cond
(= shark ()) "()"
(= (shark :direction) :left) (concat "<" (str (shark :id)))
:else (concat (str (shark :id)) ">") ) )
(defn print-sharks
"Prints out a list containing sharks and empty locations."
[lst]
(println (map str-shark lst)) )
(defn make-shark-list
"Makes a list of how-many actual sharks, and some number of empty locations."
([how-many] (make-shark-list [] 1 how-many))
([lst n how-many]
(cond
(> n how-many) lst
(> (rand) 0.75) (cons '() (make-shark-list lst n how-many))
:else (cons (make-shark n) (make-shark-list lst (inc n) how-many)) ) ) )
(defn run-me []
(do
(print-sharks (make-shark-list 3))
(print-sharks (make-shark-list 3))
(print-sharks (make-shark-list 3))
(print-sharks (make-shark-list 3)) ) )
(defn run-me-too []
(do
(let [
; create a shark called Sherman
sherman (make-shark 1)
; create a reference to Sherman, giving it a silly
; name to emphasize it's a ref, not the "real thing"
look!-a-shark! (ref sherman)]
; print Sherman in two different ways
(println sherman)
(println (str-shark sherman))
; put Sherman on a diet
(dosync
(ref-set look!-a-shark! (assoc @look!-a-shark! :hunger 4))
(ref-set look!-a-shark!
(assoc @look!-a-shark! :weight (* 0.75 (@look!-a-shark! :weight))) )
(ref-set look!-a-shark! (assoc @look!-a-shark! :status :ill-tempered))
; show off Sherman's new look
(println @look!-a-shark!)
(println (str-shark @look!-a-shark!))
; sorry, Sherman, it didn't take--you're immutable
(println sherman)
(println (str-shark sherman)) ) ) ) )