wumpus.bush

# File : wumpus.bush

    #!/usr/local/bin/bush
    --
    -- *** HUNT THE WUMPUS ***
    --
    -- Originally for the PDP-8.
    -- The Timeless cave-crawling classing based on GW-BASIC source
    -- www.ifarchive.org.  Modified for BUSH by Ken O. Burtch.
    --

    pragma ada_95;                       -- strict programming practices
    pragma restriction( no_external_commands ); -- O/S independent

    procedure wumpus is

    LOGNAME : string := "<undefined>";
    pragma unchecked_import( shell, LOGNAME );

    type player_status is ( alive, won, lost );
    status : player_status := alive;     -- playing, winner, loser (was "f")

    type tunnel_list is array(1..20) of string;
    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" );

    if LOGNAME = "root" then
       put( "SOUND EFFECTS (Y-N)? " );
       i := get_line;
       if i = "Y" or i = "y" then
          soundfx := true;
       end if;
    else
       put_line( "For sound effects, run as the superuser" );
    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 BUSH 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;