This assignment is due on Wednesday, 1/24 at 11:59 PM. Submit it using the handin server as assignment a3.
You should also be familiar with using the design recipe with two kinds of data definition, Enumerations and Intervals.
You will design functions that make use of dates as conventionally written in English. The following data definitions will be used throughout the assignment, and more will be introduced as they are needed.
; A Year is a non-negative integer ; A Month is one of: ; - "January" ; - "February" ; - "March" ; - "April" ; - "May" ; - "June" ; - "July" ; - "August" ; - "September" ; - "October" ; - "November" ; - "December" ; A Day is an integer in the range 1 to 31 inclusive
Note that in general, it will be your job to create the data definitions. However, for this assignment we will provide the data definitions so that you may focus on the subsequent steps in the design recipe.
The goal of this section is to design a program which allows a user armed with relevant information about a date to generate an image displaying that date.
Analyzing this goal, we realize that written dates have a format and a choice of format needs to be made along the way. This decision gave rise to two additional data definitions:
; A MonthFormat is one of: ; - "long" ; - "short" ; A DateOrder is one of: ; - "MDY" ; - "DMY"
We will provide additionally the next 1-2 steps of the design recipe. In this assignment, most of your work will be in carrying out steps 4 and 5. (And what are these?)
; calendar : Year Month Day -> Image ; returns an image of a date on a background
Now, notice that calendar would need carry out a number of operations to transform its input into an image. And more importantly, some of these operations have yet to be defined. Defining them all at once in the body of calendar would result at best in a complicated function definition; at worst, in a broken or buggy definition which is hard to improve.
So instead we design helper functions which will be called in the body of calendar.
; format-month : Month MonthFormat -> String ; abbreviates Month to three letters or not (define (format-month m f) ...) (check-expect (format-month "November" "long") "November") (check-expect (format-month "November" "short") "Nov")
You will find the substring function useful here. Look it up in the documentation.
Use format-month to design the following function:
; year-month-day->date : Year Month Day DateOrder MonthFormat -> String ; produces a date as a string ; given: 1936 "November" 12 "MDY" "long" expect: "November 12, 1936" ; given: 1936 "November" 12 "MDY" "short" expect: "Nov 12, 1936" ; given: 1936 "November" 12 "DMY" "long" expect: "12 November 1936" ; given: 1936 "November" 12 "DMY" "short" expect: "12 Nov 1936" (define (year-month-day->date y m d o f) ...)
For year-month-day->date and the function stubs below, be sure to write unit tests with check-expect using the examples given (as well as any other examples you see fit to devise).
You will find the string-append function useful here. Look it up in the documentation.
Once you have designed year-month-day->date, make a choice of date format and design calendar.
(If you are looking for some visual inspiration, do an image search online for the Modernist painter On Kawara.)
The goal of this section is to design a program which enables its user to calculate the number of days between two dates. As above, it would be prudent to decompose this task into subtasks to be carried out by helper functions.
To simplify, we assume that a year has 365 days.
; year-month-day->days : Year Month Day -> Number ; returns the number of days elapsed since January 1, 0 ; given: 0 "January" 1 expect: 0 ; given: 2017 "August" 28 expect: 736444
; month->days-in-year : Month -> Number ; returns the days elapsed in the year ; given: "January" expect: 0 ; given: "September" expect: 243
; days-between : Year Month Day Year Month Day -> Number
Be sure to complete the purpose statement and devise examples/tests for days-between.
In this section, the goal is to design a program which produces a simple animation of calendar. With each tick of animate, a day will pass. Lastly, the animation will be initialized to a date of your choosing.
Take a moment to reflect on this problem and where the difficulty lies. In a sense, we would like to feed calendar to animate, relax and watch the show. However, calendar takes three arguments and none of these is the number of days elapsed since 1 Jan, 0000.
So we cannot simply compose animate and calendar. But we can design functions which allow us to connect the two. To start with, we will design a function days->year:
; days->year : Number -> Year ; takes days since 1 Jan 0 and returns the year ; given: 364 expect: 0 ; given: 365 expect: 1 ; given: 736305 expect: 2017 ; given: (year-month-day->days 1999 "December" 31) expect: 1999
Notice that the last example is a witness to an important property of days->year: taken together with analogous functions into Month and into Day, we would have constructed a (left) inverse to year-month-day->days.
Also notice that days->year can be used to supply the Year argument to calendar.
; DaysInYear is an integer falling into one of 12 intervals: ; - [0,31) ; - [31,59) ; - [59,90) ; - [90,120) ; - [120,151) ; - [151,181) ; - [181,212) ; - [212,243) ; - [243,273) ; - [273,304) ; - [304,334) ; - [334,365) ; interpretation: the number of elapsed days ; since the first day of the year ; DaysInMonth is an integer in [0,31) ; interpretation: the number of elapsed days ; since the first of the month
Both days->month and days->day should be defined using helpers.
; days-in-year->month : DaysInYear -> Month ; takes days since the first of the year and returns the month ; given: 0 expect: "January" ; given: 31 expect: "February" ; given: 242 expect: "August" ; days->month : Number -> Month ; takes days since 1 Jan 0 and returns the month ; given: 59 expect: "March" ; given: 364 expect: "December" ; given: 736445 expect: "August" ; given: (year-month-day->days 1999 "December" 31) expect: "December"
; days-in-year->days-in-month : DaysInYear -> DaysInMonth ; takes days since the first of the year ; and returns days since the first of the month ; given: 0 expect: 0 ; given: 59 expect: 0 ; given: 364 expect: 30 ; days->day : Number -> Day ; takes days since 1 Jan 0 and returns the day of the month ; given: 0 expect: 1 ; given: 59 expect: 1 ; given: 736324 expect: 30 ; given: (year-month-day->days 1999 "December" 31) expect: 31
Hint: Although the input is an Enumeration, it is not necessary to use cond to write days-in-year->days-in-month. Instead, define a composite function with days-in-year->month and month->days-in-year.
Finally, we are ready to build our animation.
(define init-year ...) (define init-month ...) (define init-day ...) ; init-time : Number ; days since init-month init-day, init-year ; given: init-month := "December" ; init-year := "1999" ; init-day := 31 ; expect: 729999 (define init-time ...) ; time-passing : Number -> Image ; takes days t since 1 Jan 0, advances t by init-time ; and returns a calendar image of the corresponding date (define (time-passing t) ...)
Your final program should produce a running animation.