37
\$\begingroup\$

Notice: This challenge has completed. This means that the green checkmark, which has been awarded to C5H8NNaO4 for their entry The Observer will not be moved to any new answer.

You may still submit new entries, but there may be delays in new tournaments running as I am not actively checking for new entries anymore.

Introduction

In this challenge, you are playing an arcade game titled The Ultimate Samurai Showdown Ultimate Edition Special Version 2.0 X Alpha Omega Turbo (or just Ultimate Samurai Showdown for short). Your opponents? None other than the other members of Programming Puzzles & Code Golf!

As you might expect from a PPCG arcade game, you do not play Ultimate Samurai Showdown directly, but rather write a program that will play the game for you. This program will fight against programs submitted by other users in one on one duels. The most skilled program will be crowned the Ultimate Samurai of PPCG, and be granted the green tick of legend.

Game Description

This section describes the mechanics behind the game.

Victory Condition

A match consists of two samurai which are facing off against each other. Each samurai begins each match with 20 hit points and 1 honour. A samurai wins if his opponent is dead and he is still alive. There are two methods by which a samurai can die:

  1. If a samurai's hit points are brought down to 0, he will die.
  2. If a samurai brings their own honour below 0, he will be struck down by the gods for acting dishonourably in a duel.

Being struck down by the gods has higher priority over having hit points reduced to 0, so in a situation where one samurai is at 0 health points and the other is at -1 honour, the samurai with 0 health points will win. In a situation where both samurai are at -1 honour, they both get struck down by the gods and the game is a draw.

A match consists of up to 500 turns. If all 500 turns pass and the match has not been decided (neither samurai has died), the gods grow bored and strike down both of the samurai, thus resulting in a draw.

Actions

On each turn, the samurai must perform exactly one of the following actions:

W

The samurai shall wait and perform no action. This makes him look cool but doesn't help him defeat his opponent. This is also the default action.

B

The samurai shall bow to his opponent in an honourable fashion. This pleases the gods and thus the samurai will gain 1 Honour. Honour is vital to your samurai's success because Honour is essentially the "resource" for this game -- all moves apart from B and W can decrease Honour. Also, if a samurai gains 7 Honour or more, he is granted use of the Sword of the Gods. The implications of this are described below.
However, bowing to your opponent leaves you open if your opponent decides to strike you with his sword, so be careful when you choose to bow.

G

The samurai shall enter a defensive position and guard against any sword strikes. This move will successfully block all sword strikes, even ones made with the Sword of the Gods.
However, the gods frown upon an overly defensive samurai, so this move will consume 1 Honour if the samurai's action on the immediately preceding turn was also guarding. It does not consume Honour otherwise.

I

The samurai shall attempt to strike his opponent with a quick draw of his sword from its scabbard. If the samurai has 7 Honour or more, he will use the Sword of the Gods instead of his regular sword. This move consumes 1 Honour.
The quick draw is a fast strike that will beat slower overhead attacks, however, it will lose against parries. If the strike connects successfully it will do 1 damage, or 2 damage with the Sword of the Gods.

P

The samurai shall attempt to parry any incoming attack, then launch his own attack. If the samurai has 7 Honour or more, he will use the Sword of the Gods instead of his regular sword. This move consumes 1 Honour.
The parry is a good manoeuvre against fast strikes, but it will be overpowered by slower overhead attacks. If the strike connects successfully it will do 1 damage, or 2 damage with the Sword of the Gods.

O

The samurai shall attempt to strike his opponent with a slower overhead attack. If the samurai has 7 Honour or above, he will use the Sword of the Gods instead of his regular sword. This move consumes 1 honour.
The overhead strike can overpower parries, but it will lose against fast strikes. If the strike connects successfully it will do 1 damage, or 2 damage with the Sword of the Gods.

Sword of the Gods

A samurai with Honour that is 7 or more gains the ability to use the Sword of the Gods. If his Honour is reduced below 7, the ability to use the Sword of the Gods will be revoked from him. The Sword of the Gods deals 2 damage instead of 1.

The Sword of the Gods does not allow a strike to defeat a sword strike that it would not ordinarily defeat. For instance, a Sword of the Gods parry will still lose to an ordinary overhead strike, and a Sword of the Gods quick draw will not overpower an ordinary quick draw. Indeed, the so-called Sword of the Gods is actually not all that powerful -- perhaps it is a cosmic joke played by the gods...

Interaction Table

The Stack Snippet below contains a table which explicitly lists all the possible results of the different combinations of actions the two samurai can take. To view it, click on "Show Code Snippet", then click "Run Code Snippet".

td,
th {
  border: 1px solid #ccc;
  text-align: center;
  font-family: sans-serif;
}
<table>
  <tr>
    <th></th>
    <th>W (Wait)</th>
    <th>B (Bow)</th>
    <th>G (Guard)</th>
    <th>I (Quick Draw)</th>
    <th>P (Parry)</th>
    <th>O (Overhead Strike)</th>
  </tr>
  <tr>
    <td>W (Wait)</td>
    <td>Nothing occurs.</td>
    <td>The player that bowed gains +1 Honour.</td>
    <td>If the guarding player guarded the previous turn, that player loses 1 Honour.</td>
    <td>The player that waited takes 1 damage (or 2 if the Sword of the Gods was used.) The player that struck loses 1 Honour.</td>
    <td>The player that waited takes 1 damage (or 2 if the Sword of the Gods was used.) The player that struck loses 1 Honour.</td>
    <td>The player that waited takes 1 damage (or 2 if the Sword of the Gods was used.) The player that struck loses 1 Honour.</td>
  </tr>
  <tr>
    <td>B (Bow)</td>
    <td>The player that bowed gains +1 Honour.</td>
    <td>Both players gain +1 Honour.</td>
    <td>The player that bowed gains +1 Honour. If the guarding player guarded the previous turn, that player loses 1 Honour.</td>
    <td>The player that bowed gains +1 Honour and takes 1 damage (or 2 if the Sword of the Gods was used). The player that struck loses 1 Honour.</td>
    <td>The player that bowed gains +1 Honour and takes 1 damage (or 2 if the Sword of the Gods was used). The player that struck loses 1 Honour.</td>
    <td>The player that bowed gains +1 Honour and takes 1 damage (or 2 if the Sword of the Gods was used). The player that struck loses 1 Honour.</td>
  </tr>
  <tr>
    <td>G (Guard)</td>
    <td>If the guarding player guarded the previous turn, that player loses 1 Honour.</td>
    <td>The player that bowed gains +1 Honour. If the guarding player guarded the previous turn, that player loses 1 Honour.</td>
    <td>If a guarding player guarded the previous turn, that player loses 1 Honour.</td>
    <td>The player that struck loses 1 Honour. If the guarding player guarded the previous turn, that player loses 1 Honour. </td>
    <td>The player that struck loses 1 Honour. If the guarding player guarded the previous turn, that player loses 1 Honour.</td>
    <td>The player that struck loses 1 Honour. If the guarding player guarded the previous turn, that player loses 1 Honour.</td>
  </tr>
  <tr>
    <td>I (Quick Draw)</td>
    <td>The player that waited takes 1 damage (or 2 if the Sword of the Gods was used.) The player that struck loses 1 Honour.</td>
    <td>The player that bowed gains +1 Honour and takes 1 damage (or 2 if the Sword of the Gods was used). The player that struck loses 1 Honour.</td>
    <td>The player that struck loses 1 Honour. If the guarding player guarded the previous turn, that player loses 1 Honour.</td>
    <td>Both players lose 1 Honour. </td>
    <td>Both players lose 1 Honour. The player that quick drawed takes 1 damage (or 2 if the Sword of the Gods was used.).</td>
    <td>Both players lose 1 Honour. The player that used an overhead strike takes 1 damage (or 2 if the Sword of the Gods was used.).</td>
  </tr>
  <tr>
    <td>P (Parry)</td>
    <td>The player that waited takes 1 damage (or 2 if the Sword of the Gods was used.) The player that struck loses 1 Honour.</td>
    <td>The player that bowed gains +1 Honour and takes 1 damage (or 2 if the Sword of the Gods was used). The player that struck loses 1 Honour.</td>
    <td>The player that struck loses 1 Honour. If the guarding player guarded the previous turn, that player loses 1 Honour.</td>
    <td>Both players lose 1 Honour. The player that quick drawed takes 1 damage (or 2 if the Sword of the Gods was used.).</td>
    <td>Both players lose 1 Honour. </td>
    <td>Both players lose 1 Honour. The player that parried takes 1 damage (or 2 if the Sword of the Gods was used.).</td>
  </tr>
  <tr>
    <td>O (Overhead Strike)</td>
    <td>The player that waited takes 1 damage (or 2 if the Sword of the Gods was used.) The player that struck loses 1 Honour.</td>
    <td>The player that bowed gains +1 Honour and takes 1 damage (or 2 if the Sword of the Gods was used). The player that struck loses 1 Honour.</td>
    <td>The player that struck loses 1 Honour. If the guarding player guarded the previous turn, that player loses 1 Honour.</td>
    <td>Both players lose 1 Honour. The player that used an overhead strike takes 1 damage (or 2 if the Sword of the Gods was used.).</td>
    <td>Both players lose 1 Honour. The player that parried takes 1 damage (or 2 if the Sword of the Gods was used.).</td>
    <td>Both players lose 1 Honour. </td>
  </tr>
</table>

Program Communication

To facilitate the running of the tournament, a controller program was written to play the role of the "gods" -- it keeps records of honour and health and smites samurai accordingly. This section describes how your program will communicate with the controller program.

Input Description

The controller program will call your program from the command line like this:

<command> <history> <enemy_history> <your_health> <enemy_health> <your_honour> <enemy_honour>

where:

  • <command> is the command required to run your program. For instance, if your program is in a file super_sentai.pl, the command is probably perl super_sentai.pl.

  • <history> is a history of moves that you made. For instance, WWBP would mean you waited twice, bowed once, and parried once.

  • <enemy_history> is a history of moves your enemy made. For instance, BBBI would mean your enemy bowed three times and performed one quick draw.

  • <your_health> is your current health.

  • <enemy_health> is the enemy's current health.
  • <your_honour> is your current honour.
  • <enemy_honour> is the enemy's current honour.

For the first turn, the history and enemy_history will be empty, so your program will just be called with the last four arguments like this:

<command> <your_health> <enemy_health> <your_honour> <enemy_honour>

Please be prepared for this!

Astute readers may notice that the four arguments providing the honour and health of both samurai are, to some extent, superfluous; since this is a perfect information game, the honour and health of the samurai can be determined using only the histories.

These values are provided for convenience purposes so that you do not have to parse the history arguments. This should prove useful for implementing simple strategies, such as not attacking when your Honour is 0.

Output Description

To choose an action, your program should output one of W, B, G, I, P, or O to standard output, depending on what action you want to make. If your program doesn't output anything within 1000ms, it will be terminated and your program will be treated as if it outputted W.

If your program outputs more than one letter, only the first letter will be considered -- so outputting Parry will be the same as outputting P.

If the output of your program's first letter is not any of the options listed above, it will default to W.

Submission Format

Submit a program as an answer to this post. You may submit multiple programs. If you are submitting multiple simple programs, I recommend submitting them as a single answer; if you are submitting multiple complex programs, I recommend submitting them as separate answers. Once I have successfully added your program/s to the tournament, I will make a commit to the git repository with your entry (linked below).

If I encounter problems that prevent your program from being added to the tournament, I will leave a comment on your entry indicating the problem.

Please include the following in your submission:

  1. The human readable name of your program, for use in scoreboards. Spaces are allowed here; commas and Unicode characters are not.
  2. The language your program is written in. Please avoid writing in strange, difficult to access languages like TinyMUSH.
  3. A short synopsis of your program. This can be a description on how the program works, or just some flavour text about your program (if you want to be all secretive), or perhaps both.
  4. The command/s required to run your program. For instance, if you were writing your submission in Java called example.java, you would provide compiling instructions javac example.java then running instructions java example.
  5. The source code for the program.

To assist in submitting, I provide a submission template which can be found here. The template makes submissions look nicer. I strongly encourage using it.

I also provide two example entries. Although the example entries will be participating in the round robin, their main purpose is to clarify the submission and input/output formats for the tournament, rather than being serious contenders for the title of Ultimate Samurai.

Tournament Structure

This section describes how the tournament between the participants will be run.

Control Program

The control program is written in Python 2 and can be found on the Ultimate Samurai Showdown Github repository. If you'd like to run it yourself, instructions on how to run it are included in the README.md file in the link. However, only tournaments run on my computer will be official to avoid hardware differences affecting tournament results.

The control program will be ran on a laptop computer running Arch Linux. It has an Intel Core i7 processor and 8GB of RAM. I will endeavour to get all entries running on my computer, but I'd appreciate it immensely if you avoid languages that can't be accessed freely (as in no monetary cost).

Scoring System

The scoring system is a round robin. Each program will play eight matches against every other program. A win grants the program 1 point, a loss no points, and a draw 0.5 points. The program with the highest score wins the game. If there is a draw, I will duel the top two programs against each other to determine the winner.

The number of times each program will play each other program may be decreased from 8 if there is an extremely large number of entrants. I will add a note here if this occurs.

I will be running the round robin many times as new submissions are posted, but it is only the most recent round robin that will count.

Disqualifications

It is possible for your program to be disqualified from the tournament. Disqualification may occur if:

  • Your program does not compile or run;
  • Your program is a strategic duplicate of another program (that is, it implements the exact same strategy as another program);
  • Your program attempts to sabotage other programs by modifying the controller code, other program's code, etc;
  • Your program attempts to exploit a bug in the controller code. Instead of exploiting bugs you should instead open an issue in the git repository, make a comment here, or ping me in chat.

Past Results

Detailed results of all tournaments are made available at the wiki page.

The most recent tournament was completed on 2015-07-17 07:20. Here is a summary of the results:

The Observer: 209.0
Coward: 203.0
Monk: 173.0
Elephant Warrior: 157.0
Iniqy: 157.0
Agent 38: 144.0
Ninja: 138.0
Meiyo Senshi: 138.0
Kakashi: 136.0
Yoshimitsu: 131.0
Hermurai: 121.0
Warrior Princess: 120.0
Gargoyle: 119.5
The Honourable: 119.0
Hebi: 118.5
Predictor: 116.0
Whack-a-mole: 107.0
The Fool: 106.0
The Prophet: 105.0
Copy-san: 97.0
YAGMCSE: 80.0
The Waiter: 66.0
Swordsman: 43.0
Spork Holder: 32.5
Blessed Samurai: 27.5
Attacker: 27.0
The Terminator: 17.0
Master Yi: 16.0
\$\endgroup\$
  • 1
    \$\begingroup\$ The Waiter is doing surprisingly well. Must be racking up wins against Spork Holder when it runs out of honour. \$\endgroup\$ – StephenTG Jun 26 '15 at 13:52
  • \$\begingroup\$ This is a neat challenge. You clearly put a lot of thought and work into this, and I think it definitely paid off. Excellent job. :) \$\endgroup\$ – Alex A. Jun 26 '15 at 14:46
  • 1
    \$\begingroup\$ @C5H8NNaO4 Yes, I'll check for updates to bots before I run the next tournament. \$\endgroup\$ – absinthe Jun 27 '15 at 13:48
  • 1
    \$\begingroup\$ Notice: My laptop broke down recently. Thus, I have no current way to run the tournament in the near future. There will be delays in running the next tournament as I try to find a computer that I can use. \$\endgroup\$ – absinthe Jul 3 '15 at 22:23
  • 1
    \$\begingroup\$ @Levi Yes! The manufacturer shipped me a replacement which arrived today. There's a tournament running as we speak. \$\endgroup\$ – absinthe Jul 16 '15 at 10:11

20 Answers 20

8
\$\begingroup\$

The Monk (Java)

The Monk values honour and praises the blessings of the Gods. Being trained in patience he calmly sends his prayers to heaven until he feels being favoured by God.

Enjoying his life, he tries to protect it. When he's losing health over a certain rate, he defends himself as best as he can.

Hoping for the support of his Gods he randomly sends ejaculations[1] to heaven, otherwise he fights as best as he can.

If his opponent is worn out from the battle he finishes him using his remaining honour to grant him a fast and painless death.

Compile/Run

javac Monk.java
java Monk

public class Monk {
    public static void main(String[] args){
        char  r = 'B';
        double  s = Math.random ();
        int n = Math.max (args [0].length ()- 8, 1);
        int p = args.length > 4 ? Integer.parseInt (args [4]):0;
        int l = Integer.parseInt (args [3]);
        int m = Integer.parseInt (args [2]);
        double d = 1 + (20 - m) / n;
        double e = 1 + (20 - l) / n;

        if (((p>8&&s<.7)||l<11||m<2)&&p>0) {
                r=(s<(.14)||d>=2||e/d<.618)?'G':"OPI".charAt((int)(Math.random()*3));
        }

        System.out.print (r);
    }
}

The Ninja (Java)

The Ninja is fast and attacks even faster. He attacks right away after a friendly formal greeting, further confusing his enemy by bowing before and after every attack.

Upon being blessed the ninja keeps up this behaviour, waiting for his opponent to make his first move(s). Using this opportunity he unleashs a series of blasts, blessed by the ninja Goddess until he's too worn out from the battle. Using his remaining honor he hides under the leaves beneath, guarding himself from the next attack. He jumps out and attacks his foe from behind, being hidden as fast again.

If he receives a fatal wound he goes all out to take his opponent's live with him -- of course, keeping a miminum of honour.

javac Ninja.java
java Ninja

public class Ninja {
    public static void main(String[] args){
        char  r = 'B';
        int n = args [0].length ();
        int p = args.length > 4 ? Integer.parseInt (args [4]):0;
        int m = Integer.parseInt (args [2]);
        int a = n % 3;
        if (p>7) {
           if (m>17) {
                r = "BBI".charAt (a);
           } else if (m>13) {
                r = "BII".charAt (a); 
           } else {
               r  = "GIG".charAt (a);
           }

        } else if (p>0) {
           if (m > 10) {
                    r = "BBI".charAt (a);
           } else {
                r="IGI".charAt (n%2);
           }
        }
        System.out.print (r);
    }
}

Kakashi, The Copycat Ninja (Java)

Kakashi copies his opponents moves by randomly choosing between the last two moves the opponent made. If the opponent waits, he bows -- He keeps his honour as well.

javac Kakashi.java
java Kakashi

public class Kakashi {
    public static void main(String[] args){
        char  r;
        String h = args [1];
        if (h=="W" || Integer.parseInt ( args.length > 4?args [4]:"0") < 1){
                 r = 'B';
        } else if (Math.random ()<.1) {
            r = 'I';
        } else {
            r  = h.charAt ((int) (h.length()==1?0: h.length()-Math.random ()*2));
        }

        System.out.print (r);
    }
}


I wish Kakashi could be blessed with the sharingan.. I thought about reading the cast.txt. Simulate every round of his history against every opponent in there. Try to find out against which opponent he's fighting by comparing the simulated enemies history with the real enemies history. Then use that information to predict the next move the opponent would do and pick the best countermove from a predefined list. But I feel this could take a bit as I have super slow Internet at the moment and about no Java skills

The Observer, (node.js)

The Observer bows before trying to predict the opponent's next move from its past 5 moves, choosing the best counterpart for the predicted move.

Edit: Thanks to @apsillers for sharing the node.js boilerplate!.

node observer.js

var argv = process.argv;
var history = argv.length>6?argv[2]:"";
var enemyHistory = argv.length>6?argv[3]:"";
var offset = 8 - argv.length;
var my = { health:+argv[4-offset], honor:+argv[6-offset], history:history };
var enemy = { health:+argv[5-offset], honor:+argv[7-offset], history:enemyHistory };
my.godSword = my.honor >= 7;
enemy.godSword = enemy.honor >= 7;
function decide() {
    process.stdout.write(arguments[Math.floor(arguments.length*Math.random())]);
    process.exit();
}

var m = {
    m:{},
    l:function (a,b) {
        if (!this.m[a]) {
           this.m [a] = [];
        }
        this.m[a].push (b);
    },
    p:function (a) {
       for (var k=0;k<a.length;k++)
       for (var j=1;j<a.length;j++)
       for (var i=-1+k; i<a.length-j; i++)this.l (a.slice (i,i+j),a[i+j]);
    },
    a:function (a) {
      if (!this.m[a])return;
      return this.m[a][0|Math.random () * this.m[a].length-1]
    }
}
var g={
   B:"IPO",
   G:"B",
   I:"PG",
   O:"IG",
   P:"OG",
   W:"I"
}
var c,i=0;
m.p(enemy.history);
while (!c && i++<enemy.history.length) {
   c=m.a (enemy.history.slice (i));
}
decide.apply  (0,my.honor < 7?["B"]:g[c].split (''))

Edit: I had a major flaw in the observer, I actually don't know what I thought yesterday night. It seems he only looked at the past two moves of the enemy. He did surprisingly well like this.

His memory now get's queried for the longest (end) part of the enemies history he already has seen. This contains an array with all the moves that followed the history of moves. One is randomly selected. So if one move followed more often, it is as well more likely to be picked. Kind of like markov chains.

The Observer, now guards as well.


[1]: TIL: ejaculation has a religious meaning

\$\endgroup\$
  • \$\begingroup\$ You're #1 and #3 right now! Nice bots! :) \$\endgroup\$ – apsillers Jul 1 '15 at 17:06
  • \$\begingroup\$ Congratulations on winning with The Observer. The green tick is now yours :D \$\endgroup\$ – absinthe Jul 23 '15 at 12:43
7
\$\begingroup\$

Meiyo Senshi (Java)

Hailing from the Haijima area, not much is known about the Meiyo. They do not normally participate in games of sport, but have sent a warrior to this one in order to assess their rivals.

They are an honorable bunch, though, so you can be assured he will make his presence known to the gods in short order. Once he has seen enough of his foe to report, he will use the blessings received to strike down his opponent.

To compile run, it's the standard Java way:

> javac MeiyoSenshi.java
> java MeiyoSenshi
public class MeiyoSenshi {
    public static void main(String[] args){
        System.out.print(
                Integer.valueOf(args[args.length<5?0:2])>12 ||
                Integer.valueOf(args[args.length<5?2:4])<1  ?
                "B":
                "IPO".charAt((int)(Math.random()*3))
        );
    }
}
\$\endgroup\$
7
\$\begingroup\$

Spork Holder (Ruby)

Spork Holder bows on the first turn, then acts randomly afterwards. It is one of the two example entries.

Command: ruby spork-holder.rb

if ARGV.length == 4
    print "B"
else
    print ["W", "B", "G", "I", "P", "O"].sample
end

The Waiter (bash)

The Waiter only waits on every turn. It is one of the two example entries.

Command: echo W

There is no source code required.

\$\endgroup\$
7
\$\begingroup\$

Coward (Node.js)

I'm a coward / It's a miracle I dare breathe
Overpowered / By the gentlest summer breeze

  • Checks for BXBXBX/BBB patterns to bow (or hit you) when you're bowing.
  • Checks for GXGXGX patterns to bow when you're guarding.
  • If his random bravery roll overcomes his fear threshold for that round, he'll try for a hit.
    • Having a Sword of the Gods makes him braver.
    • An opponent with a Sword of the Gods makes him more fearful.
    • An opponent who leads by at least 5 Health or more also makes him a little scared.
  • Otherwise, he takes turns guarding and bowing.

If you want to write a Node.js submission, please feel free to use my boilerplate code; everything up to an including the decide function is fully general and free to take.


node coward.js

var argv = process.argv;
var history = argv.length>6?argv[2]:"";
var enemyHistory = argv.length>6?argv[3]:"";
var offset = 8 - argv.length;
var my = { health:+argv[4-offset], honor:+argv[6-offset], history:history };
var enemy = { health:+argv[5-offset], honor:+argv[7-offset], history:enemyHistory };
my.godSword = my.honor >= 7;
enemy.godSword = enemy.honor >= 7;
function decide() {
    process.stdout.write(arguments[Math.floor(arguments.length*Math.random())]);
    process.exit();
}

var enemyGuards = !!enemy.history.match(/G.G.G.$/);
var enemyBows = !!enemy.history.match(/(B.B.B.$)|(BBB$)/);

// open with a bow
if(!my.history) { decide("B"); }

// enemy will likely bow? Hit them with your super sword! (or bow)
if((!enemy.honor || enemyBows)) {
    if(my.godSword) { decide("P","I","O"); }
    else { decide("B"); }
}

// no point in hitting them if they're going to guard
if(enemyGuards) { decide("B"); }

// calculate bravery level
var braveryLevel = 0.3;
braveryLevel += (my.godSword * 0.2) - (enemy.godSword * 0.2);
braveryLevel -= (enemy.health - my.health > 5) * 0.1;

// if we're feeling brave, hit them
if(Math.random() < braveryLevel && my.honor) { decide("P","I","O"); }

// if we didn't just guard, and we're not feeling brave, cower in fear
if(!my.history.match(/G$/)) {
    decide("G");
}

// if we did just guard, and we're feeling cowardly,
//   if we don't have sword of the gods, bow
//   otherwise, do anything except guard
if(!my.godSword) {
    decide("B");
} else {
    decide("B","P","I","O");
}
\$\endgroup\$
  • 1
    \$\begingroup\$ That's a tough bot. Awesome boilerplate; I'll use it right away. Thanks for sharing :) \$\endgroup\$ – C5H8NNaO4 Jun 26 '15 at 21:07
6
\$\begingroup\$

Whack-a-mole (R)

Strikes when enemy is likely to bow, else guards.

args <- commandArgs(TRUE)
L <- length(args)
my_health <- as.integer(args[L-3])
enemy_health <- as.integer(args[L-2])
my_honour <- as.integer(args[L-1])
enemy_honour <- as.integer(args[L])
if(L>4){enemy_history <- args[L-4]}else{enemy_history <- ""}
if(my_honour<1){
    out <- "B"
}else if (enemy_honour<=1 | grepl("BB$",enemy_history)){
    out <- sample(c("I","O"),1)
}else{
    out <- "G"
}
cat(out)

Run using Rscript Whack-a-mole.R.

\$\endgroup\$
  • 1
    \$\begingroup\$ Nice job, plus I love the name. \$\endgroup\$ – Alex A. Jun 26 '15 at 14:57
3
\$\begingroup\$

Elephant Warrior (Java)

The Elephant Warrior is from an older, more natural time. He has seen much, and remembers all. He curries favor with the gods while he examines his opponent, and then once he takes them into his heart, he takes them apart.

Compile: javac ElephantWarrior.java
Command: java ElephantWarrior

import java.util.LinkedList;

//Elephants never forget
class ElephantWarrior
{


  static LinkedList<Choice> analysis = new LinkedList<Choice>();

  public static void main(String[] args){
      if(args.length < 6){ respond("B");}   
      String myhis = args[0];
      String enHis = args[1];
      int health = Integer.parseInt(args[2]);
      int enHealth = Integer.parseInt(args[3]);
      int honour = Integer.parseInt(args[4]);
      int enHonour = Integer.parseInt(args[5]);

        //Bow a few times until I know how he operates
        if(enHis.length() <= 5){
            respond("B");
        }

        //Special cases
        //If I'm at 0 honor, better bow
        else if(honour <= 0){
            respond("B");

        }
        else{
          analyze(enHis);

          //Narrow it down to applicable choices
          char hisLast = enHis.toCharArray()[enHis.toCharArray().length - 1];
          LinkedList<Choice> hisOptions = new LinkedList<Choice>();
          for(Choice c: analysis){
              if(c.pattern.toCharArray()[0] == hisLast){
                  hisOptions.add(c);
              }
          }

           //Default to assuming they bow
          char hisNext = 'B';
          int mostLikely = 0;

          //What will they do next?
          for(Choice c : hisOptions){
              if(c != null && c.probability > mostLikely){
                  //System.out.println("Option = " + c.pattern);
                  //System.out.println("Prob = " + c.probability);
                  mostLikely = c.probability;
                  hisNext = c.pattern.toCharArray()[1]; }
          }

          //Now go through potential case
          switch(hisNext){
              case 'W':
                  respond("I");
                  break;
              case 'B': 
                  respond("O");
                  break;
              case 'G':
                  respond("B");
                  break;
              case 'I':
                  if(enHonour  > 0){
                      respond("P");
                  }
                  else{
                      respond("B");
                  }
                  break;
              case 'P':
                  respond("O");
                  break;
              case 'O':
                  respond("I");
                  break;
              default:
                  respond("G");
          }
        }
    }





      static void analyze(String his){

        //Keep track of his previous moves
        char[] shortString = his.substring(1,his.length() - 1).toCharArray();
        char[] longString = his.toCharArray();
        for( int i = 0; i < shortString.length; i++) {
          String pattern = "" + longString[i] + shortString[i];
          boolean exists = false;
          for(Choice c : analysis){
              if(c.pattern.equals(pattern)){
                  exists = true;
                  c.probability++;
              }
          }
          if(!exists){
              analysis.add(new Choice(pattern, 1));
          }
        }
      }

      private static void respond(String s){
            System.out.println(s);
            System.exit(0);
        }

    }

class Choice{
        String pattern;
        int probability;

       Choice(String p, int i){
            pattern = p;
            probability = i;
       }
}
\$\endgroup\$
  • 2
    \$\begingroup\$ I haven't tested this, but it looks like it will go out of bounds on the first turn where there are only four args. \$\endgroup\$ – Geobits Jun 26 '15 at 17:58
  • \$\begingroup\$ Right, didn't realize that those wouldn't be included at all. I guess obviously a blank string cant be passed, thanks! \$\endgroup\$ – Cain Jun 26 '15 at 18:01
  • \$\begingroup\$ @katya It's fixed now, btw, should be included in tournament. \$\endgroup\$ – Cain Jun 26 '15 at 22:16
3
\$\begingroup\$

Warrior Princess (Julia)

This is the first King of the Hill challenge I've competed in. Let's see how this goes.

The Warrior Princess prioritizes attack and honor, and resorts to self-preservation when needed. She's rather eager and never waits. In an effort to remain nimble, she also doesn't use an overhead attack.


Save as warrior-princess.jl and run from the command line like so:

julia warrior-princess.jl <arguments>

If you don't have Julia, you can download it here. To avoid issues, the latest stable version is recommended (i.e. not the development version).


type Samurai
    history::String
    health::Int
    honor::Int
end

A = length(ARGS) < 5 ? ["", "", ARGS] : ARGS

me = Samurai(A[1], int(A[3]), int(A[5]))
opponent = Samurai(A[2], int(A[4]), int(A[6]))


if length(me.history) == 0

    # Always begin the match with an honorable bow
    action = "B"

elseif (!ismatch(r"[OIP]", opponent.history) && me.history[end] != 'G') ||
       (me.health < 2 && me.honor > 0)

    # Guard if the enemy has not yet attacked and I did not previously
    # guard, or if my health is low and my honor is sufficient
    action = "G"

elseif me.honor < 2

    # Bow if I'm low on honor
    action = "B"

elseif opponent.honor >= 7 && opponent.history[end] ∈ ['B', 'W']

    # Assume the enemy will attack with the Sword of the Gods if they
    # most recently bowed or waited
    action = "I"

else
    action = "P"
end

println(action)
\$\endgroup\$
  • 1
    \$\begingroup\$ Your first KotH entry and the first Julia KotH entry ever if i'm not mistaken: congrats! \$\endgroup\$ – plannapus Jun 27 '15 at 8:10
  • \$\begingroup\$ @plannapus Thanks! :D Perhaps I'll make a habit out of it. \$\endgroup\$ – Alex A. Jun 27 '15 at 16:21
3
\$\begingroup\$

Gargoyle (Java)

Tries to use the defensive move without consuming honor.

Since it's a java entry:

> javac Gargoyle.java
> java Gargoyle
public class Gargoyle { 
    public static void main(String args[]) {
        if (args.length < 5 || Integer.valueOf(args[4]) > 0) {
            System.out.println("IPO".charAt((int)(Math.random()*3)));
        } else if (args[0].charAt(args[0].length()-1) != 'G') {
            System.out.println('G');
        } else {
            System.out.println('B');
        }
    }
}
\$\endgroup\$
3
\$\begingroup\$

Swordsman (C/Java)

Swordsman bows on the first turn and whenever he is running low on honor. He then checks if the opponent hadn't bowed or defended or waited in the previous turn. If the opponent hadn't, there is a big probability that he will do one of these in the current turn and swordsman thus randomly strikes on the opponent. If this isn't true, he defends if he hasn't defended the previous turn. If he had, he bows to gain honor.

C version:

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

void print_and_exit(char* str)
{
    puts(str);
    exit(0);
}

int main(int argc, char** argv){

    srand(time(NULL));
    char* attack_moves[]={"I", "P", "O"};
    int random_num = rand() % 3;

    if(argc == 5 || atoi(argv[5]) == 0)
        print_and_exit("B");
    else if(argv[2][strlen(argv[2])-1] != 'B' && argv[2][strlen(argv[2])-1] != 'G' && argv[2][strlen(argv[2])-1] != 'W')
        print_and_exit(attack_moves[random_num]);
    else if(argv[1][strlen(argv[1])-1] != 'G')
        print_and_exit("G");

     print_and_exit("B");
}

Install GCC (compiler) and save the code into a file named "Swordsman.c" command for compiling:

gcc Swordsman.c -o Swordsman

Executable named "Swordsman" will be created. Run using

Swordsman

Java version:

public class Swordsman {

    public static void print_and_exit(String str)
    {
        System.out.println(str);
        System.exit(0);
    }
    public static void main(String[] argv) {

        String attack_moves[]={"I", "P", "O"};
        int random_num = (int)(Math.random()*3);

        if(argv.length == 4 || Integer.valueOf(argv[5]) == 0)
            print_and_exit("B");
        else if(argv[2].charAt(argv[2].length()-1) != 'B' && argv[2].charAt(argv[2].length()-1) != 'G' && argv[2].charAt(argv[2].length()-1) != 'W')
            print_and_exit(attack_moves[random_num]);
        else if(argv[1].charAt(argv[1].length()-1) != 'G')
            print_and_exit("G");

         print_and_exit("B");
    }

}

Install javac (compiler) and save the code into a file named "Swordsman.java" command for compiling:

javac Swordsman.java

Class file named "Swordsman.class" will be created. Run using

java Swordsman



Attacker (Java)

Attacker doesn't care about anything except that he wants his opponent dead. He randomly strikes one of the attack moves and if has low honor, bows.

public class Attacker {

    static int position = -1;

    public static void print_and_exit(String str)
    {
        System.out.println(str);
        System.exit(0);
    }
    public static void main(String[] argv) {

        String attack_moves[]={"I", "P", "O"};
        position = (position + 1) % 3;

        if(argv.length != 5 && Integer.valueOf(argv[5]) == 0)
            print_and_exit("B");
        else 
            print_and_exit(attack_moves[position]);
    }

}

Install javac (compiler) and save the code into a file named "Attacker.java" command for compiling:

javac Attacker.java

Class file named "Attacker.class" will be created. Run using

java Attacker


Predictor (C/Java)

Predictor predicts the enemies moves. In the first turn, it uses a random move. Bows if his honor is low, strikes if the enemies honor is low or has bowed in the previous turn. If predictor hasn't guarded the previous turn, guards in the current turn. Else, does the same move as the enemy has done in the previous turn, provided that it isn't 'W' in which case, Predictor bows.

C version:

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

void print_and_exit(char* str)
{
    puts(str);
    exit(0);
}

int main(int argc, char** argv){

    srand(time(NULL));
    int random = rand() % 5;
    char* moves[] = {"B", "G", "I", "P", "O"};

    if(argc == 5)
        print_and_exit(moves[random]);

    if(atoi(argv[5]) <= 0)
        print_and_exit(moves[0]);
    if(atoi(argv[6]) <= 0)
        print_and_exit(moves[4]);
    if(argv[2][strlen(argv[2])-1] == 'G')
        print_and_exit(moves[4]);
    if(argv[1][strlen(argv[1])-1] != 'G')
        print_and_exit(moves[1]);

    if(argv[2][strlen(argv[2])-1] != 'W'){
        char buf[2]={0};
        *buf = argv[2][strlen(argv[2])-1];
        print_and_exit(buf);
    }

    print_and_exit(moves[0]);

}

Install GCC (compiler) and save the code into a file named "Predictor.c" command for compiling:

gcc Predictor.c -o Predictor

Executable named "Predictor" will be created. Run using

Predictor

Java version:

public class Predicator{

    public static void print_and_exit(String str)
    {
        System.out.println(str);
        System.exit(0);
    }

    public static void main(String[] argv){

        int random = (int)(Math.random() * 5);
        String moves[] = {"B", "G", "I", "P", "O"};

        if(argv.length == 4)
            print_and_exit(moves[random]);
        else if(Integer.valueOf(argv[5]) <= 0)
            print_and_exit(moves[0]);
        else if(Integer.valueOf(argv[6]) <= 0)
            print_and_exit(moves[4]);
        else if(argv[2].charAt((argv[2].length())-1) == 'G')
            print_and_exit(moves[4]);
        else if(argv[1].charAt((argv[1].length())-1) != 'G')
            print_and_exit(moves[1]);
        else if(argv[2].charAt((argv[1].length())-1) != 'W'){
                    print_and_exit(""+argv[2].charAt((argv[2].length())-1));
        }
        else
            print_and_exit(moves[0]);
    }
}

Install javac (compiler) and save the code into a file named "Predicator.java" command for compiling:

javac Predicator.java

Class file named "Predicator.class" will be created. Run using

java Predicator


Not sure how effective these bots will be as I don't have the python2 interpreter to test it.

\$\endgroup\$
  • 1
    \$\begingroup\$ I haven't tested this (Attacker), but it looks like it will go out of bounds on the first turn where there are only four args. \$\endgroup\$ – Geobits Jun 26 '15 at 18:02
  • \$\begingroup\$ Attacker seems to be giving an ArrayIndexOutOfBoundsException on the first turn, causing it to wait on the first turn. Aside from that it is functioning. \$\endgroup\$ – absinthe Jun 27 '15 at 0:22
  • \$\begingroup\$ @Katya and Geobits , Fixed. Thanks for spotting it. \$\endgroup\$ – Spikatrix Jun 27 '15 at 6:30
  • \$\begingroup\$ When running the predictor, I get a segmentation fault (core dumped) after round 24 \$\endgroup\$ – C5H8NNaO4 Jun 29 '15 at 9:50
  • \$\begingroup\$ @C5H8NNaO4 Fixed the issue. Updated code for all three bots. Should work fine now. Thanks for pointing it out! :-D \$\endgroup\$ – Spikatrix Jun 29 '15 at 10:41
2
\$\begingroup\$

Master Yi (Python)

The master assassin gains much favor in the early game, building it up until he's invincible. Tries to attack when they least expect it.

import sys, random

class MasterYi(object):
    def __init__(self):
        self.attack = lambda: random.choice(['I','P','O'])
        self.bow   = "B"
        self.guard = "G"
        self.wait  = "W"
        if len(sys.argv)>6:
            self.hist = sys.argv[1]; self.ohist = sys.argv[2]
            self.hp   = sys.argv[3]; self.ohp   = sys.argv[4]
            self.hon  = sys.argv[5]; self.ohon  = sys.argv[6]
        else:
            self.hist = [];          self.ohist = []
            self.hp   = sys.argv[1]; self.ohp   = sys.argv[2]
            self.hon  = sys.argv[3]; self.ohon  = sys.argv[4]
        self.last  = self.hist  and self.hist[-1]  or "W"
        self.olast = self.ohist and self.ohist[-1] or "W"
        self.oGuarder = len(self.ohist)>4 and self.ohist[-4]==self.ohist[-2]=="G"

    def move(self):
        if self.hon < 1: return self.bow
        if self.olast == "G": return self.attack
        if self.hon > 6:
            if self.oGuarder: return self.bow
            if self.ohon > 6: return self.guard
            if self.ohon < 7: return self.attack
            return self.attack
        if self.ohon > 6: return self.guard
        return self.bow

Yi = MasterYi()
print(Yi.move())

To run: Save as MasterYi.py

python MasterYi.py <args>
\$\endgroup\$
2
\$\begingroup\$

Copy-san (C)

Copies every move of his opponent. Pretty sure he's guaranteed to lose. Compile: gcc copy-san.c

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

int main(int argc, char *argv[]) {
    if (argc == 5) {
        putchar('B');
    } else {
        char *enemy_hist = argv[2];
        size_t len = strlen(enemy_hist);
        putchar(enemy_hist[len - 1]);
    }
    putchar('\n');
    return 0;
}
\$\endgroup\$
2
\$\begingroup\$

Hebi (Java)

Hebi follow The Way Of The Snake.

The Snake has no need for the blessing of the gods.

The Snake slithers its strikes; like waves upon the beach, what comes in recedes back the way it came.

The Snake never waits.

The Snake has no sense of aptness, elsewise it would've been written in Python.

Running instructions:

> javac hebi.java
> java hebi

Code body:

public class hebi{

    public static void main(String args[]){

        if( (args.length < 5) || (args[0].length() % 18 == 0) ) System.out.println( "IPO".charAt((int)(Math.random()*3)) );
        else{

            int hist_size = args[0].length();

            if      (hist_size % 3 == 1) System.out.println("G");
            else if (hist_size % 3 == 2) System.out.println("B");
            else{

                if     (hist_size % 18 ==  9) System.out.println(args[0].charAt(hist_size -  3));
                else if(hist_size % 18 == 12) System.out.println(args[0].charAt(hist_size -  9));
                else if(hist_size % 18 == 15) System.out.println(args[0].charAt(hist_size - 15));
                else{

                    char move_head = args[0].charAt( (hist_size / 18) * 18 );
                    char move_mid;
                    if( hist_size % 18 == 3 ){
                        if     ( move_head == 'I' ) move_mid = "PO".charAt((int)(Math.random()*2));
                        else if( move_head == 'O' ) move_mid = "IP".charAt((int)(Math.random()*2));
                        else                        move_mid = "OI".charAt((int)(Math.random()*2));
                        System.out.println(move_mid);
                    }
                    else{
                        move_mid = args[0].charAt( ((hist_size / 18) * 18) + 3 );
                        char move_tail;

                        if( move_head == 'I' ){
                            if( move_mid == 'P' ) move_tail = 'O';
                            else                  move_tail = 'P';
                        }else if( move_head == 'P' ){
                            if( move_mid == 'O' ) move_tail = 'I';
                            else                  move_tail = 'O';
                        }else{
                            if( move_mid == 'I' ) move_tail = 'P';
                            else                  move_tail = 'I';
                        }

                        System.out.println( move_tail );

                    }

                }

            }

        }

    }

}
\$\endgroup\$
2
\$\begingroup\$

The Honourable (Java)

The Honourable values honor above all. That is, his honor above everyone else's. If the enemy samurai has greater or equal honor, he bows. None shall be more honorable than he. Otherwise, he does a random move. He never guards twice in a row - that would be dishonorable!

to compile:

> javac TheHonourable.java
> java TheHonourable

Source:

public class TheHonourable {
    public static void main(String[] args) {
        char move;

        if (args.length < 5) {
            move = 'B';
        } else if (Integer.valueOf(args[5]) >= Integer.valueOf(args[4])){
            move = 'B';
        } else {
            move =  (args[0].endsWith("G")) ?
                    "IPO".charAt((int)(Math.random()*3)) :
                    "GIPO".charAt((int)(Math.random()*4));
        }

        System.out.print(move);
    }
}
\$\endgroup\$
1
\$\begingroup\$

Blessed Samurai (Python)

This Samurai tries to keep the gods' favor for a long as possible. He rushes to get the holy sword, then alternates between Guarding and Attacking with one of the strikes, restocking honour when needed. If it looks like either he or his opponent may soon fall, he rushes in for a kill. He will easily fall to an oponent that can track his pattern, but his strategy of always attacking at two damage should be pretty effective.

import sys
import random
class BlessedSamurai(object):
    def __init__(self):
        if len(sys.argv) < 7:
            print("B")
        else:
            self.attack = ['O', 'I', 'P']
            self.hp = sys.argv[3]
            self.ohp = sys.argv[4]
            self.hon = sys.argv[5]
            self.last = sys.argv[1][-1]
            print(self.move())

    def move(self):
        #check if I have low health or should rush the kill
        if (self.hp < 5 or self.ohp < 5) and self.hon > 0:
            return(random.choice(self.attack))
        # charge honour to get SOTG
        elif self.hon < 7:
            return 'B'
        #Alternate guarding and attacking
        else:
            if self.last == 'G':
                return(random.choice(self.attack))
            return 'G'
Sam = BlessedSamurai()

To run:
Save as BlessedSamurai.py

python BlessedSamurai.py <args>
\$\endgroup\$
  • 4
    \$\begingroup\$ Your program needs to print its move. \$\endgroup\$ – mbomb007 Jun 26 '15 at 17:27
  • 3
    \$\begingroup\$ I haven't tested this, but it looks like it will go out of bounds on the first turn where there are only four args. \$\endgroup\$ – Geobits Jun 26 '15 at 18:03
  • \$\begingroup\$ I used a similar format to what he did. @Stranjyr, take a look at what I did for getting the args. \$\endgroup\$ – mbomb007 Jun 26 '15 at 18:34
  • \$\begingroup\$ Thanks to both of y'all! I don't have access to a python interpreter right now, but I think I have fixed the issues. Somehow I completly missed that the first set of instructions would not have a history. \$\endgroup\$ – Stranjyr Jun 26 '15 at 21:28
  • \$\begingroup\$ Hi, you had a small bug in your program "global name 'last' is not defined". Since it's a small bug I've changed last to self.last which seems to fix the problem. \$\endgroup\$ – absinthe Jun 26 '15 at 22:25
1
\$\begingroup\$

Hermurai (C++)

Admires his opponent, and is a little paranoid. Wants to know if he can do what other samurai can, because he still can't believe himself to be a samurai. His never-fading dream became reality before him knowing it. Which could cost his head...

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

using namespace std;

char getLastAttack(string enemy_history)
{
    size_t found = enemy_history.find_last_of("IPO");
    if(found == string::npos)
    {
        return 'I';
    }

    return enemy_history[found];
}

int main(int argc, const char * argv[])
{
    if(argc != 7){
        printf("B");
        return 0;
    }

    string enemy_history(argv[2]);

    int ho;
    string honour(argv[5]);
    stringstream(honour) >> ho;

    if(ho > 20){
        char atk = getLastAttack(enemy_history);
        printf("%c", atk);
        return 0;
    }

    char lastMove = enemy_history[enemy_history.length()-1];
    if(lastMove == 'W' || lastMove == 'G')
        lastMove = 'B';
    printf("%c", lastMove);
    return 0;
}

Iniqy (C++)

Strikes as hard as possible. Goes into unstoppable attack mode when he is in danger.

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

using namespace std;

char getLastAttack(string enemy_history)
{
    size_t found = enemy_history.find_last_of("IPO");
    if(found == string::npos)
    {
        return 'I';
    }

    return enemy_history[found];
}

int main(int argc, const char * argv[])
{
    if(argc != 7){
        printf("B");
        return 0;
    }

    string history(argv[1]);
    string enemy_history(argv[2]);
    string health(argv[3]);
    string enemy_health(argv[4]);
    string honour(argv[5]);
    string enemy_honour(argv[6]);

    int he, enemy_he, ho, enemy_ho;
    stringstream(health) >> he;
    stringstream(enemy_health) >> enemy_he;
    stringstream(honour) >> ho;
    stringstream(enemy_honour) >> enemy_ho;

    if(ho > 6 || ((he < 6 || enemy_he < 6) && ho > 0))
    {
        char atk = getLastAttack(enemy_history);
        printf("%c", atk);
        return 0;
    }


    printf("B");
    return 0;
}

Both are written in C++. To compile:

g++ iniqy.cpp -o iniqy

To run on Linux: ./iniqy

To run on Windows: iniqy.exe

\$\endgroup\$
1
\$\begingroup\$

The Terminator (ruby)

The Terminator doesn't pay attention to his own health. The Terminator has no notion of honor. The Terminator is sent from the future and simply determined to terminate its opponent. It does so by watching its opponents moves, and nothing else. It samples the moves and calculates the appropriate response in such an intricate manner that no present-day technology can predict the Terminator's actions. In fact, to anyone living in 2015 the Terminator may seem somewhat random ...

responses = {
  ?W => %w(B I),
  ?B => %w(I O),
  ?G => %w(B B),
  ?I => %w(G P),
  ?P => %w(B O),
  ?O => %w(G I)
}

if ARGV.size > 4
  pool = ARGV[1].chars.map{ |c| responses[c] }.flatten
  puts pool.sample
else
  puts %w(O I P B).sample
end
\$\endgroup\$
1
\$\begingroup\$

Agent 38[1] (C)

As a product of extensive genetic manipulation, Agent 38 has the physique and mental acuity of a super[2]-samurai, and is definitely superior to all its helplessly[citation needed] flawed[citation needed] competitors.


//Agent 38
#include <stdio.h>
#include <stdlib.h>
#include <math.h>

#ifdef _WIN32
#include <Windows.h>
unsigned int tick_count(){
    return GetTickCount();
}
#else
#include <sys/time.h>
unsigned int tick_count(){
    struct timeval t;
    gettimeofday(&t, NULL);
    return 1000 * t.tv_sec + t.tv_usec / 1000;
}
#endif

float program[5][4][4][4][4]={
    {{{{-1.192779,0.693321,-1.472931,-0.054087},{0.958562,0.557915,0.883166,-0.631304},{-0.333221,1.410731,0.496346,0.087134},{0.459846,0.629780,-0.479042,-0.025909}},{{0.547976,1.059051,-0.748062,-0.675350},{-0.607591,-0.152156,-0.400350,-0.685337},{1.686450,0.628706,0.312865,0.324119},{1.652558,0.403733,-0.456481,-0.081492}},{{0.371629,-0.036948,-0.982682,0.065115},{1.360809,0.681294,0.505074,0.782737},{-0.545192,0.954937,-0.727853,0.273542},{-0.575777,1.615253,-0.064885,-0.516893}},{{0.577015,-0.112664,0.456595,-0.007560},{-0.660930,-0.738453,0.668093,1.716388},{1.972322,0.108558,0.535114,-0.337916},{0.640208,-0.019680,-0.769389,0.873087}}},{{{-0.021140,-0.095956,-0.098309,-0.280295},{-0.926284,1.724028,0.278855,0.678060},{0.153006,-1.860947,-0.577699,-1.931683},{-0.187152,0.529719,-1.164157,0.125499}},{{0.582208,-0.835029,-0.329857,0.088176},{-0.030797,0.389396,0.584636,-0.025866},{-0.736538,1.624658,0.690493,0.387515},{0.973253,-0.530825,1.934379,-0.872921}},{{0.812884,0.138399,-1.452478,-1.504340},{-0.119595,0.986078,-0.993806,1.102894},{0.848321,-0.268764,0.876110,0.782469},{0.948619,-0.557342,0.749764,-0.712915}},{{-1.195538,0.783784,-1.973428,-0.873207},{0.085426,-0.241360,-0.534561,-0.372105},{0.029696,-0.906821,0.932227,-0.834607},{0.764903,-0.276117,-1.346102,-0.093012}}},{{{0.168113,0.855724,1.817381,-0.547482},{0.468312,0.923739,-0.723461,0.798782},{-0.875978,-0.942505,-0.684104,-0.046389},{0.893797,-0.071382,0.283264,0.811233}},{{0.391760,0.309392,-0.045396,-0.977564},{0.085694,0.257926,-0.775461,0.060361},{0.486737,-0.175236,0.806258,-0.196521},{0.691731,-0.070052,0.636548,0.464838}},{{0.532747,-1.436236,-0.900262,-0.697533},{0.566295,0.650852,0.871414,-0.566183},{-0.075736,-0.886402,0.245348,-0.438080},{-0.811976,0.022233,-0.685647,0.323351}},{{-1.864578,1.141054,1.636157,-0.455965},{0.592333,0.890900,-0.259255,0.702826},{0.404528,0.905776,0.917764,0.051214},{0.761990,0.766907,-0.595618,-0.558207}}},{{{0.209262,-1.126957,-0.517694,-0.875215},{0.264791,0.338225,0.551586,0.505277},{0.183185,0.782227,0.888956,0.687343},{0.271838,0.125254,1.071891,-0.849511}},{{0.261293,-0.445399,0.170976,-0.401571},{0.801811,0.045041,-0.990778,-0.013705},{-0.343000,-0.913162,0.840992,0.551525},{-0.526818,-0.231089,0.085968,0.861459}},{{0.540677,-0.844281,-0.888770,0.438555},{0.802355,-0.825937,0.472974,-0.719263},{-0.648519,1.281454,0.470129,-0.538160},{-0.851015,0.985721,-0.993719,0.558735}},{{1.164560,-0.302101,0.953803,0.277318},{0.886169,0.623929,1.274299,-0.559466},{-0.948670,0.807814,-1.586962,-0.502652},{-0.069760,1.387864,-0.423140,0.285045}}}},
    {{{{0.747424,-0.044005,0.402212,-0.027484},{0.785297,0.169685,0.734339,-0.984272},{-0.656865,-1.397558,0.935961,-0.490159},{-0.099856,-0.293917,0.129296,-0.920536}},{{0.546529,-0.488280,-0.516120,-1.112775},{0.155881,-0.103160,0.187689,0.485805},{0.918357,0.829929,0.619437,0.877277},{0.389621,0.360045,0.434281,0.456462}},{{-0.803458,-0.525248,-0.467349,0.714159},{-0.648302,-0.005998,-0.812863,0.205664},{0.591453,0.653762,-0.227193,-0.946375},{0.080461,0.311794,0.802115,-1.115836}},{{-0.495051,-0.869153,-0.179932,0.925227},{-1.950445,1.908723,-0.378323,-0.472620},{-0.688403,-1.470251,1.991375,-1.698926},{-0.955808,-0.260230,0.319449,-1.368107}}},{{{-0.029073,-0.622921,-1.095426,-0.764465},{-0.362713,-0.123863,0.234856,-0.772613},{0.697097,0.103340,0.831709,0.529785},{0.103735,-0.526333,-0.084778,0.696831}},{{-0.670775,0.289993,-0.082204,-1.489529},{0.336070,0.322759,0.613241,0.743160},{0.298744,-1.193191,0.848769,-0.736213},{0.472611,-0.830342,0.437290,-0.467557}},{{-0.529196,-0.245683,0.809606,-0.956047},{-1.725613,0.187572,0.528054,-0.996271},{-0.330207,0.206237,0.218373,0.187079},{0.243388,0.625787,-0.388859,0.439888}},{{-0.802928,-0.811282,0.788538,0.948829},{0.966371,1.316717,0.004928,0.832735},{-0.226313,0.364653,0.724902,-0.579910},{-0.544782,-0.143865,0.069256,-0.020610}}},{{{-0.393249,0.671239,-0.481891,0.861149},{-0.662027,-0.693554,-0.564079,-0.477654},{0.070920,-0.052125,-0.059709,0.473953},{-0.280146,-0.418355,0.703337,0.981932}},{{-0.676855,0.102765,-0.832902,-0.590961},{1.717802,0.516057,-0.625379,-0.743204},{-0.170791,-0.813844,-0.269250,0.707447},{0.057623,0.472053,-0.211435,0.147894}},{{-0.298217,0.577550,1.845773,0.876933},{0.617987,0.502801,0.951405,0.122180},{0.924724,-0.166798,0.632685,-0.466165},{-0.834315,-0.864180,-0.274019,0.568493}},{{0.669850,-0.961671,0.790462,0.738113},{-0.534215,-0.556158,0.653896,0.031419},{0.065819,0.220394,0.153365,-0.373006},{0.886610,-0.742343,1.282099,0.198137}}},{{{0.092579,-0.026559,-1.121547,0.143613},{-0.289030,0.265226,-0.350741,-0.897469},{-0.918046,0.038521,-1.515900,0.488701},{-0.759326,-1.782885,-1.787784,0.249131}},{{-0.849816,-0.857074,-0.843467,-0.153686},{0.998653,0.356216,0.926775,0.300663},{-0.749890,-0.003425,-0.607109,0.317334},{-0.561644,0.446478,-0.898901,0.711265}},{{0.232020,-0.445016,0.618918,0.162098},{0.381030,-0.036170,0.084177,0.766972},{0.493139,0.189652,-0.511946,-0.273525},{0.863772,-0.586968,0.829531,-0.075552}},{{0.191787,-0.627198,0.975013,-0.448483},{-0.197885,0.151927,-0.558646,-1.308541},{-0.582967,1.207841,0.746132,0.245631},{0.314827,-0.702463,-0.301494,0.787569}}}},
    {{{{0.670028,-1.825749,-0.739187,0.482428},{0.175521,-0.020120,-0.154805,0.187004},{0.971728,-0.160181,-0.164031,-0.868147},{-0.954732,-0.175713,0.791116,0.294173}},{{-0.958337,-0.843157,-0.472882,0.273517},{-0.999058,0.824762,-0.223130,-0.150628},{0.393747,-0.301297,0.095572,-0.798950},{-0.119787,0.746673,0.955094,0.259353}},{{0.951590,0.225539,0.503282,0.668746},{-0.384898,-0.979592,-0.005485,-0.191883},{-0.692369,-0.642401,-0.825598,0.171933},{-0.321919,-0.498635,0.449704,0.780842}},{{-0.387902,0.522435,0.565608,0.166193},{-0.799671,-0.295871,-0.702573,-0.151006},{0.040550,-0.468503,0.651076,0.636352},{-0.839299,-0.090651,0.428761,0.187043}}},{{{-0.369823,0.377011,0.422936,0.284752},{-0.181514,-0.701449,0.748768,0.540533},{0.734381,0.149410,-0.867043,-0.397142},{-0.770904,-0.581897,-1.578306,-0.402638}},{{0.859015,-0.540358,0.202715,-0.975354},{-0.773629,-0.382342,-0.022498,-0.129286},{-0.901210,-0.641866,1.219216,0.731525},{0.740457,0.858546,-0.408661,-0.364897}},{{-0.830865,-1.370657,-1.226303,-0.392147},{-0.810554,-0.975232,-0.717845,-0.825379},{-0.150096,-0.664533,0.347084,0.243443},{-0.447383,0.842164,1.491342,0.380295}},{{-0.383958,0.811219,0.160459,0.841601},{1.631515,0.371637,0.110000,0.467783},{-0.689356,-0.004289,-0.081057,-0.317243},{0.092451,-0.181268,-0.575747,-0.580061}}},{{{0.908549,-0.013975,-0.880165,-0.938937},{-0.225713,0.449478,0.372569,-0.229889},{0.255711,-0.264752,0.307982,0.260505},{0.314966,-0.540905,0.743032,-0.078475}},{{-0.307472,-1.268296,0.020383,1.798401},{-0.150954,0.909716,-0.407903,0.379046},{0.621853,-0.003629,-0.582697,0.614618},{-0.122843,-0.627133,-0.217968,0.608322}},{{0.071923,0.807315,0.538905,-0.630660},{0.495641,0.240202,-0.920822,-0.258533},{-1.760363,-0.448525,-0.351553,-0.551666},{0.152720,0.900531,0.061966,-0.544377}},{{0.648923,0.450945,-1.530020,1.570190},{0.536210,0.078454,0.577168,0.464872},{-0.888258,-0.950748,0.781474,0.958593},{0.463631,0.319614,-0.248374,-0.413144}}},{{{0.293463,0.236284,1.721511,0.107408},{-0.790508,-0.072027,-0.559467,-0.955839},{-0.777662,-0.169876,0.896220,0.776105},{0.003944,-0.745496,-0.236446,-0.824604}},{{-1.770746,-0.051266,-0.174258,0.003074},{-0.339553,-0.868807,-0.032754,-0.494847},{-0.896712,0.957339,-0.003444,-1.582125},{-0.699883,0.626691,0.799635,-0.542343}},{{-0.635123,-0.755960,0.576373,-0.899530},{-0.393745,0.718900,0.312400,0.511415},{-0.647565,0.368431,0.214726,0.892693},{-0.511960,-0.513262,0.885908,-0.536478}},{{-0.590074,0.623328,0.268674,-0.401391},{0.308868,-0.869862,0.233132,0.243337},{-0.242908,-0.557192,-0.728454,0.867029},{0.156435,-0.805308,-0.815392,-1.437798}}}},
    {{{{0.613484,1.454566,-0.363858,0.634053},{0.535096,-0.641079,-0.607553,0.852559},{0.959100,-0.398621,0.375819,0.385756},{-0.601982,0.494128,0.809699,0.608804}},{{-1.390871,-0.943062,1.556671,0.966501},{-0.013242,0.152716,-0.089592,0.230793},{0.933785,0.119358,0.057387,0.502033},{-0.332925,0.537509,-0.081436,-0.701995}},{{-0.435117,0.996885,0.646630,-0.092342},{0.004343,-0.737514,-0.716187,-0.946819},{0.814258,-0.766971,-0.488162,-0.531619},{-0.923069,0.683915,-0.023809,-1.242992}},{{-0.909155,-0.166488,-0.159273,-0.908121},{-0.783871,-0.522598,0.691845,-0.164065},{1.255966,0.051373,-0.566025,0.820081},{0.186583,0.266032,-0.793747,-0.510092}}},{{{0.890639,0.970042,-0.507885,-0.029557},{-0.771142,-0.875802,0.400070,-1.264247},{-0.881146,0.570950,-0.051624,0.347612},{0.312110,-0.374885,0.600112,0.388460}},{{-0.417107,-0.309284,-0.128477,0.689671},{-0.695866,1.254585,-0.381883,-0.313415},{0.433565,0.919626,0.159180,-0.657310},{-1.396139,0.346053,0.108768,0.061238}},{{-0.776695,0.084491,0.045357,0.312823},{-0.379268,1.217006,-0.014838,-1.032272},{-1.251344,-0.366283,-0.124786,0.729754},{0.979936,0.669519,-0.900018,-0.596954}},{{-0.998834,0.593942,0.375639,-0.627459},{0.297281,0.400240,0.839707,0.960262},{-0.872143,0.574040,-0.559580,-1.965570},{-0.559218,-0.778780,-0.955526,-0.253380}}},{{{-1.919625,-1.911049,0.025035,0.754917},{-0.110993,0.535933,-0.572788,-0.856476},{-0.810836,-0.496261,1.128368,1.758826},{-0.564368,-1.849772,-0.251560,0.635528}},{{0.768196,-0.934122,0.207228,0.884610},{-0.356145,0.265792,-0.835582,0.377675},{-0.410745,0.613212,0.245560,-0.873826},{1.725191,-0.263344,-0.077167,-0.976379}},{{-0.736299,-0.109476,0.044512,-0.004005},{0.692230,0.316670,0.267247,-1.076821},{-0.903184,0.189762,-0.674111,0.219113},{0.639162,1.347521,0.428823,-0.765664}},{{-0.509165,0.458806,-0.851011,0.455027},{-0.218564,-0.063492,0.889320,-0.762062},{0.145950,0.985037,-0.489372,-0.879851},{0.352346,-0.127275,0.896496,-0.596037}}},{{{0.402678,1.479855,0.089187,0.967153},{-0.431225,0.402980,0.883584,-0.900324},{0.262233,-0.647278,0.637005,0.142678},{-0.003253,-0.671924,0.969458,-0.316752}},{{0.345185,-0.477503,-0.326822,-0.106251},{0.239521,1.617125,0.632651,0.969976},{-1.015183,-0.676629,0.955842,0.134925},{-0.319063,-0.493157,-0.488088,0.713008}},{{-0.468621,1.301292,-1.826501,1.138666},{0.170247,-0.661171,0.895204,-0.400700},{-0.077645,-0.978179,-0.245724,0.245282},{-0.258300,0.287261,-0.006274,0.549716}},{{-0.932247,-0.274950,0.920451,0.016237},{0.888865,-0.845248,1.661716,-0.108960},{0.712357,0.586609,-0.867356,0.355058},{-0.540912,0.892622,0.302627,0.247194}}}},
    {{{{0.817578,0.719047,0.438903,0.637398},{0.750466,-0.911799,-0.609606,0.358541},{-1.782979,-0.851717,-0.802122,0.735913},{0.490604,-0.417822,-0.332074,0.836756}},{{-0.650232,-0.442026,0.874916,0.705671},{0.217602,-0.755841,0.573944,0.279365},{-0.713729,0.358880,-0.308992,0.778297},{0.832099,-0.916695,-0.887834,1.041483}},{{1.019467,1.099488,-0.130674,-0.241995},{0.792572,0.756977,0.518186,0.070411},{-0.815779,-0.790757,-1.027439,-0.163698},{0.721461,-0.403364,0.656609,-0.367364}},{{-0.279333,-0.742041,0.515832,-0.408114},{0.834577,0.736056,0.900594,0.276357},{0.726000,0.464991,-0.569281,0.098139},{-0.582324,0.875666,-0.681556,-0.903009}}},{{{1.300969,-0.798351,0.107230,1.611284},{0.239211,0.418231,-0.795764,-0.398818},{-0.939666,1.768175,-0.297023,-0.064087},{-0.239119,-0.365132,0.864138,0.595560}},{{1.898313,-0.343816,1.066256,0.876655},{-0.053636,0.544756,-0.937927,0.189233},{0.445371,-0.656790,-0.675091,0.753163},{-0.293330,-0.002717,0.341173,0.095493}},{{0.951658,0.513912,-0.678347,-0.981140},{-0.020791,0.571138,-0.890648,0.881789},{-1.783345,0.909598,-0.393155,0.240630},{-0.057908,-0.237435,-0.124993,-0.754091}},{{-0.014153,0.127172,0.097134,0.538952},{0.167943,0.786395,0.946153,-0.762513},{-0.562758,0.675657,-0.226395,0.979761},{0.850214,0.818309,0.397074,-0.372059}}},{{{0.803316,-0.659538,-1.987864,-0.186366},{-0.259213,0.315848,-0.427898,0.326521},{-0.168181,-0.620898,0.562309,0.722064},{-1.949690,0.307720,-0.147760,0.603492}},{{0.898339,0.986228,0.724530,0.105193},{0.066046,0.037689,-0.553543,0.597864},{0.296553,0.165199,0.500125,-0.395978},{0.790120,-1.873361,0.354841,-0.187812}},{{-0.559746,0.357012,0.373903,-0.113564},{-0.671918,-0.919720,0.258328,-0.283453},{0.008365,0.597272,0.355827,0.391287},{0.355297,-0.631888,0.221383,1.448221}},{{0.259199,-0.491776,0.721151,0.391427},{0.494000,0.652814,-0.153306,-0.615687},{0.142167,-0.601161,0.281702,0.563390},{0.904019,1.284241,0.901663,0.244620}}},{{{-0.664638,-0.564596,0.839897,0.153358},{-0.506883,0.822337,-0.974957,-0.098112},{-0.962870,-0.274566,0.418039,-0.020525},{-0.965969,0.954587,-0.250493,-0.031592}},{{-0.966475,0.455338,0.868491,0.723032},{-0.002141,0.021922,-0.131429,-0.601106},{-1.240003,1.483318,1.612920,-0.653210},{-0.505979,0.005588,-0.087506,-0.705789}},{{-0.203137,0.765652,-0.132974,-0.900534},{0.731132,0.133467,-1.086363,0.600763},{1.795911,-0.411613,-1.990494,0.405937},{0.729332,-0.119175,-0.979213,0.362346}},{{-0.049014,0.228577,-1.728796,-0.898348},{-0.540969,1.245881,-0.820859,0.285859},{0.430751,-0.373652,0.034535,0.434466},{0.365354,0.243261,0.910114,1.497873}}}}
};
float eval_polynomial(float variables[4],int program_index,int variable_index,int indices[4]){
    if(variable_index==4)return program[program_index][indices[0]][indices[1]][indices[2]][indices[3]];
    float result=0,base=1;
    for(int power=0;power<4;++power){
        indices[variable_index]=power;
        result+=base*eval_polynomial(variables,program_index,variable_index+1,indices);
        base*=variables[variable_index];
    }
    return result;
}
int main(int argc,char *argv[]){
    srand(tick_count());
    rand();
    float variables[4],probability[5],total=0;
    int i,indices[4],temp;
    for(i=0;i<4;++i){
        sscanf(argv[i-4+argc],"%d",&temp);
        variables[i]=temp;
    }
    temp=variables[1];
    variables[1]=variables[2];
    variables[2]=temp;
    if(variables[1]==0){ //bow if our honour is 0
        putchar('B');
        return 0;
    }

    variables[0]/=20;variables[2]/=20;
    variables[1]=1/(variables[1]+1);variables[3]=1/(variables[3]+1);
    for(i=0;i<5;++i){
        probability[i]=eval_polynomial(variables,i,0,indices);
        if(probability[i]<0)probability[i]=0;
        total+=probability[i];
        probability[i]=total;
    }
    total*=(float)rand()/RAND_MAX;
    for(i=0;i<5;++i)if(total<probability[i]){
        putchar("BGIPO"[i]);
        return 0;
    }
    putchar('B');
    return 0;
}

[1] Completely irrelevant number [2] Guaranteed to be true 1% of the time


YAGMCSE

Monte Carlo methods seem to exhibit decent play, so here's Yet Another Generic Monte Carlo Simulation Entry!

Unlike most of the other entries in this contest, this entry uses a large number of simulations of random games, and thus requires the use of the -O3 flag for optimal performance.

Compile the program with the command: gcc monte.c -o monte -O3 -std=c99

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

#ifdef _WIN32
#include <Windows.h>
unsigned int tick_count(){
    return GetTickCount();
}
#else
#include <sys/time.h>
unsigned int tick_count(){
    struct timeval t;
    gettimeofday(&t, NULL);
    return 1000 * t.tv_sec + t.tv_usec / 1000;
}
#endif

const int turn_limit=500;
enum Move{
    WAIT,BOW,GUARD,QUICK,PARRY,OVERHEAD
};
struct Player{
    int health,honour;
    enum Move lastMove;
};
typedef struct Player Player;
//<command> <history> <enemy_history> <your_health> <enemy_health> <your_honour> <enemy_honour>
//<command> <your_health> <enemy_health> <your_honour> <enemy_honour>
int damage_table[6][6][2]={
    {{0,0},{0,0},{0,0},{1,0},{1,0},{1,0}}, //P1 is waiting
    {{0,0},{0,0},{0,0},{1,0},{1,0},{1,0}}, //P1 is bowing
    {{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}}, //P1 is guarding
    {{0,1},{0,1},{0,0},{0,0},{1,0},{0,1}}, //P1 is using quick draw
    {{0,1},{0,1},{0,0},{0,1},{0,0},{1,0}}, //P1 is parrying
    {{0,1},{0,1},{0,0},{1,0},{0,1},{0,0}} //P1 is using overhead attack
};
enum Move decode_move(char x){
    switch(x){
        case 'W': return WAIT; break;
        case 'B': return BOW; break;
        case 'G': return GUARD; break;
        case 'I': return QUICK; break;
        case 'P': return PARRY; break;
        case 'O': return OVERHEAD; break;
    }
    return WAIT;
}
struct SimulationStat{
    enum Move first_me_move;
    int win,draw,lose,compound;
};
int stat_compare(const void*a,const void*b){
    return ((struct SimulationStat*)b)->compound-((struct SimulationStat*)a)->compound;
}
struct SimulationStat monte_carlo(int num_iters,enum Move first_me_move,Player original_me,Player original_opponent){
    struct SimulationStat simulation_result={first_me_move,0,0,0};

    for(int iter=0;iter<num_iters;++iter){
    Player me=original_me,opponent=original_opponent;
        int turn,game_result;
        for(turn=0;turn<turn_limit;++turn){
            enum Move me_move,opponent_move=rand()%(OVERHEAD-BOW+1)+BOW;
            if(turn==0)me_move=first_me_move;
            else me_move=rand()%(OVERHEAD-BOW+1)+BOW;

            //update honour for guarding
            if(me.lastMove==GUARD&&me_move==GUARD)--me.honour;
            if(opponent.lastMove==GUARD&&opponent_move==GUARD)--opponent.honour;

            int me_attacking=me_move==QUICK||me_move==PARRY||me_move==OVERHEAD,opponent_attacking=opponent_move==QUICK||opponent_move==PARRY||opponent_move==OVERHEAD;

            //update health of players
            me.health-=damage_table[me_move][opponent_move][0]*(1+(opponent.honour>=7));
            opponent.health-=damage_table[me_move][opponent_move][1]*(1+(me.honour>=7));

            //update honour for attacking (Sword of the Gods is revoked after the player attacks with an original honour value of 7)
            if(me_attacking)--me.honour;
            if(opponent_attacking)--opponent.honour;

            //printf("%d %d\n",me.health,me.honour);
            //printf("%d %d\n",opponent.health,opponent.honour);

            //check if any of the terminating conditions are met
            //c. both players fall off the graces of the gods (me.honour<0&&opponent.honour<0)
            if(me.honour<0&&opponent.honour<0){
                game_result=0; //draw
                break;
            }
            //a. player 1 falls off the graces of the gods (me.honour<0)
            else if(me.honour<0){
                game_result=-1; //loss
                break;
            }
            //b. player 2 falls off the graces of the gods (opponent.honour<0)
            else if(opponent.honour<0){
                game_result=1; //win
                break;
            }
            //d. both players are dead (me.health<0&&opponent.health<0)
            else if(me.health<0&&opponent.health<0){
                game_result=0; //draw
                break;
            }
            //e. player 1 is dead (me.health<0)
            else if(me.health<0){
                game_result=-1; //loss
                break;
            }
            //f. player 2 is dead (opponent.health<0)
            else if(opponent.health<0){
                game_result=1; //win
                break;
            }
        }
        //both players get struck down by the guards for being boring
        if(turn==turn_limit)game_result=0; //draw

        if(game_result==1)++simulation_result.win;
        else if(game_result==0)++simulation_result.draw;
        else ++simulation_result.lose;
    }
    return simulation_result;
}
int main(int argc,char*argv[]){
    //const int num_iters=200000,num_shortlist_iters=1000000;
    const int num_iters=20000,num_shortlist_iters=55000;

    srand(tick_count());
    Player me,opponent;
    if(argc==5){
        sscanf(argv[1],"%d",&me.health);
        sscanf(argv[2],"%d",&opponent.health);
        sscanf(argv[3],"%d",&me.honour);
        sscanf(argv[4],"%d",&opponent.honour);
        me.lastMove=WAIT;
        opponent.lastMove=WAIT;
    }else{
        sscanf(argv[3],"%d",&me.health);
        sscanf(argv[4],"%d",&opponent.health);
        sscanf(argv[5],"%d",&me.honour);
        sscanf(argv[6],"%d",&opponent.honour);
        me.lastMove=decode_move(argv[1][strlen(argv[1])-1]);
        opponent.lastMove=decode_move(argv[2][strlen(argv[2])-1]);
    }

    struct SimulationStat results[6];
    results[0].first_me_move=WAIT;
    results[0].win=0;
    results[0].draw=0;
    results[0].lose=num_iters;
    results[0].compound=-num_iters*2-1000; //waiting is worse than any other action

    for(enum Move first_me_move=BOW;first_me_move<=OVERHEAD;++first_me_move){
        results[first_me_move]=monte_carlo(num_iters,first_me_move,me,opponent);
        struct SimulationStat *cur=&results[first_me_move];
        cur->compound=cur->win*4+cur->draw*1-cur->lose*2;
    }
    qsort(results,OVERHEAD-WAIT+1,sizeof(*results),stat_compare);

    for(int i=0;i<OVERHEAD-BOW+1;++i){
        struct SimulationStat *cur=&results[i];
//        fprintf(stderr,"%c: %f%% win, %f%% draw, %f%% lose => %d\n","WBGIPO"[cur->first_me_move],(double)cur->win/num_iters*100.,(double)cur->draw/num_iters*100.,(double)cur->lose/num_iters*100.,cur->compound);
    }

    for(int i=0;i<2;++i){
        results[i]=monte_carlo(num_shortlist_iters,results[i].first_me_move,me,opponent);
        struct SimulationStat *cur=&results[i];
        cur->compound=cur->win*2+cur->draw*1;
    }
    qsort(results,2,sizeof(*results),stat_compare); 

    for(int i=0;i<2;++i){
        struct SimulationStat *cur=&results[i];
//        fprintf(stderr,"%c: %f%% win, %f%% draw, %f%% lose => %d\n","WBGIPO"[cur->first_me_move],(double)cur->win/num_shortlist_iters*100.,(double)cur->draw/num_shortlist_iters*100.,(double)cur->lose/num_shortlist_iters*100.,cur->compound);
    }
    putchar("WBGIPO"[results[0].first_me_move]);
    return 0;
}
\$\endgroup\$
  • 1
    \$\begingroup\$ He only seems to bow for whatever reason. You might want to give it a look \$\endgroup\$ – C5H8NNaO4 Jun 28 '15 at 15:46
  • \$\begingroup\$ @C5H8NNaO4 Thank you for notifying me about this serious bug. My edit should fix the bug. \$\endgroup\$ – Potatomato Jun 29 '15 at 7:34
  • \$\begingroup\$ YAGMCSE seems to do only either GBWWWWW... or BWWWW \$\endgroup\$ – C5H8NNaO4 Jul 1 '15 at 10:38
  • \$\begingroup\$ @C5H8NNaO4 That is strange. I am not able to replicate the results you have mentioned. Was the opponent of YAGMCSE perpetually bowing/guarding/waiting? \$\endgroup\$ – Potatomato Jul 1 '15 at 12:00
  • \$\begingroup\$ Yes, he was bowing the first 7 rounds. Here's a pastebin \$\endgroup\$ – C5H8NNaO4 Jul 1 '15 at 12:11
1
\$\begingroup\$

After my failed attempt to enter Target Dummy, I present to you my next bot...

ScroogeBot - Python 2

This bot will bow if he has one honor. Otherwise he will flip a coin.

If it lands on heads, he will perform a random attack. If it lands on tails, he will either bow or guard.

Command: python scroogebot.py

import random, sys
# If he has more than one honor...
if int(sys.argv[5]) > 1:
    #Flip a coin.
    coin = random.choice(['heads','tails'])
    #If the coin lands on heads...
    if coin == 'heads':
        #Attack!
        print random.choice(['I','O','P'])
    #If the coin lands on tails...
    else:
        #Don't attack!
        print random.choice(['G','B'])
#If he has 1 honor...
else:
    #Bow!
    print "B"
\$\endgroup\$
  • \$\begingroup\$ Yay, a new entry! Just a quick heads up -- it might be a while before I can get a new tournament set up, since I reimaged my operating system yesterday. I should have a new tournament done with your results in by the end of the week though. \$\endgroup\$ – absinthe Oct 9 '15 at 10:15
0
\$\begingroup\$

Yoshimitsu (JS)

Tries to not get guarded by checking the last two moves, will get bravery with higher honor. based off the template apsillers made

var attacks = ['I','P','O'];
var pasive = ['B','W'];
var argv = process.argv;
var playerHistory = argv.length>6?argv[2].split(''):[];
var enemyHistory = argv.length>6?argv[3].split(''):[];
var offset = 8 - argv.length;
var my = { health:+argv[4-offset], honor:+argv[6-offset], history:playerHistory };
var enemy = { health:+argv[5-offset], honor:+argv[7-offset], history:enemyHistory };
my.godSword = my.honor >= 7;
enemy.godSword = enemy.honor >= 7;

enemy.lastMove = enemyHistory.pop();
enemy.secondToLast = enemyHistory.pop();

enemy.didAttack = !!attacks.indexOf(enemy.lastMove);

my.lastMove = playerHistory.pop();

function decide() {
    process.stdout.write(arguments[Math.floor(arguments.length*Math.random())]);
    process.exit();
}

chooseAnAttack = function(){ decide.apply(this,attacks); };

if( ( pasive.indexOf( enemy.lastMove ) && my.honor < 15 ) || (my.honor < 7 && enemy.health > 10) || my.honor === 1 ){
    if( Math.random * 15 < my.honor ){
        chooseAnAttack();
    } else {
        decide('B');
    }
} else if( enemy.honor < 2 ){
    chooseAnAttack();
} else if( enemy.didAttack ){

    if( attacks.indexOf( enemy.secondToLast ) ){
        decide('G');
    } else if( pasive.indexOf( enemy.secondToLast ) ){
        chooseAnAttack();
    } else if( enemy.secondToLast == 'G' ){
        decide('B');
    }

} else if( enemy.lastMove = 'G' ) {
    chooseAnAttack();
} else if( enemy.lastMove === 'W' ){
    if( attacks.indexOf( enemy.secondToLast ) ){
        decide('G');
    } else if( pasive.indexOf( enemy.secondToLast ) ){
        chooseAnAttack();
    } else if( enemy.secondToLast == 'G' ){
        decide('B');
    }
}
\$\endgroup\$
0
\$\begingroup\$

The Fool (C)

The Fool implores a rather erratic strategy, never repeating the same move twice unless forced to through lack of honour. His movements are largely based on randomness, making it hard to predict his actions. His well-being is the last thing on his mind, as his thoughts are set only upon bloodshed and ultimate victory

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

const char commands[] =
{
    'W', 'B', 'G', 'I', 'P', 'O'
};

char select_candidate(const char c[])
{
    unsigned i = 0;
    int n_candidates = 0;
    char candidates[sizeof(commands)];

    for (; i < sizeof(commands); i++)
        if (c[i])
            candidates[n_candidates++] = c[i];

    /* There are no candidates for actions, so the fool blindly attacks his opponent, hoping for the best */
    return n_candidates == 0 ? 'I' : candidates[rand() % n_candidates];
}

int main(int argc, char *argv[])
{
    unsigned i = 0;
    int honour;
    char candidates[sizeof(commands)];
    char last_action;

    srand(time(NULL));

    memcpy(candidates, commands, sizeof(commands));

    /* It's the first round, the fool selects a random action except for waiting */
    if (argc != 7)
    {
        candidates[0] = 0;
        putchar(select_candidate(candidates));
        return 0;
    }

    last_action = argv[1][strlen(argv[1]) - 1];
    honour = atoi(argv[5]);

    if (honour == 0)
    {
        /* The fool realises he will meet his doom if he performs any of the following moves */
        /* and removes them from his list of possible actions */
        candidates[3] = 0;
        candidates[4] = 0;
        candidates[5] = 0;

        /* Only omit the blocking action if the last action was blocking */
        if (last_action == 'G')
            candidates[2] = 0;
    } else if (honour >= 7) {

        /* If the fool has the opportunity to abuse power, he will */
        candidates[0] = 0;
        candidates[1] = 0;
    }

    /* However unintellegent, the fool decides never to repeat the same move twice */
    for (; i < sizeof(commands); i++)
    {
        if (candidates[i] == last_action)
        candidates[i] = 0;
    }

    /* The fool randomly selects a possible action and hopes for the best */
    putchar(select_candidate(candidates));

    return 0;
}


The Prophet (C)

The Prophet uses the knowledge of his opponent's previous 2 moves in order to make a predict his next move and provides a swift and deadly counter-attack. Also, he does astrology and stuff.

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

int main(int argc, char* argv[])
{
    char* hist;
    char* enemy_hist;
    int hist_len;
    int enemy_hist_len;
    int health;
    int enemy_health;
    int honour;
    int enemy_honour;

    if (argc != 7)
    {
        /* Always start with guarding */
        putchar('G');
        return 0;
    }

    srand(time(NULL));

    /* Grab the command-line values */
    hist         = argv[1];
    enemy_hist   = argv[2];
    health       = atoi(argv[3]);
    enemy_health = atoi(argv[4]);
    honour       = atoi(argv[5]);
    enemy_honour = atoi(argv[6]);

    hist_len = strlen(hist);
    enemy_hist_len = strlen(enemy_hist);

    /* Looks like the enemy is starving for honour. */
    /* This means that they have to bow, so attack them,  */
    /* But only if we have the honour to do so. */
    if (enemy_honour == 0 && honour > 0)
    {
        putchar('O');
        return 0;
    } else if (honour == 0) {
        /* We have to bow */
        putchar('B');
        return 0;
    } else if (honour <= 3) {
        /* We have low honour, attack if the enemy has no honour, otherwise bow to restore some of our honour */
        putchar(enemy_honour == 0 ? ((rand() % 2) ? 'I' : 'O') : 'B');
        return 0;
    }

    switch (enemy_hist[enemy_hist_len - 1])
    {
        /* The enemy has previously performed a passive action, so they will likely attack this round */
        case 'W':
        case 'B':
        case 'G':
            putchar(hist[hist_len - 1] == 'G' ? 'P' : 'G'); /* Protect ourselves, using `guard` if we did not use it last turn */
            return 0;

        default:
            if (enemy_hist_len >= 2)
            {
                switch (enemy_hist[enemy_hist_len - 2])
                {
                    case 'I':
                    case 'P':
                    case 'O':
                        /* The enemy has attacked for the last 2 turns, they will likely rest now */
                        putchar((rand() % 2) ? 'I' : 'O');
                        return 0;

                    default:
                        /* Low health, block an incoming attack */
                        if (health <= 5)
                        {
                            putchar(hist[hist_len - 1] == 'G' ? 'P' : 'G');
                            return 0;
                        } else {
                            /* Choose randomly to bow or attack */
                            int decision = rand() % 3;
                            putchar(decision == 2 ? 'B' : decision == 1 ? 'I' : 'O');
                            return 0;
                        }
                }
            } else {
                /* Attack! */
                putchar((rand() % 2) ? 'I' : 'O');
                return 0;
            }
    }

    /* If somehow we get to this point, parry */
    putchar('P');
    return 0;
}


Compilation

Both programs are written in C, and can be compiled with gcc:

gcc fool.c -o fool
gcc prophet.c -o prophet


Running

*nix

./fool <args>
./prophet <args>

Windows

fool.exe <args>
prophet.exe <args>
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.