Hunt The Wumpus/Phix

From Rosetta Code
Hunt The Wumpus/Phix is part of Hunt_The_Wumpus. You may find other members of Hunt_The_Wumpus at Category:Hunt_The_Wumpus.

Phix version of Hunt The Wumpus .

Code[edit]

--Hunt the Wumpus
--the classic 70's game
--converted from the BASIC http://www.atariarchives.org/morebasicgames/showpage.php?page=179

--/*
include std/console.e
include std/text.e
include std/regex.e as re
include std/get.e
--*/
--/**/include get.e

--trying to stick closer to the spirit of the BASIC Wumpus!
constant YOU = 1, WUMPUS = 2, PITS1 = 3, PITS2 = 4, BATS1 = 5, BATS2 = 6, ARROWS = 7

---------------------------------------------------------------------------------------------
procedure instructions()
---------------------------------------------------------------------------------------------
    clear_screen()

    puts(1, "Welcome to Hunt the Wumpus\n")
    puts(1, "The wumpus lives in a cave of 20 rooms. Each room has 3 tunnels\n")
    puts(1, "leading to other rooms. (Look at a dodecahedron to see how this\n")
    puts(1, "works - if you don't know what a dodecahedron is, ask someone).\n")
    puts(1, "\n")
    puts(1, "Hazards\n")
    puts(1, "Bottomless pits - 2 rooms have bottomless pits in them. If you\n")
    puts(1, "  there you fall in (and lose). \n")
    puts(1, "Superbats - 2 other rooms have superbats. If you go there, a \n")
    puts(1, "  superbat grabs you and takes you to some other random room \n")
    puts(1, "  (which could be..... troublesome!\n")
    puts(1, "\n")
    puts(1, "The wumpus is not bothered by such hazards (he has sucker feet,\n")
    puts(1, "and is too big to lift). Usually he is asleep. Two things wake him\n")
    puts(1, "up : your entering his room, and your shooting an arrow.\n")
    puts(1, "If the wumpus wakes up, he moves one room (P=0.75) or stays\n")
    puts(1, "put (P=0.25). After that, if he is in the same room as you\n")
    puts(1, "he eats you up (and you lose), or he goes back to sleep!\n")
    puts(1, "\n")

--DEV
--/**/  puts(1,"Press any key..........")
--/**/  if wait_key() then end if
--/**/  puts(1,"\n")
--/*
    any_key("Press any key..........")
--*/

    puts(1, "Each turn, you may move, or shoot a crooked arrow.\n")
    puts(1, "  Moving - you can move one room (through a tunnel)\n")
    puts(1, "  Shooting - you have 5 arrows - you lose when you run out.\n")
    puts(1, "  Each arrow can go through 1 to 5 rooms, you aim by telling\n")
    puts(1, "  the computer the rooms you want it to go through. If the arrow\n")
    puts(1, "  can't go that way (no tunnel, it moves at random to an adjacent \n")
    puts(1, "  room. If the arrow hits the wumpus, you win, if it hits you,\n")
    puts(1, "  you lose.\n")
    puts(1, "\n")
    puts(1, "When you are 1 room away from a hazard, the computer will say\n")
    puts(1, "  Wumpus   - I smell a wumpus\n")
    puts(1, "  Bats     - Bats nearby\n")
    puts(1, "  Pit      - I feel a draft\n")
    puts(1, "\n")
    puts(1, "Good luck!\n")

    if wait_key() then end if

end procedure

---------------------------------------------------------------------------------------------
function initialise_caves()
    ---------------------------------------------------------------------------------------------
    -- Remember to swap row and column from the BASIC source in future references
    return {{2,5,8}, {1, 3, 10}, {2, 4, 12}, {3, 5, 14}, {1, 4, 6},
            {5, 7, 15}, {6, 8, 17}, {1, 7, 9}, {8, 10, 18}, {2, 9, 11},
            {10, 12, 19}, {3, 11, 13}, {12, 14, 20}, {4, 13, 15}, {6, 14, 16},
            {15, 17, 20}, {7, 16, 18}, {18, 9, 17}, {19, 11, 18}, {20, 13, 16, 19}}
end function

---------------------------------------------------------------------------------------------
function ask(sequence prompt, sequence filter)
---------------------------------------------------------------------------------------------
/*
print prompt and wait for an answer
filter is a regular expression to filter answer
*/
--/**/ -- Phix: filter is either "[ms]" or "[yn]", do it without regex...
--/*
re:regex valid_answer=re:new(filter,CASELESS)
--*/
sequence answer

    puts(1,prompt)
--/**/ filter = filter[2..-2]
    while 1 do
        answer = gets(0)
        answer = answer[1..$-1]
--/**/  answer = lower(answer)
--/**/  if length(answer)=1 and find(answer[1],filter) then
--/*
        if sequence(re:find(valid_answer,answer)) then
--*/
            exit
        else
            puts(1,"\ninvalid answer, try again\n"&prompt)
        end if
    end while
    return answer
end function

---------------------------------------------------------------------------------------------
function mkStatusList()
---------------------------------------------------------------------------------------------
sequence status = {0,0,0,0,0,0,5} --setting [7] to arrow count
    sequence list = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20}
    integer r
    for i = 1 to 6 do
        r = rand(20) -- select a number between i and 20 inclusive
        status[i] = list[r]  -- copy the value to status
        list[r] = list[i]    -- removing list[r] from the list
    end for
    return status
end function

---------------------------------------------------------------------------------------------
procedure show_where_you_are(sequence status, sequence caves)
    ---------------------------------------------------------------------------------------------
    printf(1, "You are in room %d\n", {status[YOU]})

    printf(1, "There are tunnels leading to rooms ", {})

    for i = 1 to length(caves[status[YOU]]) do
        printf(1, "%d ", {caves[status[YOU]][i]})
    end for

    puts(1, "\n")

end procedure

---------------------------------------------------------------------------------------------
procedure detect_hazards(sequence status, sequence caves)
---------------------------------------------------------------------------------------------
sequence hzd = {}

    if find(status[BATS1],caves[status[YOU]]) or find(status[BATS2],caves[status[YOU]]) then
        hzd = append(hzd, "Bats nearby!")
    end if

    if find(status[PITS1],caves[status[YOU]]) or find(status[PITS2],caves[status[YOU]]) then
        hzd = append(hzd, "I feel a draft!")
    end if

    if find(status[WUMPUS],caves[status[YOU]]) then
        hzd = append(hzd, "I smell a wumpus!")
    end if

    if length(hzd) = 0 then
        return
    end if

    for i = 1 to length(hzd) do
        puts(1, hzd[i] & "\n")
    end for

end procedure

---------------------------------------------------------------------------------------------
function move_hunter(sequence status, sequence caves)
---------------------------------------------------------------------------------------------
object dest_room
sequence s

    s = prompt_string("\nMove to which room? ")
    dest_room = value(s)
    dest_room = dest_room[2]

    if find(dest_room, caves[status[YOU]] ) = 0 then
        puts(1, "You cannot get to that room from here!\n\n")
        return status
    end if

    puts(1, "\n")
    status[YOU] = dest_room
    return status
end function

---------------------------------------------------------------------------------------------
function detect_entered_hazards(sequence status, sequence caves)
    ---------------------------------------------------------------------------------------------
    --bats
    if status[YOU] = status[PITS1] or status[YOU] = status[PITS2] then
        puts(1, "AAAAARRGGHHHHH! Fell in a pit!\n")
        status[YOU] = -1
        return status
    end if

    if status[YOU] = status[BATS1] or status[YOU] = status[BATS2] then
        puts(1, "Bats grabbed you - off to another room!\n")
        while 1 do
            status[YOU] = rand(20)
            --don't want the hunter in a room with the wumpus, bats or pits!
            if status[YOU] = status[BATS1] or status[YOU] = status[BATS1] or
            status[YOU] = status[PITS1] or status[YOU] = status[PITS1] or
            status[YOU] = status[WUMPUS] then
                continue
            else
                exit
            end if
        end while
        return status
    end if

    if status[YOU] = status[WUMPUS] then
        puts(1, "Munch munch, gobble gobble. Wumpus ate you!\n")
        status[YOU] = -1
    end if

    return status
end function

---------------------------------------------------------------------------------------------
function shoot_arrow(sequence status, sequence caves)
--fires an arrow through a number of rooms
--if you miss the wumpus, it wakes up, and moves to another room
--if you hit it, the wumpus is dead.
---------------------------------------------------------------------------------------------
object nr, ar, current_arrow_room
integer nwr

    status[ARROWS] -= 1
    current_arrow_room = status[YOU]

    puts(1, "\n")

    while 1 do
        nr = prompt_string("No. of rooms : ")
        nr = value(nr)
        nr = nr[2]
        if nr >= 1 and nr <= 5 then exit end if
        puts(1, "Between 1 and 5 rooms please.\n")
    end while

    for i = 1 to nr do
        while 1 do
            --? caves[current_arrow_room]  --uncomment this for an easier game
            ar = prompt_string("Which room : ")
            ar = value(ar)
            ar = ar[2]

            if find(ar, caves[current_arrow_room]) = 0 then
                puts(1, "Arrows aren't that crooked - try another room!\n")
                continue
            end if
            exit
        end while

        current_arrow_room = ar

        --check for pesence of wumpus
        if current_arrow_room = status[WUMPUS] then
            status[WUMPUS] = -1
            return status
        end if

        --check if you've shot back into your room
        if current_arrow_room = status[YOU] then
            puts(1, "Ouch, you shot yourself - luckily in the head, no damage!")
            exit
        end if
    end for

    --didn't get the Wumpus then, but woke it up
    nwr = rand(3)
    status[WUMPUS] = caves[status[WUMPUS]][nwr]
    if status[WUMPUS] = status[YOU] then
        puts(1, "Munch munch, gobble gobble. Wumpus ate you!\n")
        status[YOU] = -1
        return status
    end if

    if status[ARROWS] = 0 then
        status[YOU] = -1
        puts(1, "You ran out of arrows!\n")
    end if

    return status
end function

---------------------------------------------------------------------------------------------
procedure start_game(sequence status, sequence caves)
---------------------------------------------------------------------------------------------
sequence response

    while 1 do
        show_where_you_are(status, caves)
        detect_hazards(status, caves)
        response = ask("Move or shoot (m/s)", "[ms]")

        if response[1] = 'm' then
            status = move_hunter(status, caves)
            status = detect_entered_hazards(status, caves)
        else
            status = shoot_arrow(status, caves)
        end if

        if status[YOU] = -1 then
            puts(1, "You're dead!\n")
            return
        end if

        if status[WUMPUS] = -1 then
            puts(1, "You heartless fiend - you killed a defenceless Wumpus!\n")
            return
        end if

    end while

end procedure
---------------------------------------------------------------------------------------------
procedure main()
---------------------------------------------------------------------------------------------
sequence inp
sequence caves
sequence status

    inp = upper(prompt_string("Do you want instructions? (y/n)"))
    if inp[1] = 'Y' then
        instructions()
    end if

    while 1 do
        caves = initialise_caves()
        status = mkStatusList()
        start_game(status, caves)
        inp = upper(ask("Play again?", "[yn]"))
        if inp[1] = 'N' then exit end if
    end while
end procedure

main()