Hunt The Wumpus/Ruby

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

Ruby


NOTHING = 0; WUMPUS = 1; BAT = 2; PIT = 4; PLAYER = 8; FINISH = 1
PLAY_NEW = 2; PLAY_SAME = 4; S_PLAYER = 0;  MAX_ARROWS = 5; S_WUMPUS = 1
S_BAT1 = 2; S_BAT2 = 3; S_PIT1 = 4; S_PIT2 = 5; MAX_ROOMS = 20; SAVED = 6
MAX_EXITS = 3; A_PATH_LEN = 5
class Room
    attr_reader :obj
    @obj; @exit
    def initialize()
        @obj = NOTHING
        @exit = Array.new(MAX_EXITS) 
    end
    def get_exit(i)
        return @exit[i]
    end
    def clear(obj)
        @obj -= obj
        if @obj < NOTHING then @obj = NOTHING end
    end
    def empty()
        @obj = NOTHING
    end
    def set_exit(i, e)
        @exit[i] = e
    end
    def set_object(obj)
        @obj = @obj + obj
    end
end
class Cave
    @rooms
    def initialize()
        @rooms = Array.new(MAX_ROOMS)
        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, 14, 16, 19, 6, 15, 17, 8, 16, 18, 
                 10, 17, 19, 12, 15, 18]
        for i in 0..@rooms.length
            @rooms[i] = Room.new()
            r = i * MAX_EXITS; a = 0
            for e in r..(r + (MAX_ROOMS - 1))
                @rooms[i].set_exit(a, exits[e])
                a += 1
            end
        end
    end
    def clear_all_rooms()
        @rooms.each do |room|
            room.empty()
        end
    end
    def room(i)
        return @rooms[i]
    end
end
class Game
    @cave; @player; @wumpus; @arrows; @exits; @path; @saved; 
    @gameOver; @playerWins; @game_res
    
    def initialize()
        @player = MAX_ROOMS; @game_res = PLAY_NEW
        @exits = Array.new(MAX_EXITS); @path = Array.new(A_PATH_LEN);
        @saved = Array.new(SAVED); @cave = Cave.new()
        instructions()
    end
    def look()
        room = @cave.room(@player)
        puts "\n-----------------------------------"
        puts "You are in room ##{@player + 1}"
        print "Tunnels lead to rooms #: "
        
        @exits.each do |x|
            print "#{1 + x} " 
        end
        look_around()
    end
    def shoot(pathLen)
        room = @cave.room(@player)
        @path.each do |x|
            if exits(x)
                r = @cave.room(x)
            else 
                r = @cave.room(room.get_exit(rand(MAX_EXITS)))
             end
            obj = r.obj
            if ((WUMPUS & obj) == WUMPUS) 
                 @gameOver = true; @playerWins = true
                return
            end 
            if ((PLAYER & obj) == PLAYER) 
                @gameOver = true; @playerWins = false
                puts "  OUCH! Arrow got you!\n"
                return
            end
        end
        puts "  Missed!\n"; @arrows -= 1
        if @arrows == 0
            iputs "  You run out of arrows...\n"
            @gameOver = true; @playerWins = false
            return
        end
        wumpus(@player)
    end
    def result()
        if @playerWins
            puts "\n  AHA! You got the Wumpus!\n  HEE HEE HEE - " <<
            "The Wumpus'll getcha next time!!\n\n"
        else 
            puts "  HA HA HA - You lose!\n\n"
        end
        print "\nPlay again (Y/N)? "; i = gets[0].downcase
        if i == "y"
            print "Same setup (Y/N)? "; i = gets[0].downcase
            if i == "y" 
                return PLAY_SAME
            else
                return PLAY_NEW
            end
        end
        return FINISH
    end
    def look_around()
        msg = 0
        @exits.each do |x|
            obj = @cave.room(x).obj
            if ((WUMPUS & obj) == WUMPUS) then msg += WUMPUS end
            if ((BAT & obj) == BAT) then msg += BAT end
            if ((PIT & obj) == PIT) then msg += PIT end
        end
        puts "\n"
        if ((msg & WUMPUS) == WUMPUS) 
            puts "- You smell something terrible nearby." 
        end
        if ((msg & PIT) == PIT) 
            puts "- You feel a cold wind blowing from a nearby cavern." 
        end
        if ((msg & BAT) == BAT)
            puts "- You hear a rustling." 
        end
    end
    def exits(e)
        @exits.each do |x|
            return true if e == x
        end
        return false
    end
    def input()
        print "\nShoot or Move (S/M)? "; r = gets[0].downcase
        case r
            when "o"
                puts @cave.room(@player).obj
            when "m"
                print "Where to? "; ex = gets.to_i
                return false if ex == nil or ex < 0 or ex > MAX_ROOMS + 1
                ex -= 1
                if exits(ex)
                    set_player(ex)
                else 
                    puts "\nArrggh! --- You cannot go there!\n\n"
                end
                return true
            when "s"
                  pathLen = 0
                loop do
                    print "\nNumber of rooms (1-5)? "
                      pathLen = gets.to_i
                      break if pathLen > 0 and pathLen < (A_PATH_LEN + 1)
                end
                cnt = 0
                loop do
                    print "Room #"; n = gets.to_i
                    if n != nil and n > 0 and n < (MAX_ROOMS + 1)
                        @path[cnt] = n - 1
                        if cnt < 2 or @path[cnt] != @path[cnt - 2]
                            cnt += 1
                        else
                            puts "\nArrows aren't that crooked! - " <<
                            "Please, try another room.\n\n"
                        end
                    end
                    break if cnt == pathLen
                end
                shoot(pathLen)
                return true
        end
        return false
    end
    def set_player(pos)
        @cave.room(@player).clear(PLAYER) if @player < MAX_ROOMS 
        return if hazards(pos) 
        @player = pos
        room = @cave.room(@player)
        room.set_object(PLAYER)
        for i in 0..(MAX_EXITS - 1)
            @exits[i] = room.get_exit(i)
        end
    end
    def hazards(pos)
        room = @cave.room(pos); obj = room.obj
        if ((WUMPUS & obj) == WUMPUS)
            puts "\n  ...OOPS! Bumped a Wumpus!\n\n"
            if wumpus(pos)
                puts "\n  TSK TSK TSK - Wumpus got you!\n"
                @gameOver = true; @playerWins = false
                return true
            end
        end
        if ((PIT & obj) == PIT)
            puts "\n  YYYYIIIIEEEE!!!! Fell in pit!\n"
            @gameOver = true; @playerWins = false
            return true
        end
        if ((BAT & obj) == BAT)
            puts "\n  ZAP -- Super bat snatch! Elsewhereville for you!\n\n"
            set_player(rand(MAX_ROOMS))
            return true;
        end
        return false
    end
    def wumpus(pos)
        if rand(100) < 75 
            room = @cave.room(@wumpus)
            room.clear(WUMPUS)
            @wumpus = room.get_exit(rand(MAX_EXITS))
            @cave.room(@wumpus).set_object(WUMPUS)
        end
        return pos == @wumpus
    end
    def init()
        puts "\n\n\n\nHUNT THE WUMPUS\n---------------\n"
        @cave.clear_all_rooms(); @gameOver = false; @arrows = MAX_ARROWS
        if @game_res == PLAY_NEW
            @saved[S_PLAYER] = rand(MAX_ROOMS); set_player(@saved[S_PLAYER])
            @saved[S_BAT1] = fill_room(BAT); @saved[S_BAT2] = fill_room(BAT)
            @saved[S_PIT1] = fill_room(PIT); @saved[S_PIT2] = fill_room(PIT)
            @wumpus = @saved[S_WUMPUS] = fill_room(WUMPUS)
        else
            set_player(@saved[S_PLAYER]); @wumpus = @saved[S_WUMPUS]
            @cave.room(@wumpus).set_object(WUMPUS)
            @cave.room(@saved[S_BAT1]).set_object(BAT)
            @cave.room(@saved[S_BAT2]).set_object(BAT)
            @cave.room(@saved[S_PIT1]).set_object(PIT)
            @cave.room(@saved[S_PIT2]).set_object(PIT)
        end
    end
    def fill_room(obj)
        i = 0; room = nil
        loop do
            i = rand(MAX_ROOMS)
            room = @cave.room(i)
            break if room.obj == NOTHING
         end
        room.set_object(obj)
        return i
    end
    def instructions()
        print "\n\nWelcome to 'HUNT THE WUMPUS'\n\nInstructions (Y/N)? "; 
        return if gets.chomp.downcase == 'n'
        puts "\n\nThe Wumpus lives in a cave of 20 rooms: each room has 3 " <<
             "tunnels leading to other rooms.\n(Look at a Dodecahedron to " <<
             "see how this works, if you don't know what a dodecahedron is," <<
             " ask someone)\n\nHAZARDS:\n--------\n\nBottomless pits:\n" <<
             "----------------\nTwo rooms have bottomless pits in them " <<
             "- if you go there, you fall into the pit and lose!\n\nSuper" <<
             "bats:\n-----------\nTwo other rooms have super bats - if " <<
             "you go there, a bat grabs you and takes you to some other" << 
             " room at random,\nwhich might be troublesome.\n\nWumpus:\n-" <<
             "------\nThe Wumpus is not bothered by the hazards, he has " <<
             "sucker feet and is too big for a bat to lift. Usually he is " <<
             "asleep.\nTwo things wake him up: your entering his room or" <<
             " your shooting an arrow.\nIf the Wumpus wakes, he has 75% " <<
             "chance to move one room or 25% chance to stay still.\nAfter" <<
             " that, if he is where you are, he eats you up and you lose!" <<
             "\n\nYou:\n----\nEach turn you may move or shoot a crooked " <<
             "arrow.\n- Moving: you can move one room (thru one tunnel)" <<
             "\n- Arrows: you have 5 arrows. You lose when you run out.\n" <<
             "  Each arrow can go from 1 to 5 rooms, you aim by telling " << 
             "the computer the  rooms #s you want the arrow to go to.\n" <<
             "  If the arrow can't go that way (if no tunnel) it moves at" <<
             " random to the \n  next room.\n  If the arrow hits the " <<
             "Wumpus: you win, if the arrow hits you: you lose.\n \n\n" <<
             "WARNINGS:\n--------\nWhen you are one room away from " <<
             "Wumpus or any other hazard, the computer says:\nWumpus:" <<
             " 'You smell something terrible nearby.'\nBat: 'You hear" <<
             " a rustling.'\nPit: 'You feel a cold wind blowing from" <<
             " a nearby cavern.'\n\n\nPress return to play..."
        gets   
    end
    def main_loop()
        while @game_res != FINISH
            init()
            while not @gameOver 
                look()
                begin
                    i = input()
                end while not i
            end
            @game_res = result();
        end
    end
end
@game = Game.new().main_loop()