The Great Wumpus Hunt

22

2

COMPLETE

Wumpus season has ended, and with, the lives of many a vicious Wumpus and brave Hunter. As well as some cowardly, immoral and downright stupid Hunters. But at the end of the day, NascarHunter by Dr Heckle came away with the most loot and glory. We salute you, oh brave... driver?

It's open season on Wumpuses, and hunters from around the world are flocking to the Wumpus Caves to try to get rich of off valuable Wumpus Pelts.

The Game

Based on the classic Hunt the Wumpus game, with a few variations.

The Map

A dodecahedron. There are 20 rooms, each connected to 3 other room, making basically 3 rings with bridges in between.

The Wumpus

The Wumpus is a mystical beast. None are sure what it looks like, but all agree that it is ferocious. The Wumpus lives in the caves, and likes to eat dead things. If there is a corpse in a cave next to the Wumpus, he will move there and eat it. If the Wumpus happens to move into a cave containing hunters, he will kill and eat them as well. If the Wumpus hears an arrow near him, he will panic and run into a random room.

Optional traits: These are currently included to make the game more interesting, but can be removed at popular request if they add too much randomness.

Enraged Wumpus: If the Wumpus is shot, he has a 20% of surviving and rampaging for 3 days. When rampaging, he will randomly move twice a day, but still be attracted to corpses. After 3 days, he will die. A second arrow shot will also kill the Wumpus.

Wandering Wumpus: Each day, if nothing else triggers the Wumpus, he has a 25% chance of moving.

The Hunters

Four hunters can enter the caves at a time. The caves are dark, so the hunters cannot see, but they can use their other senses. Hunters can smell the Wumpus in an adjacent room, smell a corpse in an adjacent room, hear other hunters moving in adjacent rooms, and hear if an arrow is shot into an adjacent room.

Hunters have two actions: Shoot or move. A hunter can shoot an arrow into an adjacent room or his own room, and move similarly.

Gameplay

In each round, hunters will first take note of their surroundings, and then make one move. Movement occurs before arrows, so if an arrow is shot into a room that a hunter is moving out of, the hunter will survive. After all hunter moves have been made, the arrows are evaluated. If a single occupant and arrow are in the same room, the occupant will be shot and die. If two or more occupants share a room, one will randomly be hit and die. Note: Corpses are occupants, so a dead body may serve as a partial shield.

After all hunter moves, the Wumpus will respond. If a hunter has moved into the room with the Wumpus, the Wumpus will eat him/her. If the Wumpus moves, it will also eat the occupants of the new room.

After 100 days, if the hunters have not killed the Wumpus, or fallen victim, they will die of starvation within the caves.

The Code

All source code can be found here. All submissions should be in Java, unless somebody wants to write me a stdIn/stdOut adaptor ;)

Bots should extend the Hunter class. To name your Hunter, add a constructor with no parameters that sets the name field. T o respond, override the getResponse function. In this function, each turn, you will be passed an array of 5 booleans that tells you about your surroundings.

status 0 = "You smell a wumpus"

status 1 = "You hear another hunter"

status 2 = "You smell a corpse"

status 3 = "You hear an arrow clatter"

status 4 = "You feel another hunter in the same room as you"

The Hunter class has 2 slots: nextMove and nextDirection, that use the enums Move and Direction respectively. Move can either be MOVE or SHOOT, direection can be LEFT, RIGHT, BACK, or HERE. Directions are consistent, meaning back will always return you to the previous room you were in, and if entering from the same room, LEFT and RIGHT will always be the same. However, if you enter from a different direction, LEFT and RIGHT will take you to different places.

Feel free to implement your own methods as well. Memory is persistent throughout the whole tournament, meaning your hunter will only be constructed once. However, at the start of each round, the newGame() method is called to let your hunter know a new game has started.

Scoring

Four hunters compete at a time. If killed, the Wumpus pelt is worth 60 points, split evenly among all surviving hunters. Full round robin style, so each combination of 4 hunters will play together.

5 sample Hunters are included: 4 with very basic functionality, and one that allows user input to play, for testing purposes.

If you have any suggestions/requests, please let me know!

The End is in sight!

The worlds Wumpus population is being hunted at an alarming rate. The Protect Our Wumpuses Act is expected to be passed on Wednesday, June 17th. After this date, no more hunters will be allowed in the caves, and a winner will be chosen.

Scoreboard

Note : My apologies, there was a bug in the code that could cause Hunters to stay dead through multiple games. Having fixed it, it does not change the overall rankings very much, but does largely change the stats.

Scores are in, running each set of hunter in 1000 games each. NascarHunter and FullCoverageHunter lead the pack, and although the addition of AntiHunter has given the Wumpuses a 2% survival boost, they are still shaking in their suckered feet at the 32% survival rate of their kind. Arrows from fellow hunters are more than ever the biggest threat in the caves.

1. NascarHunter : 16557175 (17.08)
2. FullCoverageHunter : 15195545 (15.68)
3. Trig : 14459385 (14.92)
4. Idomeneus : 13428570 (13.85)
5. Eats Shoots and Leaves : 12763945 (13.17)
6. WalkingIdiot : 12329610 (12.72)
7. NealHunter : 12287140 (12.68)
8. Unnamed : 11013720 (11.36)
9. MonsterHunter : 10686035 (11.02)
10. Pacer : 9187000 (9.48)
11. Badger : 9042570 (9.33)
12. Stay : 8721210 (9.0)
13. Emo Wumpus : 7831050 (8.08)
14. Paranoid : 7722965 (7.97)
15. Huddle : 7465420 (7.7)
16. ElmerFudd : 7245995 (7.47)
17. Laomedon : 6963845 (7.18)
18. Pacifist : 6944960 (7.16)
19. ScaredyCat : 6937370 (7.15)
20. Wumpus : 114170 (0.11)



Total rounds: 4845000
Humans killed by arrows: 5289674 (1.09)
Humans dead by starvation: 1046024 (0.21)
Humans killed by wumpus: 1887634 (0.38)
Wumpus victories: 1563372 (0.32)

Cain

Posted 2015-06-03T21:02:02.010

Reputation: 1 149

1Can you hit another hunter with an arrow? – MegaTom – 2015-06-03T21:48:43.427

1Yessir, or yourself if you shoot an arrow at HERE – Cain – 2015-06-03T21:52:10.653

Are we allowed to examine the entire map when coming up with the move? Given that a hunter can get the current room and each room has pointers to its neighbors it should be possible to know where the wumpus and all other humans are. – Ralph Marshall – 2015-06-04T00:03:53.007

Room is actually not visible to anything that extends Hunter, because it's private not protected. So although your hunter contains a reference to the room it's in, it can't actually access it from code. So no, your hunter can't actually get the room, just the status update passed to it from getResponse – Cain – 2015-06-04T00:21:31.537

Is this by chance inspired by the Microsoft hunt the Wumpus competition? – Kyranstar – 2015-06-04T03:37:49.367

@Cain Can I submit more than one Hunter ? :p Also, tehre's a problem with your description. Room.getInfo() actually give an array of 5 boolean, not 4. The fifth one (index 4) is for when there is a Hunter in the same room as you. – Katenkyo – 2015-06-04T08:40:16.470

1Instead of an array for 5 booleans, why not just pass an int valued 0-31? We're big boys here, we can do bit operations :) – DoctorHeckle – 2015-06-04T14:05:43.327

1@DoctorHeckle Sure we are, but it's still more dev-friendly to have an array rather than a single int ^^. – Katenkyo – 2015-06-04T14:49:37.717

More than one Hunter is fine, actually if you can create multiple hunters that work together, all the better. Just keep them with at least tangibly different logic. – Cain – 2015-06-04T15:01:48.040

@Cain No problem. And thanks, will try to work on multiple hunters :). By the way, there's a problem when you write the scores. The amount of human killed by arrows and the number of wumpus wins are false. You used a bad index :) Ho, and **** Trigger, he's winning the more points out of all the current submissions x) – Katenkyo – 2015-06-04T15:11:46.790

Haha also fixed the index while I was in there, I was getting more wumpus victories than games. The trend so far seems to be the more shooting the better haha, I was hoping a little altruism might pay off, but haven't seen it yet – Cain – 2015-06-04T16:07:38.723

Quick mechanics question for @Cain:

  1. If I'm in the same room as a hunter, and Shoot.HERE, I'll kill them and not myself, correct? If there are more than one other hunters in the room, do I randomly kill another hunter?

  2. If I enter a room with a corpse, and the Wumpus comes in, will the Wumpus eat me first, or go for the corpse?

  3. Do stati 0, 2, and 3 refer to surrounding rooms AND the currently occupied room, or EXCLUSIVELY surrounding rooms?

  4. < – DoctorHeckle – 2015-06-04T16:07:46.533

@Katenkyo what's even more depressing is that RandomHunter seems to do just as well :( – euanjt – 2015-06-04T16:08:40.293

>

  • If you're in the same room and shoot here, you could kill yourself or the other hunter, it's very dark in there. 2. Anytime you are in a room with the Wumpus, you die. Although, I do like the idea of the Wumpus eating the corpse first, I could maybe add that. And then remove the corpse after, so the Wumpus doesn't get bogged down in one spot so much.
  • < – Cain – 2015-06-04T16:10:40.240

    But for now, being in the same room = death, and corpses are permanent – Cain – 2015-06-04T16:10:55.047

    Can you detect an arrow, a hunter, or a corpse in your own room? – feersum – 2015-06-04T16:16:02.267

    1For arrows and corpses, if one is in the same room as you you get the same status as if it is adjacent. Hunters are the only ones you can distinguish between being next to the room or in the room. – Cain – 2015-06-04T19:17:00.777

    @Cain The Wumpus with by starvation not because the number of days is too small, but because some entry don't move, and will never fight with the wumpus. And even when they move, if there is only 1 hunter remaining, there's a high chance he will never meet it. Anyway, I'm glad my MonsterHunter did 5/13 :D – Katenkyo – 2015-06-08T07:07:49.690

    @ Katenkyo Yeah, you're right, especially because the Wumpus becomes mostly stationary after finding a corpse – Cain – 2015-06-08T18:19:24.280

    Lots of competition! I dig it. For when Wumpus Season is over, I'd love to see which quartet is the most successful in addition to which individual hunter is most successful. – DoctorHeckle – 2015-06-08T20:26:38.383

    Am I allowed to use a language that compiles to Java (e.g. Kotlin or Scala)? – kirbyfan64sos – 2015-06-09T20:25:40.103

    If hunters are only constructed once and asked to reset each round, does that mean we can make a hunter that behaves differently depending on the round? Or do we have to reset everything each round? Basically, is it against the rules to carry over player state between rounds? – Stuntddude – 2015-06-12T04:51:56.537

    Carrying over state between rounds is completely acceptable, just be aware that you may be with different hunters as well, and have no way of knowing this. – Cain – 2015-06-12T15:31:54.230

    Well, was fun, I'm happy seeing MonsterHunter is 9/20 ! Well done for doing such a great KotH :). Do you think you'll do a variant of the wumpus hunt one day? By the way, Congratulations to @DoctorHeckle ! – Katenkyo – 2015-06-18T07:24:18.667

    @Katenkyo Thanks! Yeah, I definitely might re-visit this someday, personally I felt like the game design partially failed, when a bot that didn't use any of the statuses for along time stil wrecked as hard as it did. Basically, shooting everywhere was too strong a strategy to reward anything more clever :P My goal would be to see people mapping the caves, setting corpse traps, triangulating the wumpus, etc. But I've got a very different KotH cooked up for next week ;) – Cain – 2015-06-18T16:00:10.787

    Thanks much @Katenkyo! It appears that Occam's Razor was a little too sharp for this KotH. I'm gonna keep my eyes peeled for the next competition, @Cain. This one was a lot of fun! – DoctorHeckle – 2015-06-19T03:33:36.963

    Answers

    11

    NascarHunter

    Not much logic to it. Its rules are simple: turn left, scorched earth, repeat. And, hey, he might get lucky!

    8 June edit:

    Added in additional logic to Nascar to account of adjacency to a Wumpus relative to its last move. Consider it a pit stop, to stay in theme. If it sense a Wumpus after shooting down a hallway, then it must have arrived in one of the other two adjacent rooms, since it would've died to the shot the hunter just took. It effectively give either the Wumpus 2 turns to live if it doesn't move again, or Nascar 1 turn to live if he's standing on a corpse. Also accounts for a third option if it's the first turn, but just the once. I'll port to to FCH eventually, busy busy.

    package Hunters;
    
    import Mechanics.*;
    
    public class NascarHunter extends Hunter {
    
        private int state;
        private boolean shootHall;
        private boolean newGame;
    
        public NascarHunter(){
    
            name = "NascarHunter";
            state = 0;
            shootHall = true;
            newGame = true;
    
        }
    
        public void newGame(){
    
            state = 0;
            newGame = true;
    
        }
    
        public void getResponse(boolean[] status){
    
            // Wumpus about - stand and deliver
            if( status[0] ){
    
                nextMove = Move.SHOOT;
    
                switch( state ){
    
                case 0: // Must be in either Right or Back
                    if(newGame){
    
                        // try Left if this is the first turn, just in case
                        nextDirection = Direction.LEFT;
                        newGame = false;
    
                    }
                    else if(shootHall) nextDirection = Direction.BACK;
                    else               nextDirection = Direction.RIGHT;
                    shootHall = !shootHall;
                    break;
                case 2: // Must be in either Left or Back
                    if(newGame){
    
                        // try Right if this is the first turn, just in case
                        nextDirection = Direction.RIGHT;
                        newGame = false;
    
                    }
                    else if(shootHall) nextDirection = Direction.BACK;
                    else               nextDirection = Direction.LEFT;
                    shootHall = !shootHall;
                    break;
                default: // Must be in either Left or Right
                    if(newGame){
    
                        // try Back if this is the first turn, just in case
                        nextDirection = Direction.BACK;
                        newGame = false;
    
                    }
                    else if(shootHall) nextDirection = Direction.RIGHT;
                    else               nextDirection = Direction.LEFT;
                    shootHall = !shootHall;
                    break;
    
                }
    
            }else{
    
                // disregard state, shove out and light 'em up!
                switch( state ){
    
                case 0: // move out
                    nextMove = Move.MOVE;
                    nextDirection = Direction.LEFT;
                    state++;
                    break;
                case 1: // shoot right
                    nextMove = Move.SHOOT;
                    nextDirection = Direction.RIGHT;
                    state++;
                    break;
                case 2: // shoot behind
                    nextMove = Move.SHOOT;
                    nextDirection = Direction.BACK;
                    state++;
                    break;
                case 3: // shoot left
                    nextMove = Move.SHOOT;
                    nextDirection = Direction.LEFT;
                    state = 0;
                    break;
    
                }
    
            }
    
        }
    
    }
    

    FullCoverageHunter

    Follows the same credo of the NascarHunter, but alternates his pathing, which is guaranteed to form a loop 10 unique rooms long. Since every room is unique, and we fire at every direction per room, all rooms get fired into. This is true for any starting room (postulated by my buddy Neal, thanks Neal!). Dodecahedra are pretty cool like that!

    I'd like to point out that this is is different than our friend, the MonsterHunter, as he doesn't try any trickery or any real "tactics." The strength of this is the fact that every room gets fired into, again: the brute force solution. This has a theoretical leg up on the NascarHunter, since Nascar will only hit 10 of the 20 rooms, covering only half the area.

    11 June edit:

    Added in Wumpus detection logic pattern from NascarHunter. Should objectively improve score.

    package Hunters;
    
    import Mechanics.*;
    
    public class FullCoverageHunter extends Hunter {
    
        private int state;
        private boolean headLeft;
        private boolean shootHall;
        private boolean newGame;
    
        public FullCoverageHunter(){
    
            name = "FullCoverageHunter";
            state = 0;
            headLeft = false;
            shootHall = true;
    
        }
    
        public void newGame() {
            state = 0;
            headLeft = false;
            newGame = true;
        }
    
    
        public void getResponse(boolean[] status){
    
            // Wumpus about - stand and deliver
            if( status[0] ){
    
                nextMove = Move.SHOOT;
    
                switch( state ){
    
                case 0: // Must be in either Right or Back
                    if(newGame){
    
                        // try Left if this is the first turn, just in case
                        nextDirection = Direction.LEFT;
                        newGame = false;
    
                    }
                    else if(shootHall) nextDirection = Direction.BACK;
                    else               nextDirection = Direction.RIGHT;
                    shootHall = !shootHall;
                    break;
                case 2: // Must be in either Left or Back
                    if(newGame){
    
                        // try Right if this is the first turn, just in case
                        nextDirection = Direction.RIGHT;
                        newGame = false;
    
                    }
                    else if(shootHall) nextDirection = Direction.BACK;
                    else               nextDirection = Direction.LEFT;
                    shootHall = !shootHall;
                    break;
                default: // Must be in either Left or Right
                    if(newGame){
    
                        // try Back if this is the first turn, just in case
                        nextDirection = Direction.BACK;
                        newGame = false;
    
                    }
                    else if(shootHall) nextDirection = Direction.RIGHT;
                    else               nextDirection = Direction.LEFT;
                    shootHall = !shootHall;
                    break;
    
                }
    
            }else{
    
                // disregard state, shove out (in an alternating fashion!) and light 'em up!
                switch( state ){
    
                case 0: // move out, change alternation state
                    nextMove = Move.MOVE;
                    if(headLeft) nextDirection = Direction.LEFT;
                    else         nextDirection = Direction.RIGHT;
                    state++;
                    headLeft = !headLeft;
                    break;
                case 1: // shoot into non-exit path
                    nextMove = Move.SHOOT;
                    if(headLeft) nextDirection = Direction.RIGHT;
                    else         nextDirection = Direction.LEFT;
                    state++;
                    break;
                case 2: // shoot behind
                    nextMove = Move.SHOOT;
                    nextDirection = Direction.BACK;
                    state++;
                    break;
                default: // shoot into next room,
                    nextMove = Move.SHOOT;
                    if(headLeft) nextDirection = Direction.LEFT;
                    else         nextDirection = Direction.RIGHT;
                    state = 0;
                    break;
    
                }
    
            }
    
        }
    
    }
    

    Let me know if there're any errors, package didn't play nice with my IDE :(

    DoctorHeckle

    Posted 2015-06-03T21:02:02.010

    Reputation: 336

    1I'm pretty sure this should be called MadMaxHunter, as I don't recall too many NASCAR races involving gunfire between vehicles. Seems to do well! – Ralph Marshall – 2015-06-04T21:10:07.657

    I had to put brackets around the headLeft in the if statements to get FullCoverageHunter to work. Both of your bots do very well- NascarHunter is slightly better – euanjt – 2015-06-05T09:43:25.983

    The variable newGame in FullCoverageHunter seems to never be declared. I added a private boolean newGame and set it to true in the newGame() method, is that what you intended? – Cain – 2015-06-12T15:55:52.850

    @Cain whoops! Yeah big oversight from me, I'll edit that in here, my bad. – DoctorHeckle – 2015-06-12T16:00:06.880

    7

    Badger

    He doesn't like visitors.

    package Hunters;
    
    import Mechanics.*;
    
    public class Badger extends Hunter {
    
        public Badger(){
            name = "Badger";
        }
    
        @Override
        public void getResponse(boolean[] status){
            nextMove = Move.SHOOT;
            nextDirection = Direction.values()[((int) (Math.random() * 3))];
        }
    }
    

    TheNumberOne

    Posted 2015-06-03T21:02:02.010

    Reputation: 10 855

    6

    Elmer Fudd

    "Shhh. Be vewy vewy quiet, I'm hunting wumpus"

    Elmer is fixated on the prey and ignores everything except corpses and the Wumpus. He tries to find a corpse then backs off and starts shooting. If he smells a Wumpus, he will back off and if he still smells him he will shoot.

    My apologies to all the java programmers, this is probably extremely ugly, full of syntax errors and I have probably messed up my logic.

    package Hunters;
    
    import Mechanics.*;
    
    public class ElmerFudd extends Hunter {
    
        private state int;
        private previousDir int;
    
        public ElmerFudd(){
            name = "ElmerFudd";
        }
    
        public void newGame() {
            state=0;
            previousDir = Direction.LEFT;
        }
    
        public void getResponse(boolean[] status){
    
            nextMove = Move.MOVE;
            switch (previousDir) {
                case Direction.LEFT:
                    nextDirection = Direction.RIGHT;
                    break;
                case Direction.RIGHT:
                    nextDirection = Direction.LEFT;
                    break;
            }   
    
            if(status[2]&&state==0) {
                state = 1;
                return;
            }
    
            if(state==1){
                if(status[2]){
                    state=2;
                };
                nextDirection = Direction.BACK;
                return;
            }
    
            if(state==2){
                nextMove = Move.SHOOT;
                nextDirection = Direction.BACK;
                return;
            }
    
            if(state==3&&status[0])
                nextMove = Move.SHOOT;
                nextDirection = Direction.BACK;
                return;
            }
    
            if(state==3) {
                state = 0;
            }
    
            if(status[0]){
                state=3;
                nextDirection = Direction.BACK;
            }
    
        }
    }
    

    Pacifist

    This guy is morally against any sort of blood sport and wondering how he turned up in this situation at all. He will run away from any sort of contact and never take a shot.

    package Hunters;
    
    import Mechanics.*;
    
    public class Pacifist extends Hunter {
    
    
        public Pacifist(){
            name = "Pacifist";
        }
    
        public void getResponse(boolean[] status){
            nextMove = Move.MOVE;
            if(status[0]||status[1]||status[2]||status[3]||status[4]){
                nextDirection = Direction.values()[((int) (Math.random() * 3))];
                return;
            }
            nextDirection = Direction.HERE;
        }
    }
    

    MickyT

    Posted 2015-06-03T21:02:02.010

    Reputation: 11 735

    1I think this might work. All you have to do in a game is hope someone gets the wumpus before it gets you and you get full credit. – Ralph Marshall – 2015-06-05T00:03:03.513

    1That was the general idea. Let the others do the hard work:-) – MickyT – 2015-06-05T00:06:40.120

    1That's why I waited for you to code this, even though I thought of it first :-) – Mawg says reinstate Monica – 2017-03-07T13:03:38.503

    5

    MonsterHunter

    We are hunting a monster and we are 4... It reminds me of my favorite game ! This hunter will walk most of the map by moving left-right alternatively, and if the Wumpus is near, he will lure him by going backward to be able to determine precisely were it is.

    I could get rid of lastDirection, but I keep for semantics and readability :). Actually, it dies quite a lot, but the controller often put 2/3 hunter in the same room at the start, and often with the Wumpus near (can also be in the same room)... so insta death ^^'.

    package Hunters;
    
    import Mechanics.*;
    
    public class MonsterHunter extends Hunter 
    {
        private Direction lastDirection=Direction.HERE;
        private boolean[] lastStatus=new boolean[5];
        private int   shooted=0;
        private boolean   walkMode=true;
        private int         turnStayed=0;
    
        public MonsterHunter(){
            super();
            name = "MonsterHunter";
        }
    
        @Override
        public void getResponse(boolean[] status)
        {
            if(status[0])
            {
                if(!lastStatus[0]||shooted==0)
                {
                    nextDirection=(walkMode)?Direction.RIGHT:Direction.LEFT;;
                    nextMove=Move.SHOOT;
                }
                else if(lastStatus[0]&&shooted==1)
                {
                    nextDirection=Direction.BACK;
                    nextMove=Move.MOVE;
                }
                else
                {
                    nextDirection=Direction.BACK;
                    nextMove=Move.SHOOT;
                }
            }
    
            else if(status[2])
            {
                nextMove=Move.MOVE;
                if(Math.random()*6<turnStayed)
                {
                    nextDirection=Direction.HERE;
                    turnStayed++;
                }
                else
                    nextDirection=(walkMode)?Direction.RIGHT:Direction.LEFT;
            }
            else
            {
                nextMove=(!status[1]&&Math.random()<0.5)?Move.MOVE:Move.SHOOT;
                nextDirection=(walkMode)?Direction.RIGHT:Direction.LEFT;
            }
    
            if(nextMove==Move.MOVE)
            {
                if(shooted>0)
                    walkMode=walkMode^(shooted>0);
                if(lastStatus[0]&&shooted==1)
                    shooted++;
                else
                    shooted=0;
                lastDirection=nextDirection;
            }
            else
                shooted++;
            for(int i=0;i<status.length;i++)
                lastStatus[i]=status[i];
        }
    }
    

    Katenkyo

    Posted 2015-06-03T21:02:02.010

    Reputation: 2 857

    Thanks for pointing that out, controller is fixed so that each occupant has a unique start – Cain – 2015-06-04T14:58:03.390

    4

    PacingHunter

    Back and forth, between to rooms. if it smells a Wumpus or hears a player it shoots left then right. if a Wumpus is next to him to start with than he shoots the room he will move to.

    package Hunters;
    
    import Mechanics.Direction;
    import Mechanics.Hunter;
    import Mechanics.Move;
    
    public class PacingHunter extends Hunter {
    
        int state = 0;//Pacing
        int turn = 0;
    
        public PacingHunter() {
            name = "Pacer";
        }
    
        public void newGame() {
            turn =  0;
            state = 0;
        }
    
        public void getResponse(boolean[] status){
            turn += 1;
            if(state == 0 && status[0] && turn == 1){
                nextMove = Move.SHOOT;
                nextDirection = Direction.BACK;
                return;
            }
            if(state == 0 &&(status[0] || status[1])){
                nextMove = Move.SHOOT;
                nextDirection = Direction.LEFT;
                state = 1;
                return;
            }
            if(state == 1 && (status[0] || status[1])){
                nextMove = Move.SHOOT;
                nextDirection = Direction.RIGHT;
                state = 0;
                return;
            }
            if(status[1] && state == 0){
                nextMove = Move.SHOOT;
                nextDirection = Direction.BACK;
                state = 0;
                return;
    
        }
        nextMove = Move.MOVE;
        nextDirection = Direction.BACK;
    }
    

    }

    MegaTom

    Posted 2015-06-03T21:02:02.010

    Reputation: 3 787

    4

    ScaredyCat

    ScaredyCat is scared of everything. If it smells a wumpus or a corpse or hears an arrow or a hunter, it runs to a random direction. Otherwise, it simply keeps shooting arrows in random directions.

    package Hunters;
    
    import Mechanics.*;
    
    public class ScaredyCat extends Hunter {
    
        public ScaredyCat(){
            name = "ScaredyCat";
        }
    
        @Override
        public void getResponse(boolean[] status){
    
            for(int i=0; i<status.length; i++)
                if(status[i])
                {
                    nextMove = Move.MOVE;
                    nextDirection = Direction.values()[((int) (Math.random() * 3))];
                    return;
                }
    
            nextMove = Move.SHOOT;
            nextDirection = Direction.values()[((int) (Math.random() * 3))];
        }
    }
    

    Spikatrix

    Posted 2015-06-03T21:02:02.010

    Reputation: 1 663

    6Lol I don't know if this was intentional, but he will scare himself by shooting arrows and then run. – Cain – 2015-06-04T16:35:28.403

    4

    Eats Shoots and Leaves

    Unlike the Panda of grammar book fame, this hunter doesn't actually eat anything, but we either shoot if the Wumpus is about or we leave on a trail that should hopefully keep us from walking in circles.

    package Hunters;
    
    import java.util.Random;
    
    import Mechanics.Hunter;
    import Mechanics.Move;
    import Mechanics.Direction;
    import Mechanics.Room;
    
    public class EatsShootsAndLeaves extends Hunter {
    
        private static Direction [] allDirections = { Direction.LEFT, Direction.RIGHT, Direction.BACK, Direction.HERE };
        private static Direction [] movePath = { Direction.LEFT, Direction.RIGHT, Direction.LEFT, Direction.BACK, Direction.RIGHT, Direction.BACK };
    
        private static int numGames = 0;
        private static int totalLife = 0;
    
        private static class RoomInfo  {
    
            public boolean hasWumpus = false;
            public boolean hasLocalHunter = false;
            public boolean hasNeighborHunter = false;
            public boolean hasCorpse = false;
            public boolean hasArrow = false;
            public RoomInfo(Room r) {
                boolean [] status = r.getInfo();
                hasWumpus = status[0];
                hasNeighborHunter = status[1];
                hasCorpse = status[2];
                hasArrow = status[3];
                hasLocalHunter = status[4];
            }
    
            public String toString() {
                return new String("Status: "
                                  + (hasWumpus ? "Wumpus " : "")
                                  + (hasNeighborHunter ? "Close Hunter " : "")
                                  + (hasCorpse ? "Corpse " : "")
                                  + (hasArrow ? "Arrow " : "")
                                  + (hasLocalHunter ? "Local Hunter " : ""));
            }
        }
    
        int turnsAlive = 0;
        int shots = 0, moves = 0;
    
        public EatsShootsAndLeaves(){
            name = "Eats Shoots and Leaves";
        }
    
        public void newGame() {
    
            totalLife += turnsAlive;
            numGames++;
    
            turnsAlive = shots = moves = 0;
        }
    
        public void getResponse(boolean[] status){
    
            turnsAlive++;
    
            RoomInfo info = new RoomInfo(this.getRoom());
            if (info.hasNeighborHunter || info.hasWumpus) {
                nextMove = Move.SHOOT;
                nextDirection = allDirections[shots++ % 3];
            } else {
                nextMove = Move.MOVE;
                nextDirection = movePath[moves++ % movePath.length];
            }
        }
    }
    

    Ralph Marshall

    Posted 2015-06-03T21:02:02.010

    Reputation: 729

    3

    Idomeneus

    Idomeneus is quite simple- if the Wumpus or another hunter is nearby, he fire sarrows everywhere and prays that the goddess of hunting is on his side. If he's near a corpse he lies in wait for the Wumpus. He doesn't like other hunters and will run away if they start firing arrows near him, or if they are in the same room as him. Finally if he's feeling bored he randomly paces the eternal corridors.

    package Hunters;
    import Mechanics.Direction;
    import Mechanics.Hunter;
    import Mechanics.Move;
    import java.util.Random;
    
    
    
    public class Idomeneus extends Hunter
    {
        int direction;
        Random r;
        public Idomeneus()
        {
            super();
            name = "Idomeneus";
            direction = 0;
            r = new Random();
        }
    
        @Override
        public void getResponse(boolean[] status){
            boolean wumpusNear = status[0];
            boolean hunterNear = status[1];
            boolean corpseNear = status[2];
            boolean arrowNear = status[3];
            boolean hunterHere = status[4];
            direction++;
    
            if(wumpusNear)
            {
                //ATTACK!!!
                nextMove = Move.SHOOT;
                nextDirection = Direction.values()[direction%3];
            }
            else if(hunterHere || arrowNear)
            {
                //Run away
                nextMove = Move.MOVE;
                nextDirection = Direction.values()[r.nextInt(3)];
            }
            else if(hunterNear)
            {
                //ATTACK!!!
                nextMove = Move.SHOOT;
                nextDirection = Direction.values()[direction%3];
            }
            else if(corpseNear)
            {
                //Stay and wait...
                nextMove = Move.MOVE;
                nextDirection = Direction.HERE;
            }
            else
            {
                //wander around
                nextMove = Move.MOVE;
                nextDirection = Direction.values()[r.nextInt(3)];
            }
    
        }
    
        public void newGame(){}
    
    
    
    }
    

    euanjt

    Posted 2015-06-03T21:02:02.010

    Reputation: 502

    Be careful: According to @Cain, you can shoot yourself if you fire into your own room. – DoctorHeckle – 2015-06-05T05:16:25.563

    3

    Emo Wumpus (Hunter)

    Emo Wumpuses (related to Emo Wolves which sometimes use guns and fly planes) hate everything (especially Java). They make no distinction between Hunters and Wumpuses, and try to shoot them all the same. They also hate Nascar drivers, and will always shoot right. If no one is around to shoot, they move right, but will only do this thirteen times in a row before they get even more depressed about being alone and try to shoot themselves (thirteen is an unlucky number). On turn 99, if they are still alive, they will attempt to shoot themselves because starvation is such a lame way to die.

    Wumpuses are larger (and heavier) than Wolves, but this one has still starved itself to 424 bytes (as opposed to the hefty 2.72 kb of NascarHunter).

    package Hunters;import Mechanics.*;public class EmoWumpus extends Hunter{private int c, t;public EmoWumpus(){name="Emo Wumpus";this.c=0;this.t=0;}public void newGame(){this.c=0;this.t=0;}public void getResponse(boolean[] status){nextMove=Move.SHOOT;if(c<13 && t<100){if(status[0]||status[1]){nextDirection=Direction.RIGHT;}else{nextMove=Move.MOVE;nextDirection=Direction.RIGHT;c++;}}else{nextDirection=Direction.HERE;}t++;}}
    

    Why not just commit suicide in the first place? Emo Wumpuses believe that the one act of good that can do is end the suffering of others before killing themselves. Therefore, they will kill all that they can before it is their time to die.

    Wumpus? (Anti-Hunter)

    Um, What is a Wumpus doing on the hunters roster? This guy got super pissed that humans were killing his kin, so he decided to dress up as one of them and join in on the hunt. His main goal is to just kill hunters. He tries to hide near corpses, which will give him a chance at a shield from the hunters. If no hunters are nearby, he will move in a direction until hunters are detected, in which case he will try to kill them before moving in the other direction.

    Unfortunately, most Wumpuses are stupid, and are still going to try to kill him. Regardless, he considers his sacrifices necessary for the good of Wumpuses everywhere.

    package Hunters;
    
    import Mechanics.*;
    
    public class AntiHunter extends Hunter {
    
    private boolean left;
    
    public AntiHunter() {
        name = "Wumpus";
        this.left = true;
    }
    
    public void newGame() {
        this.left = true;
    }
    
    public void getResponse(boolean[] status) {
        if(status[4]) {
            nextMove = Move.SHOOT;
            nextDirection = Direction.HERE;
        }
        else if(status[2] || status[1]) {
            nextMove = Move.SHOOT;
            if(this.left) {
                this.left = false;
                nextDirection = Direction.LEFT;
            }
            else {
                this.left = true;
                nextDirection = Direction.RIGHT;
            }
        }
        else {
            nextMove = Move.MOVE;
            if(this.left)
                nextDirection = Direction.LEFT;
            else
                nextDirection = Direction.RIGHT;
        }
    }
    

    }

    Michael Brandon Morris

    Posted 2015-06-03T21:02:02.010

    Reputation: 271

    1No longer funny. – Martin Ender – 2015-06-12T14:32:55.923

    Good thing this isn't code golf. Was wondering how long it'd be until an Emo bot would show up, lol. – DoctorHeckle – 2015-06-12T14:33:49.357

    @Martin Note that this isn't just suicidal. Out of the bots available for testing, it did not rank last. – Michael Brandon Morris – 2015-06-12T14:39:05.847

    1EmoSolution is *always* funny ! – Mawg says reinstate Monica – 2017-03-07T13:06:37.637

    2

    Laomedon

    Laomedon wanders aimlessly trying to find a corpse. Once he's found one and works out where it is he stays in the same place next to the corpse. When he smells the Wumpus he fires arrows into the Corpse's room.

    package Hunters;
    import Mechanics.Direction;
    import Mechanics.Hunter;
    import Mechanics.Move;
    public class Laomedon extends Hunter {
        private enum status
        {
            START,
            SEARCHED_LEFT,
            SEARCHED_RIGHT,
            INITIAL_CORPSE_LEFT,
            INITIAL_CORPSE_RIGHT,
            SMELT_CORPSE,
            CORPSE_BEHIND,
            CORPSE_LEFT
        }
    
        status myState;
        public Laomedon() {
            this.name = "Laomedon";
        }
        @Override
        public void getResponse(boolean[] status) {
            boolean wumpusNear = status[0];
            boolean hunterNear = status[1];
            boolean corpseNear = status[2];
            boolean arrowNear = status[3];
            boolean hunterHere = status[4];
            switch (myState) {
            case CORPSE_BEHIND:
                if(wumpusNear)
                {
                    this.nextDirection = Direction.BACK;
                    this.nextMove = Move.SHOOT;
                }
                else
                {
                    this.nextDirection = Direction.HERE;
                    this.nextMove = Move.MOVE;
                }
                break;
            case CORPSE_LEFT:
                if(wumpusNear)
                {
                    this.nextDirection = Direction.LEFT;
                    this.nextMove = Move.SHOOT;
                }
                else
                {
                    this.nextDirection = Direction.HERE;
                    this.nextMove = Move.MOVE;
                }
                break;
            case INITIAL_CORPSE_LEFT:
                if(corpseNear)
                {
                    this.nextDirection = Direction.RIGHT;
                    this.nextMove = Move.MOVE;
                    this.myState = Laomedon.status.INITIAL_CORPSE_RIGHT;
                }
                else
                {
                    this.nextDirection = Direction.BACK;
                    this.nextMove = Move.MOVE;
                    this.myState = Laomedon.status.SEARCHED_LEFT;
                }
                break;
            case INITIAL_CORPSE_RIGHT:
                if(corpseNear)
                {
                    this.nextDirection = Direction.LEFT;
                    this.nextMove = Move.MOVE;
                    myState = Laomedon.status.INITIAL_CORPSE_LEFT;
                }
                else
                {
                    this.nextDirection = Direction.BACK;
                    this.nextMove = Move.MOVE;
                    this.myState = Laomedon.status.SEARCHED_LEFT;
                }
                break;
            case SEARCHED_LEFT:
                if(corpseNear)
                {
                    this.nextDirection = Direction.LEFT;
                    this.nextMove = Move.MOVE;
                    this.myState = Laomedon.status.SMELT_CORPSE;
                }
                else
                {
                    this.nextDirection = Direction.RIGHT;
                    this.nextMove = Move.MOVE;
                    this.myState = Laomedon.status.SEARCHED_RIGHT;
                }
                break;
            case SEARCHED_RIGHT:
                if(corpseNear)
                {
                    this.nextDirection = Direction.LEFT;
                    this.nextMove = Move.MOVE;
                    this.myState = Laomedon.status.SMELT_CORPSE;
                }
                else
                {
                    this.nextDirection = Direction.LEFT;
                    this.nextMove = Move.MOVE;
                    this.myState = Laomedon.status.SEARCHED_LEFT;
                }
                break;
            case SMELT_CORPSE:
                if(corpseNear)
                {
                    this.nextDirection = Direction.BACK;
                    this.nextMove = Move.MOVE;
                    this.myState = Laomedon.status.CORPSE_BEHIND;
                }
                else
                {
                    this.nextDirection = Direction.BACK;
                    this.nextMove = Move.MOVE;
                    this.myState = Laomedon.status.CORPSE_LEFT;
                }
                break;
            case START:
                if(corpseNear)
                {
                    this.nextDirection = Direction.LEFT;
                    this.nextMove = Move.MOVE;
                    this.myState = Laomedon.status.INITIAL_CORPSE_LEFT;
                }
                else
                {
                    this.nextDirection = Direction.LEFT;
                    this.nextMove = Move.MOVE;
                    this.myState = Laomedon.status.SEARCHED_LEFT;
                }
                break;
            }
        }
    
        @Override
        public void newGame() {
    
            super.newGame();
            myState = status.START;
        }
    }
    

    Unfortunately for him, the other hunters don't appreciate his skills and they seem to shoot him a lot...

    euanjt

    Posted 2015-06-03T21:02:02.010

    Reputation: 502

    2

    NealHunter

    After talking about this with my friend DoctorHeckle, I'd thought it would be fun to try it myself. Used the idea for alternating left and right to cover the most area, and then decided to add a bit of responding to the states, but only 0 and 1 - whether or not a Wumpus or hunter are nearby. Doesn't perform as well as NascarHunter, which surprised me at first. After some thinking though, I realized that shooting an arrow in a random direction (like this does) after hearing a hunter/smelling a Wumpus won't do anything if they're moving that turn, since arrows are shot into rooms, but movement is carried out before it kills them. Not quite as effective as I thought... still performs well though!

    package Hunters;
    
    import Mechanics.*;
    import java.util.Random;
    
    public class NealHunter extends Hunter {
    
        private boolean goLeft;
    
        public NealHunter(){
            name = "NealHunter";
            goLeft = false;
        }
    
        public void newGame() {
            goLeft = false;
        }
    
        public void getResponse(boolean[] status){
    
            Random rand = new Random();
    
            if(status[0] || status[1]){
                nextMove = Move.SHOOT;
    
                switch ( rand.nextInt(3) ){
                    case 0:
                        nextDirection = Direction.LEFT;
                        break;
                    case 1:
                        nextDirection = Direction.BACK;
                        break;
                    case 2:
                        nextDirection = Direction.RIGHT;
                        break;
                }
            } else {
                nextMove = Move.MOVE;
                if (goLeft) {
                    nextDirection = Direction.LEFT;
                } else {
                    nextDirection = Direction.RIGHT;
                }
    
                goLeft = !goLeft;
            }
        }
    }
    

    Neal

    Posted 2015-06-03T21:02:02.010

    Reputation: 61

    1

    WalkingIdiot

    This one walks until he finds the wumpus. Then, he shoots right. If the wumpus is still there, it must be on the left, so shoot once again. On the way, he doesn't care about other hunters or corpses, hence the name.

    package Hunters;
    
    import Mechanics.*;
    
    public class WalkingIdiot extends Hunter {
        private boolean wumpusNear = false;
    
        @Override
        public void newGame() {
            wumpusNear = false;
        }
    
        public WalkingIdiot(){
            name = "WalkingIdiot";
        }
    
        @Override
        public void getResponse(boolean[] status){
            boolean wumpusWasNear = wumpusNear;
            wumpusNear = status[0];
            if (status[0]) {
                nextMove = Move.SHOOT;
                if (wumpusWasNear) {
                    nextDirection = Direction.LEFT;
                } else {
                    nextDirection = Direction.RIGHT;
                }
                return;
            }
            nextMove = Move.MOVE;
            nextDirection = Math.random() < 0.5 ? Direction.LEFT : Direction.RIGHT;
        }
    }
    

    Stay

    Stay doesn't like to walk. It simply shoots around and remembers if he shot a hunter.

    package Hunters;
    
    import Mechanics.*;
    
    public class Stay extends Hunter {
        private Direction lastShot = Direction.LEFT;
        private Direction corpse = null;
        private boolean hunterNear = false;
    
        public Stay(){
            name = "Stay";
        }
    
        @Override
        public void newGame() {
            corpse = null;
            hunterNear = false;
            lastShot = Direction.LEFT;
        }
    
        @Override
        public void getResponse(boolean[] status){
            nextMove = Move.SHOOT;//always
            boolean hunterWasNear = hunterNear;
            hunterNear = status[1];
    
            if (hunterWasNear && status[2] && !status[1]) {
                corpse = lastShot;
            }
    
            if (status[0]) {
                if (corpse != null) {
                    nextDirection = corpse;
                    return;
                }
            }
            if ((status[1] && !status[4]) || status[0]) {
                switch (lastShot) {
                    case LEFT: lastShot = nextDirection = Direction.RIGHT; break;
                    case RIGHT: lastShot = nextDirection = Direction.BACK; break;
                    case BACK: lastShot = nextDirection = Direction.LEFT; break;
                }
                return;
            }
    
            //default
            lastShot = nextDirection = Direction.LEFT;
        }
    }
    

    CommonGuy

    Posted 2015-06-03T21:02:02.010

    Reputation: 4 684