首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >球拍中的猜数游戏

球拍中的猜数游戏
EN

Code Review用户
提问于 2015-04-16 12:03:18
回答 2查看 1.2K关注 0票数 10

我决定学习一种Lisp语言,我发现了一种非常奇怪和新的语法。必须的第一个程序,也使用所有的基础,是数字猜测游戏。

  • 我是定义得太少还是太多了?
  • 我的代码是否有正确的间隔和缩进?
  • 有比error更干净的方式退出循环吗?
  • 是不是太迫切性了?是否有可能在功能上写出猜数游戏?
  • define nullset!可以吗?
代码语言:javascript
复制
#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)
EN

回答 2

Code Review用户

回答已采纳

发布于 2015-07-23 12:13:15

胜利不应被视为错误。如果想要从for-循环中退出,请使用#:break。但在类似Lisp的语言中,forset!并不是真正的惯用语言。相反,更常见的是使用符合函数式编程范例的递归和let

num_message中,您可以使用cond而不是嵌套的ifs。

我对使用字符串比较来检测获胜条件并不满意:number-guessing-game函数需要知道从num_message得到什么祝贺消息。您已经通过定义一些字符串常量来解决这个问题,这使它们比人们预期的更重要。

如果num_message不修复NUM,而number-guessing-game不修复NUMTRIES,就更优雅了。

如果number-guessing-game函数被分解,它将更加清晰,因为它实际上做了两件事情:只做一次猜测,和有条件地重复。

print调用可能应该是displayln,这样也可以编写一个尾换行符。

通常,标识符中的单词是separated-by-hyphens而不是下划线。结束括号没有自己的行。

代码语言:javascript
复制
#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)
票数 5
EN

Code Review用户

发布于 2015-07-28 16:24:46

The Good

  1. 这个程序体现了一种健全的命名方法。关于什么是最好的名字,争论可能很激烈:不同的,也许更好或更坏的名字是可能的。
  2. 该程序在将常量处理为常数而不是变量方面做得很好。
  3. num-message是迈向模块化的一步。
  4. 无论是出于偶然还是直觉,for的思想指向了一个非常有用和惯用的抽象,通常出现在Lisp/racket/Lisp程序中: streams。将猜测视为要处理的流是有用的。

需要改进的

领域

  1. 模块化:用户界面仍然与num-message中的控制流混在一起。
  2. 迭代:递归是重复一个过程的惯用方法。清单理解是一种可用的功能式编程选择。

替代方法

代码演示了一些不同的也许更好,也许更糟技术。

关键的抽象是三个流:

  1. 猜测的输入流。
  2. 消息的输出流。
  3. 时钟滴答声的内部流。时钟是向上的,而不是向下的,这样我们就可以谈论第一个猜测和第一个消息,或者把有时间戳的猜测和消息写到日志中。它从1开始,因为它更好地映射到“第一,第二……”的概念。

模数

将常量声明为函数可以在不影响主控制流的情况下重新定义它们的行为。提供变量参数性允许对主循环的语义进行实验,而不依赖于函数的实现或基于参数数的分派。

代码语言:javascript
复制
  #lang racket

  #| Data Types |#

  (struct game-message (start win lose too-high too-low)) 

  #| User Interaction |#

  (define messages
    (game-message "Please make your first guess: "
                  "\nWinner Winner Chicken Dinner!\n"
                  "\nAll your guesses are belong to us :(\n"
                  "\nYour guess is too high. Please Guess again: "
                  "\nYour guess is too low. Please Guess again: "))

  (define (get-target . args)
    12)

  (define (get-guesses . args)
    6)

  (define (get-guess . args)
    (read))

  (define (inform-user message)
    (display message))

高阶函数

函数make-game以目标和多个猜测作为输入,并返回在clock流上迭代的函数,从猜测流中进行猜测,并在消息流上输出消息。

代码语言:javascript
复制
  #| Constructor |#

  (define (make-game target guesses)

  (define (game clock)
    (let ((guess (get-guess)))
        (cond
         [(equal? guess target)
          (inform-user (game-message-win messages))]
         [(= clock guesses)
          (inform-user (game-message-lose messages))]
         [(< guess target)
          (inform-user (game-message-too-low messages))
          (game (add1 clock))]
         [(> guess target)
         (inform-user (game-message-too-high messages))
         (game (add1 clock))])))

  game)

可执行子模块

一个名为“主”具有特殊地位的子模块在命令行被racket调用时:它将自动执行。

游戏执行从调用make-game作为闭锁返回的函数开始。

代码语言:javascript
复制
  #| Play game |#
  (module* main #f
    (game-message-start messages)
    ((make-game (get-target)(get-guesses)) 1))

示例使用:

请注意,这是运行在操作系统外壳,而不是球拍REPL。

代码语言:javascript
复制
  $ racket number-game.rkt
  "Please make your first guess: "
  5

  Your guess is too low. Please Guess again: 6

  Your guess is too low. Please Guess again: 9

  Your guess is too low. Please Guess again: 99

  Your guess is too high. Please Guess again: 55

  Your guess is too high. Please Guess again: 18

  All your guesses are belong to us :(
票数 1
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/87075

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档