CSC 533: Organization of Programming Languages
Spring 2026

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.

UTILITIES: In completing the functions below, two utility functions will prove useful:

  1. Define a function named round-to that takes two number inputs, the first being an integer and the second a real number. The function should return the real number rounded to the specified number of digits. For example, (round-to 1 2.437) should evaluate to 2.4, while (round-to 2 3.989) should evaluate to 3.99.
  2. Define a function named adjust that takes three real numbers. The first is an arbitrary number, and the second and third are the low and high limits of a range. The function returns the first number adjusted to fit within that range. For example, (adjust 2.7 3.0 5.0) should evaluate to 3.0, (adjust 5.7 3.0 5.0) should evaluate to 5.0, and (adjust 3.7 3.0 5.0) should evaluate to 3.7.

SPORTS BALL: Modern sports are driven by analytics. For this part of the assignment, you will define several functions that generate widely-used sports stats.

  1. In soccer, a game can end in a draw (i.e., a tie). A team earns three points for every win, no points for a loss, and one point for a draw. Define a function named points that takes three inputs, the number of wins, losses and ties for a team (in that order), and returns the points earned by that team. For example, (points 10 8 2) should evaluate to 32.
  2. In baseball, the (Modified) Pythagorean Estimate is a tool for predicting the win ratio (i.e., wins/games) for a team. The win ratio is predicted to be:
        runs-scored1.83 / (runs-scored1.83 + runs-allowed1.83)
    Define a function named pythagorean that takes two inputs, the number of runs scored and runs allowed by a team (in that order), and returns the win ratio predicted by the above formula. The percentage should be returned as a decimal number rounded to three decimal places. For example, (pythagorean 897 697) should evaluate to 0.613.
  3. Define a related function named predicted that also takes a team's runs scored and runs allowed, but returns a list containing the predicted number of wins and losses for that team over a 162-game season, using the (Modified) Pythagorean Estimate. The wins and losses should be rounded to the nearest integer. For example, (predicted 897 697) should evaluate to (99 63).
  4. The National Football League utilizes a complex formula to assign a passer rating to a quarterback. The formula utilizes four components:
  5.     CMPS = (completions/attempts - 0.3) * 5
      
        YRDS = (yards/attempts - 3) * 0.25
               
        TDS = (touchdowns/attempts) * 20
               
        INTS = 2.375 - (interceptions/attempts * 25)
    Each of these component numbers is limited to the range 0 to 2.375. If the calculated value is outside this range, it should be adjusted (i.e., less than 0 becomes 0; greater than 2.375 becomes 2.375). Finally, the passer rating is defined by the following formula:
        100 * (CMPS + YRDS + TDS + INTS)/6    
    Define a function named rating that takes 5 inputs: attempts, completions, touchdowns, interceptions, and yards (in that order), and returns the passer rating calculated using the above formula. That number should be rounded to one decimal place. For example, (rating 568 330 27 7 3942) should evaluate to 90.1. Note: you will definitely want to define helper functions to manage the complexity of this calculation.

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. Note, however, that it should be possible to insert an item at the end of the list.
  3. Define a function named roman->num that takes one input, a list of symbols representing a roman numeral, and returns the number value represented by that roman numeral. For example, (roman->num '(X V I)) should evaluate to 16. The following is a list of the roman letters and numbers they represent (M = 1000, D = 500, C = 100, L = 50, X = 10, V = 5, I = 1). You may assume the ancient roman style of writing letters, where 4 is represented IIII and 90 is represented LXXXX. A harder problem, which you may attempt if you like, is to use the modern roman style where 4 is IV and 90 is XC.
  4. Define a function named num->roman that performs the reverse conversion, from a number to a list of symbols representing a roman numeral. For example, (roman->num 66) should evaluate to (L X V I). Again, you may assume the ancient roman style of writing letters.

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

    (defn dice-roll [num-sides]
      (+ 2 (rand-int num-sides) (rand-int num-sides)))
  1. Define a function named count-roll 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-roll 1000 6 7) should simulate 1000 six-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.
  2. Define a function named percent-roll that utilizes the count-roll function to determine the percentage of dice rolls that match a specific total. The percentage should be returned as a decimal, rounded to two decimal places. For example, the call (percent-roll 6 7 10000) should simulate 10,000 dice rolls of six-sided dice and return the percentage of times 7 was rolled (e.g., 16.66).