patternMinor
Simon Says in Scheme
Viewed 0 times
schemesayssimon
Problem
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.
If you want to run it on something Unix, you'll need to change
(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").Solution
-
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
-
Not a huge fan of making a
-
Your definition of
-
You can simplify
And since Chicken has
-
For calculating the total score, I'd rather accumulate the score, rather than use recursion to hold the score. Like so:
This way, the function is totally tail-recursive.
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 in show-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 as read-line. I'd just call read-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 use list-tabulate:(define (make-sequence len) ;; not length
(list-tabulate len (lambda (_) (random button-count))))-
You can simplify
player-sequence-matches? by using SRFI 1's every:(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.
Code Snippets
(define (show-sequence seq)
(for-each (lambda (x)
(clear-screen)
(make-delay)
(display x) ;; not write
(make-delay))
seq)
(clear-screen)
(display "GO!\n"))(define (make-sequence len) ;; not length
(list-tabulate len (lambda (_) (random button-count))))(define (player-sequence-matches? seq)
(every (lambda (x)
(= (string->number (read-line)) x))
seq))(define (player-sequence-matches? seq)
(every (cut = (string->number (read-line)) <>) seq))(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)))Context
StackExchange Code Review Q#71954, answer score: 3
Revisions (0)
No revisions yet.