Beginner:
Adapted from Perl Quiz #2: [ http://perl.plover.com/~alias/list.cgi?mss:11:200210:ccbcblpijjjcnhnkabep ]
Write a function, days-diff, to compute the time difference, in days, between two dates. The dates will be strings in the format
Wed Oct 16 2002
For example:
(days-diff "Wed Oct 16 2002" "Wed Oct 23 2002") => 7
(days-diff "Wed Oct 16 2002" "Tue Oct 16 2001") => -365
Error checking: at minimum, signal an error if either value is unparsable or internally inconsistent (e.g. if 10/16/2002 is not, in fact, a Wednesday). More advanced users can establish useful restarts.
Dependencies on your Lisp's time functions are okay.
Expert:
Adapted from Expert Perl Quiz #2: [ http://perl.plover.com/~alias/list.cgi?mss:12:200210:mflioldnngfgmfnlfljf ]
The local high school baseball team, the Kent Pitman High School Phoenixes, will be playing a series of games against their rivals, the Kenny Tilton Memorial High School Growlin' Fungus. The series lasts at most five games, and ends when one team has won three games. You want to bet $80 on the Phoenixes to win the series, but your bookie will only take bets on individual games. (The bookie pays even money on all bets.)
A mathematically-inclined friend solves the problem for you, giving you the following instructions:
Bet $30 on each of the first two games.
Bet $20 on the third game if either team has won both of the first two games, $40 otherwise.
Bet $40 on the fourth game, if there is one. Bet $80 on the fifth game, if there is one.
At the end of the series, you will be ahead by exactly $80 if the Phoenixes have won the series, and behind by exactly $80 if the Growlin' Fungus have won.
We could summarize the instructions in a table like this:
If the game score is: 0 to 0, bet $30 1 to 0, bet 30 1 to 1, bet 40 2 to 0, bet 20 2 to 1, bet 40 2 to 2, bet 80
Write a function which calculates the appropriate bet for any such contest, given the total amount you want to risk on the series, the length of the series, and the current game score. For example,
(bet 80 5 2 1) => 40
because if you want to risk $80 on a 5-game series, and one team is presently ahead 2 games to 1, you should bet $40.
Similarly
(bet 1000 7 2 1) => 375
(That is, if you're trying to bet $1000 on the current [circa 10/2002] World Series baseball match, you need to bet $375 on the outcome of tonight's game. If you started with $1000, and followed this function's advice, you'd have $625 left if you had been betting on the Giants and $1375 if you had been betting on the Angels. For people living in places where the World Series is irrelevant: the match is a best-four-of-seven series of games; at present, the Anaheim Angels are beating the San Francisco Giants two games to one, with the fourth game scheduled for tonight.)
Error checking: at minimum, signal an error if any of the parameters are invalid or internally inconsistent (e.g. negatives, length of series is less than number of games played so far, etc). More advanced users can establish useful restarts.
Wow, no takers, huh. With all the talk that has been going around about lisp lately, this list is surprisingly quiet.
I suppose I might as well post my attempt. Keep in mind, i'm new to lisp so it may not be very "lispy". I'm sure someone will shortly make me feel dumb by posting a two liner with better error handling < | :)
---- start ---- (defun date-to-time (date &key (tz nil)) "Convert date to timestamp. Date expected to be formatted as: Sat Jul 20 2007 , using 3 letter abbreviations for day of week and month" (let* ((date-list (read-from-string (concatenate 'string "(" date ")"))) (utime (encode-universal-time 0 0 0 (caddr date-list) (+ (position (cadr date-list) '(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec)) 1) (cadddr date-list) tz))) (if (equal (seventh (multiple-value-list (decode-universal-time utime))) (position (car date-list) '(Mon Tue Wed Thu Fri Sat Sun))) utime (error "Supplied day (~S) does not match calculated day of week for ~S)" (first date-list) (rest date-list) ))))
(defun days-diff (start end) "Calculate difference in days between the two provided dates. Dates must be in the form accepted by date-to-time" (/ (- (date-to-time end) (date-to-time start)) 60 60 24))
---- end ---
CL-USER> (days-diff "Wed Oct 16 2002" "Wed Oct 23 2002") 7 CL-USER> (days-diff "Wed Oct 16 2002" "Tue Oct 16 2001") -365 CL-USER> (days-diff "Thu Jul 19 2007" "Mon Jul 23 2007") 4
Comments or suggestions welcome.
Cheers, Carl.
On 7/19/07, Larry Clapp larry@theclapp.org wrote:
Beginner:
Adapted from Perl Quiz #2: [ http://perl.plover.com/~alias/list.cgi?mss:11:200210:ccbcblpijjjcnhnkabep ]
Write a function, days-diff, to compute the time difference, in days, between two dates. The dates will be strings in the format
Wed Oct 16 2002
For example:
(days-diff "Wed Oct 16 2002" "Wed Oct 23 2002") => 7 (days-diff "Wed Oct 16 2002" "Tue Oct 16 2001") => -365
Error checking: at minimum, signal an error if either value is unparsable or internally inconsistent (e.g. if 10/16/2002 is not, in fact, a Wednesday). More advanced users can establish useful restarts.
Dependencies on your Lisp's time functions are okay.
--8<-- message cut -->8--
2007/7/23, Carl c.groner@gmail.com:
Wow, no takers, huh. With all the talk that has been going around about lisp lately, this list is surprisingly quiet.
Uhm... I liked your solution, even though I'm a newbie. Thanks for submitting it, you helped me to learn some new functions. And yes, almost anyone is trying to solve the quiz (me included) but at least reading the few solutions of others is helping me a lot.
Off topic: I am reading Paul Graham's ANSI Common Lisp and I have a little question: why does he uses a lot (at least until chapter 4) "and" clauses when I think he should use the "when" macro? For example, in this code snip from figure 4.1:
;; This is a binary search algorithm as you may guess. (defun bin-search (obj vec) (let ((len (length vec))) (and (not (zerop len)) ;Here is the and clause that I may change for a when (finder obj vec 0 (- len 1)))))
(defun finder (obj vec start end) ...)
I've read that at least three times I think and it seems that there will be more. I know that the and clause gives the desired behavior of returning the last value that satisfies it or the first one that doesn't, but I would have used a when for some of the cases I've read (it is more readable for me, I think). Is he using the and clause for some reason that eludes me or is it just a personal taste? Thanks.
2007/7/24, Ivan Salazar ivan.salazarv@gmail.com:
2007/7/23, Carl c.groner@gmail.com:
Wow, no takers, huh. With all the talk that has been going around about lisp lately, this list is surprisingly quiet.
Uhm... I liked your solution, even though I'm a newbie. Thanks for submitting it, you helped me to learn some new functions. And yes, almost anyone is trying to [...]
That should be: "And yes, almost no-one is trying to [...]". Sorry, a stupid typo.
This message is two replies in one.
On Tue, Jul 24, 2007 at 12:26:48AM -0500, Ivan Salazar wrote:
2007/7/23, Carl c.groner@gmail.com:
Wow, no takers, huh. With all the talk that has been going around about lisp lately, this list is surprisingly quiet.
Carl,
I didn't get your email and can't find it in my spam folder. Bummer. But I did find it in the archive:
(defun date-to-time (date &key (tz nil)) "Convert date to timestamp. Date expected to be formatted as: Sat Jul 20 2007 , using 3 letter abbreviations for day of week and month" (let* ((date-list (read-from-string (concatenate 'string "(" date ")"))) (utime (encode-universal-time 0 0 0 (caddr date-list) (+ (position (cadr date-list) '(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec)) 1) (cadddr date-list) tz))) (if (equal (seventh (multiple-value-list (decode-universal-time utime))) (position (car date-list) '(Mon Tue Wed Thu Fri Sat Sun))) utime (error "Supplied day (~S) does not match calculated day of week for ~S)" (first date-list) (rest date-list) ))))
(defun days-diff (start end) "Calculate difference in days between the two provided dates. Dates must be in the form accepted by date-to-time" (/ (- (date-to-time end) (date-to-time start)) 60 60 24))
---- end ---
CL-USER> (days-diff "Wed Oct 16 2002" "Wed Oct 23 2002") 7 CL-USER> (days-diff "Wed Oct 16 2002" "Tue Oct 16 2001") -365 CL-USER> (days-diff "Thu Jul 19 2007" "Mon Jul 23 2007") 4
Comments or suggestions welcome.
Your solution seems quite workable, and certainly does the job. I like the way you split the string into lists of atoms using read-from-string. I've seen that idiom before, but forgot about it. I used split-sequence in my solution.
Suggestions: o Instead of cadr, caddr, and cadddr, use second, third, and fourth. o Instead of embedding the lists of months and days, use a separately defined constant. (On the other hand, this is a style issue and quite debatable, especially for such a small, throw-away problem.) o Instead of (seventh (multiple-value-list ...)) use nth-value. (I did the same thing at first, though. :)
Thanks for posting! Remember to put [SPOILER] in your subject when you include a solution.
Ivan said:
Uhm... I liked your solution, even though I'm a newbie. Thanks for submitting it, you helped me to learn some new functions. And yes, almost no-one is trying to solve the quiz (me included) but
^^^^^^ fixed
at least reading the few solutions of others is helping me a lot.
Well, all we *really* know is that no-one is submitting solutions. :) I worked up a solution shortly after I posted the problem, but then wanted to add some more sophisticated condition handling, and I'm not all that familiar with the condition system, so I had to do some reading, and then Life intervened. :)
Off topic: I am reading Paul Graham's ANSI Common Lisp and I have a little question: why does he uses a lot (at least until chapter 4) "and" clauses when I think he should use the "when" macro? For example, in this code snip from figure 4.1:
;; This is a binary search algorithm as you may guess. (defun bin-search (obj vec) (let ((len (length vec))) (and (not (zerop len)) ;Here is the and clause that I may change for ;a when (finder obj vec 0 (- len 1)))))
(defun finder (obj vec start end) ...)
I've read that at least three times I think and it seems that there will be more. I know that the and clause gives the desired behavior of returning the last value that satisfies it or the first one that doesn't, but I would have used a when for some of the cases I've read (it is more readable for me, I think). Is he using the and clause for some reason that eludes me or is it just a personal taste?
In many cases I think it's just personal taste, i.e., a style issue like the one I mentioned above.
But maybe not. If you consider the published code as a snapshot of a real application, some method to this madness emerges (maybe). In particular, consider the code over time. Perhaps he started out with
(and (not (zerop len)) (other code) (finder obj vec 0 (- len 1)))
and then deleted the second clause. Maybe he didn't want to change it. Maybe he thought he might, at some later date, have to add some more code in the middle. Once you shift back and forth between
(when (foo) (baz))
and
(when (and (foo) (bar)) (baz))
enough times, you start to want to skip the middle man and just go for
(and (foo) (baz))
every time, in case you have to add the middle (bar) later.
Or so it seems to me, anyway. :)
I haven't really thought about it all that much, but I might use the following rule of thumb: Start out with
(when (foo) (baz))
The first time you have to change it to
(when (and (foo) (bar)) (baz))
change it to
(and (foo) (bar) (baz))
instead and leave it that way forever after. If it has changed once, it'll probably change again. :)
-- Larry
Off topic: I am reading Paul Graham's ANSI Common Lisp and I have a little question: why does he uses a lot (at least until chapter 4) "and" clauses when I think he should use the "when" macro? For example, in this code snip from figure 4.1:
;; This is a binary search algorithm as you may guess. (defun bin-search (obj vec) (let ((len (length vec))) (and (not (zerop len)) ;Here is the and clause that I may change for ;a when (finder obj vec 0 (- len 1)))))
(defun finder (obj vec start end) ...)
I've read that at least three times I think and it seems that there will be more. I know that the and clause gives the desired behavior of returning the last value that satisfies it or the first one that doesn't, but I would have used a when for some of the cases I've read (it is more readable for me, I think). Is he using the and clause for some reason that eludes me or is it just a personal taste?
In many cases I think it's just personal taste, i.e., a style issue like the one I mentioned above.
But maybe not. If you consider the published code as a snapshot of a real application, some method to this madness emerges (maybe). In particular, consider the code over time. Perhaps he started out with
(and (not (zerop len)) (other code) (finder obj vec 0 (- len 1)))
and then deleted the second clause. Maybe he didn't want to change it. Maybe he thought he might, at some later date, have to add some more code in the middle. Once you shift back and forth between
(when (foo) (baz))
and
(when (and (foo) (bar)) (baz))
enough times, you start to want to skip the middle man and just go for
(and (foo) (baz))
every time, in case you have to add the middle (bar) later.
Or so it seems to me, anyway. :)
I haven't really thought about it all that much, but I might use the following rule of thumb: Start out with
(when (foo) (baz))
The first time you have to change it to
(when (and (foo) (bar)) (baz))
change it to
(and (foo) (bar) (baz))
instead and leave it that way forever after. If it has changed once, it'll probably change again. :)
-- Larry
quiz mailing list quiz@common-lisp.net http://common-lisp.net/cgi-bin/mailman/listinfo/quiz
Outstanding. Thanks for the answer, Larry. I was starting to think that was the answer, but you stated it very clear.