How to resolve the algorithm Hunt the Wumpus step by step in the FORTRAN programming language
How to resolve the algorithm Hunt the Wumpus step by step in the FORTRAN 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 FORTRAN programming language
Source code in the fortran programming language
# 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 $@
! 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
You may also check:How to resolve the algorithm Loops/Infinite step by step in the VBA programming language
You may also check:How to resolve the algorithm Enumerations step by step in the PHP programming language
You may also check:How to resolve the algorithm Execute Brain step by step in the AppleScript programming language
You may also check:How to resolve the algorithm Stair-climbing puzzle step by step in the AutoHotkey programming language
You may also check:How to resolve the algorithm Farey sequence step by step in the Sidef programming language