CSC 533: Organization of Programming Languages
Spring 2025

HW5: Clojure Functions


For this assignment, you are to define a collection of Clojure functions. For simplicity, place all your function definitions in a single file named LASTNAME-hw5.clj, where LASTNAME is your last name. Be careful to name your functions exactly as defined in the exercises. Wherever possible, functions should take advantage of previously written functions if they make their task simpler.

LIGHT SPEED: As you may recall from high school physics, the speed of light is approximately 186,262 miles per second. For large distances, the time it takes for light to travel from its source to an observer can be significant. For example, light leaving the sun (93 million miles) takes more than 8 minutes to reach the earth.

  1. Define a function named delay-in-sec that takes one input, a distance in miles, and returns the number of seconds it takes for light to travel that distance. The return value should be rounded to the nearest integer. For example, (delay-in-sec 93000000) should evaluate to 499.
  2. Define a function named sec->min that takes one input, a number of seconds, and returns the corresponding number of minutes. Note that this function should always return a decimal value (not a rational). For example, (sec->min 150) should evaluate to 2.5.
  3. Define a function named delay-in-min that takes one input, a distance in miles, and returns the number of minutes it takes for light to travel that distance. For example, (delay-in-min 93000000) should evaluate to approximately 8.3.

RELATIVELY SPEAKING: One of the consequences of Einstein's Theory of Relativity is the phenomenon of time dilation. As a traveler's velocity increases, perceived time actually slows for that traveler (relative to an outside observer). For everyday velocities, e.g., riding in a car or airplane, the effect is negligible. However, if spacecraft are eventually invented whose velocities approach the speed of light, the difference in relative time would be dramatic. For example, at 0.5 of light speed, it would take 8.4 years for a ship to reach Proxima Centauri (as observed from earth), but it would only seem like 7.3 years on board the ship. The dilation factor by which relative time is determined is the square root of (1 - V2), where V is the fraction of light speed.

  1. Define a function named observer-time that takes two inputs, a distance in light years and a fraction of light speed, and returns the number of years it would take to travel that distance to an outside observer. For example, (observer-time 4.2 0.5) should evaluate to 8.4.
  2. Define a function named dilation-factor that takes one input, a fraction of light speed, and returns the corresponding dilation factor. For example, (dilation-factor 0.5) should evaluate to approximately 0.866.
  3. Define a function named traveler-time that takes two inputs, a distance in light years and a fraction of light speed, and returns the number of years it would take to travel that distance to a traveler. For example, (traveler-time 4.2 0.5) should evaluate to approximately 7.27.

FUN WITH LISTS: Consider the following functions, both of which remove the item from a list at a specified index. The first function utilizes recursion, while the second utilizes built-in list functions. Copy-and-paste these functions into your file.

    (defn remove-nth-A [arblist n]
      (if (zero? n)
        (rest arblist)
        (cons (first arblist) (remove-nth-A (rest arblist) (dec n)))))

    (defn remove-nth-B  [arblist n]
      (concat (take n arblist) (nthrest arblist (inc n))))     
  1. While both functions behave correctly if the specified index is in bounds (0 ≤ index < list size), they return different values if the index is out of bounds. The latter simply returns an unchanged copy of the list. The former returns a bizarre list, with nils added at the end. Modify remove-nth-A so that it behaves the same as remove-nth-B (i.e., returns the unchanged list) when the index is out of bounds.
  2. Define similar functions insert-nth-A and insert-nth-B, which return a copy of the list with a new value inserted into the specified index. For example, (insert-nth-A '(:a :b :c :d) 2 :x) and (insert-nth-B '(:a :b :c :d) 2 :x) should both return (:a :b :x :c :d). As before, these functions should return an unchanged copy of the list if the index is out of bounds.
  3. Define a function named replace-nth that takes three inputs, a list, an index and a value, and returns a copy of the list but with the new value replacing the value at the specified index. For example, (replace-nth '(:a :b :c :d) 2 :x) should return (:a :b :x :d). As before, it should return an unchanged copy of the list if the index is out of bounds.
  4. Define a function named inc-nth that takes two inputs, a list of numbers and an index, and returns a copy of the list with the number at the specified index incremented. For example, (inc-nth '(10 20 30) 0) should return (11 20 30). As before, it should return an unchanged copy of the list if the index is out of bounds.

FUN WITH DICE: The following function simulates the roll of a die with a specified number of sides. Copy-and-paste this function into your file.

    (defn die-roll [num-sides]
      (inc (rand-int num-sides)))      
  1. Define a function named dice-roll that has one input, the number of sides, and returns the sum of two die rolls with that number of sides each. For example, (dice-roll 8) would return the sum of two 8-sided dice.
  2. Define a function named count-rolls that takes three inputs, all positive integers, representing a number of rolls, the number of die sides and a desired dice total. The function should repeatedly call the dice-roll function to simulate the specified number of rolls and return the number of times the desired total was obtained. For example, the call (count-rolls 1000 6 7) should simulate 1000 6-sided dice rolls and return the number of times 7 was rolled. Since the number of rolls could be large, your function should utilize tail-recursion.
  3. Define a function named count-all that takes two inputs, both positive integers, representing a number of rolls and the number of die sides. The function should repeatedly call the dice-roll function to simulate that many rolls and return a list with the counts for all dice totals. For example, the call (count-all 10000 6) might return (288 526 824 1093 1388 1708 1413 1115 811 563 271), signifying that 288 rolls totaled 2, 526 rolls totaled 3, 824 rolls totaled 4, etc. Since the number of rolls could be large, your function should utilize tail-recursion. Note: you should be able to make use of your inc-nth function here.

FUN FOR THE CASINO: The following function simulates, which will be discussed in class next week, simulates a game of craps and returns either :WINNER or :LOSER to identify the result. Copy-and-paste this function into your file.

    (defn craps []
      (defn roll-until [point]
        (let [next-roll (dice-roll 6)]
          (cond (== next-roll 7) :LOSER
                (== next-roll point) :WINNER
                :else (recur point))))
      (let [roll (dice-roll 6)]
        (cond (or (== roll 2) (== roll 12)) :LOSER
              (== roll 7) :WINNER
              :else (roll-until roll))))
  1. Define a function named craps-percent that has one input, a number of games to simulate, and which returns the percentage of those simulated games that resulted in wins (as a decimal). For example, the call (craps-percent 20) might return 0.4, singifying that 8 out of the 20 games (or 40%) were wins. Since the number of games could be large, your function should utilize tail-recursion.