solve 13 and 14

(* CSCE 314, Homework 1, Provided Code *)

(* You might choose to uncomment these, like the lecture code does *)
(* #utop_prompt_dummy
   let _ = UTop.set_show_box false *)

(* Use these functions to extract parts of a date *)
let fst3 (x,_,_) = x (* gets the first element of a triple *)
let snd3 (_,x,_) = x (* gets the second element of a triple *)
let thd3 (_,_,x) = x (* gets the third element of a triple *)

(**
 * TODO: Complete the 12 function bindings described in the assignment.  For the first (2), 
 * we have given you the correct first line and an incorrect function body.
 *)

(*You will write 12 OCaml functions (and tests for them) related to calendar dates.
In all problems, a “date” is an OCaml value of type int * int * int, where the first part is the day, the
second part is the month, and the third part is the year. For example, (15, 1, 2021) represents the 15th
day of the first month (January) in the year 2021.
A “reasonable” date has a positive year, a month between 1 and 12, and a day no greater than 31 (or less
depending on the month). Your solutions need to work correctly only for reasonable dates, but do not check
for reasonable dates (that is a challenge problem) and many of your functions will naturally work correctly
for some non-reasonable dates.
A “day of year” is a number from 1 to 365 where, for example, 33 represents February 2. (We ignore leap
years except in one challenge problem.)
To access elements of an date, use the provided functions fst3, snd3, and thd3 to access the first, second,
and third components accordingly.*)

(*Solutions should be:
Correct
In good style, including indentation and line breaks
Written using features discussed in class. In particular, you must not use OCaml’s mutable references
or arrays. (Why would you?) Also do not use pattern-matching; it is the focus of the next assignment.*)

(*Here is a “cheatsheet” of library functions and operations that you may find helpful when completing your
solution, in addtion to using the provided fst3, snd3, and thd3.
List.hd (* get the head of the list *)
List.tl (* get the tail of the list *)
@ (* infix operator to append two lists *)
^ (* infix operator to concatenate two strings *)
string_of_int (* convert an integer into a string *)
Option.get (* if the argument = Some value, return value, otherwise raise an exception *)
Option.is_some (* return true if the argument = Some value *)
Option.is_none (* return true if the argument = None *)
3*)

(* 1 *) (* DONE *)
(*Write a function is_older that takes two dates and evaluates to true or false. It evaluates to true if
the first argument is a date that comes before the second argument. (If the two dates are the same,
the result is false.)*)
(*val is_older : (int * int * int) * (int * int * int) -> bool*)
let is_older ((date1 : int * int * int), (date2 : int * int * int)) =

  if thd3 date1 < thd3 date2 then true
  else if thd3 date1 > thd3 date2 then false
  
  (* if we get to this point, years are equal, so compare months *)
  else
    if snd3 date1 < snd3 date2 then true
    else if snd3 date1 > snd3 date2 then false

    (* months are equal, so compare days *)
    else
      if fst3 date1 < fst3 date2 then true
      else false

(* 2 *)
(*Write a function number_in_month that takes a list of dates and a month (i.e., an int) and returns
how many dates in the list are in the given month.*)
(*val number_in_month : (int * int * int) list * int -> int*)
let rec number_in_month ((dates : (int * int * int) list), (month : int)) =
  if dates = [] then 0
  else let count_rest = number_in_month (List.tl dates, month) in
  if snd3 (List.hd dates) = month then 1 + count_rest else count_rest

(*3*)
(*Write a function number_in_months that takes a list of dates and a list of months (i.e., an int list)
and returns the number of dates in the list of dates that are in any of the months in the list of months.
Assume the list of months has no number repeated. Hint: Use your answer to the previous problem.*)
(*val number_in_months : (int * int * int) list * int list -> int*)
let rec number_in_months ((dates : (int * int * int) list), (months : int list)) : int =
  if months = [] then 0
  else number_in_month (dates, List.hd months) + number_in_months (dates, List.tl months)

(*5*)
(*Write a function dates_in_months that takes a list of dates and a list of months (i.e., an int list)
and returns a list holding the dates from the argument list of dates that are in any of the months in
the list of months. Assume the list of months has no number repeated. Hint: Use your answer to the
previous problem and OCaml’s list-append operator (@)*)
(*val dates_in_months : (int * int * int) list -> int list -> (int * int * int) list*)
let rec dates_in_months (dates : (int * int * int) list) (months : int list) : (int * int * int) list =
  if months = [] then []
  else let hd_month = List.hd months in
       let tl_months = List.tl months in
        dates_in_month dates hd_month @ dates_in_months dates tl_months


  
(*13*)
(*Challenge Problem: Write functions number_in_months_challenge and dates_in_months_challenge
that are like your solutions to problems 3 and 5 except having a month in the second argument multiple
times has no more effect than having it once. (Hint: Remove duplicates, then use previous work.)*)

(*14*)
(*Challenge Problem: Write a function reasonable_date that takes a date and determines if it
describes a real date in the common era. A “real date” has a positive year (year 0 did not exist), a
month between 1 and 12, and a day appropriate for the month. Solutions should properly handle leap
years. Leap years are years that are either divisible by 400 or divisible by 4 but not divisible by 100.
(Do not worry about days possibly lost in the conversion to the Gregorian calendar in the Late 1500s.)*)

SOLVE 13 and 14