Survival Game - Create Your Wolf

  • The Board


    The Board is a two dimensional array of cells. Cells are populated by Animals. Every day, all Animals on the Board simultaneously make one move. If two or more Animals move to the same cell, they fight until one remains. The possible moves and attacks are as follows:



    • Moves - { Move.UP, Move.RIGHT, Move.DOWN, Move.LEFT, Move.HOLD }

    • Attacks - { Attack.ROCK, Attack.PAPER, Attack.SCISSORS, Attack.SUICIDE }


    Animals fight by playing Rock-Paper-Scissors. Standard rules apply but with two modifications. First, you may commit suicide at any time. Second, a tie is broken pseudorandomly. If more than two Animals collide, two are pseudorandomly selected to fight until one remains.


    The Players


    Animal behavior and appearance is as follows.



    • Lion

      • Represented by the character L. Moves DOWN, RIGHT, then repeats. Pseudorandomly attacks with PAPER or SCISSORS.



    • Bear

      • Represented by the character B. Moves DOWN x 4, RIGHT x 4, UP x 4, LEFT x 4, then repeats. Attacks with PAPER.



    • Stone

      • Represented by the character S. Moves HOLD. Attacks with ROCK.



    • Wolf

      • Only wolves that are submitted as an answer will be included. Represented by 'W'. Moves with any Move. Attacks with any Attack




    You will implement the Wolf by filling in the blanks in the following template. All submissions must be in Java and must be contained in a single file. Alternatively, @ProgrammerDan has written a wrapper class that extends the competition to non-java submissions.



    // Optional code here
    public class Wolf extends Animal {
    // Optional code here
    public Wolf() { super('W'); /* Optional code here */ }
    public Attack fight(char opponent) { /* Required code here. Must return an Attack. */ }
    public Move move() { /* Required code here. Must return a Move. */ }
    // Optional code here
    }

    The submission with the highest average number of living wolves after five trials with 1,000 iterations wins. I will update the winner each time a new answer is posted (but not within the first 24 hours).


    Tools



    • You are provided with a small map of your immediate surroundings in the following form.

      • char[][] surroundings A zero indexed, 3 by 3 matrix of characters that represent nearby animals. Empty tiles are represented by a space character (' '). You are at surroundings[1][1]. For example, to your right would be surroundings[1][2], and above you is surroundings[0][1]. Your surroundings are updated just before being asked to move, but may be out of date when asked to fight.



    • You may persist data between invocations of your Wolf, Move requests, and Attack requests. You may neither read from nor modify files created by another Wolf class.

    • You are provided with the size of the map in the following form

      • int MAP_SIZE




    Assumptions



    • All submission will compete on the same board against all other submissions as well as Lions, Bears, and Stones

    • The board is a square with sides of length sqrt(n+3)*20 where n is the number of submissions. All sides wrap, so you can safely move in any direction infinitely.

    • Simulation begins at ~25% board capacity with 100 of each Animal pseudorandomly distributed across the board.

    • If an Animal throws an exception when asked to move, that Animal will HOLD

    • If an Animal throws an exception when asked to fight, that Animal will SUICIDE

    • If an Animal has no letter when the controller checks, that Animal will immediately die


    Getting Started and Testing Instructions


    The tools you need to test your submission can be found here. The following files should be available at that link.



    • ExampleRun.gif - A 5-10 second gif of the program running.

    • Scoreboard - The latest results of the competition.

    • Wild.jar - An executable that you can run to watch the premade Animals run around.

    • Wild.zip - The NetBeans project that houses the controller program with a few premade Animals added. Use this to develop your submission.

    • WildPopulated.zip - Same as above, but with and about 40 submissions added for you to test against. The GUI has also been removed because of performance issues. The results will simply appear a few moments after you run. The non-Java submissions are commented out because they require extra downloads and effort. Use this to test your submission against the field.

    • Wolf.txt - A naive implementation of the Wolf class in Java. You may use and expand that implementation without crediting me.


    To test your class:



    • Download Wild.zip

    • Rename your Wolf.java and Wolf class to something unique

    • Add your UniquelyNamedWolf.java file to Wild\src\animals\

    • In the Wild class, add your class to classes array, like this.

      • Class[] classes = { UniquelyNamedWolf.class, Bear.class, Lion.class, Stone.class, Wolf.class };



    • Rebuild and run


    I also included another project containing all of the submissions, for testing purposes. I creatively named it "WildPopulated". The three or four non-Java wolves were commented out, because getting them to run requires a lot of extra work and downloads. The one I posted should run with zero extra work. The GUI was also commented out for the sake of speed.


    Scoreboard April 22, 2014


    The Scoreboard has been moved to Google Drive. View it here. It will be updated on a casual basis (i.e., when I get to it) as new submissions come in.


    Side Challenge - NoHOLD


    Removed because no (as in zero) participation. It wasn't part of the original challenge anyway.


    When you say "simulation begins ... with 100 of each animal"... does that mean 100 per "breed" of wolf?

    @m.buettner Correct. Simulation starts with 100 of each Wolf submission (breed), 100 Stones, 100 Lions, and 100 Bears.

    @m.buettner I'm tempted to write a wrapper that would allow non-java submissions, if Rusher doesn't forbid me from doing so :D

    @ProgrammerDan If it does not cripple the controller or force the tester (me) to download a compiler/interpreter for every submission, I will add your wrapper, and then community wiki the challenge so that I gain no more rep from it. I would be happy to see it work.

    @Rusher That sounds terrible. I could just community wiki my answer that contains the Wrapper. As for the compiler/interpreter issue, I suppose it'd be up to the submittee to provide you with clear instructions on usage, and if the instructions where unclear or too complex, you could reject the submission :)

    "* You are provided with the size of the map in the following form: `int MAP_SIZE`" I'm having trouble figuring out how to use this. Netbeans says there's no instance of the string `MAP_SIZE` in any of the files in the project.

    To help testing, I modified your `Game.toString()` to use a `StringBuilder` instead of countless concats. It speeds things up dramatically(I also took out the `sleep()` in my copy). The mod is here on pastebin.

    how about trees showing paper?

    @m.buettner wrapper posted, ping me with questions on how to use, but if your language/interpreter of choice supports piped inputs and outputs, you are good to go.

    @ProgrammerDan awesome! I think if I have to set up javac on my machine anyway, I might just write an answer in Java right away, though. But it's certainly helpful for people who don't know any Java at all.

    @Rusher, I think some people are doing this already, but is inter-Wolf communication allowed via static members (within your own breed)?

    @m.buettner Allowed. Go forth and build your hive-minded wolf.

    @ProgrammerDan MAP_SIZE bug fixed. All wolves should be able to access it now. It is inherited from Animal. Download the new controller from the same link in the question.

    Ah, the nostalgia of intro programming courses

    When is the deadline for entering?

    One more thing, just to clarify: if animals move through each other (i.e. swap places) there is no fight?

    @Kevin No foreseeable deadline. I will update this post with results as I learn how to compile them (I'm currently learning how to run an R program). If, in a few months, I get tired of updating it, I'll just slap a timer on it.

    @m.buettner If they swap places, there is no fight. In other words, you don't "collide" halfway between cells.

    Wow this is awesome. I sense a whole new breed of computer gaming here haha.

    If you want players to be able to run the program themselves to see the winner, you could ensure that everyone is using the same random number generator (in a deterministic order) and promise to seed it with a future random number.

    Does this need JDK 8?

    What is the syntax for the surrounding char[][] array? By that I mean, assuming my character is in position 1,1, does Move.UP imply that I will move to position 0,1 or 1,0 or 1,2 or 2,1? It might be nice if this was explicitly stated.

    @Sheph Good question. I edited the "Tools" section to reflect your orientation on the board.

    @user3188175 Yes. I messed up and included one line of code that requires Java 8. I blame the ever changing ArrayList syntax!

    Is there a good graphical representation of the playing field that I'm just not seeing, or do I have to write one myself? (e.g. johnchen902's display)

  • Herjan

    Herjan Correct answer

    7 years ago

    HerjanWolf



    Updated 10-4-2014 at 15:00



    Averages of 100 rounds, 1000 iterations:



    Standard mobs:



    class animals.Bear - 2.2600002
    class animals.Lion - 41.21
    class animals.Stone - 20.159998
    class animals.HerjanWolf - 99.99 <-- kind of flawless


    20+ Species (Keep in mind, don't trust these scores since we keep calculating avgs until our wolves score best!)



    class animals.Bear - 0.1
    class animals.Lion - 0.0
    class animals.Stone - 1.5
    class animals.AlphaWolf - 75.5
    class animals.HerjanWolf - 86.4 <-- #1
    class animals.GatheringWolf - 39.5
    class animals.OmegaWolf - 85.4 <-- #2
    class animals.ShadowWolf - 71.1
    class animals.MOSHPITFRENZYWolf - 8.8
    class animals.WolfWithoutFear - 11.5
    class animals.MimicWolf - 0.5
    class animals.LazyWolf - 52.8
    class animals.Sheep - 38.3
    class animals.HonorWolf - 80.7
    class animals.CamperWolf - 52.8
    class animals.GamblerWolf - 14.7
    class animals.WolfRunningWithScissors - 0.0
    class animals.LionHunterWolf - 27.6
    class animals.StoneEatingWolf - 70.8
    class animals.Wion - 0.1
    class animals.ProAlpha - 79.3
    class animals.HybridWolf - 83.2


    My Wolf:



    package animals;

    public class HerjanWolf extends Animal {

    private boolean lionTopLeft = false, lionTopLeftReady = false;
    private boolean lionRight = false, lionRightReady = false;
    private boolean lionBot = false, lionBotReady = false;
    private boolean lionDanger = false, careful = true, firstmove = true;
    private final int hold = 0, down = 1, right = 2, left = 3, up = 4;

    public HerjanWolf() {
    super('W');
    }

    public Attack fight(char c){
    switch (c) {
    case 'B':
    return Attack.SCISSORS;
    case 'L':
    return Attack.SCISSORS;
    case 'S':
    return Attack.PAPER;
    default:
    int rand = (int) (Math.random()*3);
    if(rand < 1)
    return Attack.PAPER;
    else if(rand < 2)
    return Attack.SCISSORS;
    else
    return Attack.ROCK;
    }

    }
    public Move move() { //surroundings[y][x]

    checkLions();

    if(firstmove){
    if(surroundings[2][0] == 'L')
    lionBotReady = true;
    if(surroundings[0][2] == 'L')
    lionRightReady = true;
    firstmove = false;
    }

    int[] dang = new int[4]; // 0 is left side, 1 is top side, 2 is right side, 3 is down side

    for(int y = 0; y < 3; y++){
    for(int x = 0; x < 3; x++){
    if(surroundings[y][x] == 'W'){
    if(y == 0){
    dang[1]++;
    if(x == 1)
    dang[1]+=2;
    }if(y == 2){
    dang[3]++;
    if(x == 1)
    dang[3]+=2;
    }if(x == 0){
    dang[0]++;
    if(y == 1)
    dang[0]+=2;
    }if(x == 2){
    dang[2]++;
    if(y == 1)
    dang[2]+=2;
    }
    }
    }
    }

    int maxIndex = 0, minIndex = 0, minIndex2 = 0;
    for(int i = 1; i < dang.length; i++){
    if(dang[i] > dang[maxIndex])
    maxIndex = i;
    if(dang[i] <= dang[minIndex]){
    minIndex2 = minIndex;
    minIndex = i;
    }
    }

    if(lionDanger || surroundings[1][0] == 'L' && lionTopLeftReady || surroundings[0][1] == 'L' && lionTopLeftReady || dang[maxIndex] >= 3){

    switch(minIndex){
    case 0:
    if (isSafe(1, 0)){
    newMove(left);
    return Move.LEFT;
    }
    case 1:
    if (isSafe(0, 1)){
    newMove(up);
    return Move.UP;
    }
    case 2:
    if(isSafe(1,2)){
    newMove(right);
    return Move.RIGHT;
    }

    case 3:
    if (isSafe(2, 1)){
    newMove(down);
    return Move.DOWN;
    }
    }

    switch(minIndex2){
    case 0:
    if (isSafe(1, 0)){
    newMove(left);
    return Move.LEFT;
    }
    case 1:
    if (isSafe(0, 1)){
    newMove(up);
    return Move.UP;
    }
    case 2:
    if(isSafe(1,2)){
    newMove(right);
    return Move.RIGHT;
    }

    case 3:
    if (isSafe(2, 1)){
    newMove(down);
    return Move.DOWN;
    }
    }

    if(dang[maxIndex]<3){ //if that was not the reason its really obligated (because of lions)
    if (isSafe(2, 1)){
    newMove(down);
    return Move.DOWN;
    }else if(isSafe(1,2)){
    newMove(right);
    return Move.RIGHT;
    }else if (isSafe(0, 1)){
    newMove(up);
    return Move.UP;
    }else{
    newMove(left);
    return Move.LEFT;
    }
    }
    }

    return Move.HOLD;
    }

    boolean isSafe(int y, int x){
    if(y <= 1){
    if(x <= 1){
    if(surroundings[y][x] != 'W' && !lionTopLeft)
    return true;
    }else if(surroundings[1][2] != 'W' && !lionRightReady)
    return true;
    }else if(surroundings[2][1] != 'W' && !lionBotReady)
    return true;

    return false;
    }

    public void checkLions(){
    int y = 0, x = 0;

    if(lionTopLeft)
    lionTopLeftReady = true;
    else
    lionTopLeftReady = false;

    if(surroundings[y][x] == 'L')
    lionTopLeft = true;
    else
    lionTopLeft = false;

    if(lionRight)
    lionRightReady = true;
    else
    lionRightReady = false;

    if(surroundings[y][x+1] == 'L') // && !lionTopLeftReady
    lionRight = true;
    else
    lionRight = false;

    if(lionBot)
    lionBotReady = true;
    else
    lionBotReady = false;

    if(surroundings[y+1][x] == 'L' && !lionTopLeftReady)
    lionBot = true;
    else
    lionBot = false;

    if(careful){
    if(surroundings[y+1][x] == 'L'){
    lionDanger = true;
    }else if(surroundings[y][x+1] == 'L'){
    lionDanger = true;
    }

    careful = false;
    }
    }

    public void newMove(int move){
    lionTopLeft = false;
    lionRight = false;
    lionBot = false;

    lionTopLeftReady = false;
    lionRightReady = false;
    lionBotReady = false;

    lionDanger = false;

    if(move == down){
    if(surroundings[1][0] == 'L')
    lionTopLeft = true;
    if(surroundings[2][0] == 'L')
    lionBot = true;

    }else if(move == right){
    if(surroundings[0][1] == 'L')
    lionTopLeft = true;
    if(surroundings[0][2] == 'L')
    lionRight = true;

    }else
    careful = true;
    }
    }

    Including only the "top" wolves in test runs normally skews the numbers. With 30+ species on the field, the numbers can change dramatically. If you haven't yet, I'd recommend testing that also.

    With nearly all the wolves and 1000 iterations, this wolf averages ~55.

    @user3188175 You're right, I just edited it with more wolves, as Geobits suggested. Sad results :( It was fun though.

    @user20220 It is pretty good in theory(and in practice with relatively less wolves) though.

    @user3188175 Fixed a problem works lots and lots better in large groups now

    @user20220 It does seem to be much better, running a simulation right now.

    @user20220 Nice! It shares the 1st place with HonorWolf(88 survival rate).

    @user3188175 Yeah I tweaked it again lol, now the avg is 2 units better. It's so much fun!

    Could you explain what your wolf does?

    @Quincunx Ah, that feels good :) I originally designed it to make it lionproof and when that was 100% done I programmed interaction with other wolves, but that was at cost of my anti-lion strategy. But I'm honored ;)

    @plannapus Yes, what I do is: check the topleft corner 0 and after that to 2 (and with the right side I do the same [0][1] to [0][2] to [1][2]). So if the lion is going [2][1] HerjanWolf will be sure to not go down.

    @user20220 Wolf-collision happens much more frequently, so you should add another wolf handling that. Also, can you please describe how this wolf works?

    @Quincunx Yes I know I programmed interaction with other wolves later as I stated above, but since I first programmed a 100% lionproof wolf it works good with lots of lions. I just answered how the anti-lion strategy works, the wolf handling isn't that spectacular, if there is a wolf next to you it tries to move to the direction with the least amount of wolves.

    @Quincunx: I think the best anti-lion strategy per se is Wion, since it will *never* encounter any lion. Although it can't be adapted to anything else, unlike this one, which can be adapted to avoid wolves also.

    @justhalf If you take a look at my data, you can see that HerjanWolf does better with more lions. This is because Wion runs into the other Wolves that are avoiding lions.

    Yap, if you consider other wolves, of course, Wion is bad, like I said. My point is, if the only aim is to avoid lion, Wion has the best strategy.

    @justhalf Certainly not, my wolf dodges lions better than the Wion, my wolf does way more than only avoiding lions, but if it has no choice it moves automagically the same way lions do, but better than Wion, since my wolves keep track of all lions in sight and so knows which moves they are going to make. My previous wolf, which had not any wolf-dodging built in at all was 100% lionproof. But ofcourse you can test and see it with your own eyes, btw here is still the source of my old wolf: http://www.java-gaming.org/topics/ai-challenge-on-stackexchange-right-now-create-your-wolf/32708/view.html

    @Herjan: How can one be better in avoiding lions compared to wolves that do not collide with lions at all? Yours is not better in terms of avoiding lions, it is better since it also has the wolf-dodging capability. The lion-avoiding capability is the same, which is the maximum (i.e., doesn't collide with lions at all)

    @justhalf Okay, it's not better, it's just as good then. My wolf dodges all lions as well, I first made my wolf 100% lionproof before I built the wolf-dodging. The difference is that my wolf tries to escape lions (the less movement, the better). So it's just as good at lion-dodging as the Wion, both 100% lionproof, but since my wolf tries to escape lions, and not boringly moves the same as a lion I can still build wolf-dodging in as well, it's just way more complex.

    About to post the new Scoreboard in minutes. You won this week.

    @Herjan I didn't initially understand for whatever reason that it was a wolf free for all. I honestly don't know how I thought the scoring worked under that assumption. You made the same key observation that there is always at least one lion safe move.

License under CC-BY-SA with attribution


Content dated before 7/24/2021 11:53 AM