Four-Man Standoff

54

17

4-Man Standoff

Description

You've somehow found yourself into a four-way standoff. A loaded gun rests in your hands, and some grenades are hooked on your belt.

The objective is to have the most health at the end of a standoff. A standoff is over when at most one person has a positive amount of health.

Each player has 5 health, and dies when their health drops to/below 0. The turn a player dies is the last turn that player can take damage.

If there is a live player at the end of a standoff, that player wins. Otherwise, the player with the least negative health wins.

Actions

  • Shoot: Take a shot at someone.

    • 2 damage if shooting a live enemy
    • 0 damage if shooting a dead enemy
    • health_at_start_of_turn+2 damage if shooting yourself. (Note that this will leave you with at MOST -2 health.)
    • If one enemy shoots at you on the same turn you shoot yourself, you will end the standoff with -4 health (you still take damage from other players the turn you kill yourself).
    • Your action the following turn will be ignored (and assumed to be Nothing).
  • Dodge: Try to dodge a single opponent's shot.

  • Prepare: Unhook your grenade and prepare to throw it.

    • You only have three turns to throw it, before you get blown up (6 damage to yourself, 3 damage to all live enemies)
    • Dying with an unthrown grenade is equivalent to not throwing the grenade for three turns.
  • Throw: Chuck the grenade towards someone and hope for the best.

    • Target receives 8 damage if alive
    • Everyone else (including yourself) receives 3 damage if alive
  • Nothing: Stand idly for a turn and watch everyone die.

Input

Your program will be passed the following information:

  • The health of each player
  • A list of actions taken by that player since the start of the standoff Below is the format for the information passed per player:

    [Health],[Action 1],[Action 2],[Action 3],...
    

Actions will be given in the format specified in the Output section.

You will recieve 4 such strings, separated by a space, and passed as a single argument. The order of these strings is:

[Player Info] [Opponent 1 Info] [Opponent 2 Info] [Opponent 3 Info]

The strings are passed as the second argument. The first argument contains an integer that uniquely identifies the standoff being enacted. Standoffs between the same set of players are guaranteed not to be simultaneous. However, multiple standoffs will occur at the same time.

For example:

$./Player.bash 5 "3,S2,N 5,P,N 3,S0,N -2,S3,N"

Currently, the player and the second opponent have 3 health, the first opponent has 5 health, and the third opponent has -2 health and is dead.

On the first turn:

  • Player 1 shot enemy 2
  • Enemy 1 prepared a grenade
  • Enemy 2 shot player
  • Enemy 3 shot himself

On the second turn:

  • All players did nothing. (Player and enemy 2 can not do anything since they shot on the previous turn. Enemy 3 is dead: he will do Nothing for the rest of the standoff.)

The second argument at the start of a standoff is: 5 5 5 5.

Output

A command should be outputted in the below listed format. An invalid output is interpreted as 'Nothing'. A command requiring a target should be followed by an integer (0-3, with 0 representing the player, and 1-3 representing enemies 1-3).

  • S[target]: Shoots [target].
  • D[target]: Tries to dodge [target].
  • P: Prepare a grenade.
  • T[target]: Throw the grenade at [target].
  • N: Do nothing.

A command that needs a target, but is fed a target not between 0 and 3 or not fed a target entirely will be assumed to target 0 (the player).

Scoring

At the end of each standoff, players receive a score calculated by the following formula:

35 + health at end of standoff 

In the case that a player ends a standoff with negative health, they will receive a score below 35. The following points are also rewarded as a bonus:

  • Most health: +4 points
  • Second most health: +2 points
  • Third most health: +1 point.

In case of a tie, the lower bonus is granted (if two people tie with most health, both are granted +2; if there are 3 people with the most health, +1, and if everyone ends equally, +0).

The final score is determined by calculating the mean of all individual scores.

Rules/Details

  • Order of events within a turn are as follows:
    • All players do their actions.
    • Players who have 0 or less health die.
    • Unthrown grenades that need to explode, will explode (players who just died are still hurt, as this is still the turn they died).
  • No collaboration between entries.
  • Three* standoffs will occur between each set of 4 players. (Order of players may vary with each standoff).
  • Entries consuming excessive amounts of memory of disk space will be disqualified.
  • Reading from or modifying files other than your entry's will disqualify your entry.
  • A truck, driven by a drunkard, will run over all living players after the 50th turn, if the standoff is not yet over at the end of the 50th turn.
    • This truck deals 20 damage to all live players.
  • Standoffs happen quickly. Programs are cut off after 1 second.
  • Your program will be called every turn, even after you have died.
  • You may read or write files to your directory only (if your entry is named JohnDoe, you may save files in the directory players/JohnDoe/); however, this will NOT be the current directory while your script is running.
  • The standoffs will take place on a machine running Arch Linux (Release 2014.08.01).

The controller is available on GitHub.

Please include the following in your post:

  • A name for your bot
  • A shell command to run the bot (ex. java Doe.java) Input will be passed through the command line as a single argument (java Doe.java 5 "-2,S0 -2,S1 -2,S2 5,N")
  • Code of your bot
  • How the bot should be compiled (if applicable)
  • Language (and version if applicable, especially for python)

*Controller is taking way too long for six.

Scoreboard

                      Observer 43.280570409982
                   MuhammadAli 43.134861217214
                         Osama 43.031983702572
                    LateBoomer 42.560275019099
                 SimpleShooter 42.412885154062
             LessSimpleShooter 42.3772
                           Neo 42.3738
                        Scared 42.3678
                     Richochet 42.3263
                   Equivocator 42.2833
  TwentyFourthsAndAHalfCentury 42.2640
                        Darwin 42.1584
                       HanSolo 42.1025
                        Coward 42.0458
           ManipulativeBastard 41.8948
                        Sadist 41.7232
                     Aggressor 41.7058
                 CourageTheDog 41.5629
                     Grenadier 40.9889
                     Bomberman 40.8840
                         Spock 40.8713
                        Sniper 40.6346
                 DONTNUKEMEBRO 39.8151
               PriorityTargets 39.6126
                     Hippolyta 39.2480
                     EmoCowboy 39.2069
                      Zaenille 39.1971
                 AntiGrenadier 39.1919
      PoliticallyCorrectGunman 39.1689
                 InputAnalyzer 39.1517
                      Rule0Bot 39.1000
                     BiasedOne 39.0664
                      Pacifist 39.0481
               StraightShooter 39.0292
                         Ninja 38.7801
                           MAD 38.2543
                        Monkey 37.7089
                   Label1Goto1 36.2131
Generated: 2014/08/22 03:56:13.470264860 UTC

Logs: on GitHub

es1024

Posted 2014-08-09T20:54:50.450

Reputation: 8 953

I wonder if a neural net could be built now that would slaughter the current submissions, converging on an optimal strategy – Cruncher – 2018-10-12T15:25:11.573

If shot/killed while throwing a grenade, it's still thrown, correct? – Geobits – 2014-08-09T21:15:54.490

@Geobits yes; your action on the turn you get killed always happens. – es1024 – 2014-08-09T21:18:33.703

Seems like a cool challenge! Might have a go at this. — Finally a KOTH challenge where the OP's language isn't Java but C++! Kudos :D – tomsmeding – 2014-08-09T21:21:58.370

After starting up a JVM, how much time will a program have left before being cut off? – comperendinous – 2014-08-09T21:37:45.177

@comperendinous at least 7/8ths of a second will be left after the JVM starts up before the cutoff – es1024 – 2014-08-09T22:20:37.520

@es1024 That's all right then. The wait for the JVM often feels interminable on my ageing computer, and I was concerned about the load of parallel standoffs; but that doesn't seem to overly disadvantage Java competitors who try something complex. – comperendinous – 2014-08-09T22:33:14.907

I'm a bit unclear about dying with a grenade. If I prepare one on the first turn and I'm also shot by all three enemies, taking me down to -1 health (dead), how does the grenade explosion affect me? Does it do a further 6 damage since I was alive at the start of the turn? Does it do no further damage since it only explodes once I'm dead? Does it explode on that first turn, or on the second when I'm definitely dead? – comperendinous – 2014-08-09T22:43:13.593

@comperendinous All player's actions (including your preparing a grenade) occur before players die. Therefore, the grenade will explode if you die on the turn you prepare it, and you will take 6 more damage (because it is still the turn that you died). – es1024 – 2014-08-09T22:44:51.437

@es1024 Good. That should prevent P,S0 from being a winning strategy by virtue of being the least-dead player. Thank you for your clarifications. – comperendinous – 2014-08-09T22:48:40.947

1Do you have exactly one grenade, or do you have many? Can you have multiple grenades being prepared at a time? – isaacg – 2014-08-09T23:52:29.907

@isaacg multiple grenades, but can only prepare one at a time; multiple prepares without throwing is the same as doing nothing – es1024 – 2014-08-10T00:50:25.757

Do files stored in our directory persist between standoffs? – Davis Yoshida – 2014-08-10T21:37:28.280

@DavisYoshida Yes. – es1024 – 2014-08-10T22:04:00.857

You've stated that players may "try to dodge [target]". What is the success rate? Can players only dodge bullets, or grenades too? – comperendinous – 2014-08-11T00:29:12.843

@comperendinous Only dodges bullets from the target, with a 100% success rate. – es1024 – 2014-08-11T00:36:43.547

I really expected an EmoWolf submission by now :( – Bob – 2014-08-11T00:58:55.267

A curiosity though. How come the DONTNUKEMEBRO bot suddenly fell to last place? – Doktoro Reichard – 2014-08-11T01:28:04.243

@DoktoroReichard From the logs, it seems that DONTNUKEMEBRO got hit by the truck ~35 times. – es1024 – 2014-08-11T01:42:17.300

2

@Bob Pretty sure EmoWolf got added to Standard Loopholes which are no longer funny. Though a suicidal entry might not actually do so terribly.

– es1024 – 2014-08-11T01:48:38.590

3Lesson to everyone : Don't drink and drive. – Zaenille – 2014-08-11T01:56:46.200

8@es1024 Where suicide is actually a viable strategy, an EmoWolf-type submission really should be allowed. Especially when the available actions explicitly include suiciding! Not so much a "loophole" now, is it? And not really an unfair advantage, which most of those loopholes really are. But that's just my opinion. – Bob – 2014-08-11T02:20:44.323

@DoktoroReichard Yeah, that's kinda painful to see. My little guy get punished because he lasts so long. But I've made some changes to him that will hopefully set that right. – AndoDaan – 2014-08-11T04:28:14.290

Is this thing still on the road? – AndoDaan – 2014-08-11T22:11:43.970

1@AndoDaan I'm running the controller again once I get the entries updated. – es1024 – 2014-08-11T22:43:46.137

3Based on running the controller a couple times it seems pretty noisy. If this contest ever gets closed you should probably up the number of runs to smooth it out a bit. – Davis Yoshida – 2014-08-12T04:47:53.793

I posted just as this one ran... T^T – Josef E. – 2014-08-12T21:04:56.857

In all your logs, my bot just gives N...so I m assuming it didn't work (since it's not supposed to ever give a N)? – plannapus – 2014-08-13T06:01:52.010

@plannapus Seems that some of the extra text Rscript outputted might have interfered; I fixed the controller and Bomberman seems to be responding appropriately. – es1024 – 2014-08-13T07:48:03.203

Could I suggest to add an alternative scoring method where you get a point for every life you have less than the winner at the end of a fight and where more points is worse? This would make grenades more of an option. – overactor – 2014-08-13T08:46:21.420

@es1024 thanks for the feedback! – plannapus – 2014-08-13T08:58:40.063

1@overactor Bonuses for getting 1st/2nd/3rd were added (as originally intended, but it seems I forgot to add them in earlier), and the main post has been updated. This should make grenades more of an option. – es1024 – 2014-08-14T07:37:10.360

Answers

7

Observer

This guy analyses his enemies. The goal is to survive until only one "aggressive" opponent is left, and then kill that one in an epic standoff.

Compile: javac Observer.java Run: java Observer arg0 arg1

import java.util.List;
import java.util.ArrayList;
import java.util.Random;

class Observer {
    private static List<Integer> aggressiveEnemies = new ArrayList<>();
    private static List<Integer> enemyGrenadiers = new ArrayList<>();
    private static List<Integer> aliveEnemies = new ArrayList<>();

    public static void main(String[] args) {
        if (args[1].length() <= 7) { //first round
            Random rand = new Random();
            printResult("D" + (rand.nextInt(3) + 1));
        }
        String players[] = args[1].split(" ");

        if (truckIsOnWay(players[0])) {
            printResult("P");
        }       

        calcEnemyInfo(players);

        // end this standoff now
        if (truckWillHit(players[0])) {
            if (isGrenadier(players[0]))
                printResult("T" + aliveEnemies.get(0));
            else
                printResult("S0");
        }

        // shoot enemy who is not aggressive
        if (aggressiveEnemies.size() == 0) {
            printResult("S" + aliveEnemies.get(0));
        }

        // only one enemy to handle
        if (aggressiveEnemies.size() == 1) {
            String player = players[aggressiveEnemies.get(0)];
            if (isGrenadier(player)) {
                printResult("S" + aggressiveEnemies.get(0));
            } else if (shotLastTurn(player, aggressiveEnemies.get(0))) {
                //safe to shoot him without receiving damage
                printResult("S" + aggressiveEnemies.get(0));
            } else {
                printResult("D" + aggressiveEnemies.get(0));
            }
        }

        // multiple aggressive enemies
        if (enemyGrenadiers.size() > 0) {
            printResult("S" + enemyGrenadiers.get(0));
        } else {
            int id = aggressiveEnemies.get(0);
            for (int playerId : aggressiveEnemies) {
                if (!shotLastTurn(players[playerId], playerId)) {
                    id = playerId;
                }
            }
            printResult("D" + id);
        }
    }

    private static void printResult(String result) {
        System.out.print(result);
        System.exit(0);
    }

    private static boolean isAlive(String player) {
        return !(player.charAt(0) == '-' || player.charAt(0) == '0');
    }

    private static void calcEnemyInfo(String[] players) {
        for (int i = 1; i < players.length; i++) {
            if (isAlive(players[i])) {
                aliveEnemies.add(i);
                if (isAggressive(players[i], i)) {
                    aggressiveEnemies.add(i);
                }
                if (isGrenadier(players[i])) {
                    enemyGrenadiers.add(i);
                }
            }
        }
    }

    private static boolean truckIsOnWay(String player) {
        return player.length() - player.replace(",", "").length() == 48;
    }

    private static boolean truckWillHit(String player) {
        return player.length() - player.replace(",", "").length() == 49;
    }

    private static boolean isAggressive(String player, int id) {
        return (player.contains("S") || player.contains("P")) && !player.contains("S" + id);
    }

    private static boolean isGrenadier(String player) {
        return player.contains("P");
    }

    private static boolean shotLastTurn(String player, int id) {
        return player.charAt(player.length() - 2) == 'S' && !player.contains("S" + id);
    }
}

CommonGuy

Posted 2014-08-09T20:54:50.450

Reputation: 4 684

!player.contains("S" + id) is this a necessary condition in the "isAggressive" function? A suicidal player will be dead anyway – Cruncher – 2018-05-01T23:17:25.573

22

Grenadier

Guns are overrated. A true Scotsman's standoff goes like this:

  • Prepare
  • Throw at enemy with most health
  • Repeat (if by some miracle you're still alive)

While this seems trivial, it's probably not a terrible strategy. Since guns and grenades both have a two-turn cycle, this is by far the more efficient1 way to deal damage.

Of course, if all three opponents shoot me on the first round it's no good. But not much else would be, either.

public class Grenadier {
    public static void main(String[] args) {
        if(args.length < 2)
            return;
        String[] list = args[1].split(" ");
        if(list.length < 4)
            return;

        if(list[0].charAt(list[0].length()-1) != 'P'){
            System.out.print("P");
            return;
        }

        int target = 1;
        for(int i=2;i<4;i++)
            if(list[i].charAt(0)>list[target].charAt(0))
                target = i;

        System.out.print("T"+target);
    }
}

Compile/run in the standard Java way:

> javac Grenadier.java
> java Grenadier arg0 arg1

1 Pointless footnote

Geobits

Posted 2014-08-09T20:54:50.450

Reputation: 19 061

41hahaha the footnote – proud haskeller – 2014-08-09T23:16:56.360

I think throwing a grenade, and then shooting is more efficient. The chance of you surviving 4 turns with this strategy is numbingly low. But 3 maybe (yes, both take 2, but the second turn for shooting is after the action, not before) – Cruncher – 2014-08-11T14:05:50.347

@Cruncher You're probably right. Eric said the same thing in chat. I told him my guy doesn't believe in guns and is too stubborn to use that logic, so he posted that strategy. However, I still believe this to be more efficient, if we're strictly talking damage dealt. That doesn't mean it's more effective at winning the game. Even if I die on the third turn, my second grenade still goes off. So if I live until then, that's guaranteed 6+ damage to everyone, game over.

– Geobits – 2014-08-11T14:20:50.127

@Geobits now that I think about it, this may be better. The thing that matters most is the delta between you and opponents. When the grenade blows up, you gain +3 delta with who you threw it at, and +0 with the rest. A net of +3. Shooting. Gains you a +2 delta with who you shoot. +0 with the rest. I think the problem is that you -3 with people that are already dead. You should shoot if anyone is dead :) – Cruncher – 2014-08-11T14:46:35.907

@Cruncher If I successfully throw the grenade, I get +5 against that person, since it does 8 damage. Either way, since the target is guaranteed dead after one throw, that logic just leads back to "P,Tx,Sx" again :) – Geobits – 2014-08-11T14:50:23.413

@Geobits I mis-read. I thought grenade did 6 damage. It really packs a punch! So after 1 throw, if 1 guy is dead(doesn't take damage), then you get a +5 delta, and a -3. So still +2 which ties with the gun. This is also much more dramatic ^.^ – Cruncher – 2014-08-11T14:56:20.460

@Geobits I think Han Solo is beating you because in your games (even if you win them), the average health is lower than in Han Solo games. The scoring should award extra points for winning. In which case, I think you may win – Cruncher – 2014-08-11T14:58:12.677

@Cruncher Probably. I'm okay with 2nd place. I came up with a simple tactic and it's serving me fairly well. – Geobits – 2014-08-11T15:03:46.610

Is this a Team Fortress reference? – codebreaker – 2014-08-11T15:10:39.097

2

@codebreaker Never played it. It's a real life reference.

– Geobits – 2014-08-11T15:11:45.373

16

Asimov's Rule Number 0 Bot - Python

A robot may not harm humanity, or, by inaction, allow humanity to come to harm.

Pretty straight forward, he'll attack the first player he sees holding a grenade in order to protect the majority of humans. If no one is a threat to the majority of humans, he'll do nothing.

import sys

def total_humans_alive(humans):
  return sum([is_alive(human) for human in humans])

def is_alive(x):
  return int(x.split(",")[0]) > 0  

def is_threat_to_humanity(lastAction):
  return lastAction == "P"

action = "N"
threat_id = 1
humans = sys.argv[2].split()[1:];

if total_humans_alive(humans) == 3:
  for human in humans:
    if is_threat_to_humanity(human[-1]):
      action = "S" + str(threat_id)
      break
    threat_id= threat_id+ 1

print action

Run it like:

python rule0bot.py

William Barbosa

Posted 2014-08-09T20:54:50.450

Reputation: 3 269

2Your robot is illogical. If the player holding the grenade throws, humanity takes 8+3+3+3=17 damage. If you kill him with the shot, humanity takes 2+6+3+3+3=17 damage. In both scenarios, whoever has the grenade blow up on them takes 8 and all others take 3 (unless they were previously dead). Humanity as a whole is not affected. I still like it, though. +1 :D – Geobits – 2014-08-11T16:11:12.970

4Actually, the best scenario for humanity is to hope the grenade is tossed at the robot ;) – Geobits – 2014-08-11T16:14:04.617

1@Geobits Not trying to stop someone who's a threat is against the nature of robots. It'll try to stop someone holding a grenade to prevent the majority (other two) from being hurt. Have you read I, Robot? This logic is backed by Little Lost Robot and The Evitable Conflict. – William Barbosa – 2014-08-11T16:15:54.103

I've read it, but what I'm saying is that shooting them doesn't stop it here. If he dies while holding the grenade, it still explodes. Not only that, but the total amount of damage done to humanity remains the same. You're doing direct harm to a human with no gain to humanity. – Geobits – 2014-08-11T16:17:21.250

-1. This is virtually identical to my answer, which was posted about 20 minutes before yours.

– Kyle Kanos – 2014-08-11T19:48:46.353

@KyleKanos I commented it on your answer, but then I realized mine is different because it does nothing if the grenade won't hurt the majority (if someone is dead). I began writing it before your submission was posted. I suck balls at Python, though, that's why it took me so long to write and post. I'm sorry if it looks like I copied you, it's all due to my lack of python skills :| – William Barbosa – 2014-08-11T19:52:22.247

Does print work just like return in total_humans_alive ()? – comperendinous – 2014-08-11T19:57:35.097

@comperendinous Nope. Pasted the wrong script. Thanks for letting me know – William Barbosa – 2014-08-11T20:00:17.413

@WilliamBarbosa: Mine skips dead people as well, the first line in the loop is if moves:sub(1,1)~="-" the negative sign means the player is dead, so it skips those players (~= is not equals). The only difference between ours is the language and name. – Kyle Kanos – 2014-08-11T20:02:17.790

2+1 I disagree with Kyle Kanos's vote and want to nullify it. Also, Geobits is wrong in assuming this does nothing to help humanity. Sure, humanity may not come out better in the worst case scenario, but if the other two players shoot the grenade wielding douche then they're all better for it. – FreeAsInBeer – 2014-08-11T21:24:46.703

Clearly doing the same amount of damage to an already dead person is less harm done to humanity than the same to an alive person. – Steven Lu – 2014-08-13T21:42:23.943

14

Han Solo - Python

Han shot first. In this case, he'll shoot first by picking the closest target alive.

import sys

def is_alive(player):
  return int(player.split(",")[0]) > 0

closest_living_target = 1;

for player in sys.argv[2].split()[1:]:
  if is_alive(player):
    action = "S" + str(closest_living_target)
    break

  closest_living_target = closest_living_target + 1

print action

Run it like:

python hansolo.py

Note: This is the first thing I ever wrote in Python, so if you see any python-specific bad practices, please let me know.

William Barbosa

Posted 2014-08-09T20:54:50.450

Reputation: 3 269

python hansolo.py 3 "5 5 5 5" gives the following error: File "hansolo.py", line 15. print action. SyntaxError: invalid syntax – es1024 – 2014-08-10T02:06:00.107

@es1024 Fixed it. – William Barbosa – 2014-08-10T02:20:19.567

Pythonic version using list comprehension for shooting someone: print("S" + next(str(x) for x in range(1,4) if isAlive(sys.argv[2].split()[x]))) (not thoroughly tested though) – MrLemon – 2014-08-11T12:47:47.723

1pep8 style suggests your method should be is_alive – Daenyth – 2014-08-11T15:02:54.613

@Daenyth I like python, but hate the variable naming conventions. Is that bad? always hated underscores – Cruncher – 2014-08-11T15:05:00.697

Well, you asked for python-specific feedback; It's standard across pretty much every python project so if you ever work with other people you should expect it. – Daenyth – 2014-08-11T15:08:44.257

@Daenyth Thanks, man. Does this convention apply to variables and class names too? – William Barbosa – 2014-08-11T15:38:19.470

4

@WilliamBarbosa have a look at pep8, it's the python style guide that everyone uses. http://legacy.python.org/dev/peps/pep-0008/

– Daenyth – 2014-08-11T15:57:29.757

2Congratulations on being the only bot with an average health greater than 0, in the 8/11 round. – isaacg – 2014-08-11T17:51:25.107

6IMO, "style guides" are for hair dressers, not programmers. – Kyle Kanos – 2014-08-11T18:39:40.230

2@KyleKanos It's nice to have some consistency, though. I mean, if half the developers of a project use camel case and the other half types like this, the result will be "blergh" – William Barbosa – 2014-08-11T19:00:59.033

@WilliamBarbosa: Perhaps it's the scientist (comp. astro.) in me, but so long as it's commented enough & works, I don't care what it looks like. If you really want to cry about ugly code that works beautifully, take a look at CCSE's Castro or the Enzo-project code. – Kyle Kanos – 2014-08-11T19:04:20.380

@Daenyth I didn't say that I refuse to use the style guide. Simply that I dislike it :) – Cruncher – 2014-08-11T19:51:34.317

@KyleKanos from someone who works as a software developer, style guides are important for consistency. If you're working on my code, I don't care what style you use, provided it's the same as everyone else working on the code. If I see a project I want to contribute to, and it has a style I don't like, I either 1) don't contribute or 2) contribute with the same style. If you're the only one who will add code to a project, it's a moot point. – skeggse – 2014-08-12T07:17:18.997

@distilledchaos: In a way, I am a software developer (I work on an academic-research-level hydrodynamics code with several other people). I don't care much for style, so long as it (a) works, (b) doesn't @%$# up the rest of the code and (c) is commented enough to see what is being done (e.g., references for equations). – Kyle Kanos – 2014-08-12T23:55:31.040

I've been on that side of the puzzle, and the biggest difference I've seen is that software development geared towards customer use is/should be based upon maintainability. If the customer has your software, it's harder to fix bugs when they crop up, and having consistent style means that it's easier for anyone on your team to review changes and fix things, removing (perhaps not altogether) the dependency on the original developer. – skeggse – 2014-08-13T05:23:58.863

12

EmoCowboy

Why wait to die? Just kill yourself now. Hopefully the rest of the fools will blow eachother up to much less than -2.

Score will normally be -2. Sometimes -4 if people decide to shoot me off the bat. Rarely more than that, which means this should beat several of the current submissions.

Python

print('S0')

python EmoCowboy.py

EDIT: This isn't a joke, which is generally why these emo submissions are frowned upon. This is a legitimate strategy. Being alive is deadly!

Cruncher

Posted 2014-08-09T20:54:50.450

Reputation: 2 135

11

Pacifist

He's a real swell guy, just got caught up with the wrong crowd.

main = putStr "N"

Run as runghc pacifist.hs, but you might want to compile it with -O3 if efficiency is an issue.

killmous

Posted 2014-08-09T20:54:50.450

Reputation: 369

1

Please rename it Luigi and let's see if he'll win anything!

– William Barbosa – 2014-08-10T00:50:46.793

1

@WilliamBarbosa Luigi? Did you say Luigi?

– killmous – 2014-08-10T01:01:36.777

7Lol as if -O3 makes a freakin' difference. – tomsmeding – 2014-08-10T16:42:31.343

@tomsmeding It's slow on the runghc side. Actually it's 10 times slower on my Linux box. – Ray – 2014-08-10T21:31:25.047

wouldn't dodging pacifist be better? – Dunno – 2014-08-11T15:18:34.947

5That implies the existence of violence, an implication our pacifist is not prepared to handle – killmous – 2014-08-11T15:20:29.383

@Dunno: I posted a dodger-only called Ninja (and probably around the same time you posted that comment).

– Kyle Kanos – 2014-08-11T20:04:22.103

@KyleKanos And Pacifist is beating Ninja, what's up with that?! – Michael – 2014-08-13T04:13:52.207

@William: I thought that was a reference to Luigi wins by doing absolutely nothing

– 3Doubloons – 2014-08-13T05:35:26.137

9

Monkey -- Python (First ever entry!)

Monkey see, monkey do. Will repeat exactly the last action taken by a random player.

import sys, random
targetData = sys.argv[2].split()[random.randint(0,3)]
print(targetData.split(',')[len(targetData.split(','))-1])

Can be run like this: "python monkey.py args" No extra steps required.

Elias Benevedes

Posted 2014-08-09T20:54:50.450

Reputation: 285

2I hope they weren't shooting at you! Python supports negative array indices, so you don't need to calculate the length and subtract one; just use -1 directly. – comperendinous – 2014-08-11T04:13:01.603

@comperendinous Say I'm S3 in their list. If I execute S3, it won't shoot me silly. Also, the -1 index will return the last element? If so, cool! I'll be sure to add it. – Elias Benevedes – 2014-08-11T04:18:37.880

And don't forget the first (integer) argument. You need argv[2] to get the players history. – comperendinous – 2014-08-11T19:48:46.867

Just hope you don't get matched up with Emo Cowboy. – codebreaker – 2014-08-13T14:47:01.150

6

Simple Shooter - Perl (fixed bug)

This bot shoots at the opponent with the most health. It's a very simple strategy, but I think it has a decent chance of actually doing well.

@history = map([split(",",$_)],split(" ",$ARGV[1]));
$target = 1;
for(2..3){
 if($history[$_][0] >= $history[$target][0]){$target = $_}
}
print "S$target"

This is how to run it using some example input:

perl simpleshooter.plx 7 "3,S2,N 5,P,N 3,S0,N -2,S3,N"

PhiNotPi

Posted 2014-08-09T20:54:50.450

Reputation: 26 739

Wow. Simple and smart. – Soham Chowdhury – 2014-08-19T17:37:26.637

6

Spock, in Python 3.x

This code is more of a though experiment (hence named after Spock because... he's a vulcan, and they're pretty good at these sort of things) but was fun building it nonetheless. The main reasoning behind all this code are assumptions a good, logical being, like Spock, would do, if given the game's rules:


The objective of this game is to maximize score, which would be done by everyone just standing still, which isn't possible, due to the truck.

  • One of the directives Spock has to follow is to prevent the truck from appearing, making sure that everyone but one is dead before the truck appears.

The way Spock plays in the rest of the game can be summed up by his famous quote: "The needs of the many outweigh the needs of the few". In other words, Spock has to make sure that the least amount of damage is suffered, by killing those that do it. How he does it:

  • If no player has prepped a grenade, target the least healthy player that's still playing.
  • If there are players that prepped grenades, from those target the least healthy.

The reasoning is that, by targeting the weakest players, we are terminating sources of damage. The reasoning behind the grenades is that they are going off regardless and they do less damage if they aren't thrown.


And so this bot works. I haven't tested extensively for input failures (so please warn me if something goes awry) but I'm confident I worked out most of the kinks. I based a small part of the code from the HanSolo bot but for the most part it's a tangled mess of code. Enjoy.

def IsAlive(player):
  return int(player[1].split(",")[0]) > 0
def IsTarget(player, target_health):
  return int(player[1].split(",")[0]) < target_health
def HasGrenade(player):
  max_range = max(-4,-current_turn)
  for foo in range(-1,max_range,-1):
    if "P" in player[1].split(",")[foo]:
      for bar in range(-1,foo-1,-1):
        if player[1].split(",")[bar] not in ["T0", "T1", "T2", "T3"]:
          return True
  return False

import sys
info_list = sys.argv[2].split()
current_turn = len(info_list[0].split(","))
action = "N"

def Startgame():
  global action

  target = 1
  target_health = 5
  grenade_list=[]

  for player in zip(range(1,4),info_list[1:]):
    if HasGrenade(player):
      grenade_list.append(player)

  if not grenade_list:
    foo_list = []
    for player in zip(range(1,4),info_list[1:]):
      foo_list.append(player)
    target_list = foo_list
  else:
    target_list = grenade_list

  # Choose the least healthy player
  for player in target_list:
    if IsAlive(player) and IsTarget(player, target_health):
      target = player[0]
      target_health = int(player[1][0])

  action = "S" + str(target)

def Endgame(turn):
  global action

  if turn in [47, 49]:
    # Check if in 2 moves he can do enough damage
    rem_health = 0
    for player in zip(range(1,4),info_list[1:]):
      if IsAlive(player): rem_health += player[0]

    if rem_health < 5:
      Startgame() # It's lazy, but it should work
      return
    else:
      action = "P"
      return

  if turn in [48, 50]:
    # If Spock shot someone before, it needs to shoot again
    if info_list[0].split(",")[-1] in ["S0", "S1", "S2", "S3"]:
      Startgame()
      return
    else:
    # There's no rule against throwing grenades to dead bodies, so if
    # possible it will be thrown there.    
      target = 1
      target_health = 5

      foo_list = []
      for player in zip(range(1,4),info_list[1:]):
        foo_list.append(player)
      target_list = foo_list

      for player in target_list:
        if IsTarget(player, target_health):
          target = player[0]
          target_health = int(player[1][1])

      action = "T" + str(target)
      return

if current_turn > 46:
  Endgame(current_turn)
else:
  Startgame()

print(action)

Run it like:

python spock.py

2014-08-12 - Minor bugfix regarding grenade detection
2014-08-14 - Minor bugfix regarding endgame, thanks to isaacg for pointing it out before

Doktoro Reichard

Posted 2014-08-09T20:54:50.450

Reputation: 419

You're not allowed to shoot more than once every two rounds. Read the spec on shooting. – isaacg – 2014-08-11T17:52:58.903

@isaacg Thanks for the reminder (which does explain the behavior), but there seems to be some latent bugs. For instance in this Spock should have shot InputAnalyser because he had a live grenade (even if Solo would have more 2 health).

– Doktoro Reichard – 2014-08-11T22:33:58.513

Traceback (most recent call last): File "./players/Spock/Spock.py", line 87, in <module>: Endgame(current_turn) File "./players/Spock/Spock.py", line 79, in Endgame: if IsTarget(player, target_health): File "./players/Spock/Spock.py", line 4, in IsTarget: return int(player[1].split(",")[0]) < target_health TypeError: unorderable types: int() < str() – es1024 – 2014-08-12T20:54:49.973

player[1][1] should be int(player[1][1]). – isaacg – 2014-08-12T22:38:56.140

@isaacg again, I thank you for the help. I would have done this sooner but I've been swamped with stuff. Spock was ultimately built upon a misguided concept on how this would play out, hence the relatively lower score he has gotten. I do have some ideas for new bots, but with so many I now have to make sure that the main idea is original. – Doktoro Reichard – 2014-08-14T22:05:43.490

5

Straight Shooter

He's a trained part of the cavalry and talks in many languages but, being blinkered, Straight Shooter can only see the one enemy in front of him. Being a horse, he doesn't understand that you have to wait between shots.

print('S2')

Perl, Python 2/3, Ruby: this horse really is a polygot entry.

I'm winning anyway. I can't lose. You can shoot me but you can't kill me. Mister Ed ain't got shit on me!

For an answer that has a little more thought (and some functional paradigm) put into it, see Twenty-Fourth and a Halfth Century.

comperendinous

Posted 2014-08-09T20:54:50.450

Reputation: 466

5

Politically Correct Gunman

Very politically correct, as it doesn't discriminate against anything. Thus it isn't very smart.

import random

array = ["P", "N", "S0", "S1", "S2", "S3", "D1", "D2", "D3", "T1", "T2", "T3"]

print(array[random.randrange(0,11)])

It... doesn't really matter what arguments get passed to it how. python politicallycorrectgunman.py

Undo

Posted 2014-08-09T20:54:50.450

Reputation: 413

I don't think the square brackets are supposed to part of the output. Perhaps @es1024 can confirm that. And do you know about random.choice? It's great for these kind of selections. – comperendinous – 2014-08-10T00:31:55.933

there can't be anything before the action and target in the output, though anything after is ignored – es1024 – 2014-08-10T01:22:09.620

Does that look better @es1024? – Undo – 2014-08-10T01:39:56.410

@Undo Yes, works perfectly now – es1024 – 2014-08-10T02:25:13.553

7Couldn't you just use random.choice(array)? – user2357112 supports Monica – 2014-08-10T13:10:16.887

5

Anti-grenadier

Grenades are bad. Very bad. So if anyone is preparing one, best thing to do is shoot them. Otherwise, we'll just hang out.

-- Antigrenadier
local args = {...}  -- command line arguments

match = args[2]     -- store the set of matches

-- why this isn't standard in Lua....
function string:split( inSplitPattern, outResults )
  if not outResults then
    outResults = { }
  end
  local theStart = 1
  local theSplitStart, theSplitEnd = string.find( self, inSplitPattern, theStart )
  while theSplitStart do
    table.insert( outResults, string.sub( self, theStart, theSplitStart-1 ) )
    theStart = theSplitEnd + 1
    theSplitStart, theSplitEnd = string.find( self, inSplitPattern, theStart )
  end
  table.insert( outResults, string.sub( self, theStart ) )
  return outResults
end

-- set up the players
players = match:split(" ")

-- search other players for someone who pulled a grenade
for i=2,#players do
   moves = players[i]
   -- test if person is alive
   if moves:sub(1,1) ~= "-" then
      -- cycle through all elements of the string
      for j=#moves,2,-1 do
         -- if found, shoot!
         if moves:sub(j,j) == "P" then
            print("S"..i-1)
            os.exit()
         end
      end
   end
end

-- otherwise we just relax
print("N")

Kyle Kanos

Posted 2014-08-09T20:54:50.450

Reputation: 4 270

4

Aggressor

Pulls on round one, throws at highest health opponent on round 2, shoots at highest health opponent thereafter.

#include <cstdio>
#include <cstring>

int main(int argc, char** argv){
   char* t;
   t = strtok(argv[2]," ");
   int len = strlen(t);
   int max = -50, maxP;
   for(int i=1;i<4;i++){
      int cur;
      t = strtok(NULL," ");
      if(t[0]=='-'){cur = -1*(t[1]-'0');}
      else{cur = t[0]-'0';}
      if(cur>max){
         max = cur;
         maxP = i;
      }
   }
   if(len == 1){printf("P\n"); return 0;}
   if(len == 3){printf("T%d\n",maxP); return 0;}
   printf("S%d\n",maxP);
   return 0;
}

Run this like ./agg ID "5 5 5 5".

Eric Tressler

Posted 2014-08-09T20:54:50.450

Reputation: 1 913

4

Ricochet - Perl

Simple strategies seem to do decently in this challenge, so here's another. It shoots a random living player. It has the added feature of committing suicide at the end to avoid the truck.

@history = map([split(",",$_)],split(" ",$ARGV[1]));
$health = $history[0][0];
@options = ();
for(1..3){
 if($history[$_][0] > 0){
  push(@options,$_);
 }
}
$target = @options[int(rand(~~@options))];
if(~~@{$history[0]} == 50){
 $target = 0;
}
print"S$target";

Run like so:

perl ricochet.plx 5 "-2,S0 -2,S1 -2,S2 5,N" 

PhiNotPi

Posted 2014-08-09T20:54:50.450

Reputation: 26 739

4

Ninja

Just dodges randomly trying to avoid getting hit.

math.randomseed(os.time())
print("D"..tostring(math.random(4)-1))

run as

lua ninja.lua

Args are unnecessary, but can be added w/o issue.

Kyle Kanos

Posted 2014-08-09T20:54:50.450

Reputation: 4 270

2@KyleKanos will Ninja dodge its own shots? – skeggse – 2014-08-12T07:27:13.777

2@distilledchaos: ...yes, yes he will. – Kyle Kanos – 2014-08-12T11:14:28.923

4

Name: PriorityTargets

Shell Command: ruby PriorityTargets.rb 5 [game_state]

Language: Ruby V2.1.2

Description: PriorityTargets attempts to find common playstyles. It then decides, based on those playstyles, who it wants to attack and what weapon to use.

Note: First Code Golf submission! Much larger than the other submissions because I went a little crazy.

#!/usr/bin/env ruby

class PriorityTargets
  class PlayerAction
    SHOOT = 'S'
    DODGE = 'D'
    PREPARE_GRENADE = 'P'
    THROW_GRENADE = 'T'
    NOTHING = 'N'
    attr_accessor :action, :target

    def initialize(action_string)
        @action = action_string[0, 1]
        @target = self.has_target? ? action_string[1, 1].to_i : false
    end

    def to_s
      string = @action
      string << @target.to_s if self.has_target?
      string
    end

    def has_cooldown?
      [SHOOT].include? @action
    end

    def is_aggressive?
      [SHOOT, PREPARE_GRENADE, THROW_GRENADE].include? @action
    end

    def has_target?
      [SHOOT, DODGE, THROW_GRENADE].include? @action
    end
  end


  class Player
    attr_reader :identifier, :health, :history
    attr_accessor :playstyles

    def initialize(player_identifier, player_string)
      @identifier = player_identifier
      @playstyles = []

      player_info = player_string.split(',')
      @health = player_info.shift.to_i
      @history = parse_history(player_info)
    end


    def has_attacked?(player, round = nil)
      round ||= self.history.length - 1
      player.history[0, round].each do |turn|
        did_attack = true and break if turn.is_aggressive? && turn.has_target? && turn.target == player.identifier
      end
      did_attack ||= false
    end

    def is_holding_grenade?(round = nil)
      round ||= self.history.length
      turn_history = self.history[0, round]
      is_holding = false

      turn_history.each_with_index do |turn, curr_round|
        if turn.action == PlayerAction::PREPARE_GRENADE && curr_round >= round - 3
          is_holding = true if turn_history.drop(curr_round).select{|turn| turn.action == PlayerAction::THROW_GRENADE }.length == 0
        end
      end

      is_holding
    end

    def is_dead?; self.health <= 0; end
    def is_on_cooldown?
      return false if self.history.length == 0
      self.history.last.has_cooldown?
    end

    def turn_at_round(round); self.history[round-1]; end

    private

      def parse_history(history_array)
        parsed = []
        history_array.each {|action_string| parsed << PlayerAction.new(action_string) }
        parsed
      end
  end

  class PlayerList
    include Enumerable

    def initialize(player_list = [], filter_list = false)
      @list = player_list
      @filter = filter_list if filter_list
    end

    #Enumerable Methods
    def each
      list = @list.select{|player| @filter.include?(player.identifier) } if @filter
      list = @list unless @filter
      list.each {|player| yield(player) }
    end

    def <<(player); @list << player; end
    def [](key)
      player = @list.select{|player| @filter.include?(player.identifier) }[key] if @filter
      player = @list[key] unless @filter
      player
    end

    def length
      list = @list.select{|player| @filter.include?(player.identifier) } if @filter
      list = @list unless @filter
      list.length
    end

    def empty?; self.length == 0; end
    def not_empty?; self.length > 0; end

    def create_filtered_list(player_ids)
      new_player_list = PlayerList.new(@list, player_ids)
      new_player_list
    end

    #PlayerList Methods
    def includes_playstyle?(playstyle)
      (self.with_playstyle(playstyle).length > 0)
    end

    def have_executed_action?(action)
      action_found = false
      self.each {|player| action_found = true and break if player.history.select {|turn| turn.action == action}.length > 0 }
      action_found
    end

    def direct_damages(round = nil)
      round ||= self.first.history.length

      damage_list = {}
      @list.each {|player| damage_list[player.identifier] = 0 }

      if round >= 1
        @list.each do |player|
          player.history[0, round].each_with_index do |turn, curr_round|

            if turn.has_target?
              target_player = @list.select{|curr_player| curr_player.identifier == turn.target }.first
              target_turn = target_player.turn_at_round(curr_round)

              damage_list[turn.target] += 8 if turn.action == PlayerAction::THROW_GRENADE

              if turn.action == PlayerAction::SHOOT
                damage_list[turn.target] += 2 unless target_turn.action == PlayerAction::DODGE && target_turn.target == player.identifier
              end
            end
          end
        end
      end

      damage_list.select! {|key| @filter.include? key } if @filter
      damage_list
    end


    def filtered_with_condition(&condition_block)
      player_ids = []
      self.each {|player| player_ids << player.identifier if condition_block.call(player) }
      create_filtered_list(player_ids)
    end

    def on_cooldown; filtered_with_condition {|player| player.is_on_cooldown?} end
    def not_on_cooldown; filtered_with_condition {|player| !player.is_on_cooldown?} end

    def dead; filtered_with_condition {|player| player.is_dead?} end
    def not_dead; filtered_with_condition {|player| !player.is_dead?} end

    def with_playstyle(playstyle); filtered_with_condition {|player| player.playstyles.include?(playstyle)} end
    def not_with_playstyle(playstyle); filtered_with_condition {|player| !player.playstyles.include?(playstyle)} end

    def with_max_health(round = nil)
      round ||= self.first.history.length
      player_damages = direct_damages(round)
      filtered_with_condition {|player| player_damages[player.identifier] == player_damages.values.min }
    end

    def with_identifier(identifier)
      matches = self.with_identifiers([ identifier ])
      return nil if matches.empty?
      matches.first
    end

    def with_identifiers(identifiers)
      create_filtered_list(identifiers)
    end
  end

  class PlayerTypes
    GRENADIER = :GRENADIER
    COWBOY = :COWBOY
    SKIDDISH = :SKIDDISH
    AGGRESSOR = :AGGRESSOR
    DEFENSIVE = :DEFENSIVE
    ANTI_GRENADIER = :ANTI_GRENADIER
    PLAYSTYLE_ORDER = [GRENADIER, COWBOY, SKIDDISH, AGGRESSOR, DEFENSIVE, ANTI_GRENADIER]

    def initialize(player_list)
      @players = player_list
    end

    def analyze_playstyles
      return if @players.first.history.length == 0

      PLAYSTYLE_ORDER.each do |playstyle|
        check_fnc = "is_"+playstyle.to_s+'?'
        @players.each {|player| player.playstyles << playstyle if self.send(check_fnc, player) }
      end
    end

    def is_GRENADIER?(player)
      #Grenade on first turn
      #Used more than one grenade
      #Never used gun, only grenade
      shoot_count = player.history.count {|turn| turn.action == PlayerAction::SHOOT }
      grenade_count = player.history.count {|turn| turn.action == PlayerAction::PREPARE_GRENADE }

      profiled ||= true if player.history.first.action == PlayerAction::PREPARE_GRENADE
      profiled ||= true if grenade_count > 1
      profiled ||= true if shoot_count == 0 && grenade_count > 0
      profiled ||= false
    end

    def is_COWBOY?(player)
      #Never used grenade, only gun
      shoot_count = player.history.count {|turn| turn.action == PlayerAction::SHOOT }
      grenade_count = player.history.count {|turn| turn.action == PlayerAction::PREPARE_GRENADE }

      profiled ||= true if grenade_count == 0 && shoot_count > 0
      profiled ||= false
    end

    def is_SKIDDISH?(player)
      #Dodged more than once
      #Never hurts anybody
      dodge_count = player.history.count {|turn| turn.action == PlayerAction::DODGE }
      attack_count = player.history.count {|turn| turn.is_aggressive? }

      profiled ||= true if dodge_count > 1
      profiled ||= true if attack_count == 0 && player.history.length > 1
      profiled ||= false
    end

    def is_AGGRESSOR?(player)
      #Only shoots person >= most health
      profiled = false
      player.history.each {|turn| profiled = true if turn.is_aggressive? && turn.has_target? }

      player.history.each_with_index do |turn, round|
        if turn.is_aggressive? && turn.has_target?
          profiled = false if !@players.with_max_health(round).include? @players.with_identifier(turn.target)
        end
      end
      profiled
    end

    def is_DEFENSIVE?(player)
      #Only hurts people who hurt them first
      player.history.each {|turn| profiled = true if turn.is_aggressive? && turn.has_target? }

      player.history.each_with_index do |turn, round|
        if turn.is_aggressive? && turn.has_target?
          target_player = @players.with_identifier(turn.target)
          profiled = false unless target_player.has_attacked?(player, round)
        end
      end
      profiled ||= false
    end

    def is_ANTI_GRENADIER?(player)
      #After a Grenadier has been shown, only shoots grenadier
      shots_fired = 0
      shots_fired_while_holding = 0

      player.history.each_with_index do |turn, round|
        if turn.is_aggressive? && turn.has_target?
          target_player = @players.with_identifier(turn.target)
          shots_fired += 1
          shots_fired_while_holding += 1 if target_player.is_holding_grenade?(round)
        end
      end

      (shots_fired > 0 && shots_fired/2.0 <= shots_fired_while_holding)
    end
  end




  def initialize(game_state)
    players_info = game_state.split(' ')
    @player = Player.new(0, players_info.shift)
    @players = PlayerList.new
    @players << @player
    enemy_identifiers = []

    players_info.each_with_index {|info, index| @players << Player.new(index+1, info); enemy_identifiers << index+1; }

    @enemies = @players.with_identifiers(enemy_identifiers  )
  end

  def analyze_playstyles
    types = PlayerTypes.new(@players)
    types.analyze_playstyles
  end

  def find_dodge_target
    armed_aggressors = @enemies.with_playstyle(PlayerTypes::AGGRESSOR).not_on_cooldown().not_dead()

    if armed_aggressors.not_empty?
      return armed_aggressors.with_max_health().first if @players.with_max_health().include?(@player) && @players.with_max_health().length == 1
    end

    return @enemies[Random.rand(3)] if @player.history.length == 0
    nil
  end

  def find_target
    unarmed_aggressors = @enemies.with_playstyle(PlayerTypes::AGGRESSOR).on_cooldown().not_dead()
    anti_grenadiers = @enemies.with_playstyle(PlayerTypes::ANTI_GRENADIER).not_dead()
    grenadiers = @enemies.with_playstyle(PlayerTypes::GRENADIER).not_dead()
    cowboys = @enemies.with_playstyle(PlayerTypes::COWBOY).not_dead()
    skiddish = @enemies.with_playstyle(PlayerTypes::SKIDDISH).not_dead()
    defensive = @enemies.with_playstyle(PlayerTypes::DEFENSIVE).not_dead()

    if unarmed_aggressors.not_empty?
      return unarmed_aggressors.with_max_health().first if @players.with_max_health().include?(@player) && @players.with_max_health().length == 1
    end

    return anti_grenadiers.with_max_health().first if anti_grenadiers.not_empty?
    return grenadiers.with_max_health().first if grenadiers.not_empty?
    return cowboys.with_max_health().first if cowboys.not_empty?
    return skiddish.with_max_health().first if skiddish.not_empty?
    return defensive.with_max_health().first if defensive.not_empty?
    return @enemies.with_max_health().not_dead().first if @enemies.with_max_health().not_dead().length > 0
    nil
  end

  def find_weapon
    return PlayerAction::THROW_GRENADE if @player.is_holding_grenade?

    anti_grenadiers = @enemies.with_playstyle(PlayerTypes::ANTI_GRENADIER).not_dead()

    return PlayerAction::PREPARE_GRENADE if anti_grenadiers.empty? && @enemies.have_executed_action?(PlayerAction::PREPARE_GRENADE)
    PlayerAction::SHOOT
  end

  def make_decision
    dodge_target = self.find_dodge_target
    target = self.find_target
    weapon = self.find_weapon

    decision ||= PlayerAction.new(PlayerAction::NOTHING) if @player.is_on_cooldown? || @enemies.with_max_health().not_dead().length == 0
    decision ||= PlayerAction.new(PlayerAction::DODGE + dodge_target.identifier.to_s) if dodge_target
    decision ||= PlayerAction.new(weapon + target.identifier.to_s)
    STDOUT.write decision.to_s
  end
end

priority_targets = PriorityTargets.new(ARGV[1])
priority_targets.analyze_playstyles
priority_targets.make_decision

fingerco

Posted 2014-08-09T20:54:50.450

Reputation: 61

1I like your approach, I look forward to seeing how it will do. – overactor – 2014-08-17T18:10:34.327

Sadly, it seems that it had a bug in it which created a Grenadier. Ah well, will do better next time :) – fingerco – 2014-08-23T02:59:11.313

3

Coward -- Perl

Acts very cowardly. When he feels healthy, he chooses an enemy who does not feel so and shoots him. Bonus points for those enemies which were shooting the last turn (because they are known to be doing Nothing this turn and so be absolutely defenceless). When he feels not so good, he runs for cover to save his hide in, occassionally shooting someone.

#!/usr/bin/perl

@allinfo = map { [split/,/] } split / /, $ARGV[1];
@life = map { $_->[0] } @allinfo;
@action = map { @$_>1 ? $_->[-1] : () } @allinfo;

if($life[0] < 3 && rand() < .5 )
{
    printf "D%d", +(sort { ($life[$a]>0)*($action[$a] eq "N") <=> ($life[$b]>0)*($action[$b] eq "N") } 1..3)[2]
}
else
{
    @score = map { $life[$_]>0 ? (5/$life[$_] + 2*($action[$_] =~ /S./)) : 0 } 1..3;
    printf "S%d", +(sort { $score[$a] <=> $score[$b] } 1..3);
}

Pretty standard Perl code; save it in some file and then run perl file argument argument [...]. I have checked for syntax and it was OK, so I hope for no problems with this.

E: eliminated a potential for division by 0 error.

Ramillies

Posted 2014-08-09T20:54:50.450

Reputation: 1 923

3

Bomberman

Bot written in R, command line should be: Rscript Bomberman.R arg0 arg1
I realized after starting to write this bot that Geobits already made a grenadier but I think mine is significantly different, in that it checks its health is above 3 before preparing a grenade, throws it at the last shooter first, and the most healthy second, and if its health is below 3 it will dodge the dangerous player (neither dead nor shooter in the last round) or shoot one of the remaining player.

input <- commandArgs(TRUE)
history <- do.call(rbind,strsplit(scan(textConnection(input[2]),"",quiet=TRUE),","))
health <- as.integer(history[,1])
last_shooter <- which(grepl("S",history[-1,ncol(history)]))
last_prepare <- which(history[1,]=="P")
if(!length(last_prepare)) last_prepare <- -1
last_throw <- which(grepl("T",history[1,]))
if(!length(last_throw)) last_throw <- 0
most_healthy <- which.max(health[-1])
dead <- which(health[-1]<=0)
inoffensive <- c(last_shooter,dead)
danger <- which(!(1:3)%in%inoffensive)
alive <- which(!(1:3)%in%dead)
if(health[1]>3 & last_throw > last_prepare) out <- "P"
if(last_throw < last_prepare) out <- ifelse(length(last_shooter),paste("T",last_shooter[1],sep=""),paste("T",most_healthy[1],sep=""))
if(health[1]<=3 & last_throw > last_prepare){
    if(length(danger)){
        out <- paste("D",sample(danger,1),sep="")
    }else{
        out <- paste("S",sample(alive,1),sep="")
    }
}
cat(out)

Edit

There seems to be some communication problem between this bot and your controller since all logs that I looked showed that my bot only output N. So, here is the same bot but rewritten in Python, in the hope that if this one also have communications problem, someone will see it.
To be called with python Bomberman.py arg0 arg1.

import sys,re,random

history = sys.argv[2]
history = [k.split(",") for k in history.split()]
health = [k[0] for k in history]
last_turn = [k[-1] for k in history]
last_shooter = [i for i,x in enumerate(last_turn) if re.search(r'S[0-3]',x)]
last_prepare = [i for i,x in enumerate(history[0]) if x=='P']
if not len(last_prepare):
    last_prepare = [-1]

last_throw = [i for i,x in enumerate(history[0]) if re.search(r'T[0-3]',x)]
if not len(last_throw):
    last_throw = [0]

most_healthy = [i for i,x in enumerate(health) if x==max(health)]
dead = [i for i,x in enumerate(health) if x<=0]
inoffensive = last_shooter+dead
danger = [k for k in range(1,4) if k not in inoffensive]
alive = [k for k in range(1,4) if k not in dead]
if health[0]>3 and last_throw[-1] > last_prepare[-1]:
    out = 'P'

if last_throw[-1] < last_prepare[-1]:
    if len(last_shooter):
        out = 'T'+random.choice(last_shooter)
    else:
        out = 'T'+random.choice(most_healthy)

if health[0]<=3 and last_throw[-1] > last_prepare[-1]:
    if len(danger):
        out = 'D'+random.choice(danger)
    else:
        out = 'S'+random.choice(alive)

print(out)

plannapus

Posted 2014-08-09T20:54:50.450

Reputation: 8 610

The name of the bot is relatively weak, but I ran out of idea, if anyone can think of a better name, please comment :) – plannapus – 2014-08-11T09:53:52.187

GymnastBomber!! – Cruncher – 2014-08-11T14:12:45.597

3

Neo

Dodge a living player who did not shoot last turn. If everybody alive shot last turn, shoot a random living player. Suicide when you see headlights.

import java.util.Random;
public class Neo {
    public static void main(String[] args) {
        if(args.length < 2)
            return;
        String[] list = args[1].split(" ");
        if(list.length < 4)
            return;
        Random rand = new Random();
        int turn = list[0].split(",").length;
        if(turn == 49){
            System.out.print("S0");
            return;
        }
        int target=0;
        for(int i=1;i<4;i++)
            if(list[i].length()<2 || (list[i].charAt(0)!='-' && list[i].charAt(list[i].length()-2)!='S'))
                target=i;
        if(target>0){
            System.out.print("D"+target);
            return;
        }
        while(target<1){
            int i=rand.nextInt(3)+1;
            if(list[i].charAt(0)!='-')
                target=i;
        }
        System.out.print("S"+target);
    }
}

I don't expect much from this guy against grenade-chuckers, but against shooters it might work pretty well. We'll see.

Geobits

Posted 2014-08-09T20:54:50.450

Reputation: 19 061

I used some of your boilerplate code in my answer. I hope that's okay.

– overactor – 2014-08-12T15:06:43.243

Exception in thread "main" java.lang.StringIndexOutOfBoundsException: String index out of range: -1 at java.lang.String.charAt(String.java:658) at Neo.main(Neo.java:17) – es1024 – 2014-08-12T20:55:28.263

@es1024 Should be good to go now, and won't do nothing on every first turn. – Geobits – 2014-08-18T15:43:27.370

2

InputAnalyzer

The key a game such as this is analyze how all your opponents are playing to respond accordingly. My bot will do just that using complicated algorithms that will result in using my opponents turns to my advantage giving a decisive victory!

Edit: I now

  1. dodge any player who has a live grenade
  2. will no longer attempt to shoow/throw/dodge myself.

import System.Environment   
import Data.Char (ord)
import Data.List.Split

main = do 
    args <- getArgs
    let secondArg = (last args)
    let opt = (argCount secondArg 0)
    let list = (splitOn " " secondArg)
    let enemysToCheck = [1,2,3]
    let target = (avoidShootingSelf (findTarget (last args) 0 0 0 0))
    putStrLn (decide list enemysToCheck opt target)

argCount :: String -> Int -> Int
argCount (s:str) i
    |(length str) == 0 = i `mod` 4
    | otherwise = (argCount str (i + (ord s)))

--myPseudo takes number 0-3, and a possible target and translates it to a command 
myPseudo :: Int -> Int -> String
myPseudo 0 b = "S" ++ (show b)
myPseudo 1 b = "D" ++ (show b)
myPseudo 2 b = "P"
myPseudo 3 b = "T" ++ (show b)

decide :: [String] -> [Int] -> Int -> Int -> String
decide [] [] a b = (myPseudo a b)
decide (x:xs) [] a b = (myPseudo a b)
decide xs (y:ys) a b
    | (liveGrenade z 0) == True = "D" ++ (show y)
    | otherwise = (decide xs ys a b)
    where z = xs!!y

--checks if a player has a live grenade
liveGrenade :: String -> Int -> Bool
liveGrenade [] a = a > 0
liveGrenade (s:str) a
    | s == 'T' = (liveGrenade str (a - 1))
    | s == 'P' = (liveGrenade str (a + 1))
    | otherwise = (liveGrenade str a)

--findTarget picks a target by doing some irrelevant string processing on the 2nd argument
findTarget :: String -> Int -> Int -> Int -> Int -> Int
findTarget [] a b c d = ((maximum [a,b,c,d]) `mod` 4)
findTarget (s:str) a b c d
    | s == 'S' = (findTarget str (a + 1) b c d)
    | s == 'D' = (findTarget str a (b + 1) c d)
    | s == 'P' = (findTarget str a b (c + 1) d)
    | s == 'T' = (findTarget str a b c (d + 1))
    | s == 'N' = (findTarget str a b c (d + 1))
    | otherwise = (findTarget str a b c d)

--Makes sure I do target myself takes int 0-3
avoidShootingSelf :: Int -> Int
avoidShootingSelf 0 = 1
avoidShootingSelf a = a

Compile the bot with the following command (Need to have ghc)

ghc --make InputAnalyzer.hs

Shell Command to run should be the following

./InputAnalyzer

Note: I tested on windows so if you have any trouble regarding compling/running please say so in comment in and I will do my best to find out the correct command.

Sahar Rabinoviz

Posted 2014-08-09T20:54:50.450

Reputation: 281

1Well, I suppose that's one way of getting a weighted pseudorandom generator in Haskell. – comperendinous – 2014-08-10T00:59:37.040

2

Zaenille - C

Priorities :

  1. Shoot if it's a 1 on 1 left
  2. Shoot grenadiers
  3. Dodge
  4. Nothing (just to confuse some)

Compile with gcc <filename.c>.

Run with ./a.out <parameters>.

#include <stdio.h>
#include <string.h>

int main(int argc, char *argv[]){
    char* input = argv[2];
    int enemyCount=1;
    int aliveCount=0;
    int aliveEnemy=0;

    //default
    char action = 'N';
    int target = NULL;

    const char delim[1] = " ";
    char *token;

    //first turn
    if(strcmp(input,"5 5 5 5")==0){
        printf("D1");
        return 0;
    }

    token = strtok(input, delim);
    token = strtok(NULL, delim); //skip to the first enemy

    while(token != NULL){
        //if someone is alive :
        if(strstr(token,"-")==NULL && token[0]!='0'){
            aliveCount++;
            aliveEnemy=enemyCount;
            //if that person did nothing this turn, take it as a tip that he will shoot next turn, and dodge
            if(strstr(token, "N")!=NULL){
                action = 'D';
                target=enemyCount;
            }

            //if that person prepared a grenade, shoot him down
            if(strstr(token, "P")!=NULL){
                action = 'S';
                target=enemyCount;
            }
        }

        token = strtok(NULL, delim);
        enemyCount++;
    }

    //if there is 1 enemy left, shoot him down
    if(aliveCount==1){
        action='S';
        target=aliveEnemy;
    }

    printf(action=='N'?"N":"%c%d",action,target);

    return 0;
}

Zaenille

Posted 2014-08-09T20:54:50.450

Reputation: 538

1The first (integer) argument doesn't indicate the round count, if the examples given in the question are anything to go by. You wouldn't want to shoot yourself on the first turn just because you'd been assigned to standoff number 82. – comperendinous – 2014-08-11T19:43:47.510

Really? D: Thanks @comperendinous. Will edit the code. – Zaenille – 2014-08-11T23:55:28.903

2

Twenty-Fourth and a Halfth Century

This Python entry ducks and dodges until only passive players or a single aggressive player remains, then starts shooting. It hopes a passing martian takes care of grenadiers and drunken truck drivers.

Unless I've done something wrong, this is functional Python. It certainly doesn't look like the kind of Python I wrote before Haskell and friends found me, and I don't think I've mutated anything in place. But if you know better, please do tell me.

#!/usr/bin/env python
import sys
import random

## ==== Move Types ================================================== ##
def move_type (move):
    if "" == move:
        return "N"
    return move[0]

def is_passive_move (move):
    if "N" == move:
        return True
    if "D" == move_type (move):
        return True
    return False

def is_aggressive_move (move):
    return not is_passive_move (move)

def passive_moves (moves):
    return [m for m in moves if is_passive_move (m)]

def aggressive_moves (moves):
    return [m for m in moves if is_aggressive_move (m)]
## ================================================== Move Types ==== ##

## ==== Player Model ================================================ ##
class Player:
    def __init__ (self, number, health, moves):
        self.number = number
        self.health = health
        self.moves  = moves

    def last_move (self):
        if 0 == len (self.moves):
            return ""
        return self.moves[-1]

def player_from (number, player_string):
    x = player_string.split (",")
    health = int (x[0].strip ())
    moves = [move.strip () for move in x[1:]]

    return Player (number, health, moves)

def players_from (game_state):
    return [player_from (n, p) for (n, p) in
                                   zip (range(4), game_state.split ())]

def is_alive (player):
    return 0 < player.health

def i_am_dead (me):
    return not is_alive (me)

def can_shoot (player):
    return "S" != move_type (player.last_move ())

def is_passive (player):
    passive_move_count = len (passive_moves (player.moves))
    aggressive_move_count = len (aggressive_moves (player.moves))

    return passive_move_count > (aggressive_move_count + 1)

def players_who_can_breathe (players):
    return [p for p in players if is_alive (p)]

def players_who_can_shoot (players):
    return [p for p in players if can_shoot (p)]

def players_who_stand_around (players):
    return [p for p in players if is_passive (p)]
## ================================================ Player Model ==== ##

## ==== Actions ===================================================== ##
def shoot_randomly_at (possible_targets):
    chosen_target = random.choice (possible_targets)
    return "S{0}".format (chosen_target.number)

def dodge_one_of_the (potential_shooters):
    chosen_shooter = random.choice (potential_shooters)
    return "D{0}".format (chosen_shooter.number)

def do_nothing ():
    return "N"

def pick_move (game_state):

    players = players_from (game_state)
    me = players[0]
    enemies = players[1:]

    if i_am_dead (me):
        return do_nothing ()

    living_enemies = players_who_can_breathe (enemies)
    if 1 == len (living_enemies):
        return shoot_randomly_at (living_enemies)

    passive_enemies = players_who_stand_around (living_enemies)
    if len (living_enemies) == len (passive_enemies):
        return shoot_randomly_at (passive_enemies)

    potential_shooters = players_who_can_shoot (living_enemies)
    if 0 < len (potential_shooters):
        return dodge_one_of_the (potential_shooters)

    return do_nothing ()
## ===================================================== Actions ==== ##

if "__main__" == __name__:

    game_state = sys.argv[2]
    print (pick_move (game_state))

Run as:

python twenty-fourth-and-a-halfth-century.py 0 "5 5 5 5"

comperendinous

Posted 2014-08-09T20:54:50.450

Reputation: 466

2

Sniper - Lua

On the first turn it will shoot a random person, then it will shoot any players that it can kill (2 or 1 health). If neither of those work it will try to shoot the player that shot it last, otherwise it will shoot a random player. Run with lua Sniper.lua

turns = arg[2]
health = string.sub(turns, 1, 1)
--make random numbers random
math.randomseed(io.popen("date +%s%N"):read("*all"))
math.random(); math.random(); math.random()
function Split(str, delim, maxNb)
    -- Eliminate bad cases...
    if string.find(str, delim) == nil then
        return { str }
    end
    if maxNb == nil or maxNb < 1 then
        maxNb = 0    -- No limit
    end
    local result = {}
    local pat = "(.-)" .. delim .. "()"
    local nb = 0
    local lastPos
    for part, pos in string.gmatch(str, pat) do
        nb = nb + 1
        result[nb] = part
        lastPos = pos
        if nb == maxNb then break end
    end
    -- Handle the last field
    if nb ~= maxNb then
        result[nb + 1] = string.sub(str, lastPos)
    end
    return result
end
enemies = Split(turns, " ")
--first turn
if #enemies[1] == 1 then
  print(string.format("S%i",math.random(1,3)))
  os.exit()
end
--kills if possible
for enemy=1,3 do
  if (tonumber(string.sub(enemies[enemy + 1],1,1)) or 0) < 3 and string.sub(enemies[enemy + 1],1,1) ~= "-" then
    print(string.format("S%i",enemy))
    os.exit()
  end
end
--shoots the last person that shot at it
for enemy=1,3 do
  if string.sub(enemies[enemy + 1],#enemies[enemy + 1]-1) == "S0" and tonumber(string.sub(enemies[enemy + 1],1,1)) > 0 then
    print(string.format("S%i",enemy))
    os.exit()
  end
end
--otherwise shoot a random alive person
local aliveEnemies = {}
for enemy=1,3 do
  if string.sub(enemies[enemy + 1],1,1) ~= "-" then
    aliveEnemies[#aliveEnemies+1]=enemy
  end
end
print(string.format("S%i",math.random(1,#aliveEnemies)))

waylon531

Posted 2014-08-09T20:54:50.450

Reputation: 411

It'll actually be run with an extra argument first; e.g., lua Sniper.lua 3 "5,S1 3,D3 5,N 5,P". You might need to check your arg index. – comperendinous – 2014-08-11T19:35:42.603

@comperendinous, thanks, fixed now – waylon531 – 2014-08-11T21:03:08.123

Hi, @waylon531, question about Lua: the randomseed math.randoms "math.randomseed(os.time()) math.random(); math.random(); math.random()" isn't enough to randomize the script? – AndoDaan – 2014-08-11T22:13:41.470

1

AndoDaan, according to http://lua-users.org/wiki/MathLibraryTutorial some OS's always return the same number the first time math.random() is called.

– waylon531 – 2014-08-11T23:16:56.563

lua: ./players/Sniper/Sniper.lua:38: attempt to compare nil with number stack traceback: ./players/Sniper/Sniper.lua:38: in main chunk [C]: in ? – es1024 – 2014-08-12T20:56:25.100

Fixed, my entry now correctly handles negative numbers – waylon531 – 2014-08-12T21:03:04.107

2

Scared

This submission is scared of everyone. But it's especially scared of some people. So it figures out who's the most dangerous, and shoots them. If multiple enemies look the most dangerous, it shoots at a random one.

import sys
import random


def is_alive(player):
    return int(player.split(",")[0]) > 0


# Anyone with a live grenade who is alive is dangerous
def is_dangerous(player):
    return player.count("P") > player.count("T") and \
        int(player.split(",")[0]) > 0


def health(player):
    return int(player.split(",")[0])


# Failing that, healthy people are dangerous
def danger_rating(player):
    return 6 if is_dangerous(player) else health(player)

enemies = sys.argv[2].split()[1:]

highest_danger = max(danger_rating(enemy) for enemy in enemies)
most_dangerous_enemy = random.choice(
    [enemy_num+1 for enemy_num in range(len(enemies))
     if danger_rating(enemies[enemy_num]) == highest_danger])

print("S"+str(most_dangerous_enemy))

This is python (2 or 3, same result in either.) Save as scared.py, run with python3 scared.py

isaacg

Posted 2014-08-09T20:54:50.450

Reputation: 39 268

2

Dog named Courage

First thing - shoot the bad guys on sight. Then dodge randomly until someone prepares a grenade. Then when everyone shoots at him, prepare my own grenade and throw it on anyone. But the distraction man.

Edit: Now implemented as I thought It should be. Before, the score was: 35.9

Updated: Sometimes shoots instead of dodgeing

couragethedog.py

import sys
from collections import defaultdict as ddict
from random import choice
args = sys.argv
info = " ".join(args[2:]).strip('"').split(" ")
players = ddict(dict)
for i,s in enumerate(info):
    parts = s.split(",")
    players[i]["health"]=int(parts[0])
    players[i]["last"]=parts[-1]
    players[i]["history"]=parts[1:]
    players[i]["turn"]=len(parts)
me=0
others=[1,2,3]
turn=players[me]["turn"]
alive = filter(lambda p:players[p]["health"]>0,others)
def act():
    if turn is 1:
        return "S%d" % choice(alive)
    if "P" == players[me]["history"][-1]:
        targets = set(alive)
        for i in alive:
            if "P" == players[i]["history"][-2]:
                targets.remove(i)
        return "T%d" % choice(list(targets))
    for i in others:
        if players[i]["history"][-1] is "P":
            return "P"
    if choice([True,False,False]):
        return "S%d" % choice(alive)
    return "D%d" % choice(alive)
print act()

Run as

python couragethedog.py

loa_in_

Posted 2014-08-09T20:54:50.450

Reputation: 121

2

Manipulative Bastard – Python

Prepares and throws grenades. If he thinks there's no time or there are too few enemies, he shoots. If he's alone he tries to outsmart the other guy.

import sys

def health(p):
    return int(p[0])

def is_alive(p):
    return health(p) > 0

def can_act(p):
    return is_alive(p) and p[-1][0] != 'S'

def can_throw(p):
    return is_alive(p) and p[-1][0] == 'P'

def shot_first(p):
    if len(p) == 1:
        return False
    return p[1][0] == 'S'

def act(a):
    print a
    sys.exit(0)

player = sys.argv[2].split()[0].split(',')
enemies = [e.split(',') for e in sys.argv[2].split()[1:]]
healthiest = sorted(enumerate(enemies, 1), key=lambda e:health(e[1]))[-1]
alive = sum(is_alive(e) for e in enemies)

if alive == 1:
    i, e = healthiest
    if health(e) <= 2 and not can_act(e):
        act('S%d' % i)
    if can_throw(player):
        act('T%d' % i)
    if can_throw(e):
        act('S%d' % i)
    if can_act(e) and shot_first(e) and len(player) < 40:
        act('D%d' % i)
    if len(player) > 45:
        act('P')
    act('S%d' % i)

if can_throw(player):
    i, e = healthiest
    act('T%d' % i)

if len(player) > 45:
    act('P')

if health(player) <= 2 or any(can_throw(e) for e in enemies) or alive == 2:
    i, e = healthiest
    act('S%d' % i)

act('P')

fhyqrkka

Posted 2014-08-09T20:54:50.450

Reputation: 59

2

MAD - Java

The MAD bot trust in the power of intimidation through mutual assured destruction. Whenever he doesn't have a ready grenade, he prepares one. He then dodges possible gunners until either someone tries to deal damage to him or his grenade is about to explode. From the moment he gets attacked, he chucks grenades at whoever has tried to deal more damage to him this match so far. If his grenade is about to explode, he bombs the leading player. MAD is not against taking a shot at someone when there's nothing to dodge or directly chuck a grenade at and his grenade is still good for at least one turn.

    import java.util.ArrayList;
import java.util.Random;

public class MAD 
{
    public static void main(String[] args) 
    {
        if(args.length < 2)
        {
            return; // nothing to do here
        }
        String[] players = args[1].split(" ");
        if(players.length < 4 || !isAlive(players[0]))
        {
            return; // nothing to do here
        }
        Random rand = new Random();

        int grenadeExplodes = grenadeExplodes(players[0]);        
        if(grenadeExplodes==-1)
        {
            System.out.print("P"); // I don't feel safe without a prepared grenade in my hand
            return;
        }

        int highestDamage = -1;
        int playerToShoot = -1;        
        for(int i=1; i<4; i++) // did anyone try to hit me?
        {
            int damage = damageAttempted(players[i], 0);
            if(isAlive(players[i]) && (damage>highestDamage || (damage==highestDamage && rand.nextDouble()>0.5)))
            {
                highestDamage = damage;
                playerToShoot = i;
            }           
        }

        if(highestDamage > 0)
        {
            System.out.print("T" + Integer.toString(playerToShoot)); // don't tell me I didn't warn you
            return;
        }

        int highestHealth = -1;
        int healthiestPlayer = -1;      
        for(int i=1; i<4; i++) // who is doing too well for their own good?
        {
            int health = getHealth(players[i]);
            if(health>highestHealth || (health==highestHealth && rand.nextDouble()>0.5))
            {
                highestHealth = health;
                healthiestPlayer = i;
            }
        }

        if(grenadeExplodes==0)
        {
            System.out.print("T" + Integer.toString(healthiestPlayer).charAt(0)); // get this hot head outta here!!
            return;
        }

        // I've got time to flaunt my grenade around

        ArrayList<Integer> playersToDodge = new ArrayList<Integer>();       
        for(int i=1; i<4; i++) // lets see who could shoot me
        {
            if(canMove(players[i]) && grenadeExplodes(players[i])!=0)
            {
                playersToDodge.add(i);
                if(grenadeExplodes(players[i])==-1) // players who have no grenade are more likely to shoot
                {
                    playersToDodge.add(i);
                }
            }
        }

        if(playersToDodge.size()>0)
        {
            System.out.print("D" + Integer.toString(playersToDodge.get(rand.nextInt(playersToDodge.size() - 1))).charAt(0)); // what do we say to would-be gunners?
            return;
        }

        if(grenadeExplodes!=1)
        {
            System.out.print("S" + Integer.toString(healthiestPlayer).charAt(0)); // seems like I can take a free shot at someone
        }
        else
        {
            System.out.print("N"); // wouldn't want to end up with an exploding grenade in my hand while being unable to throw it.
        }

    }

    public static boolean isAlive(String player) 
    {
        return player.charAt(0)!='-'; 
    }

    public static boolean canMove(String player)
    {
        return isAlive(player) && player.charAt(player.length()-2)!='S';
    }

    public static int grenadeExplodes(String player)
    {
        String[] actions = player.split(",");

        if(actions.length>3 && actions[actions.length - 3].charAt(0)=='P' 
            && actions[actions.length - 2].charAt(0)=='T' 
            && actions[actions.length - 1].charAt(0)=='P')
        {
            return 0;
        } 
        else if(actions.length>2 && actions[actions.length - 2].charAt(0)=='P' 
            && actions[actions.length - 1].charAt(0)=='T')
        {
            return 1;
        } 
        else if(actions.length>1 && actions[actions.length - 1].charAt(0)=='P')
        {
            return 2;
        }
        else
        {
            return -1;
        }
    }

    public static int damageAttempted(String player, int target)
    {
        String[] actions = player.split(",");
        int damage = 0;
        char targetChar = Integer.toString(target).charAt(0);
        for(int i=0; i<actions.length; i++)
        {
            if(actions[i].charAt(0)=='S' && actions[i].charAt(1)==targetChar)
            {
                damage += 2;
            } 
            else if (actions[i].charAt(0)=='T')
            {
                if(actions[i].charAt(1)==targetChar)
                {
                    damage += 8;
                }
                else
                {
                    damage += 3;
                }
            }
        }

        return damage;
    }

    public static int getHealth(String player)
    {
        return Integer.parseInt(player.split(",")[0]);
    }
}

This Bot will likely perform poorly, but I liked the idea anyway. MAD would probably do better in a field with smarter bots that log the behavior of other bots and with more matches run between 4 bots.

overactor

Posted 2014-08-09T20:54:50.450

Reputation: 3 500

Some credit shoudl go to Geobits, I stole some boiler plate code of his Neo entry. – overactor – 2014-08-12T15:05:29.960

You didn't take much, no credit needed :) – Geobits – 2014-08-12T15:32:54.210

Calling java MAD 43 "5 5 5 5" appears to output nothing. – es1024 – 2014-08-18T02:16:29.433

2

Osama

I've been trying this for a day or so, now it's time to post and see how the others have evolved in the meantime.

module Main where

import Data.List
import Data.Ord
import System.Environment

words' "" = []
words' s = s' : words' (tail' s'')
  where
    (s', s'') = break (==',') s
    tail' (',':r) = r
    tail' r = r

nRound = length . words'

lastAction = last . words'

health :: String -> Int
health = read . head . words'

alive = (>0) . health

grenadeAge :: String -> Int
grenadeAge p | not (alive p) = 0
             | otherwise = g 0 $ tail $ words' p
  where
    g n (a:b:r) | head a == 'S' = g (if n>0 then n+2 else 0) r
    g 0 ("P":r) = g 1 r
    g n (('T':_):r) | n>0 = g 0 r
    g n (_:r) | n>0 = g (n+1) r
    g n (_:r) = g n r
    g n [] = n

prepared :: String -> Bool
prepared p = alive p && head (lastAction p) /= 'S'

nShotMe = length . filter (=="S0") . words'

getPlayer = (!!)

action players@(me:them) | not (prepared me) = "S2" -- bogus
                         | nRound me >= 49 = "S0"
                         | grenadeAge me >= 1 = 'T':(show $ maximumBy (comparing (nShotMe . getPlayer players)) l)
                         | any prepared them && nRound me > 0 = 'D':(show $ maximumBy (comparing (nShotMe . getPlayer players)) l)
                         | otherwise = 'S':(show $ maximumBy (comparing (health . getPlayer players)) l)
  where l = filter (alive . (getPlayer players)) [1..3]



main = do
  players <- fmap (words . head . tail) getArgs
  putStrLn $ action players

Compile with ghc -O2 osama.hs, then run using ./players/Osama/osama.

TheSpanishInquisition

Posted 2014-08-09T20:54:50.450

Reputation: 421

2

Darwin

Survival of the fittest means the least healthy must die.

Rationale

Looking at the batch of results from Tuesday (12th), there seem to be three distinct groupings: survivors; the effectively suicidal; and the worse than useless. The survivors share simple shooting-based strategies. While a couple of other bots (Spock, Coward) will target the least healthy enemy, they also complicate their strategies with other actions. This one does not. Like Simple Shooter, it has a clear definition of the target and sticks with it relentlessly. It'll be interesting to see where it fits into the results.

#!/usr/bin/env python

import sys
import random

## ==== Player Model ================================================ ##
class Player:
    def __init__ (self, number, health):
        self.number = number
        self.health = health

def player_from (number, player_string):
    x = player_string.split (",")
    health = int (x[0].strip ())

    return Player (number, health)

def players_from (game_state):
    return [player_from (n, p) for (n, p) in
                                   zip (range(4), game_state.split ())]

def is_alive (player):
    return 0 < player.health

def i_am_dead (me):
    return not is_alive (me)

def players_who_can_breathe (players):
    return [p for p in players if is_alive (p)]

def players_by_health (players):
    return sorted (players, key=lambda p: p.health)

def least_healthy_players (players):
    sorted_living_players = \
        players_by_health (players_who_can_breathe (players))
    lowest_living_health = sorted_living_players[0].health
    return [p for p in players if lowest_living_health == p.health]
## ================================================ Player Model ==== ##

## ==== Actions ===================================================== ##
def shoot_randomly_at (possible_targets):
    chosen_target = random.choice (possible_targets)
    return "S{0}".format (chosen_target.number)

def do_nothing ():
    return "N"

def pick_move (game_state):
    players = players_from (game_state)
    me = players[0]
    enemies = players[1:]

    if i_am_dead (me):
        return do_nothing ()

    least_healthy_enemies = least_healthy_players (enemies)
    return shoot_randomly_at (least_healthy_enemies)
## ===================================================== Actions ==== ##

if "__main__" == __name__:

    game_state = sys.argv[2]
    print (pick_move (game_state))

This is a stripped-down, slightly modified version of my earlier Twenty-Fourth and a Halfth Century, and shares its invocation:

python darwin.py 3 "5 5 5 5"

comperendinous

Posted 2014-08-09T20:54:50.450

Reputation: 466

2

Muhammad Ali - Java

Floats like a butterfly, stings like a bee; will normally dodge the player who has taken most shots and is ready to shoot. Shoots the healthiest looking player whenever no one can move or if it's one on one and the other player has a grenade prepared. Will not hesitate to take his own life should it be necessary.

import java.util.ArrayList;
import java.util.Random;

public class MuhammadAli {

    public static void main(String[] args) {
        if(args.length < 2)
        {
            return; // nothing to do here
        }
        String[] players = args[1].split(" ");
        if(players.length < 4 || !isAlive(players[0]))
        {
            return; // nothing to do here
        }
        Random rand = new Random();

        int turn = players[0].split(",").length;

        int highestHealth = -1;
        int healthiestPlayer = -1; 
        int livingPlayers = 0;
        for(int i=1; i<4; i++) // who is doing too well for their own good?
        {
            int health = getHealth(players[i]);
            if(health>=0)
            {
                livingPlayers++;
            }
            if(health>highestHealth || (health==highestHealth && rand.nextDouble()>0.5))
            {
                highestHealth = health;
                healthiestPlayer = i;
            }
        }

        if(livingPlayers==1 && ((turn==49 && highestHealth<2) || grenadeExplodes(players[healthiestPlayer])>-1))
        {
            System.out.print("S" + Integer.toString(healthiestPlayer).charAt(0)); // you had it coming dude
        }

        if(turn!=49)
        {
            int mostShots = -1;
            int triggerHappyPlayer = -1;        
            for(int i=1; i<4; i++) // who's the most trigger happy player?
            {
                int shots = shotsTaken(players[i]);
                if(canMove(players[i]) && (shots>=mostShots))
                {
                    if(shots>mostShots || ((grenadeExplodes(players[i])==-1 || rand.nextDouble()>0.5) && grenadeExplodes(players[triggerHappyPlayer])==-1)) // if you're holding a grenade, you'll have other things on your mind than shooting.
                    mostShots = shots;
                    triggerHappyPlayer = i;
                }           
            }

            if(mostShots>0 || turn < 2)
            {
                System.out.print("D" + Integer.toString(triggerHappyPlayer)); // you didn't get your hopes up, did you?
                return;
            }
        }

        if(highestHealth>2 && turn==49)
        {
            System.out.print("S0"); // Goodbye, cruel world
        }
        else
        {
            System.out.print("S" + Integer.toString(healthiestPlayer).charAt(0)); // seems like I can take a free shot at someone
        }

    }

    public static boolean isAlive(String player) 
    {
        return player.charAt(0)!='-'; 
    }

    public static boolean canMove(String player)
    {
        return isAlive(player) && (player.length() == 1 || player.charAt(player.length()-2)!='S');
    }

    public static int grenadeExplodes(String player)
    {
        String[] actions = player.split(",");

        if(actions.length>3 && actions[actions.length - 3].charAt(0)=='P' 
            && actions[actions.length - 2].charAt(0)=='T' 
            && actions[actions.length - 1].charAt(0)=='P')
        {
            return 0;
        } 
        else if(actions.length>2 && actions[actions.length - 2].charAt(0)=='P' 
            && actions[actions.length - 1].charAt(0)=='T')
        {
            return 1;
        } 
        else if(actions.length>1 && actions[actions.length - 1].charAt(0)=='P')
        {
            return 2;
        }
        else
        {
            return -1;
        }
    }

    public static int shotsTaken(String player)
    {
        String[] actions = player.split(",");
        int shots = 0;
        for(int i=0; i<actions.length; i++)
        {
            if(actions[i].charAt(0)=='S')
            {
                shots ++;
            }
        }

        return shots;
    }

    public static int getHealth(String player)
    {
        return Integer.parseInt(player.split(",")[0]);
    }
}

I'm hoping this will do quite well, since he is pretty smart about dodging and only starts agression when it really seems to play in his advantage.

overactor

Posted 2014-08-09T20:54:50.450

Reputation: 3 500

Outputs nothing when java MuhammadAli 32 "5 5 5 5" is called. – es1024 – 2014-08-18T02:22:58.503

Whoops, forgot an exclamationmark. – overactor – 2014-08-18T05:50:34.083

Exception in thread "main" java.lang.StringIndexOutOfBoundsException: String index out of range: -1 at java.lang.String.charAt(String.java:658) at MuhammadAli.canMove(MuhammadAli.java:82) at MuhammadAli.main(MuhammadAli.java:49) only for the input 5 5 5 5 – es1024 – 2014-08-18T23:01:06.220

@es1024 damn, I need to think more about what I code, should be fixed now. – overactor – 2014-08-19T04:35:46.077

2

Sadist

python

His priority is to cause pain and grenades hurt. He pulls first turn. He likes to kill when you can't attack. He toys with SSSs (single simple shooters) by dodging and pulling to prolong the domination. He even choses to attack those first who've done nothing to anyone.

Because he uses grenades, he (and everyone else) will ususally not survive the second or third round. If he is paired up with another grenadeer, everyone will die. This means I don't expect to win but I wrote this to learn python (never used it before and I'm trying to get an introduction into a bunch of new languages). There are several other, "pull firsts" so if you feel it is too simular let me know. The others don't seem to be willing to pull and then dodge, however.

import sys    

def ident(thatguy):

    return int(thatguy.split(",")[0])

def health(thatguy):
    return int(thatguy.split(",")[1])

def shooter(thatguy):
    if(len(thatguy.split(","))<3):
        return 1==1
    else: return thatguy.split(",")[2][0]=="S"

def mosthealth(group):
    bigbad=group[0]
    for foe in group:
        if (health(foe)>health(bigbad)): bigbad=foe
    return bigbad

def igotanuke(mine):
    return mine.count("P")-mine.count("T")>0

def guytonuke(allguys,fighters):
    backup=allguys[:]
    for Aguy in backup:
        if(health(Aguy)<4):
            allguys.remove(Aguy)
            if (shooter(Aguy)): fighters.remove(Aguy)

    if(len(allguys)==0): return mosthealth(backup)
    if (len(allguys)==len(fighters)):
        return mosthealth(allguys)
    else:
        for fighter in fighters: allguys.remove(fighter)
        return mosthealth(allguys)

raw = sys.argv[2]
player = raw.split(" ")
thisisme=player.pop(0)
turn = len(player[0].split(","))-1

guys=[]
gunners=[]
c=1
for dude in player:
    dude=str(c)+","+dude
    c+=1
    if (health(dude)>0): 
        guys.append(dude)
        if (shooter(dude)):
            gunners.append(dude)

if (turn==0): print "P"
elif(turn==49): print"S0"
elif(igotanuke(thisisme))&( turn % 2 == 1): print "T"+str(ident(guytonuke(guys,gunners)))
elif(len(guys)<2)&(len(gunners)>0) & (turn % 2 == 1): print P
elif(turn % 2 == 0) & (len(gunners)>0): print "D"+str(ident(mosthealth(gunners)))
elif(turn % 2 == 1) & (len(gunners)>0): print "S"+str(ident(mosthealth(gunners)))
else: print "S"+str(ident(mosthealth(guys)))

kaine

Posted 2014-08-09T20:54:50.450

Reputation: 536

I don't think that raw_input is going to work. sys.argv[2] seems to be the consensus for Python entries. You might also find use for pop, which would allow you to condense thisisme=player[0];player.remove(player[0]) into the simpler thisisme=player.pop(0).

– comperendinous – 2014-08-18T19:17:17.883

@comperendinous I was testing the code at Ideone and sys.argv doesn't work at all (likely due to importing sys). That is why i used raw_input. Is there a difference that would cause the latter not to work? If so I likely will need to find another online compiler for python. Thanks for the suggestion with pop! I didn't realise that command allow the index to be specified. I will use it for any future python code. – kaine – 2014-08-18T19:27:09.833

1raw_input pulls from STDIN, but the player history is passed to your program as a command-line argument, which is why you need sys.argv. For the sake of testing, you could just set it manually with sys.argv = ["sadist.py", "0", "5 5 5 5"]. Then you should be able to call player=sys.argv[2].split(). If importing sys really is impossible, for testing you could even drop the dot and call the array sysargv. So long as everything else works and you go back to sys.argv in your submission, it should be fine. – comperendinous – 2014-08-18T19:43:25.930

@comperendinous to confirm, if I call sys.argv it will return as an array the name of program in 0, that single number in 1 and the actual part I use in 2? They are all strings. With that info I should be able to edit it properly. Thank you very much! – kaine – 2014-08-18T19:46:45.210

2

Late Boomer

Ruby

There are 3 types of players right now. Ones who never use grenades, ones who pull first turn, and one idiot who can do anything (that actually sounds inspiring). This class attempts to change that slightly. He pulls the 4th turn should more than 1 opponent be alive, he has no less than 3 health, and noone else has pulled. While I've included a python entry, these are clearly not colluding as he nukes this guy turn 2 ususally.

def health(guy)
    return guy.split(",")[1].to_i
end

def bomb(past)
    return past.count("P")-past.count("T")>0    
end

def maxhealth(players)
    target=players[0]
    for dude in players
        if health(dude)>health(target)
            target=dude
        end
    end
    return target
end

def reloading(past)
    return past[past.length-2]=="S"
end

input=ARGV[1]
them = input.split(" ")
me = "0,"+them.delete_at(0)
turn = me.split(",").length-1

x=0
y=0

while y<them.length do
    x +=1
    them[y]=x.to_s+","+them[y]
    if health(them[y])<1
        them.delete_at(y)
        y -=1
    end
    y +=1
end

if turn==1 
    print "D1"
elsif bomb(me)
    print "T"+ maxhealth(them)[0][0].to_s
elsif turn>2 and not(bomb(input)) and them.length>1 and health(me)>2 and not(reloading(me))
    print "P"
elsif bomb(input)
    print "S"+maxhealth(them)[0][0].to_s
else
    print "S"+them[0][0]
end 

kaine

Posted 2014-08-09T20:54:50.450

Reputation: 536

1

DON'T NUKE ME BRO! - Lua

Doesn't like it when people use their grenades. Is a hypocrite when more than one person is shooting at him.

--Don't Nuke Me Bro

math.randomseed(os.time())

info=arg[2]

function tablelength(T)
  local count = 0
  for _ in pairs(T) do count = count + 1 end
  return count
end

function parseEnemies(s) -- Makes sense of the input Data
    local e={}
    local pStatus={{},{},{},{}}
    for w in string.gmatch(s, "%S+") do table.insert(e,w) end

    for p = 1, 4 do
        for a in string.gmatch(e[p], "%P+") do
            table.insert(pStatus[p], a)
        end
    end
    for i = 1 , 4 do
        pStatus[i][1]=tonumber(pStatus[i][1])
    end
    return pStatus
end

function analyseEnemies(ps)
    moveList={{},{}}
    sFlag = 0
    if tablelength(ps[1])>=35 then
        for i = 2, 4 do
            if ps[i][1]>0 then
                table.insert(moveList[1], "S"..i-1)
                table.insert(moveList[2], 100)

            end
        end
    elseif tablelength(ps[1])>=42 then
        table.insert(moveList[1], "P")
        table.insert(moveList[2], 100)
    elseif tablelength(ps[1])>=48 then
        table.insert(moveList[1], "S0")
        table.insert(moveList[2], 100)


    else
        for i=2,4 do
            pHealth = ps[i][1]
            lan=tablelength(ps[i])
            lAction=ps[i][lan]
            llAction=ps[i][lan-1]

            if pHealth <= 0 then
            else
                if lAction=="P" then -- Doesn't Like it when people goes nuclear
                    table.insert(moveList[1], tostring("S"..i-1))
                    h=8-pHealth
                    table.insert(moveList[2], h)
                end

                if llAction=="S0" then -- takes notice when someone shoots at him
                    sFlag = sFlag +1
                    if pHealt == 2 or 1 then
                        table.insert(moveList[1],tostring("S".. i-1))
                        table.insert(moveList[2], 2)
                    else
                        table.insert(moveList[1],tostring("D"..i-1))
                        table.insert(moveList[2], 3)
                    end
                end

            end
        end
    end
    nmla = tablelength(ps[1])

    if nmla == 2 and ps[1][nmla] == "P" then -- gotta get rid of this grenade
        tH= 0
        target = 1
        for i = 2, 4 do
            if ps[i][1]>=tH then
                target= i-1
            end
        end
        table.insert(moveList[1],tostring("T"..target))
        table.insert(moveList[2], 6)
    end


    if nmla == 3 and ps[1][nmla-1] == "P" then -- Makes sure he throws the damn grenade
        tH= 0
        target = 1
        for i = 2, 4 do
            if ps[i][1]>=tH then
                target= i-1
            end
        end
        table.insert(moveList[1],tostring("T"..target))
        table.insert(moveList[2], 20)

    end

    if sFlag >=2 then -- if 2 or more people shoot at him during a round, he goes nuclear.
        table.insert(moveList[1],tostring("P"))
        table.insert(moveList[2], 9)
    end
    r=math.random(3)
    table.insert(moveList[1], "D"..r) -- random ducking if all else fails
    table.insert(moveList[2], 1)
    lan=tablelength(ps[1])
        lAction=ps[1][lan]
        if lAction =="P" then
            for i = 2, 4 do
                if ps[i][1]>0 then
                    table.insert(moveList[1], "T"..i-1)
                    table.insert(moveList[2], 100)

                end
            end
        end
    return moveList
end

function makeMove(mList) -- picks the highest rated move
    m = ""
    nml = tablelength(mList[2])
    c = 0
    m = 1
    for i = 1, nml do
        if mList[2][i]>= c then
            c = mList[2][i]
            m = mList[1][i]
        end
    end

    print(m)
end

makeMove(analyseEnemies(parseEnemies(info)))

run it like

lua DONTNUKEMEBRO.lua "input string"

AndoDaan

Posted 2014-08-09T20:54:50.450

Reputation: 2 232

lua DONTNUKEMEBRO.lua 43 "5 5 5 5" gives: lua: DONTNUKEMEBRO.lua:28: bad argument #1 to gmatch (string expect, got nil), status traceback: [C]: in function 'gmatch' DONTNUKEMEBRO.lua:28: in function 'parseEnemies' DONTNUKEMEBRO.lua:119: in main chunk [C]: in ? – es1024 – 2014-08-10T05:07:54.750

@es1024 Yep, forgot about the unique stand off number. Sorry about that. It should be okay to go now. – AndoDaan – 2014-08-10T07:17:23.437

lua: DONTNUKEMEBRO.lua:43: attempt to call field 'getn' (a nil value) stack traceback: DONTNUKEMEBRO.lua:43: in function 'analyseEnemies' DONTNUKEMEBRO.lua:119: in main chunk [C]: ? – es1024 – 2014-08-10T07:22:44.263

@es1024 Okay, I think I got it now. I was using an out of date function. Sorry for the hassle. – AndoDaan – 2014-08-10T08:16:43.940

1Everything works now. – es1024 – 2014-08-10T08:24:34.900

@es1024 Hey. I made some changes to my bot so it will deal with the end game a little better, and not get run over by the retirement truck. – AndoDaan – 2014-08-11T04:23:55.927

1

Take 'em with me -- VB (what, no love?)

This guy tries to hide while everyone else is shooting, and assuming he is still around when the truck rolls near, will try to nuke the healthiest looking target that is left standing. If he still sees the truck barreling down at him, then he takes the cowards way out.

Module Module1
    Dim players As String()
    Dim numTurns As Integer

Public Sub Main(args() As String)
    'split results into the different players
    players = args(1).Split(" ")
    'how many turns have we been going?
    numTurns = players(0).Split(",").Length
    If numTurns = 48 Then 'can hear the truck
        Console.Write("P")
    ElseIf numTurns = 49 Then ' can see the truck
        Console.Write("T" & PlayerWithHighestHealth())
    ElseIf numTurns = 50 Then 'can smell the truck
        Console.Write("S0")
    Else ' hiding is best
        Console.Write("D" & PlayerWithHighestHealth())
    End If
End Sub

Private Function PlayerWithHighestHealth() As Integer
    Dim p As Integer = 1
    Dim health As Integer = 1
    For i = 1 To 3
        If players(i).Split(",")(0) > health Then 'this is the healthiest looking guy
            p = i
            health = players(i).Split(",")(0)
        End If
    Next
    Return p
End Function

End Module

Run as Standoff.exe 5 "3,S2,N 5,P,N 3,S0,N -2,S3,N" for example

APrough

Posted 2014-08-09T20:54:50.450

Reputation: 111

2Don't forget about the first integer argument that nobody seems to bother with. The players history is actually the second argument. – comperendinous – 2014-08-11T19:06:03.440

@comperendinous. Thanks. I don't know how I missed that little note about the first argument being the standoff #. Updated my code to get the right argument. – APrough – 2014-08-11T19:11:52.227

It's no fun shooting at you if the scoring program is just assigning you "N" all the time (-; – comperendinous – 2014-08-11T19:15:47.907

TakeEmWithMe.vb (7,23) : Error VBNC99999: After removing narrowing (except object) candidates for method 'Split', nothing was found – es1024 – 2014-08-12T00:27:30.967

1

SolidSnake - Java

Take advantage of enemy down times. Dodge all other times. A little aggressive for Snake... But he's mad because Big Boss is in the spot light all the time.

War... War never changes....

import java.util.Random;

public class SolidSnake {

    public static void main(String[] args) {
        int target;
        char hp;
        Random rand = new Random();

        if(args.length == 0) {
            target = rand.nextInt(3) + 1;
            System.out.println("D"+target);
            return;
        }

        String[] list = args[1].split(" ");

        for(int i = 1; i <= list.length; ++i) {
            hp = list[i].charAt(0);
            if(hp > 0) {
                char c = list[i].charAt(list[i].length()-1);
                String lastMove = String.valueOf(c);

                //Check for P
                if(lastMove.equals('P')) {
                    target = i;
                    System.out.println("S"+target);
                    return;
                }

                //Check for S*
                if(Character.isDigit(lastMove.charAt(lastMove.length() - 1))) {
                    target = i;
                    System.out.println("S"+target);
                    return;
                }
            }
        }

        //If not any P or S*
        for(int i = 1; i <= list.length; ++i) {
            hp = list[i].charAt(0);
            if(hp > 0) {
                target=i;
                System.out.print("D"+target);
                return;
            }
        }

        //Catch-safe
        System.out.print("D1");
        return;
    }

}

Compile/run:

javac SolidSnake.java 
java SolidSnake arg0 arg1

Josef E.

Posted 2014-08-09T20:54:50.450

Reputation: 131

Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 4 at SolidSnake.main(SolidSnake.java:19) when passed 30023 "5,S1 3,N 5,N 5,N" – es1024 – 2014-08-18T23:27:45.297

1

Equivocator

The Equivocator finds those who are alive & closest in health to him and shoots them.

function string:split( inSplitPattern, outResults )
   if not outResults then
      outResults = { }
   end
   local theStart = 1
   local theSplitStart, theSplitEnd = string.find( self, inSplitPattern, theStart )
   while theSplitStart do
      table.insert( outResults, string.sub( self, theStart, theSplitStart-1 ) )
      theStart = theSplitEnd + 1
      theSplitStart, theSplitEnd = string.find( self, inSplitPattern, theStart )
   end
   table.insert(outResults, string.sub( self, theStart ) )
   return outResults
end

function RunRound()
   -- set up the players
   players = match:split(" ")
   myHealth = string.sub(players[1],1,1)
   closestHealth = 10
   enemy = 3
   if myHealth == "-" then
      return "N"
   end

   -- find someone with health close to mine
   for i=2,#players do
      moves = players[i]
      playerHealth = moves:sub(1,1)
      if playerHealth ~= "-" then
         if math.abs(playerHealth - myHealth) <= closestHealth then
            enemy = i-1
            closestHealth = math.abs(playerHealth - myHealth)
         end
      end
   end
   return "S"..enemy
end

local args = {...}  -- command line arguments
match = args[2]     -- store the set of matches
action = RunRound()
print(action)

Kyle Kanos

Posted 2014-08-09T20:54:50.450

Reputation: 4 270

1

BiasedOne - Java

Pun intended


public class BiasedOne {
    public static void main(String[] args) {
        System.out.println("S1");
        return;
    }
}

Compile/run:

javac BiasedOne .java 
java BiasedOne arg0 arg1

Josef E.

Posted 2014-08-09T20:54:50.450

Reputation: 131

I think you might have meant "S1" in stead of "S"+1 – overactor – 2014-08-14T15:34:05.983

oops! ty @overactor i was in a rush :P – Josef E. – 2014-08-14T15:35:03.533

This was Straight Shooter's original strategy, before Politically Correct Gunman came along. It'll be interesting to see if S1 does any better than S2, which is about as far from a winning strategy as it can get. There are a few bots which sweep through the numbers to choose a target, so I suppose it's possible the position of the fixed target might influence the outcome. – comperendinous – 2014-08-14T23:54:10.167

1

Hippolyta

This Amazon Warrior Shooter, like her namesake, is destined to be slain.

Since we now have an S0, an S1, and an S2 bot, for completeness, here's an S3 bot to see if the position of the fixed target makes any significant difference to the result.

void
main ()
{
  print ("S3");
}

Compile as Vala:

valac hippolyta.vala

Run as any other executable:

./hippolyta 3 "5 5 5 5"

comperendinous

Posted 2014-08-09T20:54:50.450

Reputation: 466

1

Label1Goto1 - Python

I ran out of good names (or I'm too lazy to think about others), but I have been doing some relatively repetitive work nowadays, hence came the name of the lowest common denominator of a loop structure.

The bot is relatively simple (in comparison to Spock, my previous work). Label 1, Dodge it, Prepare it, Shoot it, Wait it, Throw it, Goto 1.

def IsAlive(player):
  return int(player[1].split(",")[0]) > 0

import sys
info_list = sys.argv[2].split()
current_turn = len(info_list[0].split(","))
action = "N"

target_list = []
for player in zip(range(1,4),info_list[1:]):
    if IsAlive(player): target_list.append(player[0])

import random
target = random.choice(target_list)

round = (current_turn - 1) % 5

if   round == 0: action = "D" + str(target)
elif round == 1: action = "P"
elif round == 2: action = "S" + str(target)
elif round == 3: action = "N"
elif round == 4: action = "T" + str(target)

print(action)

Run it as:

python label1goto1.py

Doktoro Reichard

Posted 2014-08-09T20:54:50.450

Reputation: 419

1

Less Simple Shooter

This is basically the Simple Shooter but with the added directive to shoot himself before the truck comes.

If, for some reason, another entry already uses this exactly strategy, then I will withdraw it.

@history = map([split(",",$_)],split(" ",$ARGV[1]));
$target = 1;
for(2..3){
 if($history[$_][0] >= $history[$target][0]){$target = $_}
}
if(~~@{$history[0]} >= 50){
 $target = 0;
}
print "S$target"

I run it like this:

perl lesssimpleshooter.plx 5 "-2,S0 -2,S1 -2,S2 5,N"

PhiNotPi

Posted 2014-08-09T20:54:50.450

Reputation: 26 739