【问题标题】:Recursive Scheme Function Value Error递归方案函数值错误
【发布时间】:2014-10-01 05:52:47
【问题描述】:

我正在编写一个计划中的小刽子手游戏,遇到了一个非常奇怪的问题,几乎看起来像是一个特定于语言的问题。

在我的游戏中,我有一个变量来保存允许的错误数量,并且在我的游戏循环的每次递归调用中,如果需要更改它,我会“让”这个值到一个新的值。这里有一些代码可以帮助我可视化我是如何运行游戏循环的。

guessed_list - 包含旧猜测和一个新猜测的字符串字符列表(例如 '("a" "x" "b"),其中 "a" 是新猜测)

game_word - '("a" "b" "c")

display_word - 一个字符串字符列表,其中包含我匹配的字母和连字符,用于我的游戏循环的这次迭代(例如 '("" "b" "")来自guessed_list 的“a”将在此循环迭代中被评估)

mistakes_left - 我在比赛结束前因猜错而出现的错误数。最初从 6 开始,但在我当前的示例中应该是 5,因为 1 个字母“x”被猜错了。

     ;; Game Loop.
  (define (game-loop guessed_list display_word mistakes_left)
    (let ((n_mistakes_left 
            (- mistakes_left (if (contains? game_word (car guessed_list))
                                 0 1))))   
      (if (= n_mistakes_left 0)
          (display n_mistakes_left);; End game output
          (let ((display_word (fill-in-guess (list (car guessed_list)) 
                                             game_word display_word))
                (guessed_list (sort guessed_list string<?)))

            (display "You have guessed: ")
            (display-list guessed_list ", ")
            (display "\n\n")
            (draw-hangman n_mistakes_left)
            (display "\n\nWord: ")
            (display-list display_word " ")

            (cond ((contains? display_word "_")
                     (display "\n\nEnter a letter to guess: ")
                     (game-loop (append (list (symbol->string (read))) guessed_list)
                                display_word n_mistakes_left))
                  (else (display "\n\nYou Won!")))))))

如有必要,我可以发布我的辅助方法 contains?、fill-in-guess、display-list、draw-hangman,但它们都按应有的方式工作,并且不会更改我的 errors_left 变量的值以实现其功能。

我遇到的问题是我的 errors_left 变量从 6 开始,并在第一次调用游戏循环时很好地通过,但在随后的调用中,即使猜测正确的值也会变小。我已经单独提取了每一块,对其进行了测试,errors_left 得出了正确的值,直到我递归为止。

我怀疑它与递归和“让”我的变量有关,但如果有人可以或指出我遗漏的最可能的简单错误,我想要一个明确的答案!

编辑:

这是要测试的其余代码,我仍然遇到问题。我认为 append 有效,因为它将第二个列表附加到第一个列表,所以在这个意义上 cons 和 append 给了我相同的输入。

  (define zero_wrong "
  |---------

  |        |

  |      

  |        

  |         

  |         

  |         

  |         

  |         

  |_______________")
  (define one_wrong "
  |---------

  |        |
          ___
  |      |. .|
          ---
  |        

  |         

  |         

  |         

  |         

  |         

  |_______________")
  (define two_wrong "
  |---------

  |        |
          ___
  |      |. .|
          ---
  |        |
           |
  |        |
           |
  |         

  |         

  |         

  |         

  |_______________")
  (define three_wrong "
  |---------

  |        |
          ___
  |      |. .|
          ---
  |        |
           |----
  |        |
           |
  |         

  |         

  |         

  |         

  |_______________")
  (define four_wrong "
  |---------

  |        |
          ___
  |      |. .|
          ---
  |        |
       ----|----
  |        |
           |
  |         

  |         

  |         

  |         

  |_______________")
  (define five_wrong "|---------

  |        |
          ___
  |      |. .|
          ---
  |        |
       ----|----
  |        |
           |
  |         \\
             \\
  |         

  |         

  |         

  |_______________")
  (define six_wrong "|---------

  |        |
          ___
  |      |x x|
          ---
  |        |
       ----|----
  |        |
           |
  |       / \\
         /   \\
  |         

  |         

  |         

  |_______________")

  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  ;; Read list value at x.
  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  (define (get-str-at x str_lst)
     (cond ((equal? x 0)
        (car str_lst))
     (else
        (get-str-at (- x 1) (cdr str_lst))
     )
     )
  )

  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  ;; Car operation for strings.
  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  (define (string-car str)
     (substring str 0 1)
  )

  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  ;; Cdr operation for strings.
  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  (define (string-cdr str)
     (substring str 1 (string-length str))
  )

  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  ;; Converts a string into a 
  ;; list of character strings.
  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

  (define (string-to-char-string-list str)
     (cond 
        ((equal? (string-cdr str) "")
           (list str) 
        )
        (
           (append (list (string-car str)) (string-to-char-string-list (string-cdr str)))
        )
     )
  )

  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  ;; Tests if a list contains a spefified object.
  ;;
  ;; Method code from:
  ;; http://stackoverflow.com/questions/1869116/scheme-built-in-to-check-list-containment
  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  (define (contains? list item)
    (if (empty? list)
           #f
        (or (eq? (first list) item)
           (contains? (rest list) item)
        )
     )
  )

  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  ;; Displays a list with the 
  ;; given separater.
  ;;
  ;; Base code from:
  ;; ftp://ftp.cs.utexas.edu/pub/garbage/cs345/schintro-v13/schintro_99.html
  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

  (define (display-list a_list separater)
     (if (null? a_list)
        (display "")
        (begin 
           (display (car a_list))
           (if (null? (cdr a_list))
              (display "")
              (display separater))
           (display-list (cdr a_list) separater)
        )
     )
  )


  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  ;; Gets the Xth word in the 
  ;; provided file.
  ;; 
  ;; Does not check for eof
  ;; condition, so x must be 
  ;; within range of the file.
  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  (define (get-word x file)
     (cond 
        ((= 1 x)
           (read file))
        (else
           (read file)
           (get-word (- x 1) file)
        )
     )
  )


  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  ;; Returns a list of blanks
  ;; equal to the number of
  ;; letters in provided word.
  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

  (define (init-display-word game_word)
     (cond 
        ((null? game_word)
           (list))
        (else
           (append (init-display-word (cdr game_word)) '("_"))
        )
     )
  )


  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  ;; Fills in the blank spaces
  ;; in the display word with
  ;; the letter that matches
  ;; those positions in the
  ;; game word.
  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

  (define (fill-in-guess letter game_word display_word)
     (cond
        ((null? game_word)
           (list)
        )
     (else
     (cond 
        ((equal? letter (list (car game_word)))
           (append letter (fill-in-guess letter (cdr game_word) (cdr display_word)))
        )
        (else
           (append (list (car display_word)) (fill-in-guess letter (cdr game_word) (cdr display_word)))
        )
     )
     )
     )
  )

  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  ;; Draws the hanging man.
  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

  (define (draw-hangman guesses_left)
      (cond ((equal? guesses_left 6)
                (display zero_wrong))
      (else (cond ((equal? guesses_left 5)
                (display one_wrong))
      (else (cond ((equal? guesses_left 4)
                (display two_wrong))
      (else (cond ((equal? guesses_left 3)
                (display three_wrong))
      (else (cond ((equal? guesses_left 2)
                (display four_wrong))
      (else (cond ((equal? guesses_left 1)
                (display five_wrong))
      (else (display six_wrong))
      )))))))))))
  )

【问题讨论】:

  • 除了检查值是否在列表中之外,contains? 谓词是否还有其他作用?如果没有,请改用内置的 Racket 函数member
  • 不,它不做任何其他工作。我对Scheme还很陌生,所以我还不熟悉许多内置结构,但谢谢你。我将在我的代码中更改它。
  • 如果答案解决了您的问题。请接受。
  • 您的解决方案虽然更简单,但不起作用。猜出有效字母时,图像仍然显示不正确。

标签: recursion scheme logic racket


【解决方案1】:

我对您的代码做了几处修改。我在函数上方用 cmets 标记了我的更改,并对其进行了解释。您的问题是您对guessed_list 进行了排序。没有必要这样做。我已经对其进行了测试,并且可以正常工作。请记住,如果您使用空的猜测列表调用game-loop,则会出错。要解决这个问题,您需要测试 guessed_list 是否为空,并且还返回 0 进行减法。我会把它留给你。 同样在您的代码中的许多地方,您已经嵌套了 conds 这不是必需的。在这里阅读:cond

(define game_word '("a" "b" "c"))

 (define zero_wrong "
  |---------

  |        |

  |      

  |        

  |         

  |         

  |         

  |         

  |         

  |_______________")
  (define one_wrong "
  |---------

  |        |
          ___
  |      |. .|
          ---
  |        

  |         

  |         

  |         

  |         

  |         

  |_______________")
  (define two_wrong "
  |---------

  |        |
          ___
  |      |. .|
          ---
  |        |
           |
  |        |
           |
  |         

  |         

  |         

  |         

  |_______________")
  (define three_wrong "
  |---------

  |        |
          ___
  |      |. .|
          ---
  |        |
           |----
  |        |
           |
  |         

  |         

  |         

  |         

  |_______________")
  (define four_wrong "
  |---------

  |        |
          ___
  |      |. .|
          ---
  |        |
       ----|----
  |        |
           |
  |         

  |         

  |         

  |         

  |_______________")
  (define five_wrong "|---------

  |        |
          ___
  |      |. .|
          ---
  |        |
       ----|----
  |        |
           |
  |         \\
             \\
  |         

  |         

  |         

  |_______________")
  (define six_wrong "|---------

  |        |
          ___
  |      |x x|
          ---
  |        |
       ----|----
  |        |
           |
  |       / \\
         /   \\
  |         

  |         

  |         

  |_______________")

  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  ;; Read list value at x.
  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define (get-str-at x str_lst)
  (cond ((equal? x 0)
         (car str_lst))
        (else
         (get-str-at (- x 1) (cdr str_lst)))))

  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  ;; Car operation for strings.
  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define (string-car str)
  (substring str 0 1))

  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  ;; Cdr operation for strings.
  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; *** This is enough.
(define (string-cdr str)
  (substring str 1))

  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  ;; Converts a string into a 
  ;; list of character strings.
  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(define (string-to-char-string-list str)
  (cond 
    ((equal? (string-cdr str) "")
     (list str))
    ((append (list (string-car str)) (string-to-char-string-list (string-cdr str))))))

  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  ;; Tests if a list contains a spefified object.
  ;;
  ;; Method code from:
  ;; http://stackoverflow.com/questions/1869116/scheme-built-in-to-check-list-containment
  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define (contains? list item)
  (if (empty? list)
      #f
      (or (string=? (first list) item)
          (contains? (rest list) item))))

  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  ;; Displays a list with the 
  ;; given separater.
  ;;
  ;; Base code from:
  ;; ftp://ftp.cs.utexas.edu/pub/garbage/cs345/schintro-v13/schintro_99.html
  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(define (display-list a_list separater)
  (if (null? a_list)
      (display "")
      (begin 
        (display (car a_list))
        (if (null? (cdr a_list))
            (display "")
            (display separater))
        (display-list (cdr a_list) separater))))


  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  ;; Gets the Xth word in the 
  ;; provided file.
  ;; 
  ;; Does not check for eof
  ;; condition, so x must be 
  ;; within range of the file.
  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define (get-word x file)
  (cond 
    ((= 1 x)
     (read file))
    (else
     (read file)
     (get-word (- x 1) file))))


  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  ;; Returns a list of blanks
  ;; equal to the number of
  ;; letters in provided word.
  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(define (init-display-word game_word)
  (cond 
    ((null? game_word)
     (list))
    (else
     (append (init-display-word (cdr game_word)) '("_")))))


  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  ;; Fills in the blank spaces
  ;; in the display word with
  ;; the letter that matches
  ;; those positions in the
  ;; game word.
  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

; No need for append here. Just use cons when adding to the start of the list. 
; No need to nest conds
(define (fill-in-guess letter game_word display_word)
  (cond
    ((null? game_word)
     '())
    ((equal? letter (car game_word))
     (cons letter (fill-in-guess letter (cdr game_word) (cdr display_word))))
    (else
     (cons (car display_word)
           (fill-in-guess letter (cdr game_word) (cdr display_word))))))

  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  ;; Draws the hanging man.
  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

; You used cond as an if/else statement. You can have multiple clauses in a cond.
; You only need one final else cluase.
(define (draw-hangman guesses_left)
  (cond ((equal? guesses_left 6)
         (display zero_wrong))
        ((equal? guesses_left 5)
         (display one_wrong))
        ((equal? guesses_left 4)
         (display two_wrong))   
        ((equal? guesses_left 3)
         (display three_wrong))
        ((equal? guesses_left 2)
         (display four_wrong))
        ((equal? guesses_left 1)
         (display five_wrong))
        (else (display six_wrong))))

; Don't sort the guessed-list. 
; You had display when guess left was 0. Not draw_hagman
(define (game-loop guessed_list display_word mistakes_left)
  (let ((n_mistakes_left 
         (- mistakes_left (if (contains? game_word (car guessed_list))
                              0 1))))   
    (if (= n_mistakes_left 0)
        (draw-hangman n_mistakes_left);; End game output
        (let ((display_word (fill-in-guess (car guessed_list) 
                                           game_word display_word)))

          (display "You have guessed: ")
            (display-list guessed_list ", ")
          (display "\n\n")
          (draw-hangman n_mistakes_left)
          (display "\n\nWord: ")
          (display-list display_word " ")

          (cond ((contains? display_word "_")
                 (display "\n\nEnter a letter to guess: ")
                 (game-loop (cons (symbol->string (read)) guessed_list)
                            display_word n_mistakes_left))
                (else (display "\n\nYou Won!")))))))

【讨论】:

    【解决方案2】:

    我将这个问题概括为不关注它的刽子手方面。问题立即得到了解答,cmets 进一步解释了错误的原因。您可以在这篇文章中找到所有这些信息:Scheme Recursion Loop Incorrect Values and Variable Binding

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-09-22
      • 1970-01-01
      • 1970-01-01
      • 2017-05-18
      • 2019-07-02
      • 1970-01-01
      相关资源
      最近更新 更多