HiveBrain v1.2.0
Get Started
← Back to all entries
patternMinor

Number guessing game in Racket

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
gamenumberracketguessing

Problem

I decided to learn a Lisp-ish language and I am discovering a very weird and new syntax. The obligatory first program, that also uses all the fundamentals, is the number guessing game.

  • Did I define too few or too many constants?



  • Is my code properly spaced and indented?



  • Is there a cleaner way to exit the loop than error?



  • Is it too imperative? Is it even possible to write the number guessing game functionally?



  • Is it OK to define null and set!?



#lang racket

(define NUM 12)
(define TRIES 6)
(define CORRECT "Correct! Well guessed!")
(define TOO_LOW "... Too Low ...")
(define TOO_HIGH "... Too high ...")

(define (num_message player_num)
  (if (= player_num NUM)
      CORRECT
       (if (> player_num NUM)
          TOO_HIGH
          TOO_LOW      
      )
    )
  )

(define (number-guessing-game)
  (define out null)
  (for ([i (range TRIES)])
    (set! out (num_message (read)))
    (print out)
    (when (equal? out CORRECT)
        (print "You won")
        (error "Exiting")
    )
  )
  (print "Too many attempts")
)

(number-guessing-game)

Solution

Winning shouldn't be considered an error. If you want a way to exit from the for-loop, use #:break. But for and set! aren't really idiomatic in Lisp-like languages. Instead, it is more common to use recursion and let, which conform to the functional programming paradigm.

In num_message, you can use a cond instead of nested ifs.

I'm not happy about the use of a string comparison to detect the winning condition: the number-guessing-game function needs to know what congratulatory message to expect from num_message. You've worked around that problem by defining some string constants, which gives them more importance than one would expect.

It would be more elegant for num_message not to have NUM fixed, and for number-guessing-game not to have NUM and TRIES fixed.

The number-guessing-game function would be clearer if it were broken up, because it is actually doing two things: play one guess, and conditionally repeat.

The print calls should probably be displayln instead, to also write a trailing newline.

Conventionally, words in identifiers are separated-by-hyphens rather than underscores. Closing parentheses don't get their own line.

#lang racket

(define NUM 12)
(define TRIES 6)

(define (num-message delta)
  (cond [( delta 0) "... Too high ..."]
        [else        "Correct! Well guessed!"]))

(define (guess-number target)
  (let ([delta (- (read) target)])
       (displayln (num-message delta))
       (zero? delta)))

(define (number-guessing-game target tries)
  (cond [(zero? tries)         (displayln "Too many attempts")]
        [(guess-number target) (displayln "You won")]
        [else                  (number-guessing-game target (- tries 1))]))

(number-guessing-game NUM TRIES)

Code Snippets

#lang racket

(define NUM 12)
(define TRIES 6)

(define (num-message delta)
  (cond [(< delta 0) "... Too low ..."]
        [(> delta 0) "... Too high ..."]
        [else        "Correct! Well guessed!"]))

(define (guess-number target)
  (let ([delta (- (read) target)])
       (displayln (num-message delta))
       (zero? delta)))

(define (number-guessing-game target tries)
  (cond [(zero? tries)         (displayln "Too many attempts")]
        [(guess-number target) (displayln "You won")]
        [else                  (number-guessing-game target (- tries 1))]))

(number-guessing-game NUM TRIES)

Context

StackExchange Code Review Q#87075, answer score: 5

Revisions (0)

No revisions yet.