Ok, it's not completely like Simon Says, since it's text-based. There is nothing about memorizing based on visual cues and/or sound here, just memorizing long sequences of numbers. I wanted to do it in the language I write the least code in, Scheme (w/ Chicken), and see what happens.
(use posix)
(use (srfi 1))
(define button-count 4)
(define (clear-screen)
(system "cls"))
(define (make-delay)
(sleep 2))
(define (show-sequence sequence)
(if (not (null? sequence))
(begin
(clear-screen)
(make-delay)
(write (car sequence))
(make-delay)
(show-sequence (cdr sequence)))
(begin
(clear-screen)
(write-line "GO!"))))
(define (show-score score)
(format #t "Your score: ~A~%" score))
(define (get-player-input)
(read-line))
(define (make-sequence length)
(map random (make-list length button-count)))
(define (player-sequence-matches? target-sequence)
(cond
[(null? target-sequence) #t]
[(string=? (get-player-input) (number->string (car target-sequence)))
(player-sequence-matches? (cdr target-sequence))]
[else #f]))
(define (simon-says difficulty)
(let [(current-sequence (make-sequence difficulty))]
(show-sequence current-sequence)
(if (player-sequence-matches? current-sequence)
(+ 1 (simon-says (+ difficulty 1)))
0)))
(define (play-simon-says)
(show-score (simon-says 1)))
If you want to run it on something Unix, you'll need to change (system "cls")
to (system "clear")
.
1 Answer 1
Ideally I'd like to use termcap or terminfo or the like to clear the terminal without shelling out. Alas, it seems Chicken doesn't have an egg for either termcap or terminfo. (It does have an egg for curses, but I consider that to be too heavyweight for just clearing a terminal.)
I'd probably use
for-each
for iterating through the items inshow-sequence
, rather than the recursive approach you have:(define (show-sequence seq) (for-each (lambda (x) (clear-screen) (make-delay) (display x) ;; not write (make-delay)) seq) (clear-screen) (display "GO!\n"))
Not a huge fan of making a
get-player-input
function that's exactly the same asread-line
. I'd just callread-line
directly.Your definition of
make-sequence
is quite clever, but it's not very idiomatic. Since you have SRFI 1 loaded, I'd just uselist-tabulate
:(define (make-sequence len) ;; not length (list-tabulate len (lambda (_) (random button-count))))
You can simplify
player-sequence-matches?
by using SRFI 1'severy
:(define (player-sequence-matches? seq) (every (lambda (x) (= (string->number (read-line)) x)) seq))
And since Chicken has
cut
builtin, you can simplify even further:(define (player-sequence-matches? seq) (every (cut = (string->number (read-line)) <>) seq))
For calculating the total score, I'd rather accumulate the score, rather than use recursion to hold the score. Like so:
(define (simon-says difficulty) (let loop ((difficulty difficulty) (score 0)) (define seq (make-sequence difficulty)) (show-sequence seq) (if (player-sequence-matches? seq) (loop (add1 difficulty) (add1 score)) score)))
This way, the function is totally tail-recursive.
-
\$\begingroup\$ Any chance you've got a sec to take a look at my latest attempt at Lisp-ing? :) codereview.stackexchange.com/questions/105174/… \$\endgroup\$user29120– user291202015年09月20日 16:23:11 +00:00Commented Sep 20, 2015 at 16:23