Hunt the Wumpus: Difference between revisions

m
m (→‎{{header|Wren}}: Minor tidy)
(14 intermediate revisions by 6 users not shown)
Line 1:
{{task|Games}}
{{Clarify_task}}
Create a simple implementation of the classic textual game [http[w://en.wikipedia.org/wiki/Hunt_the_WumpusHunt the Wumpus|Hunt Thethe Wumpus]].
 
The rules are:
Line 40:
 
'''Wumpus package specification'''
<langsyntaxhighlight Adalang="ada">package Wumpus is
procedure Start_Game;
end Wumpus;
</syntaxhighlight>
</lang>
'''Wumpus package body'''
<langsyntaxhighlight Adalang="ada">with Ada.Numerics.Discrete_Random;
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Integer_Text_IO; use Ada.Integer_Text_IO;
Line 472:
 
end Wumpus;
</syntaxhighlight>
</lang>
'''Main procedure'''
<syntaxhighlight lang="ada">
<lang Ada>
with Wumpus; use Wumpus;
 
Line 481:
Start_Game;
end Main;
</syntaxhighlight>
</lang>
 
=={{header|BASIC}}==
<langsyntaxhighlight BASIClang="basic">10 DEFINT A-Z: DIM R(19,3),P(1),B(1)
20 FOR I=0 TO 19: READ R(I,0),R(I,1),R(I,2): NEXT
30 INPUT "Enter a number";X: X=RND(-ABS(X))
Line 535:
520 DATA 4,6,14, 5,7,16, 0,6,8, 7,9,17, 1,8,10
530 DATA 9,11,18, 2,10,12, 11,13,19, 3,12,14, 5,13,15
540 DATA 14,16,19, 6,15,17, 8,16,18, 10,17,19, 12,15,18</langsyntaxhighlight>
 
=={{header|APL}}==
Line 547:
 
=={{header|C++}}==
<syntaxhighlight lang="cpp">
<lang CPP>
// constant value 2d array to represent the dodecahedron
// room structure
Line 1,035:
}
 
</syntaxhighlight>
</lang>
 
=={{header|Common Lisp}}==
 
<syntaxhighlight lang="common lisp">
<lang Common Lisp>
;;; File: HuntTheWumpus.lisp
 
Line 1,400:
)
(StartGame)
</syntaxhighlight>
</lang>
 
=={{header|FORTRAN}}==
This code names rooms by alphabetic character, thereby making use of index function and simplifying the input to single characters. Compiled with gfortran, source compatible with FORTRAN 2008. You're welcome to move this content to a separate webpage.
Makefile
<syntaxhighlight lang="gnu make">
# gnu make
 
COMMON := -Wall -g -fPIC -fopenmp
override FFLAGS += ${COMMON} -ffree-form -fall-intrinsics -fimplicit-none
 
%: %.F08
gfortran -std=f2008 $(FFLAGS) $< -o $@
 
%.o: %.F08
gfortran -std=f2008 -c $(FFLAGS) $< -o $@
 
%: %.f08
gfortran -std=f2008 $(FFLAGS) $< -o $@
 
%.o: %.f08
gfortran -std=f2008 -c $(FFLAGS) $< -o $@
</syntaxhighlight>
The paint subroutine is a place-holder where is envisioned to place additional symbols representing possible hazards and determined hazards. With ANSI graphics or actual pictures. Source:
<syntaxhighlight lang="f08">
! compilation, linux. Filename htw.f90
! a=./htw && make $a && $a
 
! default answers eliminate infinite cycles,
! as does the deal subroutine.
 
module constants
implicit none
integer, parameter :: you = 1
integer, parameter :: wumpus = 2
integer, parameter :: pit1 = 3
integer, parameter :: pit2 = 4
integer, parameter :: bat1 = 5
integer, parameter :: bat2 = 6
character(len=20), parameter :: rooms = 'ABCDEFGHIJKLMNOPQRST'
character(len=3), dimension(20), parameter :: cave = (/ &
& 'BEH','ACJ','BDL','CEN','ADF','EGO','FHQ','AGI','HJR','BIK', &
& 'JLS','CKM','LNT','DMO','FNP','OQT','GPR','IQS','KRT','MPS' &
& /)
end module constants
 
program htw
use constants
implicit none
! occupied(you:you) is the room letter
character(len=bat2) :: occupied
! character(len=22) :: test ! debug deal
integer :: arrows
logical :: ylive, wlive
! get instructions out of the way
if (interact('Do you want instructions (y-n):') .eq. 'Y') then
call instruct
end if
! initialization
arrows = 5
call random_seed()
call deal(rooms, occupied)
! call deal(rooms, test) ! debug deal
! write(6,*) test(1:20) ! debug deal
ylive = .true.
wlive = .true.
write(6,*) 'Hunt the wumpus'
do while (ylive .and. wlive)
call paint(occupied(you:you))
call warn(occupied)
if (interact('Move or shoot (m-s):') .eq. 'S') then
call shoot(occupied)
arrows = arrows - 1
else
call move(occupied)
end if
wlive = 0 .lt. (index(rooms, occupied(wumpus:wumpus)))
ylive = (fate(occupied) .and. (0 .lt. arrows)) .or. (.not. wlive)
end do
if (wlive) then
write(6,*) 'The wumpus lives. Game over.'
else
write(6,*) 'You killed the wumpus lives. Game over.'
end if
 
contains
 
subroutine paint(room)
! interesting game play when the map must be deciphered
! The wumpus map was well known, so it is provided
implicit none
character(len=31), dimension(14), parameter :: map = (/ &
& ' A...................B ', &
& ' .. \ / . ', &
& ' . H-----I------J . ', &
& ' .. / | \ . ', &
& ' . G _ . R- _ \ . ', &
& ' .. / Q -S---K . ', &
& ' . / \ / \ . ', &
& ' . _-F_ \ / _L_ . ', &
& 'E - \_ /P-----T _/ \ C', &
& ' .. O/ \M/ ... ', &
& ' ... \__ _ / ... ', &
& ' ... \ N/ ... ', &
& ' ... | ... ', &
& ' ... D ' &
& /)
character(len=31) :: marked_map
character(len=1), intent(in) :: room
integer :: i, j
write(6,*)
do i=1, 14
marked_map = map(i)
j = index(marked_map, room)
if (0 < j) then
marked_map(j:j) = 'y'
end if
! write(6,'(a,6x,a)') map(i), marked_map ! noisy
write(6,'(6x,a)') marked_map
end do
write(6,*)
write(6,'(3a/)') 'you are in room ', room, ' marked with y'
end subroutine paint
 
function raise(c) ! usually named "to_upper"
! return single character input as upper case
implicit none
character(len=1), intent(in) :: c
character(len=1) :: raise
character(len=26), parameter :: lower_case = 'abcdefghijklmnopqrstuvwxyz'
character(len=26), parameter :: upper_case = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
integer :: n
n = index(lower_case, c)
if (n .ne. 0) then
raise = upper_case(n:n)
else
raise = c
end if
end function raise
 
function interact(prompt)
implicit none
! prompt, get answer, return as upper case
character(len=1) :: interact
character(len=*), intent(in) :: prompt
character(len=1) :: answer
write(6,*) prompt
read(5,*) answer
interact = raise(answer)
end
 
subroutine instruct
implicit none
write(6,*) 'Welcome to wumpus hunt'
write(6,*) ''
write(6,*) 'The wumpus sleeps within a cave of 20 rooms.'
write(6,*) 'Goal: shoot the wumpus with 1 of 5 crooked arrows.'
write(6,*) 'Each room has three tunnels leading to other rooms.'
write(6,*) 'At each turn you can move or shoot up to 5 rooms distant'
write(6,*) ''
Write(6,*) 'Hazards:'
write(6,*) ' 2 rooms have bottomless pits. Enter and lose.'
write(6,*) ' 2 rooms have giant bats. Enter & they carry you elsewhere.'
write(6,*) ' 1 room holds the wumpus. Enter and it eats you.'
write(6,*) ''
write(6,*) 'Warnings: Entering a room adjoining a hazard'
write(6,*) ' Pit "I feel a draft"'
write(6,*) ' Bat "Bat nearby"'
write(6,*) ' Wumpus "I smell a wumpus"'
write(6,*) ''
write(6,*) 'Shooting awakens the wumpus, which moves to an'
write(6,*) 'adjoining room with (75%) else stays put.'
write(6,*) 'The wumpus eats you if it enters your space.'
write(6,*) 'choose arrow path wisely lest you shoot yourself'
end subroutine instruct
 
integer function random_integer(n)
implicit none
! return a random integer from 1 to n
! replaces FN[ABC]
integer, intent(in) :: n
double precision :: r
call random_number(r)
random_integer = 1 + int(r * n)
end function random_integer
 
subroutine deal(deck, hand)
! deal from deck into hand ensuring to not run indefinitely
! by selecting from set of valid indexes
implicit none
character(len=*), intent(in) :: deck
character(len=*), intent(out) :: hand
integer, dimension(:), allocatable :: idx
integer :: k, j, n
n = len(deck)
allocate(idx(n))
do k=1, n
idx(k) = k
end do
do k=1, min(len(deck), len(hand))
j = random_integer(n)
hand(k:k) = deck(idx(j):idx(j))
idx(j:n-1) = idx(j+1:n) ! shift indexes
n = n - 1
end do
deallocate(idx)
end subroutine deal
 
subroutine warn(occupied)
use constants
implicit none
character(len=6), intent(in) :: occupied
character(len=3) :: neighbors
neighbors = cave(index(rooms, occupied(you:you)))
if (0 .lt. index(neighbors, occupied(wumpus:wumpus))) write(6,*) 'I smell a wumpus!'
if (0 .lt. (index(neighbors, occupied(pit1:pit1)) + index(neighbors, occupied(pit2:pit2)))) &
& write(6,*) 'I feel a draft.'
if (0 .lt. (index(neighbors, occupied(bat1:bat1)) + index(neighbors, occupied(bat2:bat2)))) &
& write(6,*) 'Bats nearby.'
! write(6,*) occupied ! debug
end subroutine warn
 
subroutine shoot(occupied)
use constants
implicit none
character(len=3), dimension(5), parameter :: ordinal = (/'1st','2nd','3rd','4th','5th'/)
character(len=6), intent(inout) :: occupied
character(len=5) :: path
character(len=3) :: neighbors
character(len=1) :: arrow ! location
integer :: i, j, n
logical :: valid
n = max(1, index(rooms(1:5), interact('Use what bow draw weight? a--e for 10--50 #s')))
! well, this is the intent I understood of the description
write(6,*) 'define your crooked arrow''s path'
do i=1, n
path(i:i) = interact(ordinal(i)//' ')
end do
! verify path
valid = .true.
do i=3, n ! disallow 180 degree turn
j = i - 1
valid = valid .and. (path(i:i) .ne. path(j:j))
end do
if (.not. valid) write(6,*)'Arrows are''t that crooked!'
! author David Lambert
arrow = occupied(you:you)
do i=1, n ! verify connectivity
j = index(rooms, arrow)
neighbors = cave(j)
if (0 .lt. index(neighbors, path(i:i))) then
arrow = path(i:i)
else
valid = .false.
end if
end do
if (.not. valid) then ! choose random path, which can include U-turn, lazy.
do i=1, n
j = index(rooms, arrow)
neighbors = cave(j)
call deal(neighbors, arrow)
path(i:i) = arrow
end do
end if
! ... and the arrow
i = mod(index(path, occupied(you:you)) + 6, 7)
j = mod(index(path, occupied(wumpus:wumpus)) + 6, 7)
if (i .lt. j) then
write(6, *) 'Oooof! You shot yourself'
occupied(you:you) = 'x'
else if (j .lt. i) then
write(6, *) 'Congratulations! You slew the wumpus.'
occupied(wumpus:wumpus) = 'x'
else ! wumpus awakens, rolls over and back to sleep or moves.
i = index(rooms, occupied(wumpus:wumpus))
neighbors = cave(i)
call deal(neighbors // occupied(wumpus:wumpus), occupied(wumpus:wumpus))
end if
end subroutine shoot
 
subroutine move(occupied)
use constants
implicit none
character(len=6), intent(inout) :: occupied
character(len=3) :: neighbors
integer :: i
neighbors = cave(index(rooms, occupied(you:you)))
i = index(neighbors, interact('Where to? '//neighbors//' defaults to '//neighbors(1:1)))
i = max(1, i)
occupied(you:you) = neighbors(i:i)
end subroutine move
 
logical function fate(occupied)
! update position of you and bat
! return
use constants
implicit none
character(len=6), intent(inout) :: occupied
character(len=1) :: y, w, p1, p2, b1, b2
integer :: i
y = occupied(you:you)
if (0 .eq. index(rooms, y)) then
fate = .false.
return
end if
w = occupied(wumpus:wumpus)
if (0 .eq. index(rooms, w)) then
fate = .true.
return
end if
p1 = occupied(pit1:pit1)
p2 = occupied(pit2:pit2)
b1 = occupied(bat1:bat1)
b2 = occupied(bat2:bat2)
! avoiding endless flight, the bats can end up in same room
! these bats reloacate. They also grab you before falling
! into pit.
if (w .eq. y) then
write(6,*)'You found the GRUEsome wumpus. It devours you.'
fate = .false.
return
end if
if ((b1 .eq. y) .or. (b2 .eq. y)) then
write(6,*)'A gigantic bat carries you to elsewhereville, returning to it''s roost.'
i = random_integer(len(rooms))
y = rooms(i:i)
occupied(you:you) = y
end if
if (w .eq. y) then
write(6,*)'and drops you into the wumpus''s GRUEtesque fangs'
fate = .false.
else if ((p1 .eq. y) .or. (p2 .eq. y)) then
write(6,*)'you fall into a bottomless pit'
fate = .false.
else
fate = .true.
end if
end function fate
 
end program htw
</syntaxhighlight>
short sample run
<pre>
$ ./htw
Do you want instructions (y-n):
n
Hunt the wumpus
 
A...................B
.. \ / .
. H-----I------J .
.. / | \ .
. G _ . R- _ \ .
.. / Q -S---K .
. / \ / \ .
. _-F_ \ / _L_ .
y - \_ /P-----T _/ \ C
.. O/ \M/ ...
... \__ _ / ...
... \ N/ ...
... | ...
... D
 
you are in room E marked with y
 
Bats nearby.
Move or shoot (m-s):
m
Where to? ADF defaults to A
x
A gigantic bat carries you to elsewhereville, returning to it's roost.
 
 
A...................B
.. \ / .
. H-----I------J .
.. / | \ .
. G _ . R- _ \ .
.. / Q -S---K .
. / \ / \ .
. _-F_ \ / _y_ .
E - \_ /P-----T _/ \ C
.. O/ \M/ ...
... \__ _ / ...
... \ N/ ...
... | ...
... D
 
you are in room L marked with y
 
I feel a draft.
Move or shoot (m-s):
m
Where to? CKM defaults to C
c
you fall into a bottomless pit
The wumpus lives. Game over.
</pre>
 
=={{header|FreeBASIC}}==
<langsyntaxhighlight lang="freebasic">data 7,13,19,12,18,20,16,17,19,11,14,18,13,15,18,9,14,16,1,15,17,10,16,20,6,11,19,8,12,17
data 4,9,13,2,10,15,1,5,11,4,6,20,5,7,12,3,6,8,3,7,10,2,4,5,1,3,9,2,8,14
data 1,2,3,1,3,2,2,1,3,2,3,1,3,1,2,3,2,1
Line 1,518 ⟶ 1,915:
print "You have slain the Wumpus!"
print "You have won!"
end</langsyntaxhighlight>
 
=={{header|Go}}==
Line 1,530 ⟶ 1,927:
 
4. If the Wumpus wakes up and moves to an 'adjacent' room, it means a room adjacent to the Wumpus not necessarily the player.
<langsyntaxhighlight lang="go">package main
 
import (
Line 1,692 ⟶ 2,089:
}
}
}</langsyntaxhighlight>
 
=={{header|Haskell}}==
 
<langsyntaxhighlight Haskelllang="haskell">import System.Random
import System.IO
import Data.List
Line 1,860 ⟶ 2,257:
putStrLn "*** HUNT THE WUMPUS ***"
putStrLn ""
playGame</langsyntaxhighlight>
 
=={{header|IS-BASIC}}==
<langsyntaxhighlight ISlang="is-BASICbasic">100 PROGRAM "Wumpus.bas"
110 RANDOMIZE
120 NUMERIC RO(1 TO 20,1 TO 3),LO(1 TO 20),WPOS
Line 1,936 ⟶ 2,333:
810 END DEF
820 DATA 2,6,5,3,8,1,4,10,2,5,2,3,1,14,4,15,1,7,17,6,8,7,2,9,18,8,10,9,3,11
830 DATA 19,10,12,11,4,13,20,12,14,5,11,13,6,16,14,20,15,17,16,7,18,17,9,19,18,11,20,19,13,16</langsyntaxhighlight>
 
=={{header|Java}}==
Line 1,946 ⟶ 2,343:
=={{header|Julia}}==
A translation from the original Basic, using the original Basic code and text at https://github.com/kingsawyer/wumpus/blob/master/wumpus.basic as a guide.
<langsyntaxhighlight lang="julia">const starttxt = """
 
ATTENTION ALL WUMPUS LOVERS!!!
Line 2,136 ⟶ 2,533:
end
end
</syntaxhighlight>
</lang>
 
=={{header|M2000 Interpreter}}==
For Windows only (in Linux you hear nothing, using Wine 3.6): In Sense() you can change Print with Speech so you Hear your sense;
 
<syntaxhighlight lang="m2000 interpreter">
<lang M2000 Interpreter>
Module WumpusGame {
Print "Game: Hunt The Wumpus"
Line 2,244 ⟶ 2,641:
WumpusGame
 
</syntaxhighlight>
</lang>
 
=={{header|MiniScript}}==
<langsyntaxhighlight MiniScriptlang="miniscript">exits = [[1,4,7], [0,2,9], [1,3,11], [2,4,13], [0,3,5],
[4,6,14], [5,7,16], [0,6,8], [7,9,17], [1,8,10],
[9,11,18], [2,10,12], [11,13,19], [3,12,14], [5,13,15],
Line 2,327 ⟶ 2,724:
break
end while
end while</langsyntaxhighlight>
 
=={{header|Nim}}==
{{trans|Go}}
<langsyntaxhighlight Nimlang="nim">import random, strformat, strutils
 
type Adjacent = array[3, int]
Line 2,463 ⟶ 2,860:
randomize()
var game = initGame()
game.play()</langsyntaxhighlight>
 
{{out}}
Line 2,495 ⟶ 2,892:
=={{header|Perl}}==
Besides running in a terminal, it also can run under xinetd.
<langsyntaxhighlight lang="perl">#!/usr/bin/perl
 
use strict; # see https://rosettacode.org/wiki/Hunt_the_Wumpus
Line 2,537 ⟶ 2,934:
}
else { print "I don't understand :(\n"; }
}</langsyntaxhighlight>
 
=={{header|Phix}}==
Line 2,548 ⟶ 2,945:
https://github.com/jburse/jekejeke-samples/raw/master/pack/games/wumpus-1.0.0.zip
 
<langsyntaxhighlight lang="prolog">
/**
* Simple text based dungeon game in Prolog.
Line 2,923 ⟶ 3,320:
write(' BAT - ''BATS NEARBY'''), nl,
write(' PIT - ''I FEEL A DRAFT'''), nl, nl.
</syntaxhighlight>
</lang>
 
=={{header|Python}}==
Line 2,929 ⟶ 3,326:
This implementation of "Hunt the Wumpus" follows is based on the rules of the original game (see discussion page for more information). It uses python 3 syntax and the standard library random.
 
<langsyntaxhighlight lang="python">
import random
 
Line 3,206 ⟶ 3,603:
WG.gameloop()
 
</syntaxhighlight>
</lang>
 
Example run (on a windows system):
 
<langsyntaxhighlight lang="cmd">
D:\Workspace\rosettacode>python wumpus.py
HUNT THE WUMPUS
Line 3,225 ⟶ 3,622:
 
Game over!
</syntaxhighlight>
</lang>
 
To create an example for a valid edge list, navigate to the folder where you saved wumpus.py, open up a python interactive shell and do:
 
<langsyntaxhighlight lang="cmd">
>>> import wumpus
>>> WG = wumpus.WumpusGame()
Line 3,235 ⟶ 3,632:
>>> print edges
[[1,2], [1,3], [1,4], [2,1], [2,5], [2,6], [3,1], ...]
</syntaxhighlight>
</lang>
 
=={{header|Quackery}}==
 
<syntaxhighlight lang="Quackery"> [ table
[ 1 4 7 ] [ 0 2 9 ] [ 1 3 11 ] [ 2 4 13 ]
[ 0 3 5 ] [ 4 6 14 ] [ 5 7 16 ] [ 0 6 8 ]
[ 7 9 17 ] [ 1 8 10 ] [ 9 11 18 ] [ 2 10 12 ]
[ 11 13 19 ] [ 3 12 14 ] [ 5 13 15 ] [ 14 16 19 ]
[ 6 15 17 ] [ 8 16 18 ] [ 10 17 19 ] [ 12 15 18 ] ] is adjacent ( n --> [ )
 
[ stack ] is player ( --> s )
[ stack ] is arrows ( --> s )
[ stack ] is wumpus ( --> s )
[ stack ] is bat1 ( --> s )
[ stack ] is bat2 ( --> s )
[ stack ] is pit1 ( --> s )
[ stack ] is pit2 ( --> s )
 
[ over find swap found ] is has ( [ n --> b )
 
[ dup dup size random peek join ] is addrand ( [ --> [ )
 
[ trim reverse trim reverse
$->n not if [ drop -1 ] ] is validate ( $ --> n )
 
[ say "A giant bat transports you to chamber "
20 random dup echo say "." cr
player replace
20 random swap replace ] is relocate ( s --> )
 
[ player share
dup bat1 share = iff
[ drop bat1 relocate ] again
dup bat2 share = iff
[ drop bat2 relocate ] again
dup pit1 share =
over pit2 share = or iff
[ say "You fell into a bottomless pit."
drop false ]
done
dup wumpus share = iff
[ say "The Wumpus eats you." drop false ]
done
say "You are in chamber " dup echo say "." cr
say "Adjacent chambers are: "
adjacent dup witheach
[ echo i 0 = iff [ say "." cr ]
else
[ say ", "
i 1 = if [ say "and " ] ] ]
say "You have " arrows share echo say " arrows." cr
dup wumpus share has if
[ say "You smell something terrible nearby." cr ]
dup bat1 share has
over bat2 share has or if
[ say "You hear a rustling." cr ]
dup pit1 share has
swap pit2 share has or if
[ say "You feel a cold wind "
say "blowing from a nearby chamber." cr ]
true ] is report ( --> b )
 
[ $ "Move to which chamber? " input validate
player share adjacent
dup addrand unrot find
peek player put true ] is move ( --> b )
 
[ true
$ "Shoot into which chambers? " input nest$
dup [] = if [ drop ' [ [ -1 ] ] ]
player share swap witheach
[ $->n not if [ drop -1 ]
swap adjacent
dup addrand unrot find peek
say "The arrow enters chamber "
dup echo say "." cr
dup player share = iff
[ say "You shot yourself." cr
dip not conclude ]
done
dup wumpus share = iff
[ say "You shot the Wumpus." cr
dip not conclude ]
done ]
drop dup while
say "You did not hit anything." cr
4 random 0 != if
[ wumpus take adjacent
3 random peek wumpus put ]
-1 arrows tally
arrows share 0 = if
[ say "You have run out of arrows." cr not ] ] is shoot ( --> b )
 
[ $ "Move or shoot? " input space join
0 peek upper dup char M = iff [ drop move ] done
char S = iff shoot done
again ] is action ( b --> b )
 
[ cr
say "Your mission is to anaesthetise an ailing "
say "Wumpus so that it can be healed." cr
say "It is in a dodecahedral labyrinth "
say "that is fraught with dangers." cr
say "The labyrinth has 20 chambers numbered 0 to "
say "19 which are connected by tunnels." cr cr
say "- The Wumpus will eat you if it sees you." cr
say "- Two of the chambers are bottomless pits." cr
say "- There are two giant bats that will "
say "transport you to a random chamber." cr cr
say "You can smell the Wumpus from an adjoining "
say "chamber. It smells terrible." cr
say "When you are in a chamber next to a bottomless "
say "pit you can feel a cold wind." cr
say "You can hear the giant bats rustle from a "
say "chamber away." cr cr
say "You are equipped with five progammable arrows." cr
say "They can be programmed with up to five "
say "adjoining chambers." cr
say "If a destination is invalid the arrow will move "
say "to a random adjoining chamber." cr cr
say "Be careful! Do not shoot yourself. Wumpus "
say "anasthetic is lethal to humans." cr
say "If you miss the Wumpus it will probably wake "
say "and move to an adjoining chamber." cr cr ] is rules ( --> )
 
[ say "Hunt the Wumpus, the Quackery cut." cr cr
randomise
5 arrows put
[] 20 times [ i join ] shuffle
' [ player wumpus bat1 bat2 pit1 pit2 ]
witheach [ dip behead put ]
drop
$ "Would you like to see the rules? " input
space join 0 peek upper char Y = if rules
[ report while
action while
cr again ]
' [ player arrows wumpus bat1 bat2 pit1 pit2 ]
witheach release ] is play ( --> )
 
play</syntaxhighlight>
 
{{out}}
 
Sample game.
 
<pre>Hunt the Wumpus, the Quackery cut.
 
Would you like to see the rules? y
 
Your mission is to anaesthetise an ailing Wumpus so that it can be healed.
It is in a dodecahedral labyrinth that is fraught with dangers.
The labyrinth has 20 chambers numbered 0 to 19 which are connected by tunnels.
 
- The Wumpus will eat you if it sees you.
- Two of the chambers are bottomless pits.
- There are two giant bats that will transport you to a random chamber.
 
You can smell the Wumpus from an adjoining chamber. It smells terrible.
When you are in a chamber next to a bottomless pit you can feel a cold wind.
You can hear the giant bats rustle from a chamber away.
 
You are equipped with five progammable arrows.
They can be programmed with up to five adjoining chambers.
If a destination is invalid the arrow will move to a random adjoining chamber.
 
Be careful! Do not shoot yourself. Wumpus anasthetic is lethal to humans.
If you miss the Wumpus it will probably wake and move to an adjoining chamber.
 
You are in chamber 13.
Adjacent chambers are: 3, 12, and 14.
You have 5 arrows.
You feel a cold wind blowing from a nearby chamber.
Move or shoot? m
Move to which chamber? 12
 
You are in chamber 12.
Adjacent chambers are: 11, 13, and 19.
You have 5 arrows.
You hear a rustling.
Move or shoot? m
Move to which chamber? 19
 
You are in chamber 19.
Adjacent chambers are: 12, 15, and 18.
You have 5 arrows.
Move or shoot? m
Move to which chamber? 12
 
You are in chamber 12.
Adjacent chambers are: 11, 13, and 19.
You have 5 arrows.
You hear a rustling.
Move or shoot? m
Move to which chamber? 11
 
A giant bat transports you to chamber 18.
You are in chamber 18.
Adjacent chambers are: 10, 17, and 19.
You have 5 arrows.
Move or shoot? s
Shoot into which chambers? 10 18 17 8 0
The arrow enters chamber 10.
The arrow enters chamber 18.
You shot yourself.
</pre>
 
=={{header|Racket}}==
 
<langsyntaxhighlight lang="racket">
#lang racket
 
Line 3,439 ⟶ 4,042:
(let ([current-game-state (new-game-state)])
(game-loop current-game-state)))
</syntaxhighlight>
</lang>
 
<langsyntaxhighlight lang="cmd">
Start the game with
 
Line 3,453 ⟶ 4,056:
 
S 2
</syntaxhighlight>
</lang>
 
=={{header|Raku}}==
(formerly Perl 6)
See [[Hunt_The_WumpusHunt the Wumpus/Raku]]
 
=={{header|Red}}==
<langsyntaxhighlight lang="red">
Red [
Title: "Hunt the Wumpus"
Line 3,784 ⟶ 4,387:
 
start
</syntaxhighlight>
</lang>
 
=={{header|Ruby}}==
Line 3,793 ⟶ 4,396:
 
=={{header|SenseTalk}}==
<langsyntaxhighlight lang="sensetalk">
-- HUNT THE WUMPUS
-- BY GREGORY YOB
Line 4,058 ⟶ 4,661:
end if
end move
</syntaxhighlight>
</lang>
 
=={{Header|Shale}}==
<langsyntaxhighlight lang="shale">
#!/usr/local/bin/shale
 
Line 4,517 ⟶ 5,120:
init()
toplevel()
</syntaxhighlight>
</lang>
 
=={{header|SparForte}}==
As a structured script.
<syntaxhighlight lang="ada">#!/usr/local/bin/spar
-- HUNT THE WUMPUS
 
pragma annotate( summary, "wumpus" );
pragma annotate( description, "Hunt the Wumpus" );
pragma annotate( description, "Originally for the PDP-8." );
pragma annotate( description, "The Timeless cave-crawling classic based on GW-BASIC source" );
pragma annotate( description, "www.ifarchive.org. Modified for SparForte by Ken O. Burtch." );
pragma annotate( description, "For sound effects, run as superuser" );
pragma annotate( author, "Ken O. Burtch" );
pragma license( unrestricted );
 
pragma ada_95; -- strict programming practices
pragma restriction( no_external_commands ); -- O/S independent
 
procedure wumpus is
 
type player_status is ( alive, won, lost );
status : player_status := alive; -- playing, winner, loser (was "f")
 
t_delim : constant character := ",";
tunnels : array(1..20) of string; -- adjacent room list
 
arrows : integer; -- number of arrows (was "a")
i : string; -- user input
player_room : positive; -- player room (was "l")
k : natural;
arrow_path : array(1..5) of positive; -- list of rooms for arrow (was "p")
 
type room_contents is ( player, wumpus, pit1, pit2, bats1, bats2 );
type room_list is array( player..bats2 ) of positive;
room : room_list; -- room contents (was "l()")
original_room : room_list; -- initial contents (was "m()")
 
good : boolean; -- for searches
soundfx : boolean := false;
 
begin
 
put_line( "HUNT THE WUMPUS" );
 
put( "SOUND EFFECTS (Y-N)? " );
i := get_line;
if i = "Y" or i = "y" then
soundfx := true;
end if;
 
put( "INSTRUCTIONS (Y-N)? " );
i := get_line;
if i = "Y" or i = "y" then
put_line( "WELCOME TO 'HUNT THE WUMPUS'" );
put_line( " THE WUMPUS LIVES IN A CAVE OF 20 ROOMS. EACH ROOM" );
put_line( "HAS 3 TUNNELS LEADING TO OTHER ROOMS. (LOOK AT A" );
put_line( "DODECAHEDRON TO SEE HOW THIS WORKS-IF YOU DON'T KNOW" );
put_line( "WHAT A DODECAHEDRON IS, ASK SOMEONE)" );
new_line;
put_line( " HAZARDS:" );
put_line( " BOTTOMLESS PITS - TWO ROOMS HAVE BOTTOMLESS PITS IN THEM" );
put_line( " IF YOU GO THERE, YOU FALL INTO THE PIT (& LOSE!)" );
put_line( " SUPER BATS - TWO OTHER ROOMS HAVE SUPER BATS. IF YOU" );
put_line( " GO THERE, A BAT GRABS YOU AND TAKES YOU TO SOME OTHER" );
put_line( " ROOM AT RANDOM. (WHICH MAY BE TROUBLESOME)" );
new_line;
put_line( " WUMPUS:" );
put_line( " THE WUMPUS IS NOT BOTHERED BY HAZARDS (HE HAS SUCKER" );
put_line( " FEET AND IS TOO BIG FOR A BAT TO LIFT). USUALLY" );
put_line( " HE IS ASLEEP. TWO THINGS WAKE HIM UP: YOU SHOOTING AN" );
put_line( " ARROW OR YOU ENTERING HIS ROOM." );
put_line( " IF THE WUMPUS WAKES HE MOVES (P=.75) ONE ROOM" );
put_line( " OR STAYS STILL (P=.25). AFTER THAT, IF HE IS WHERE YOU" );
put_line( " ARE, HE EATS YOU UP AND YOU LOSE!" );
new_line;
put_line( "HIT RETURN TO CONTINUE" );
i := get_line;
put_line( " YOU:" );
put_line( " EACH TURN YOU MAY MOVE OR SHOOT A CROOKED ARROW" );
put_line( " MOVING: YOU CAN MOVE ONE ROOM (THRU ONE TUNNEL)" );
put_line( " ARROWS: YOU HAVE 5 ARROWS. YOU LOSE WHEN YOU RUN OUT" );
put_line( " EACH ARROW CAN GO FROM 1 TO 5 ROOMS. YOU AIM BY TELLING" );
put_line( " THE COMPUTER THE ROOM#S YOU WANT THE ARROW TO GO TO." );
put_line( " IF THE ARROW CAN'T GO THAT WAY (IF NO TUNNEL) IT MOVES" );
put_line( " AT RANDOM TO THE NEXT ROOM." );
put_line( " IF THE ARROW HITS THE WUMPUS, YOU WIN." );
put_line( " IF THE ARROW HITS YOU, YOU LOSE." );
put_line( "HIT RETURN TO CONTINUE" );
i := get_line;
put_line( " WARNINGS:" );
put_line( " WHEN YOU ARE ONE ROOM AWAY FROM A WUMPUS OR HAZARD," );
put_line( " THE COMPUTER SAYS:" );
put_line( " WUMPUS: 'I SMELL A WUMPUS'" );
put_line( " BAT : 'BATS NEARBY'" );
put_line( " PIT : 'I FEEL A DRAFT'" );
end if;
 
-- *** SET UP CAVE (DODECAHEDRAL NODE LIST) ***
-- dim tunnels(20,3) but SparForte has no true 2-d arrays. So we'll fake-it using
-- 1-D arrays and text fields
 
tunnels(1) := "2,5,8";
tunnels(2) := "1,3,10";
tunnels(3) := "2,4,12";
tunnels(4) := "3,5,14";
tunnels(5) := "1,4,6";
tunnels(6) := "5,7,15";
tunnels(7) := "6,8,17";
tunnels(8) := "1,7,9";
tunnels(9) := "8,10,18";
tunnels(10) := "2,9,11";
tunnels(11) := "10,12,19";
tunnels(12) := "3,11,13";
tunnels(13) := "12,14,20";
tunnels(14) := "4,13,15";
tunnels(15) := "6,14,16";
tunnels(16) := "15,17,20";
tunnels(17) := "7,16,18";
tunnels(18) := "9,17,19";
tunnels(19) := "11,18,20";
tunnels(20) := "13,16,19";
 
-- *** LOCATE L ARRAY ITEMS ***
-- *** 1-YOU, 2-WUMPUS, 3&4-PITS, 5&6-BATS ***
 
loop
good := true;
for j in player..bats2 loop
room(j) := numerics.rnd(20);
original_room(j) := room(j);
end loop;
 
-- *** CHECK FOR CROSSOVERS (IE la(1)=la(2), ETC) ***
 
for j in player..bats2 loop
for k in player..bats2 loop
if j /= k then
if room(j) = room(k) then
good := false;
end if;
end if;
end loop;
end loop;
exit when good;
end loop;
 
-- *** SET NO. OF ARROWS ***
 
arrows := 5;
player_room := room(player);
 
-- *** RUN THE GAME ***
 
-- *** PRINT LOCATION & HAZARD WARNINGS ***
 
loop
 
new_line;
put_line( "YOU ARE IN ROOM " & strings.image( room(player) ) );
good := false; -- don't play bats twice
for j in wumpus..bats2 loop
for k in 1..3 loop
if numerics.value( strings.field( tunnels(room(player)), k, t_delim ) ) = room(j) then
case j is
when wumpus => put_line( "I SMELL A WUMPUS!" );
when pit1 => put_line( "I FEEL A DRAFT" );
when pit2 => put_line( "I FEEL A DRAFT" );
when bats1 => put_line( "BATS NEARBY!" );
if not good and soundfx then
sound.play( "./bats.wav" );
good := true;
end if;
when bats2 => put_line( "BATS NEARBY!" );
if not good and soundfx then
sound.play( "./bats.wav" );
good := true;
end if;
when others => put_line( "<<unexpected case j value>>" );
end case;
end if;
end loop;
end loop;
 
put_line( "TUNNELS LEAD TO " &
strings.field( tunnels(player_room), 1, t_delim) & " " &
strings.field( tunnels(player_room), 2, t_delim) & " " &
strings.field( tunnels(player_room), 3, t_delim) );
new_line;
 
-- Main Loop
-- *** MOVE OR SHOOT ***
 
loop
put( "SHOOT OR MOVE (S-M)" );
i := get_line;
if i = "S" or i = "s" then
i := "1";
exit;
elsif i = "M" or i = "m" then
i := "2";
exit;
end if;
end loop;
 
if i = "1" then
 
-- *** ARROW ROUTINE ***
 
declare
arrow_path_length : integer; -- was "j9"
begin
-- *** PATH OF ARROW ***
status := alive;
loop
put( "NO. OF ROOMS (1-5)" );
arrow_path_length := numerics.value( get_line );
exit when arrow_path_length >= 1 and arrow_path_length <= 5;
end loop;
 
for k in 1..arrow_path_length loop
loop
put( "ROOM #" );
arrow_path(k) := numerics.value( get_line );
exit when k <= 2;
exit when arrow_path(k) /= arrow_path(k-2);
put_line( "ARROWS AREN'T THAT CROOKED - TRY ANOTHER ROOM" );
end loop;
end loop;
 
-- *** SHOOT ARROW ***
 
good := false;
player_room := room(player);
for k in 1..arrow_path_length loop
for k1 in 1..3 loop
if numerics.value( strings.field( tunnels(player_room), k1, t_delim)) = arrow_path(k) then
good := true;
player_room := arrow_path(k);
if soundfx then
sound.play( "./arrow.wav" );
end if;
if player_room = room(wumpus) then
put_line( "AHA! YOU GOT THE WUMPUS!" );
status := won;
elsif player_room = room(player) then
put_line( "OUCH! ARROW GOT YOU!" );
if soundfx then
sound.play( "./scream.wav" );
end if;
status := lost;
end if;
end if;
end loop; -- k1
 
-- *** NO TUNNEL FOR ARROW ***
-- pick random direction
 
if not good then
player_room := numerics.value( strings.field( tunnels(player_room), numerics.rnd(3), t_delim ) );
 
if player_room = room(wumpus) then
put_line( "AHA! YOU GOT THE WUMPUS!" );
status := won;
elsif player_room = room(player) then
put_line( "OUCH! ARROW GOT YOU!" );
if soundfx then
sound.play( "./scream.wav" );
end if;
status := lost;
end if;
end if;
end loop; -- k
end; -- shoot declarations
 
player_room := room(player); -- player_room now player again
if status = alive then
put_line( "MISSED" );
 
-- MOVE THE WUMPUS
 
k := natural( numerics.rnd(4) );
if k /= 4 then
room(wumpus) := numerics.value( strings.field( tunnels(room(wumpus)), k, t_delim) );
if player_room = room(wumpus) then
put_line( "TSK TSK TSK - WUMPUS GOT YOU!" );
if soundfx then
sound.play( "./scream.wav" );
end if;
status := lost;
end if;
end if;
 
arrows := arrows-1;
if arrows < 1 then
put_line( "THE HUNT IS OVER. THAT WAS YOUR LAST ARROW" );
status := lost;
end if;
end if;
 
elsif i = "2" then -- move player
 
-- *** MOVE ROUTINE ***
status := alive;
loop
loop
put( "WHERE TO?" );
player_room := numerics.value( get_line );
exit when player_room >= 1 and player_room <= 20;
end loop;
-- *** CHECK IF LEGAL MOVE ***
 
if player_room = room(player) then
good := true;
else
good := false;
for k in 1..3 loop
if numerics.value( strings.field( tunnels(room(player)), k, t_delim) ) = player_room then
good := true;
end if;
end loop;
end if;
if good then
if soundfx then
sound.play( "./run.wav" );
end if;
loop
room(player) := player_room;
if player_room = room(wumpus) then
put_line( "... OOPS! BUMPED A WUMPUS!" );
k := natural( numerics.rnd(4) );
if k /= 4 then
room(wumpus) := numerics.value( strings.field( tunnels(room(wumpus)), k, t_delim) );
if player_room = room(wumpus) then
put_line( "TSK TSK TSK - WUMPUS GOT YOU!" );
if soundfx then
sound.play( "./run.wav" );
end if;
status := lost;
end if;
end if;
exit;
elsif player_room = room(pit1) or player_room = room(pit2) then
put_line( "YYYYIIIIEEEE . . . FELL IN PIT" );
if soundfx then
sound.play( "./pit.wav" );
end if;
status := lost;
exit;
elsif player_room = room(bats1) or player_room = room(bats2) then
put_line( "ZAP--SUPER BAT SNATCH! ELSEWHEREVILLE FOR YOU!" );
if soundfx then
sound.play( "./bats.wav" );
end if;
player_room := numerics.rnd(20);
else
exit;
end if;
end loop; -- bat loop
exit;
else
put( "NOT POSSIBLE -" );
end if;
end loop; -- good move loop
 
end if; -- if move or shoot
 
if status /= alive then
if status = lost then
-- *** LOSE ***
put_line( "HA HA HA - YOU LOSE!" );
else
-- *** WIN ***
put_line( "HEE HEE HEE - THE WUMPUS'LL GET YOU NEXT TIME!!" );
if soundfx then
sound.play( "./clap.wav" );
end if;
end if;
for j in player..bats2 loop
room(j) := original_room(j);
end loop;
return; -- restart not done
-- restart not done
--put( "SAME SETUP (Y-N)" );
--i := get_line;
--365 if (i$ <> "Y") and (i$ <> "y") then 170
end if;
end loop; -- main loop
 
end wumpus;
</syntaxhighlight>
 
=={{header|Swift}}==
{{trans|Go}}
<syntaxhighlight lang="swift">
import Foundation
 
//All rooms in cave
var cave: [Int:[Int]] = [
1: [2, 3, 4],
2: [1, 5, 6],
3: [1, 7, 8],
4: [1, 9, 10],
5: [2, 9, 11],
6: [2, 7, 12],
7: [3, 6, 13],
8: [3, 10, 14],
9: [4, 5, 15],
10: [4, 8, 16],
11: [5, 12, 17],
12: [6, 11, 18],
13: [7, 14, 18],
14: [8, 13, 19],
15: [9, 16, 17],
16: [10, 15, 19],
17: [11, 20, 15],
18: [12, 13, 20],
19: [14, 16, 20],
20: [17, 18, 19]
]
 
// initialize curr room, wumpus's room, bats room
var player: Int = 0, wumpus: Int = 0, bat1:Int = 0, bat2:Int = 0, pit1:Int = 0, pit2:Int = 0
 
//number of arrows left
var arrows = 5
 
//check if room is empty
func isEmpty(r:Int)->Bool {
if r != player &&
r != wumpus &&
r != bat1 &&
r != bat2 &&
r != pit1 &&
r != pit2 {
return true
}
return false
}
 
//sense if theres bat/pit/wumpus in adjacent rooms
func sense(adj: [Int]) {
var bat = false
var pit = false
for ar in adj {
if ar == wumpus {
print("You smell something terrible nearby.")
}
switch ar {
case bat1, bat2:
if !bat {
print("You hear rustling.")
bat = true
}
case pit1, pit2:
if !pit {
print("You feel a cold wind blowing from a nearby cavern.")
pit = true
}
default:
print("")
}
}
}
 
//check if there are more than 1 arrow then add plural to arrow message
func plural(n: Int)->String {
if n != 1 {
return "s"
}
return ""
}
 
 
func game() {
//set current room to 1, start the game
player = 1
//wumpus, bats, pits will be in a random room - except start room
wumpus = Int.random(in: 2..<21)
bat1 = Int.random(in: 2..<21)
//bat2 must be in different room to bat1
while true {
bat2 = Int.random(in: 2..<21)
if bat2 != bat1 {
break
}
}
//pit1 and pit2 must be in different rooms from bats and each other
while true {
pit1 = Int.random(in: 2..<21)
if pit1 != bat1 && pit1 != bat2 {
break
}
}
while true {
pit2 = Int.random(in: 0..<21)
if pit2 != bat1 && pit2 != bat2 && pit2 != pit1 {
break
}
}
//player session
while true {
print("\nYou are in room \(player) with \(arrows) arrow\(plural(n: arrows)) left\n")
//list of adjacent rooms
let adj = cave[player]!
print("The adjacent rooms are \(adj)\n")
//check adjacent rooms
sense(adj: adj)
//variable to keep track of next room player gonna choose
var room: Int?
while true {
print("Choose an adjacent room: ")
//validate the room player choose
if let roomInput = Int(readLine()!) {
room = roomInput
if !adj.contains(room!) {
print("\ninvalid response, try again\n")
print("The adjacent rooms are \(adj)\n")
} else {
break
}
} else {
print("\ninvalid response, try again\n")
print("The adjacent rooms are \(adj)\n")
}
}
//initialize variable to store user input/action(shoot or walk)
var action: String = ""
//player action
while true {
print("Walk or shoot w/s: ")
//validate the action player choose
if var reply = readLine() {
reply = reply.lowercased()
if reply.count != 1 || (reply.count == 1 && Array(reply)[0] != "w" && Array(reply)[0] != "s") {
print("Invalid response, try again")
} else {
//if valid store the action
action = Array(arrayLiteral: reply)[0]
break
}
} else {
print("Invalid response, try again")
}
}
if action == "w" {
//if walk, set current room to selected room
player = room!
switch player {
//if the selected room is wumpus/pit, player lose
case wumpus:
print("You have been eaten by the wumpus and lost the game")
return
case pit1, pit2:
print("You have fallen down a bottomless pit and lost the game!")
return
//if the room has bat, player got transport to a random empty room
case bat1, bat2:
while true {
room = Int.random(in: 2..<21)
if isEmpty(r: room!) {
print("A bat has transported you to a random empty room.")
player = room!
break
}
}
default:
break
}
} else {
//if player shoot to wumpus room, player win
if room == wumpus {
print("You have killed the wumpus and won the game!!")
return
} else {
//chance player will miss the room with wumpus, wumpus will move to a different room
let chance = Int.random(in: 0..<4)
if chance > 0 {
wumpus = cave[wumpus]![Int.random(in: 0..<3)]
//if the room is the player room, player lost
if player == wumpus {
print("You have been eaten by the wumpus and lost the game!")
return
}
}
}
//reduce arrow after shoot
arrows-=1
if arrows == 0 {
print("You have run out of arrows and lost the game!")
return
}
}
}
}
game()
 
</syntaxhighlight>
 
=={{header|Wren}}==
Line 4,524 ⟶ 5,737:
{{libheader|Wren-ioutil}}
{{libheader|Wren-str}}
<langsyntaxhighlight ecmascriptlang="wren">import "random" for Random
import "./fmt" for Fmt
import "./ioutil" for Input
import "./str" for Str
 
var cave = {
Line 4,635 ⟶ 5,848:
}
}
}</langsyntaxhighlight>
9,476

edits