递归方案函数值错误

时间:2014-10-01 05:52:48

标签: recursion scheme logic racket

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

在我的游戏中,我有一个变量,它保存了允许的错误数量,并且在我的游戏循环的每次递归调用中,如果需要更改,我将“值”设置为新值。这里有一些代码可以帮助我们了解如何运行游戏循环。

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

game_word - '(“a”“b”“c”)

display_word - 包含我已匹配的字母的字符串字符列表,以及那些我没有达到游戏循环迭代次数的字符串(ex'(“”“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!")))))))

我可以发布我的帮助方法包含?,fill-in-guess,display-list,draw-hangman,如果有必要,但是所有这些方法都可以正常运行,并且不会为了它们的功能而更改my mist_left变量的值。 / p>

我遇到的问题是我的mistakes_left变量从6开始并在游戏循环的第一次调用时通过罚款,但在后续调用中,即使在猜测正确的值时也会变小。我已经单独拍摄了每一件作品,并对其进行了测试,并且错误地给出了正确的值,直到我递归为止。

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

编辑:

以下是要测试的其余代码,我仍然遇到问题。我认为追加工作是因为它将第二个列表附加到第一个列表,所以在这个意义上,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))
      )))))))))))
  )

2 个答案:

答案 0 :(得分:1)

我对您的代码进行了一些修改。我在功能上面用注释标记了我的更改,并解释了它们。你的问题是你排序guessed_list。没有必要这样做。我测试了它,它的工作原理。请记住,如果您使用空的猜测列表调用game-loop,则会出错。要解决此问题,您需要测试guessed_list是否为空,并且还为减法返回0。我会把它留给你。 此外,在您的代码中的许多地方,您嵌套了cond s这是没有必要的。请在此处阅读: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!")))))))

答案 1 :(得分:0)

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