How to resolve the algorithm Hunt the Wumpus step by step in the Racket programming language

Published on 12 May 2024 09:40 PM

How to resolve the algorithm Hunt the Wumpus step by step in the Racket programming language

Table of Contents

Problem Statement

Create a simple implementation of the classic textual game Hunt the Wumpus. The rules are: The game is set in a cave that consists of a 20 room labyrinth. Each room is connected to 3 other rooms (the cave is modeled after the vertices of a dodecahedron). The objective of the player is to find and kill the horrendous beast Wumpus that lurks in the cave. The player has 5 arrows. If they run out of arrows before killing the Wumpus, the player loses the game. In the cave there are: If the player enters a room with the Wumpus, he is eaten by it and the game is lost. If the player enters a room with a bottomless pit, he falls into it and the game is lost. If the player enters a room with a giant bat, the bat takes him and transports him into a random empty room. Each turn the player can either walk into an adjacent room or shoot into an adjacent room. Whenever the player enters a room, he "senses" what happens in adjacent rooms. The messages are: When the player shoots, he wins the game if he is shooting in the room with the Wumpus. If he shoots into another room, the Wumpus has a 75% of chance of waking up and moving into an adjacent room: if this is the room with the player, he eats him up and the game is lost.

Let's start with the solution:

Step by Step solution about How to resolve the algorithm Hunt the Wumpus step by step in the Racket programming language

Source code in the racket programming language

#lang racket

; Hunt the Wumpus

(require racket/random)

(struct game-state (labyrinth
                    player-location
                    number-of-arrows
                    wumpus-location
                    bat-locations
                    pit-locations) #:mutable #:transparent)

; The labyrinth-data list contains 20 lists that hold the information for
; each rooms connections to other rooms in the labyrinth.
; e.g. (1 2 5 8) shows that room 1 has connections to rooms 2, 5 and 8.

(define labyrinth-data '(
                         (1 2 5 8)
                         (2 1 3 10)
                         (3 2 4 12)
                         (4 3 5 14)
                         (5 1 4 6)
                         (6 5 7 15)
                         (7 6 8 17)
                         (8 1 7 9)
                         (9 8 10 18)
                         (10 2 9 11)
                         (11 10 12 19)
                         (12 3 11 13)
                         (13 12 14 20)
                         (14 4 13 15)
                         (15 6 14 16)
                         (16 15 17 20)
                         (17 7 16 18)
                         (18 9 17 19)
                         (19 11 18 20)
                         (20 13 16 19)))

(define example-game-state (game-state labyrinth-data
                                       1
                                       5
                                       2
                                       '(3 4)
                                       '(5 6)))

(define (new-game-state)
  (let ([ngs (game-state labyrinth-data 1 5 1 '(1 1) '(1 1))])
    (set-game-state-wumpus-location! ngs (safe-empty-room ngs))
    (set-game-state-bat-locations! ngs (list (safe-empty-room ngs)))
    (set-game-state-bat-locations! ngs (cons (safe-empty-room ngs)
                                             (game-state-bat-locations ngs)))
    (set-game-state-pit-locations! ngs (list (safe-empty-room ngs)))
    (set-game-state-pit-locations! ngs (cons (safe-empty-room ngs)
                                             (game-state-pit-locations ngs)))
    ngs))

(define (move-player room current-game-state)
  (set-game-state-player-location! current-game-state room))

(define (disturb-wumpus current-game-state)
  (if (<= (random) 0.75)
      (set-game-state-wumpus-location! current-game-state
                                       (room-for-wumpus-move current-game-state))
      #f))

(define (room-for-wumpus-move current-game-state)
  (let ([choices (append (neighbours
                          (game-state-wumpus-location current-game-state)
                          current-game-state)
                         (list (game-state-wumpus-location current-game-state)))])
    (findf (λ (room) (and (not (pit-room? room current-game-state))
                          (not (bat-room? room current-game-state)))) choices)))

(define (lost? current-game-state)
  (or (= (game-state-player-location current-game-state) (game-state-wumpus-location current-game-state))
      (member (game-state-player-location current-game-state)
              (game-state-pit-locations current-game-state))
      (= 0 (game-state-number-of-arrows current-game-state))))

(define (won? current-game-state)
  (= 0 (game-state-wumpus-location current-game-state)))

(define (shoot-arrow room current-game-state)
  (if (= room (game-state-wumpus-location current-game-state))
      (set-game-state-wumpus-location! current-game-state 0)
      (disturb-wumpus current-game-state))
  (set-game-state-number-of-arrows! current-game-state
                                    (- (game-state-number-of-arrows current-game-state) 1)))

(define (move-player-with-bats current-game-state)
  (set-game-state-player-location! current-game-state (safe-empty-room current-game-state)))

(define (safe-empty-room current-game-state)
  (let ([room (+ 1 (random 20))])
    (if (or (= room (game-state-wumpus-location current-game-state))
            (= room (game-state-player-location current-game-state))
            (member room (game-state-bat-locations current-game-state))
            (member room (game-state-pit-locations current-game-state)))
        (safe-empty-room current-game-state)
        room)))

(define (find-room room-number current-game-state)
  (assoc room-number (game-state-labyrinth current-game-state)))

(define (neighbours room-number current-game-state)
  (rest (find-room room-number current-game-state)))

(define (pit-room? room current-game-state)
  (member room (game-state-pit-locations current-game-state)))

(define (bat-room? room current-game-state)
  (member room (game-state-bat-locations current-game-state)))

(define (nearby? room-number entity-room-number current-game-state)
  (member entity-room-number (neighbours room-number current-game-state)))

(define (any-of-in? of-lst in-lst)
  (for/or ([item of-lst])
    (member item in-lst)))

(define (pit-nearby? room current-game-state)
  (any-of-in? (neighbours room current-game-state) (game-state-pit-locations current-game-state)))

(define (bat-nearby? room current-game-state)
  (any-of-in? (neighbours room current-game-state) (game-state-bat-locations current-game-state)))

(define (wumpus-nearby? room current-game-state)
  (member (game-state-wumpus-location current-game-state) (neighbours room current-game-state)))

(define (resolve-command str-list current-game-state)
  (let ([command (string-upcase (first str-list))]
        [room (string->number (second str-list))])
    (if (nearby? (game-state-player-location current-game-state)
                 room current-game-state)
        (cond [(equal? command "W") (if (bat-room? room current-game-state)
                                        (display-bat-attack current-game-state)
                                        (move-player room current-game-state))]
              [(equal? command "S") (shoot-arrow room current-game-state)]
              [else (displayln "Unknown command")])
        (displayln "You cannot move or shoot there!"))))

(define (display-bat-attack current-game-state)
  (move-player-with-bats current-game-state)
  (display "Argh! A Giant Bat has carried you to room ")
  (displayln (game-state-player-location current-game-state)))

(define (display-hazards current-game-state)
  (when (wumpus-nearby? (game-state-player-location current-game-state) current-game-state)
    (displayln "You smell something nearby."))
  (when (bat-nearby? (game-state-player-location current-game-state) current-game-state)
    (displayln "You hear a rustling."))
  (when (pit-nearby? (game-state-player-location current-game-state) current-game-state)
    (displayln "You feel a cold wind blowing from a nearby cavern.")))
         
(define (display-room-numbers lst)
  (display (string-join (map number->string lst) ", " #:before-last " or " #:after-last ".")))

(define (display-lost-message current-game-state)
  (cond [(= (game-state-player-location current-game-state)
            (game-state-wumpus-location current-game-state)) (displayln "The Wumpus has eaten you!")]
        [(member (game-state-player-location current-game-state)
                 (game-state-pit-locations current-game-state)) (displayln "You have fallen down a pit!")]
        [(= 0 (game-state-number-of-arrows current-game-state)) (displayln "You have run out of arrows.")]
        [else (displayln "Unknown loss")]))

(define (display-won-message current-game-state)
  (displayln "Congratulations, you have slain the Wumpus!"))

(define (display-information current-game-state)
  (display "You can (W)alk or (S)hoot to rooms ")
  (display-room-numbers (neighbours (game-state-player-location current-game-state) current-game-state))
  (newline)
  (display "You have ")
  (display (game-state-number-of-arrows current-game-state))
  (displayln " arrows left.")
  (display-hazards current-game-state))

(define (debug-game-state current-game-state)
  (display "    Player Location : ")
  (displayln (game-state-player-location current-game-state))
  (display "    Wumpus Location : ")
  (displayln (game-state-wumpus-location current-game-state))
  (display "    Bat Locations : ")
  (displayln (game-state-bat-locations current-game-state))
  (display "    Pit Locations : ")
  (displayln (game-state-pit-locations current-game-state)))

(define (game-loop current-game-state)
  ;(debug-game-state current-game-state)
  (display-information current-game-state)
  (resolve-command (string-split (read-line)) current-game-state)
  (cond [(lost? current-game-state) (display-lost-message current-game-state)]
        [(won? current-game-state) (display-won-message current-game-state)]
        [else (game-loop current-game-state)]))

(define (start-game)
  (let ([current-game-state (new-game-state)])
    (game-loop current-game-state)))


Start the game with

(start-game)

Then walk to a room with

W 2

Or shoot into a room with

S 2

  

You may also check:How to resolve the algorithm Singly-linked list/Traversal step by step in the Kotlin programming language
You may also check:How to resolve the algorithm Averages/Simple moving average step by step in the Logo programming language
You may also check:How to resolve the algorithm Character codes step by step in the 68000 Assembly programming language
You may also check:How to resolve the algorithm 100 doors step by step in the uBasic/4tH programming language
You may also check:How to resolve the algorithm Permutations step by step in the ooRexx programming language