# Question
Title: The Rock, Paper, Scissors, Lizard, Spock Tournament of Epicness
# Most Recent Leaderboard @ 2014-08-02 12:00

```
| Pos # | Author               | Name                    | Language   | Score | Win   | Draw  | Loss  | Avg. Dec. Time |
+-------+----------------------+-------------------------+------------+-------+-------+-------+-------+----------------+
| 1st   | Emil                 | Pony                    | Python2    | 064   | 064   | 000   | 005   | 0026.87 ms     |
| 2nd   | Roy van Rijn         | Gazzr                   | Java       | 062   | 062   | 001   | 006   | 0067.30 ms     |
| 2nd   | Emil                 | Dienstag                | Python2    | 062   | 062   | 001   | 006   | 0022.19 ms     |
| 4th   | ovenror              | TobiasFuenke            | Python2    | 061   | 061   | 001   | 007   | 0026.89 ms     |
| 5th   | PhiNotPi             | BayesianBot             | Perl       | 060   | 060   | 000   | 009   | 0009.27 ms     |
| 6th   | Claudiu              | SuperMarkov             | Python2    | 058   | 058   | 001   | 010   | 0026.77 ms     |
| 7th   | histocrat            | Alternator              | Ruby       | 057   | 057   | 001   | 011   | 0038.53 ms     |
| 8th   | histocrat            | LeonardShelby           | Ruby       | 053   | 053   | 000   | 016   | 0038.55 ms     |
| 9th   | Stretch Maniac       | SmarterBot              | Java       | 051   | 051   | 002   | 016   | 0070.02 ms     |
| 9th   | Martin Büttner       | Markov                  | Ruby       | 051   | 051   | 003   | 015   | 0038.45 ms     |
| 11th  | histocrat            | BartBot                 | Ruby       | 049   | 049   | 001   | 019   | 0038.54 ms     |
| 11th  | kaine                | ExcitingishBot          | Java       | 049   | 049   | 001   | 019   | 0065.87 ms     |
| 13th  | Thaylon              | UniformBot              | Ruby       | 047   | 047   | 001   | 021   | 0038.61 ms     |
| 14th  | Carlos Martinez      | EasyGame                | Java       | 046   | 046   | 002   | 021   | 0066.44 ms     |
| 15th  | Stretch Maniac       | SmartBot                | Java       | 045   | 045   | 001   | 023   | 0068.65 ms     |
| 16th  | Docopoper            | RoboticOboeBotOboeTuner | Python2    | 044   | 044   | 000   | 025   | 0156.55 ms     |
| 17th  | Qwix                 | Analyst                 | Java       | 043   | 043   | 001   | 025   | 0069.06 ms     |
| 18th  | histocrat            | Analogizer              | Ruby       | 042   | 042   | 000   | 027   | 0038.58 ms     |
| 18th  | Thaylon              | Naan                    | Ruby       | 042   | 042   | 004   | 023   | 0038.48 ms     |
| 20th  | Thaylon              | NitPicker               | Ruby       | 041   | 041   | 000   | 028   | 0046.21 ms     |
| 20th  | bitpwner             | AlgorithmBot            | Python2    | 041   | 041   | 001   | 027   | 0025.34 ms     |
| 22nd  | histocrat            | WereVulcan              | Ruby       | 040   | 040   | 003   | 026   | 0038.41 ms     |
| 22nd  | Ourous               | QQ                      | Cobra      | 040   | 040   | 003   | 026   | 0089.33 ms     |
| 24th  | Stranjyr             | RelaxedBot              | Python2    | 039   | 039   | 001   | 029   | 0025.40 ms     |
| 25th  | JoshDM               | SelfLoathingBot         | Java       | 038   | 038   | 001   | 030   | 0068.75 ms     |
| 25th  | Ourous               | Q                       | Cobra      | 038   | 038   | 001   | 030   | 0094.04 ms     |
| 25th  | Ourous               | DejaQ                   | Cobra      | 038   | 038   | 001   | 030   | 0078.31 ms     |
| 28th  | Luis Mars            | Botzinga                | Java       | 037   | 037   | 002   | 030   | 0066.36 ms     |
| 29th  | kaine                | BoringBot               | Java       | 035   | 035   | 000   | 034   | 0066.16 ms     |
| 29th  | Docopoper            | OboeBeater              | Python2    | 035   | 035   | 002   | 032   | 0021.92 ms     |
| 29th  | Thaylon              | NaanViolence            | Ruby       | 035   | 035   | 003   | 031   | 0038.46 ms     |
| 32nd  | Martin Büttner       | SlowLizard              | Ruby       | 034   | 034   | 004   | 031   | 0038.32 ms     |
| 33rd  | Kyle Kanos           | ViolentBot              | Python3    | 033   | 033   | 001   | 035   | 0032.42 ms     |
| 34th  | HuddleWolf           | HuddleWolfTheConqueror  | .NET       | 032   | 032   | 001   | 036   | 0029.86 ms     |
| 34th  | Milo                 | DogeBotv2               | Java       | 032   | 032   | 000   | 037   | 0066.74 ms     |
| 34th  | Timmy                | DynamicBot              | Python3    | 032   | 032   | 001   | 036   | 0036.81 ms     |
| 34th  | mccannf              | YAARBot                 | JS         | 032   | 032   | 002   | 035   | 0100.12 ms     |
| 38th  | Stranjyr             | ToddlerProof            | Java       | 031   | 031   | 010   | 028   | 0066.10 ms     |
| 38th  | NonFunctional User2..| IHaveNoIdeaWhatImDoing  | Lisp       | 031   | 031   | 002   | 036   | 0036.26 ms     |
| 38th  | john smith           | RAMBOBot                | PHP        | 031   | 031   | 002   | 036   | 0014.53 ms     |
| 41st  | EoinC                | SimpleRandomBot         | .NET       | 030   | 030   | 005   | 034   | 0015.68 ms     |
| 41st  | Martin Büttner       | FairBot                 | Ruby       | 030   | 030   | 006   | 033   | 0038.23 ms     |
| 41st  | Docopoper            | OboeOboeBeater          | Python2    | 030   | 030   | 006   | 033   | 0021.93 ms     |
| 44th  | undergroundmonorail  | TheGamblersBrother      | Python2    | 029   | 029   | 000   | 040   | 0025.55 ms     |
| 45th  | DrJPepper            | MonadBot                | Haskel     | 028   | 028   | 002   | 039   | 0008.23 ms     |
| 46th  | Josef E.             | OneBehind               | Java       | 027   | 027   | 007   | 035   | 0065.87 ms     |
| 47th  | Ourous               | GitGudBot               | Cobra      | 025   | 025   | 001   | 043   | 0053.35 ms     |
| 48th  | ProgramFOX           | Echo                    | .NET       | 024   | 024   | 004   | 041   | 0014.81 ms     |
| 48th  | JoshDM               | SelfHatingBot           | Java       | 024   | 024   | 005   | 040   | 0068.88 ms     |
| 48th  | Trimsty              | Herpetologist           | Python3    | 024   | 024   | 002   | 043   | 0036.93 ms     |
| 51st  | Milo                 | DogeBot                 | Java       | 022   | 022   | 001   | 046   | 0067.86 ms     |
| 51st  | William Barbosa      | StarWarsFan             | Ruby       | 022   | 022   | 002   | 045   | 0038.48 ms     |
| 51st  | Martin Büttner       | ConservativeBot         | Ruby       | 022   | 022   | 001   | 046   | 0038.25 ms     |
| 51st  | killmous             | MAWBRBot                | Perl       | 022   | 022   | 000   | 047   | 0016.30 ms     |
| 55th  | Mikey Mouse          | LizardsRule             | .NET       | 020   | 020   | 007   | 042   | 0015.10 ms     |
| 55th  | ja72                 | BlindForesight          | .NET       | 020   | 020   | 001   | 048   | 0024.05 ms     |
| 57th  | robotik              | Evolver                 | Lua        | 019   | 019   | 001   | 049   | 0008.19 ms     |
| 58th  | Kyle Kanos           | LexicographicBot        | Python3    | 018   | 018   | 003   | 048   | 0036.93 ms     |
| 58th  | William Barbosa      | BarneyStinson           | Lua        | 018   | 018   | 005   | 046   | 0005.11 ms     |
| 60th  | Dr R Dizzle          | BartSimpson             | Ruby       | 017   | 017   | 001   | 051   | 0038.22 ms     |
| 60th  | jmite                | IocainePowder           | Ruby       | 017   | 017   | 003   | 049   | 0038.50 ms     |
| 60th  | ArcticanAudio        | SpockOrRock             | PHP        | 017   | 017   | 001   | 051   | 0014.19 ms     |
| 60th  | Dr R Dizzle          | BetterLisaSimpson       | Ruby       | 017   | 017   | 000   | 052   | 0038.23 ms     |
| 64th  | Dr R Dizzle          | LisaSimpson             | Ruby       | 016   | 016   | 002   | 051   | 0038.29 ms     |
| 65th  | Martin Büttner       | Vulcan                  | Ruby       | 015   | 015   | 001   | 053   | 0038.26 ms     |
| 65th  | Dr R Dizzle          | Khaleesi                | Ruby       | 015   | 015   | 005   | 049   | 0038.29 ms     |
| 67th  | Dr R Dizzle          | EdwardScissorHands      | Ruby       | 014   | 014   | 002   | 053   | 0038.21 ms     |
| 67th  | undergroundmonorail  | TheGambler              | Python2    | 014   | 014   | 002   | 053   | 0025.47 ms     |
| 69th  | cipher               | LemmingBot              | Python2    | 011   | 011   | 002   | 056   | 0025.29 ms     |
| 70th  | Docopoper            | ConcessionBot           | Python2    | 007   | 007   | 000   | 062   | 0141.31 ms     |
+-------+----------------------+-------------------------+------------+-------+-------+-------+-------+----------------+
Total Players: 70
Total Matches Completed: 2415
Total Tourney Time: 06:00:51.6877573

```

**Tourney Notes**

**Excluded Bots**

* BashRocksBot - still no joy with .net execing cygwin bash scripts
* CounterPreferenceBot - awaiting bug fix
* RandomlyWeighted - awaiting bug fix
* CasinoShakespeare - excluded because it requires an active internet connection

# Original Posted Question

You've swung around to your friends house for the most epic showdown Battle ever of Rock, Paper, Scissors, Lizard, Spock. In true BigBang nerd-tastic style, none of the players are playing themselves but have created console bots to play on their behalf. You whip out your USB key and hand it over to the **Sheldor the Conqueror** for inclusion in the showdown. Penny swoons. Or perhaps Howard swoons. We don't judge here at Leonard's apartment.

**Rules**

Standard Rock, Paper, Scissors, Lizard, Spock rules apply.

* Scissors cut Paper
* Paper covers Rock
* Rock crushes Lizard
* Lizard poisons Spock
* Spock smashes Scissors
* Scissors decapitate Lizard
* Lizard eats Paper
* Paper disproves Spock
* Spock vaporizes Rock
* Rock crushes Scissors

Each player's bot will play one *Match* against each other bot in the tournament.

Each Match will consist of 100 iterations of an RPSLV game.

After each match, the winner is the player who has won the most number of games/hands out of 100.

If you win a match, you will be assigned 1 point in the league table. In the result of a draw-match, neither player will gain a point.

**Bot Requirements**

Your bot must be runnable from the command line.

Sheldor's \*nix box has died, so we're running it off his windows 8 Gaming Laptop so make sure your provided solution can run on windows. Sheldor has graciously offered to install any required runtimes (within reason) to be able to run your solution. (.NET, Java, Php, Python, Ruby, Powershell ...)

**Inputs**

In the first game of each match no arguments are supplied to your bot. In each subsequent game of each match: \- Arg1 will contain the history of your bots hands/decisions in this match. \- Arg2 will contain the history of your opponents hands/decisions in this match.

History will be represented by a sequence of single capital letters representing the possible hands you can play.

```
 | R | Rock     |
 | P | Paper    |
 | S | Scissors |
 | L | Lizard   |
 | V | Spock    |

```

E.g.

* Game 1: MyBot.exe
* Game 2: MyBot.exe S V
* Game 3: MyBot.exe SS VL
* Game 4: MyBot.exe SSR VLS

**Output**

Your bot must write a single character response representing his "hand" for each game. The result should be written to STDOUT and the bot should then exit. Valid single capital letters are below.

```
 | R | Rock     |
 | P | Paper    |
 | S | Scissors |
 | L | Lizard   |
 | V | Spock    |

```

In the case where your bot does not return a valid hand (i.e. 1 of the above 5 single capital letters, then you automatically forfeit that hand and the match continues.

In the case where both bots do not return a valid hand, then the game is considered a draw and the match continues.

**Match Format**

Each submitted bot will play one match against each other bot in the tournament.

Each match will last exactly 100 games.

Matches will be played anonymously, you will not have an advanced knowledge of the specific bot you are playing against, however you may use any and all information you can garner from his decision making during the history of the current match to alter your strategy against your opponent. You may also track history of your previous games to build up patterns/heuristics etc... (See rules below)

During a single game, the orchestration engine will run your bot and your opponents bot 100 milliseconds apart and then compare the results in order to avoid any PRNG collisions in the same language/runtime. (this actually happened me during testing).

**Judging & Constraints**

Dr. Sheldon Cooper in the guise of Sheldor the Conqueror has kindly offered to oversee the running of the tournament. Sheldor the Conqueror is a fair and just overseer (mostly). All decisions by Sheldor are final.

Gaming will be conducted in a fair and proper manner:

* Your bot script/program will be stored in the orchestration engine under a subfolder `Players\[YourBotName]\`
* You may use the subfolder `Players\[YourBotName]\data` to log any data or game history from the current tournament as it proceeds. Data directories will be purged at the start of each tournament run.
* You may not access the Player directory of another player in the tournament
* Your bot cannot have specific code which targets another specific bots behavior
* Each player may submit more than one bot to play so long as they do not interact or assist one another.

**Edit - Additional Constraints**

* Regarding forfeits, they won't be supported. Your bot must play one of the 5 valid hands. I'll test each bot outside of the tournament with some random data to make sure that they behave. Any bots that throw errors (i.e. forfeits errors) will be excluded from the tourney til they're bug fixed.
* Bots may be derivative so long as they are succinctly different in their behaviour. Bots (including in other languages) that perform exactly the same behaviour as an existing bot will be disqualified
* There are already spam bots for the following so please don't resubmit
* + Rock - BartSimpson
* + Paper - LisaSimpson
* + Scissor - EdwardScissorhands
* + Spock - Vulcan
* + Lizard - Khaleesi
* + Pseudo Random - SimpleRandomBot & FairBot
* + Psuedo Random RPS - ConservativeBot
* + Psuedo Random LV - Barney Stinson
* Bots may not call out to 3rd party services or web resources (or anything else which significantly slows down the speed/decision making time of the matches). `CasinoShakespeare` is the only exception as that bot was submitted prior to this constraint being added.

Sheldor will update this question as often as he can with Tournament results, as more bots are submitted.

**Orchestration / Control Program**

The orchestration program, along with source code for each bot is available on github.

https://github.com/eoincampbell/big-bang-game

**Submission Details**

Your submission should include

* Your Bot's name
* Your Code
* A command to
    + execute your bot from the shell e.g.
    + ruby myBot.rb
    + python3 myBot.py
    + OR
    + first compile your both and then execute it. e.g.
    + csc.exe MyBot.cs
    + MyBot.exe

**Sample Submission**

```
BotName: SimpleRandomBot
Compile: "C:\Program Files (x86)\MSBuild\12.0\Bin\csc.exe" SimpleRandomBot.cs
Run:     SimpleRandomBot [Arg1] [Arg2]

```

Code:

```
using System;
public class SimpleRandomBot
{
    public static void Main(string[] args)
    {
        var s = new[] { "R", "P", "S", "L", "V" };
        if (args.Length == 0)
        {
            Console.WriteLine("V"); //always start with spock
            return;
        }
        char[] myPreviousPlays = args[0].ToCharArray();
        char[] oppPreviousPlays = args[1].ToCharArray();
        Random r = new Random();
        int next = r.Next(0, 5);
        Console.WriteLine(s[next]);
    }
}

```

**Clarification**

Any questions, ask in the comments below.

# Answer
# Pony (Python 2)

This is based on a rock-paper-scissors bot I wrote some time ago for a programming challenge at the end of a Udacity online class. I changed it to include Spock and lizard and made some improvements.

The program has 11 different simple strategies, each with 5 variants. It chooses from among these based on how well they would have performed over the last rounds.

I removed a fallback strategy that just played random against stronger opponents. I guess it's more fun like this.

```
import sys

# just play Spock for the first two rounds
if len(sys.argv)<2 or len(sys.argv[1])<2: print 'V'; sys.exit()

# initialize and translate moves to numbers for better handling:
my_moves, opp_moves = sys.argv[1], sys.argv[2]
moves = ('R', 'P', 'S', 'V', 'L')
history = zip([moves.index(i) for i in my_moves],
              [moves.index(i) for i in opp_moves])

# predict possible next moves based on history
def prediction(hist):
    N = len(hist)

    # find longest match of the preceding moves in the earlier history
    cand_m = cand_o = cand_b = range(N-1)
    for l in xrange(1,min(N, 20)):
        ref = hist[N-l]
        cand_m = ([c for c in cand_m if c>=l and hist[c-l+1][0]==ref[0]]
                  or cand_m[-1:])
        cand_o = ([c for c in cand_o if c>=l and hist[c-l+1][1]==ref[1]]
                  or cand_o[-1:])
        cand_b = ([c for c in cand_b if c>=l and hist[c-l+1]==ref]
                  or cand_b[-1:])

    # analyze which moves were used how often
    freq_m, freq_o = [0]*5, [0]*5
    for m in hist:
        freq_m[m[0]] += 1
        freq_o[m[1]] += 1

    # return predictions
    return ([hist[-i][p] for i in 1,2 for p in 0,1]+   # repeat last moves
            [hist[cand_m[-1]+1][0],     # history matching of my own moves
             hist[cand_o[-1]+1][1],     # history matching of opponent's moves
             hist[cand_b[-1]+1][0],     # history matching of both
             hist[cand_b[-1]+1][1],
             freq_m.index(max(freq_m)), # my most frequent move
             freq_o.index(max(freq_o)), # opponent's most frequent move
             0])                        # good old rock (and friends)

# what would have been predicted in the last rounds?
pred_hist = [prediction(history[:i]) for i in xrange(2,len(history)+1)]

# how would the different predictions have scored?
n_pred = len(pred_hist[0])
scores = [[0]*5 for i in xrange(n_pred)]
for pred, real in zip(pred_hist[:-1], history[2:]):
    for i in xrange(n_pred):
        scores[i][(real[1]-pred[i]+1)%5] += 1
        scores[i][(real[1]-pred[i]+3)%5] += 1
        scores[i][(real[1]-pred[i]+2)%5] -= 1
        scores[i][(real[1]-pred[i]+4)%5] -= 1

# return best counter move
best_scores = [list(max(enumerate(s), key=lambda x: x[1])) for s in scores]
best_scores[-1][1] *= 1.001   # bias towards the simplest strategy
if best_scores[-1][1]<0.4*len(history): best_scores[-1][1] *= 1.4
strat, (shift, score) = max(enumerate(best_scores), key=lambda x: x[1][1])
print moves[(pred_hist[-1][strat]+shift)%5]

```

Run as:

```
python Pony.py

```

*Edit*: I made a small change by putting in a bias towards the simplest strategy (i.e. always play the same move) in unsure cases. This helps a bit to not try to find overly complicated patterns where there are none, e.g. in bots like ConservativeBot.

*Note*: I tried to explain the basic history matching strategy that this bot uses in the post for my other bot Dienstag.
> 29 votes

# Answer
## ConservativeBot, Ruby

New things are bad things.

```
puts ['R','P','S'].sample

```

Run like

```
ruby conservative.rb

```
> 20 votes

# Answer
## Markov, Ruby

Looks at the opponent's last two moves and determines the possible (and most likely) follow ups. If the combination hasn't been picked before, he just uses all of the opponent's moves (so far) instead. Then he collects all the possible responses for these and picks a random one.

```
responses = {
  'R' => ['P', 'V'],
  'P' => ['S', 'L'],
  'S' => ['R', 'V'],
  'L' => ['S', 'R'],
  'V' => ['P', 'L']
}

if ARGV.length == 0 || (history = ARGV[1]).length < 3
    choices = ['R','P','S','L','V']
else
    markov = Hash.new []
    history.chars.each_cons(3) { |chars| markov[chars[0..1].join] += [chars[2]] }

    choices = []
    likely_moves = markov.key?(history[-2,2]) ? markov[history[-2,2]] : history.chars
    likely_moves.each { |move| choices += responses[move] }
end

puts choices.sample

```

Run like

```
markov.rb

```
> 20 votes

# Answer
## Star Wars Fan - Ruby

Screw you, Spock

```
puts ['R','P','L','S'].sample

```

Run it like:

```
ruby starwarsfan.rb

```
> 14 votes

# Answer
## Barney Stinson - Lua

I only have one rule: New is always better. Screw old Jo Ken Po or whatever you call it.

```
math.randomseed(os.time())
print(math.random() > 0.5 and "V" or "L")

```

Run it like:

```
lua legenwaitforitdary.lua

```
> 13 votes

# Answer
## IocainePowder, Ruby

Based off (shamelessly stolen from) the RPS strategy here. The bot looks chooses a guess identical to the Markov bot, but then assumes the opponent has guessed what it's going to choose, and chooses a move to beat that one accordingly.

Note that I've just adapted the basic idea of the linked strategy, not followed it in detail.

```
responses = {
  'R' => ['P', 'V'],
  'P' => ['S', 'L'],
  'S' => ['R', 'V'],
  'L' => ['S', 'R'],
  'V' => ['P', 'L']
}

if ARGV.length == 0 || (history = ARGV[1]).length < 3
    choices = ['R','P','S','L','V']
else
    markov = Hash.new []
    history.chars.each_cons(3) { |chars| markov[chars[0..1].join] += [chars[2]] }

    choices = []
    likely_moves = markov.key?(history[-2,2]) ? markov[history[-2,2]] : history.chars
    likely_moves.each { |move| choices += responses[move] }
end

myChoice = choices.sample
theirChoice = responses[myChoice].sample
actualChoice = responses[theirChoice].sample
puts actualChoice

```

Run like

```
iocaine.rb

```
> 9 votes

# Answer
## HuddleWolfTheConqueror - C#

HuddleWolf is back and better than ever. He will beat Sheldor the Conqueror at his own silly game. HuddleWolf is smart enough to identify and counter spammerbots. For more intelligent opponents, HuddleWolf uses his knowledge of basic 5th grade statistics and utilizes a weighted dice roll based on the opposition's history of plays.

```
using System;
using System.Collections.Generic;
using System.Linq;

public class HuddleWolfTheConqueror
{

    public static readonly char[] s = new[] { 'R', 'P', 'S', 'L', 'V' };

    public static void Main(string[] args)
    {
        if (args.Length == 0)
        {
            Console.WriteLine(pickRandom());
            return;
        }

        char[] myPlays = args[0].ToCharArray();
        char[] oppPlays = args[1].ToCharArray();

        char tryPredict = canPredictCounter(oppPlays);
        if (tryPredict != '^')
        {
            Console.WriteLine(tryPredict);
        }
        else
        {
            Console.WriteLine(pickRandom());
        }
        return;
    }

    public static char canPredictCounter(char[] history)
    {
        // don't predict if insufficient data
        if (history.Length < 5)
        {
            return '^';
        }

        // calculate probability of win for each choice
        Dictionary<char, double> dic = getBestProabability(history);

        // get item with highest probability of win
        List<char> maxVals = new List<char>();
        char maxVal = '^';
        double mostFreq = 0;
        foreach (var kvp in dic)
        {
            if (kvp.Value > mostFreq)
            {
                mostFreq = kvp.Value;
            }
        }
        foreach (var kvp in dic)
        {
            if (kvp.Value == mostFreq)
            {
                maxVals.Add(kvp.Key);
            }
        }

        // return error
        if (maxVals.Count == 0)
        {
            return maxVal;
        }

        // if distribution is not uniform, play best play
        if (maxVals.Count <= 3)
        {
            Random r = new Random(Environment.TickCount);
            return maxVals[r.Next(0, maxVals.Count)];
        }

        // if probability is close to uniform, use weighted dice roll
        if (maxVals.Count == 4)
        {
            return weightedRandom(dic);
        }

        // if probability is uniform, use random dice roll
        if (maxVals.Count >= 5)
        {
            return pickRandom();
        }

        // return error
        return '^';
    }

    public static Dictionary<char, double> getBestProabability(char[] history)
    {
        Dictionary<char, double> dic = new Dictionary<char, double>();
        foreach (char c in s)
        {
            dic.Add(c, 0);
        }
        foreach (char c in history)
        {
            if (dic.ContainsKey(c))
            {
                switch(c)
                {
                    case 'R' :
                        dic['P'] += (1.0/(double)history.Length);
                        dic['V'] += (1.0/(double)history.Length);
                        break;
                    case 'P' :
                        dic['S'] += (1.0/(double)history.Length);
                        dic['L'] += (1.0/(double)history.Length);
                        break;
                    case 'S' :
                        dic['V'] += (1.0/(double)history.Length);
                        dic['R'] += (1.0/(double)history.Length);
                        break;
                    case 'L' :
                        dic['R'] += (1.0/(double)history.Length);
                        dic['S'] += (1.0/(double)history.Length);
                        break;
                    case 'V' :
                        dic['L'] += (1.0/(double)history.Length);
                        dic['P'] += (1.0/(double)history.Length);
                        break;
                    default :
                        break;

                }
            }
        }
        return dic;
    }

    public static char weightedRandom(Dictionary<char, double> dic)
    {
        Random r = new Random(Environment.TickCount);
        int next = r.Next(0, 100);
        int curVal = 0;
        foreach (var kvp in dic)
        {
            curVal += (int)(kvp.Value*100);
            if (curVal > next)
            {
                return kvp.Key;
            }
        }
        return '^';
    }

    public static char pickRandom()
    {
        Random r = new Random(Environment.TickCount);
        int next = r.Next(0, 5);
        return s[next];
    }
}

```
> 8 votes

# Answer
# Boring Bot (Java)

He assumes everyone always plays the same thing and plans accordingly. He usually picks rocks in a ties though ’cause so does everyone else right?

```
public class BoringBot
{
    public static void main(String[] args)
    {
        int Rock=0;
        int Paper=0;
        int Scissors=0;
        int Lizard=0;
        int Spock=0;

        if (args.length == 0)
        {
            System.out.print("P");
            return;
        }

        char[] oppPreviousPlays = args[1].toCharArray();

        for (int j=0; j<oppPreviousPlays.length; j++) {
            switch(oppPreviousPlays[j]){
                case 'R': Rock++; break;
                case 'P': Paper++; break;
                case 'S': Scissors++; break;
                case 'L': Lizard++; break;
                case 'V': Spock++;
            }
        }

        int Best = Math.max(Math.max(Lizard+Scissors-Spock-Paper,
                                     Rock+Spock-Lizard-Scissors),
                            Math.max(Math.max(Paper+Lizard-Spock-Rock,
                                              Paper+Spock-Rock-Scissors),
                                     Rock+Scissors-Paper-Lizard));

        if (Best== Lizard+Scissors-Spock-Paper){
            System.out.print("R"); return;
        } else if (Best== Rock+Spock-Lizard-Scissors){
            System.out.print("P"); return;
        } else if (Best== Paper+Lizard-Spock-Rock){
            System.out.print("S"); return;
        } else if(Best== Paper+Spock-Rock-Scissors){
            System.out.print("L"); return;
        } else {
            System.out.print("V"); return;
        }
    }
}

```
> 8 votes

# Answer
# ToddlerProof

This fairly stupid bot assumes it is playing a toddler who will "chase" its moves, always trying to beat whatever was last thrown. If the bot is beaten several times in a row, it jumps to a new point in the pattern. It is based on my strategy for always beating my *much* younger brother. :)

**EDIT::** Changed the length of a loss streak required to jump into random throws. Also fixed a major bug with the random jump.

Save as `ToddlerProof.java`, compile, then run with `java ToddlerProof [me] [them]`

```
import java.util.HashMap;
public class ToddlerProof
{
    char[] moves = new char[]{'R', 'P', 'S', 'L', 'V'};
    public static void main(String[] args)
    {
        if(args.length<1) //first Round
        {
            System.out.print('V');//Spock is best
            return;
        }
        else
        {
            String them = args[1];
            String me = args[0];
            int streak = 0;

            HashMap<Character, Character> nextMove = new HashMap<Character, Character>();
            //Next move beats things that beat my last move
            nextMove.put('L', 'V');
            nextMove.put('V', 'S');
            nextMove.put('S', 'P');
            nextMove.put('P', 'R');
            nextMove.put('R', 'L');
            //Check if last round was a tie or the opponent beat me
            int lastResult = winner(me.charAt(me.length()-1), them.charAt(them.length()-1));
            if(lastResult == 0)
            {
                //tie, so they will chase my last throw
                System.out.print(nextMove.get(me.charAt(me.length()-1)));

                return;
            }
            else if(lastResult == 1)
            {
                //I won, so they will chase my last throw
                System.out.print(nextMove.get(me.charAt(me.length()-1)));

                return;
            }

            else{
                //I lost
                //find streak
                for(int i = 0; i<me.length(); i++)
                {
                    int a = winner(me.charAt(i), them.charAt(i));
                    if(a >= 0) streak = 0;
                    else streak++;
                }
                //check lossStreak
                //If the streak is 2, then a rotation will make it even.
                //if it is >2, something bad has happened and I need to adjust.
                if(streak>2)
                {
                    //if they are on to me, do something random-ish
                    int r = (((them.length()+me.length()-1)*13)/7)%4;
                    System.out.print(move[r]);
                    return;
                }
                //otherwise, go on with the plan
                System.out.print(nextMove.get(me.charAt(me.length()-1)));
                return;
            }
        }
    }
    public static int winner(char me, char them)
    {
        //check for tie
        if(me == them) return 0;
        //check if they won
        if(me=='V' && (them == 'L' || them == 'P')) return -1;
        if(me=='S' && (them == 'V' || them == 'R')) return -1;
        if(me=='P' && (them == 'S' || them == 'L')) return -1;
        if(me=='R' && (them == 'P' || them == 'V')) return -1;
        if(me=='L' && (them == 'R' || them == 'S')) return -1;
        //otherwise, I won
        return 1;
    }
}

```
> 8 votes

# Answer
## Bart Simpson

"Good old rock! Nothing beats rock!"

```
puts 'R'

```

Run as

```
ruby DoTheBartman.rb

```

---

## Lisa Simpson

"Poor, predictable Bart. Always chooses rock."

```
puts 'P'

```

Run as

```
ruby LisaSimpson.rb

```

---

## Better Lisa Simpson

I felt bad about making Lisa quite so stupid, so I allowed her to randomly choose between either of the hands that will beat rock. Still stupid, but she is a Simpson after all. Maybe a crayon got stuck in her brain?

```
puts ['P','V'].sample

```

Run as

```
ruby BetterLisaSimpson.rb

```
> 8 votes

# Answer
# Echo

Written in C#. Compile with `csc Echo.cs`. Run like `Echo.exe ARG1 ARG2`.

The first run, Echo takes a random option. Every run after the first, Echo simply repeats the opponent's latest action.

```
using System;

namespace Echo
{
    class Program
    {
        static void Main(string[] args)
        {
            if (args.Length == 0)
            {
                Random r = new Random();
                string[] options = new string[] { "R", "P", "S", "L", "V" };
                Console.WriteLine(options[r.Next(0, options.Length)]);
            }
            else if (args.Length == 2)
            {
                string opponentHistory = args[1];
                Console.WriteLine(opponentHistory[opponentHistory.Length - 1]);
            }
        }
    }
}

```
> 7 votes

# Answer
## Vulcan, Ruby

My fingers are glued together.

```
puts 'V'

```

Run like

```
ruby vulcan.rb

```

(I think this is the only in-character strategy for your background setting.)
> 7 votes

# Answer
Tyrannosaurus, Godzilla, Barney... Lizards Rule. Occasionally they get in trouble and need to call Spock or throw Rocks

```
using System;
public class LizardsRule
{
    public static void Main(string[] args)
    {
        if (args.Length == 0)
        {
            Console.WriteLine("L");
            return;
        }
        char[] oppPreviousPlays = args[1].ToCharArray();
        var oppLen = oppPreviousPlays.Length;
        if (oppPreviousPlays.Length > 2
            && oppPreviousPlays[oppLen - 1] == 'R'
            && oppPreviousPlays[oppLen - 2] == 'R'
            && oppPreviousPlays[oppLen - 3] == 'R')
        {
            //It's an avalance, someone call Spock
            Console.WriteLine("V");
            return;
        }

        if (oppPreviousPlays.Length > 2
                && oppPreviousPlays[oppLen - 1] == 'S'
                && oppPreviousPlays[oppLen - 2] == 'S'
                && oppPreviousPlays[oppLen - 3] == 'S')
        {
            //Scissors, Drop your tail and pick up a rock
            Console.WriteLine("R");
            return;
        }

        //Unleash the Fury Godzilla
        Console.WriteLine("L");
    }
}

```
> 6 votes

# Answer
# BayesianBot, Perl (now v2!)

Above everything else, this is a unique program. In it, you shall see the brilliant fusion of statistics and horrible programming form. Also, this bot probably breaks many rules of Bayesian statistics, but the name sounds cooler.

The core essence of this bot is its creation of 250 different predictive models. Each model takes the form of *"Given that I played rock last turn and my opponent played scissors two turns ago, this is the probability distribution for my opponent's next move."* Each probability distribution takes the form of a multi-dimensional Dirichlet distribution.

Each turn, the predictions of all applicable models (typically 10) are multiplied together to form an overall prediction, which is then used to determine which moves have the highest expected payoff.

Edit 1: In this version, I changed the prior distribution and made the bot more randomized when it is losing.

There are a few things which may be subject to improvement, such as the number of models (250 is only a 3 digit number), the choice of prior distribution (currently Dir(3,3,3,3,3)), and the method of fusing predictions. Also, I never bothered to normalize any of the probability distributions, which is okay for now because I'm multiplying them.

I don't have super high expectations, but I hope this bot will be able to do well.

```
my ($phist, $ohist) = @ARGV;

my %text2num = ('R',0,'V',1,'P',2,'L',3,'S',4);  #the RVPLS ordering is superior
my @num2text = ('R','V','P','L','S');

@phist = map($text2num{$_},split(//,$phist));
@ohist = map($text2num{$_},split(//,$ohist));

$lowerlimit = 0;
for($lowerlimit..~~@phist-3){$curloc=$_;
 $result = $ohist[$curloc+2];
 @moveset = ($ohist[$curloc],$ohist[$curloc+1],$phist[$curloc],$phist[$curloc+1]);
 for(0..3){$a=$_;
  for(0..$a){$b=$_;
   $predict[$a][$b][$moveset[$a]][$moveset[$b]][$result]++;
  }
 }
}

@recentmoves = ($ohist[-2],$ohist[-1],$phist[-2],$phist[-1]);

@curpred = (1,1,1,1,1);

for(0..3){$a=$_;
 for(0..$a){$b=$_;
  for(0..4){$move=$_;
   $curpred[$move] *= $predict[$a][$b][$recentmoves[$a]][$recentmoves[$b]][$move]/3+1;
  }
 }
}

@bestmove = (0,0,0,0,0);
for(0..4){
 $bestmove[$_] = $curpred[$_]/2+$curpred[$_-1]+$curpred[$_-2];
}

$max = 0;
for(0..4){
 if($bestmove[$_]>$max){
  $max = $bestmove[$_];
 }
}
@options=();
$offset=0;
if(($ohist[-1] - $phist[-1])%5 < 2 && ($ohist[-2] - $phist[-2])%5 < 2 && ($ohist[-3] - $phist[-3])%5 < 2){  #frequentist alert!
 $offset=int(rand(3));
}
for(0..4){
 if($bestmove[$_] == $max){
  push(@options,$num2text[($_+$offset)%5]);
 }
}
$outputb = $options[int(rand(~~@options))];

print "$outputb";

```

I've been running this program like so:

```
perl BayesianBot.plx

```
> 6 votes

# Answer
## DynamicBot

Dynamic bot is almost always changing. It really hates repeating itself

```
import sys, random
choices = ['L','V','S','P','R'] * 20
if len(sys.argv) > 1:
    my_history = sys.argv[1]
    [choices.remove(my_history[-1]) for i in range(15)]
print(choices[random.randrange(len(choices))])

```

Language: Python 3.4.1

Command: `python dynamicbot.py <history>` or `python3 dynamicbot.py <history>` depending on your system
> 5 votes

# Answer
# SpockOrRock - PHP

When played in the real world, most people instinctively pick scissors. This bot picks either Spock or Rock to beat the average player. It's not bothered about previous rounds.

run with `php spockorrock.php`

```
<?php

//Pick either Spock or Rock
if (rand(0,1) == 0)     echo("R\n");
else                    echo("V\n");

?>

```
> 5 votes

# Answer
# SmartBot - Java

My first ever entry for anything on this site!

Though not a very creative name...

SmartBot finds sequences of moves where the opponent and/or itself's moves are similar to the moves last made and plans accordingly.

`name = SmartBot`

I think to run it, correct me if I am wrong.

`java -jar SmartBot.jar`

```
import java.util.ArrayList;
public class SmartBot {
    public static void main(String[] args) {
        if(args.length ==0){
            System.out.print("L");
            return;
        }
        if(args[0].length()<3){
            String[] randLetter = new String[]{"R","P","S","L","V"};
            System.out.print(randLetter[(int) Math.floor(Math.random()*5)]);
            return;
        }
        String myHistory = args[0];
        String otherHistory = args[1];

        double rScore,pScore,sScore,lScore,vScore;//score - highest = highest probability of next opponent move
        rScore = pScore = sScore = lScore = vScore = 0;
        lScore = .001;
        ArrayList<ArrayList<Integer>> moveHits = new ArrayList<ArrayList<Integer>>();
        for(int g = 0;g<2;g++){
            for(int i=1;i<(myHistory.length() / 2) + 1;i++){
                if(g==0){
                    moveHits.add(findAll(myHistory.substring(myHistory.length() - i),myHistory));
                }
                else{
                    moveHits.add(findAll(otherHistory.substring(otherHistory.length() - i),otherHistory));
                }
            }
            for(int i = 0; i < moveHits.size();i++){
                int matchingMoves = i+1;
                ArrayList<Integer> moveIndexes = moveHits.get(i);
                for(Integer index:moveIndexes){
                    if(index+matchingMoves +1<= otherHistory.length()){
                        char nextMove = otherHistory.charAt(index + matchingMoves-1);
                        if(nextMove=='R'){rScore = rScore + matchingMoves;}
                        if(nextMove=='P'){pScore = pScore + matchingMoves;}
                        if(nextMove=='S'){sScore = sScore + matchingMoves;}
                        if(nextMove=='L'){lScore = lScore + matchingMoves;}
                        if(nextMove=='V'){vScore = vScore + matchingMoves;}
                    }
                }
            }
        }
        if(rScore >= pScore && rScore >= sScore && rScore >= lScore && rScore >= vScore){
            System.out.print("V");
            return;
        }
        if(pScore >= rScore && pScore >= sScore && pScore >= lScore && pScore >= vScore){
            System.out.print("L");
            return;
        }
        if(sScore >= pScore && sScore >= rScore && sScore >= lScore && sScore >= vScore){
            System.out.print("R");
            return;
        }
        if(vScore >= pScore && vScore >= sScore && vScore >= lScore && vScore >= rScore){
            System.out.print("L");
            return;
        }
        if(lScore >= pScore && lScore >= sScore && lScore >= rScore && lScore >= vScore){
            System.out.print("S");
        }
        return;
    }
    public static ArrayList<Integer> findAll(String substring,String realString){
        ArrayList<Integer> ocurrences = new ArrayList<Integer>();
        Integer index = realString.indexOf(substring);
        if(index==-1){return ocurrences;}
        ocurrences.add(index+1);
        while(index!=-1){
            index = realString.indexOf(substring,index + 1);
            if(index!=-1){
                ocurrences.add(index+1);
            }
        }
        return ocurrences;
    }
}

```

It assigns a score for each possible next move by the number of times similar patterns have happened.

It slightly favors lizard.
> 5 votes

# Answer
## SlowLizard, Ruby

After starting with Lizard, it always picks a random move which beats the opponent's previous move.

```
responses = {
  'R' => ['P', 'V'],
  'P' => ['S', 'L'],
  'S' => ['R', 'V'],
  'L' => ['S', 'R'],
  'V' => ['P', 'L']
}

if ARGV.length == 0
  puts 'L'
else
  puts responses[ARGV[1][-1]].sample
end

```

Run like

```
ruby slowlizard.rb

```
> 4 votes

# Answer
# LexicographicBot

This bot likes to order his letters, so he will choose a response that is 1 higher than his opponent gave in the previous round--unless the opponent chose Vulcan, then he randomly picks a response.

```
import sys
import random

choices = ["L", "P", "R", "S", "V"]

total = len(sys.argv)
if total==1:
    print("L")
    sys.exit()

opponent = sys.argv[2]
opponent_last = opponent[-1]

if opponent_last == choices[-1]:
    print(random.choice(choices))
else:
    next = choices.index(opponent_last)+1
    print(choices[next])

```

This expects the opponent hand to be dealt second:

```
                           me
                            v
python LexicographicBot.py SR RV
                              ^
                            opponent

```
> 4 votes

# Answer
# Analogizer - Ruby

Run with `ruby analogizer.rb`. I've made a logic fix to the code, but no idea why there were errors with this.

```
@rules = {

  'L' => %w[V P],
  'P' => %w[V R],
  'R' => %w[L S],
  'S' => %w[P L],
  'V' => %w[R S]
}

@moves = @rules.keys

def defeats?(move1, move2)
  @rules[move1].include?(move2)
end

def score(move1, move2)
  if move1 == move2
    0
  elsif defeats?(move1, move2)
    1
  else
    -1
  end
end

def move
  player, opponent = ARGV

  case player.to_s.size
  # Throw six lizards in the beginning to confuse opponent
  when 0..5
    'L'
  when 6
    'V'
  when 7
    'S'
  when 8
    'P'
  when 9
    'R'
  else
    analyze_history(player.chars.to_a, opponent.chars.to_a)
  end

end

def analyze_history(player, opponent)
  my_last_move = player.last
  predicted_moves = Hash.new {0}
  opponent_reactions = player.zip(opponent.drop(1))

  # Check whether opponent tended to make a move that would've beaten, lost, or tied my last move
  opponent_reactions.each do |my_move, reaction|
    score = score(reaction, my_move)
    analogous_moves = @moves.select { |move| score == score(move, my_last_move) }
    analogous_moves.each { |move| predicted_moves[move] += 1 }
  end

  # Assume if an opponent has never made a certain move, it never will
  @moves.each { |m| predicted_moves[m] = 0 unless opponent.include?(m) }

  # Pick the move with the best score against opponent's possible moves, weighted by their likelihood, picking randomly for ties
  @moves.shuffle.max_by{ |m| predicted_moves.map { |predicted, freq| score(m, predicted) * freq }.reduce(0,:+) }

end

puts move

```

Assumes the opposing bot is always reacting to my previous move, and either picking something that would beat it, something that would lose to it, or the same move, possibly from a restricted set of possible moves. It then picks the best move given that assumption.

Except that the first ten moves are hardcoded: first I pretend I only know lizard, then I assume my opponent always throws something to beat the last thing I threw until I have enough data for proper analysis.
> 4 votes

# Answer
# The Gambler - Python 2

```
import sys
import random

MODE = 1

moves = 'RSLPV'

def element_sums(a, b):
    return [a[i] + b[i] for i in xrange(len(a))]

def move_scores(p):
    def calc(to_beat):
        return ['LDW'.find('DLLWW'[moves.find(m)-moves.find(to_beat)]) for m in moves]

    return dict(zip(moves, element_sums(calc(p[0]), calc(p[1]))))

def move_chooser(my_history, opponent_history):
    predict = sorted(moves, key=opponent_history.count, reverse=MODE)[-2:]
    scores = move_scores(predict)
    return max(scores, key=lambda k:scores[k])

if __name__ == '__main__':
    if len(sys.argv) == 3:
        print move_chooser(*sys.argv[1:])
    elif len(sys.argv) == 1:
        print random.choice(moves)

```

Contrary to the name, the only time randomness is used in this program is on the first round, when there's no information. Instead, it's named for the gambler's fallacy, the belief that if a random event has happened less often in the past, it's more likely to happen in the future. For example, if you flip a fair coin 20 times, and the first 15 are heads, the gambler's fallacy states that the odds of the remaining flips being tails are increased. Of course, this is untrue; regardless of the previous flips, a fair coin's odds of coming up tails is always 50%.

This program analyzes the opponent's history, finds the 2 moves that it has used the least so far, and assumes that the opponent's move this time will be one of those two. Assigning 2 to a win, 1 to a draw and 0 to a loss, it finds the move with the maximum score against these two predicted moves and throws that.

# The Gambler's Brother - Python 2

```
import sys
import random

MODE = 0

moves = 'RSLPV'

def element_sums(a, b):
    return [a[i] + b[i] for i in xrange(len(a))]

def move_scores(p):
    def calc(to_beat):
        return ['LDW'.find('DLLWW'[moves.find(m)-moves.find(to_beat)]) for m in moves]

    return dict(zip(moves, element_sums(calc(p[0]), calc(p[1]))))

def move_chooser(my_history, opponent_history):
    predict = sorted(moves, key=opponent_history.count, reverse=MODE)[-2:]
    scores = move_scores(predict)
    return max(scores, key=lambda k:scores[k])

if __name__ == '__main__':
    if len(sys.argv) == 3:
        print move_chooser(*sys.argv[1:])
    elif len(sys.argv) == 1:
        print random.choice(moves)

```

By switching the `MODE` variable to 0, this program will operate based on a related fallacy, also sometimes referred to as the gambler's fallacy. It states that if a random event has been happened more often in the past, it's more likely to happen in the future. For example, if you flip a coin 20 times and the first 15 are heads, this fallacy states that the remaining flips are more likely to be heads, since there's currently a streak. In mode 0, this program operates the same way, except that it assumes the opponent will throw one of the two moves it's thrown most often so far.

So yes, these two programs are only one character apart. :)
> 4 votes

# Answer
# Werevulcan - Ruby

Run as `ruby werevulcan.rb`

```
@rules = {

  'L' => %w[V P],
  'P' => %w[V R],
  'R' => %w[L S],
  'S' => %w[P L],
  'V' => %w[R S]
}

@moves = @rules.keys

def defeats?(move1, move2)
  @rules[move1].include?(move2)
end

def score(move1, move2)
  if move1 == move2
    0
  elsif defeats?(move1, move2)
    1
  else
    -1
  end
end

def move
  player, opponent = ARGV

  # For the first 30 rounds, pick a random move that isn't Spock
  if player.to_s.size < 30
    %w[L P R S].sample
  elsif opponent.chars.to_a.uniq.size < 5
    exploit(opponent)
  else
    # Pick a random move that's biased toward Spock and against lizards
    %w[L P P R R S S V V V].sample
  end

end

def exploit(opponent)
  @moves.shuffle.max_by{ |m| opponent.chars.map{|o| score(m,o) }.reduce(:+) }
end

puts move

```

The werevulcan looks normal by day, but when the moon rises, its ears grow pointy, and its moves grow more logical.
> 4 votes

# Answer
# Java - SelfLoathingBot

```
BotName: SelfLoathingBot
Compile: Save as 'SelfLoathingBot.java'; compile.
Run:     java SelfLoathingBot [me] [them]

```

Bot starts randomly, then ~33% to go random, or ~33% to play a winning tactic against either of the immediately prior plays, with 50% choice of winning tactic.

```
import java.util.Random;

public class SelfLoathingBot {

    static final Random RANDOM = new Random();

    private static char randomPlay() {

        switch (RANDOM.nextInt(5)) {

            case 0 : return 'R';

            case 1 : return 'P';

            case 2 : return 'S';

            case 3 : return 'L';

            default : return 'V';
        }
    }

    private static char antiPlay(String priorPlayString) {

        char[] priorPlays = priorPlayString.toCharArray();

        int choice = RANDOM.nextInt(2);

        switch (priorPlays[priorPlays.length - 1]) {

            case 'R' : return choice == 0 ? 'P' : 'V';

            case 'P' : return choice == 0 ? 'S' : 'L';

            case 'S' : return choice == 0 ? 'V' : 'R';

            case 'L' : return choice == 0 ? 'R' : 'S';

            default : return choice == 0 ? 'L' : 'P'; // V
        }
    }

    public static void main(String[] args) {

        int choice = args.length == 0 ? 0 : RANDOM.nextInt(3);

        char play;

        switch (choice) {

            case 1 :

                // 33.3% chance Play myself
                play = antiPlay(args[0]);
                break;

            case 2 :

                // 33.3% chance Play opponent just in case opponent is screwy like that
                play = antiPlay(args[1]);
                break;

            default :

                // 33.3% chance 100% Random
                play = randomPlay();
        }

        System.out.print(play);
        return;
    }
}

```
> 4 votes

# Answer
# The Analyst

The analyst analyzes some stuff and does some things to try to beat you.

compile with `javac Analyst.java` and run as `java Analyst`

```
import java.util.Random;

public class Analyst{
    public static void main(String[] args){
        char action = 'S';

        try{
            char[] enemyMoves = null, myMoves = null;

            //first move is random
            if(args.length == 0){
                System.out.print(randomMove());
                System.exit(0);
            //moves 2-3 will beat their last move
            }else if(args[0].length() < 8){
                System.out.print(counterFor(args[1].charAt(args[1].length()-1)));
                System.exit(0);
            //following moves will execute some analyzation stuff
            }else{
                //get previous moves
                myMoves = args[0].toCharArray();
                enemyMoves = args[1].toCharArray();
            }

            //test if they're trying to beat our last move
            if(beats(enemyMoves[enemyMoves.length-1], myMoves[myMoves.length-2])){
                action = counterFor(counterFor(myMoves[myMoves.length-1]));
            }
            //test if they're copying our last move
            else if(enemyMoves[enemyMoves.length-1] == myMoves[myMoves.length-2]){
                action = counterFor(myMoves[myMoves.length-1]);
            }
            //else beat whatever they've done the most of
            else{
                action = counterFor(countMost(enemyMoves));
            }

            //if they've beaten us for the first 40 moves, do the opposite of what ive been doing
            if(theyreSmarter(myMoves, enemyMoves)){
                action = counterFor(action);
            }

        //if you break my program do something random
        }catch (Exception e){
            action = randomMove();
        }

        System.out.print(action);
    }

    private static char randomMove(){
        Random rand = new Random(System.currentTimeMillis());
        int randomMove = rand.nextInt(5);

        switch (randomMove){
            case 0: return 'R';
            case 1: return 'P';
            case 2: return 'S';
            case 3: return 'L';
            default: return 'V';
        }
    }

    private static char counterFor(char move){
        Random rand = new Random(System.currentTimeMillis());
        int moveSet = rand.nextInt(2);

        if(moveSet == 0){
            switch (move){
                case 'R': return 'P';
                case 'P': return 'S';
                case 'S': return 'R';
                case 'L': return 'R';
                default: return 'P';
            }
        }else{
            switch (move){
                case 'R': return 'V';
                case 'P': return 'L';
                case 'S': return 'V';
                case 'L': return 'S';
                default: return 'L';
            }
        }
    }

    private static boolean beats(char move1, char move2){
        if(move1 == 'R'){
            if((move2 == 'S') || (move2 == 'L')){
                return true;
            }else{
                return false;
            }
        }else if(move1 == 'P'){
            if((move2 == 'R') || (move2 == 'V')){
                return true;
            }else{
                return false;
            }
        }else if(move1 == 'S'){
            if((move2 == 'L') || (move2 == 'P')){
                return true;
            }else{
                return false;
            }
        }else if(move1 == 'L'){
            if((move2 == 'P') || (move2 == 'V')){
                return true;
            }else{
                return false;
            }
        }else{
            if((move2 == 'R') || (move2 == 'S')){
                return true;
            }else{
                return false;
            }
        }
    }

    private static char countMost(char[] moves){
        int[] enemyMoveList = {0,0,0,0,0};

        for(int i=0; i<moves.length; i++){
            if(moves[i] == 'R'){
                enemyMoveList[0]++;
            }else if(moves[i] == 'P'){
                enemyMoveList[1]++;
            }else if(moves[i] == 'S'){
                enemyMoveList[2]++;
            }else if(moves[i] == 'L'){
                enemyMoveList[3]++;
            }else if(moves[i] == 'V'){
                enemyMoveList[4]++;
            }
        }

        int max = 0, maxIndex = 0;
        for(int i=0; i<5; i++){
            if(enemyMoveList[i] > max){
                max = enemyMoveList[i];
                maxIndex = i;
            }
        }

        switch (maxIndex){
            case 0: return 'R';
            case 1: return 'P';
            case 2: return 'S';
            case 3: return 'L';
            default: return 'V';
        }
    }

    private static boolean theyreSmarter(char[] myMoves, char[] enemyMoves){
        int loseCounter = 0;

        if(enemyMoves.length >= 40){
            for(int i=0; i<40; i++){
                if(beats(enemyMoves[i],myMoves[i])){
                    loseCounter++;
                }
            }
        }else{
            return false;
        }

        if(loseCounter > 20){
            return true;
        }else{
            return false;
        }
    }
}

```
> 4 votes

# Answer
# Dienstag (Python 2)

My first entry Pony seems to fare quite well with all its second guessing (tripple guessing, ...) and meta reasoning. But is that even necessary?

So, here is Dienstag, Pony's little friend, with only one of the 55 strategies: Predict the opponent's next move and beat it.

On the long run Dienstag wins or ties with every Bot in the top ten of the current leaderboard. Except for Pony that is.

```
import sys
if len(sys.argv)<2 or len(sys.argv[1])<2: print 'L'; sys.exit()
hist = [map('RPSVL'.index, p) for p in zip(sys.argv[1], sys.argv[2])]
N = len(hist)
cand = range(N-1)
for l in xrange(1,N):
    cand = ([c for c in cand if c>=l and hist[c-l+1]==hist[-l]] or cand[-1:])
print 'RPSVL'[(hist[cand[-1]+1][1]+(1,3)[N%2==0])%5]

```

Run as:

```
python Dienstag.py

```

I admit that the code is a bit obfuscated. Should anyone care to know more about it, I might add explanations.

*Edit:* Here is a short example walkthrough to explain the idea:

* The program gets the history of it's own and the opponent's moves:

`sys.arg[1] = 'LLVLLVL', sys.arg[2] = 'RPSPSSP'`
* The history is combined into a list of pairs and the moves are translated to numbers (R=0, ...):

`hist = [[4, 0], [4, 1], [3, 2], [4, 1], [4, 2], [3, 2], [4, 1]]`
* The number of rounds played so far is determined:

`N = 7`
* The basic idea now is to look for the longest unbroken chain of exactly the last moves in the earlier history. The program keeps track of where such a chain ends in the list `cand` (for 'candidates'). In the beginning, without checking, every position in the history except for the last one is considered:

`cand = [0, 1, 2, 3, 4, 5]`
* Now the length of possible chains is increased step by step. For chain length `l = 1` it looks for previous occurrences of the last move pair `[4, 1]`. This can be found at history position `1` and `3`. Only these are kept in the `cand` list:

`cand = [1, 3]`
* Next, for `l = 2` it checks which of the possible candidates was preceded by the second to last move pair `[3, 2]`. This is only the case for position `3`:

`cand = [3]`
* For `l = 3` and more there are no previous chains of that length and `cand` would be empty. In this case the last element of `cand` is kept:

`cand = [3]`
* The bot now assumes that history will repeat. The last time the cain `[3, 2], [4, 1]` occurred, it was followed by `[4, 2]`. So, the opponent played `2` (scissors) which can be beaten by `(2+1)%5 = 3` (Spock) or `(2+3)%5 = 0` (rock). The bot answers, with the first or second alternative depending on whether `N` is odd or even just to introduce some variance.
* Here move `3` is chosen which is then translated back:

`print 'V'`

*Note:* Dienstag has time complexity O(*N*<sup>2</sup>) for returning the next move after *N* rounds. Pony has time complexity O(*N*<sup>3</sup>). So in this aspect they are probably much worse then most other entries.
> 4 votes

# Answer
## FairBot, Ruby

Let's start simple.

```
puts ['R','P','S','L','V'].sample

```

Run like

```
ruby fairbot.rb

```
> 3 votes

# Answer
# ViolentBot

This bot choices the most violent option based on the opponents previous choice:

```
import sys

choice_dict = {"L" : "S", "P" : "S", "R" : "V", "S" : "V", "V" : "L"}

total = len(sys.argv)
if total==1:
    print("L")
    sys.exit()

opponent = sys.argv[2]
opponent_last = opponent[-1]

print(choice_dict[opponent_last])

```

Run as

```
python ViolentBot.py (me) (opp)

```
> 3 votes

# Answer
## Bash Rocks

Is cygwin too much to ask as a runtime?

bashrocks.sh:

```
#!/bin/bash
HAND=(R P S L V)
RAND=`od -A n -t d -N 1 /dev/urandom | xargs`
echo ${HAND[ $RAND  % 5 ]}

```

and run it like so:

```
sh bashrocks.sh

```
> 3 votes

# Answer
# Nitpicker (Ruby)

```
BotName: Nitpicker
Run:     ruby nitpicker.rb [Mine] [Theirs]

```

Code Update: Now counts more stuff.

Code

```
scores = [ 0 ] * 9

@moves = { "R" => 0, "P" => 1, "S" => 2, "L" => 3, "V" => 4 }
@responses = [ "R", "P", "S", "L", "V" ]
@counters = { "R" => [ "P", "V" ], "P" => [ "S", "L" ], "S" => [ "V", "R" ], "L" => [ "R", "S" ], "V" => [ "P", "L" ] }

def try( theirs, mine )
  return @counters[theirs].include? mine
end

def counter( move )
  return @counters[move][rand(2)]
end

def follower( move )
  return @responses[(@moves[move]+1)%5]
end

def echo( move )
  return move
end

if ARGV[1] != nil
  for i in 2 .. ARGV[1].length - 1
    points = i > ARGV[1].length - 10 ? 10 - ( ARGV[1].length - i ) : 1
    if try( ARGV[1].split("")[i], counter( ARGV[0].split("")[i-1] ))
      scores[0] += points
    end
    if try( ARGV[1].split("")[i], follower( ARGV[0].split("")[i-1] ))
      scores[1] += points
    end
    if try( ARGV[1].split("")[i], echo( ARGV[0].split("")[i-1] ))
      scores[2] += points
    end
    if try( ARGV[1].split("")[i], counter( ARGV[1].split("")[i-1] ))
      scores[3] += points
    end
    if try( ARGV[1].split("")[i], follower( ARGV[1].split("")[i-1] ))
      scores[4] += points
    end
    if try( ARGV[1].split("")[i], echo( ARGV[1].split("")[i-1] ))
      scores[5] += points
    end
    if try( ARGV[1].split("")[i], counter( ARGV[1].split("")[i-2] ))
      scores[6] += points
    end
    if try( ARGV[1].split("")[i], follower( ARGV[1].split("")[i-2] ))
      scores[7] += points
    end
    if try( ARGV[1].split("")[i], echo( ARGV[1].split("")[i-2] ))
      scores[8] += points
    end
  end
end

bestId = -1;
bestScore = 0;

for j in 0 .. scores.length - 1
  if scores[j] > bestScore
    bestScore = scores[j]
    bestId = j
  end
end

if bestId == 0
  puts counter( ARGV[0].split("")[-1] )
elsif bestId == 1
  puts follower( ARGV[0].split("")[-1] )
elsif bestId == 2
  puts echo( ARGV[0].split("")[-1] )
elsif bestId == 3
  puts counter( ARGV[1].split("")[-1] )
elsif bestId == 4
  puts follower( ARGV[1].split("")[-1] )
elsif bestId == 5
  puts echo( ARGV[1].split("")[-1] )
elsif bestId == 6
  puts counter( ARGV[1].split("")[-2] )
elsif bestId == 7
  puts follower( ARGV[1].split("")[-2] )
elsif bestId == 8
  puts echo( ARGV[1].split("")[-2] )
else
  puts @responses[rand(5)]
end

```
> 3 votes

# Answer
# Algorithm

An algorithm for the sake of having one.

Cuz' it always feels safer doing something, the more complicated the better.

Haven't done some serious Math yet, so this algorithm may not be that effective.

```
import random, sys

if __name__ == '__main__':

    # Graph in adjacency matrix here
    graph = {"S":"PL", "P":"VR", "R":"LS", "L":"VP", "V":"SR"}
    try:
        myHistory = sys.argv[1]
        opHistory = sys.argv[2]
        choices = ""

        # Insert some graph stuff here. Newer versions may include advanced Math.
        for v in graph:
            if opHistory[-1] == v:
                for u in graph:
                    if u in graph[v]:
                        choices += graph[u]

        print random.choice(choices + opHistory[-1])

    except:
        print random.choice("RPSLV")

```

Python 2 program: `python algorithm.py`
> 3 votes

# Answer
# Haskell - MonadBot

I don't know if ghc is considered "within reason", but let's just assume it is. This bot's strategy is to counter its opponent's most popular move.

```
Compile: ghc monadbot.hs
Run:     ./monadbot [Arg1] [Arg2]

```

Code:

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

main :: IO ()
main = do
  args <- getArgs
  let moves = if not (null args) then args !! 1 else ""
      fave = if not (null moves) then head $ maximumBy (comparing length) (group $ sort moves) else 'V'
  putChar $ case fave of 'R' -> 'P'
                         'P' -> 'S'
                         'S' -> 'R'
                         'L' -> 'R'
                         'V' -> 'P'
                         _   -> 'V'

```
> 3 votes

# Answer
# SuperMarkov, Python

An improved version of the current Markov bot. Makes chains of length 0, 1, and 2, using either only our moves, only his moves, or both, to predict. Weighs the chains and picks what it expects the best result to be. Takes the result less seriously if the sample size is small.

```
Bot: SuperMarkov
Run: python SuperMarkov.py [Arg1] [Arg2]

```

Code:

```
import pprint
import sys
import random

if len(sys.argv) < 2:
    our_hist = opp_hist = "x"
else:
    our_hist = 'x'+sys.argv[1]
    opp_hist = 'x'+sys.argv[2]

hist = zip(opp_hist, our_hist)

def build_chains(length):
    chains = {}
    for typ in ('ours', 'theirs', 'both'):
        chain = {}
        for i in xrange(0, len(hist)-length):
            if typ == 'ours':
                prev = our_hist[i:i+length]
            elif typ == 'theirs':
                prev = opp_hist[i:i+length]
            elif typ == 'both':
                prev = tuple(hist[i:i+length])
            else:
                raise ValueError()
            next = opp_hist[i+length]
            if next == 'x':
                continue

            chain.setdefault(prev, {})
            if next not in chain[prev]:
                chain[prev][next] = 1
            else:
                chain[prev][next] += 1

        #normalize the chain
        # for prev in chain:
        #     total = sum(v for v in chain[prev].values())
        #     for next in list(chain[prev]):
        #         chain[prev][next] /= float(total)

        chains[typ] = chain

    return chains

beats = {
    "S": "LP",
    "P": "VR",
    "R": "SL",
    "L": "VP",
    "V": "SR",
}
beaten_by = {
    "S": "VR",
    "P": "SL",
    "R": "PV",
    "L": "SR",
    "V": "PL",
}

weighted_evs = dict((c, 0) for c in "SPRLV")
chain_weights = {0: 1, 1: 2, 2: 4}
chain_type_weights = {'theirs': 1, 'ours': 1, 'both': 3}

for L in (0, 1, 2):
    chains = build_chains(L)
    for typ, chain in chains.items():
        if typ == 'ours':
            this_prev = our_hist[-L:] if L > 0 else ''
        elif typ == 'theirs':
            this_prev = opp_hist[-L:] if L > 0 else ''
        elif typ == 'both':
            this_prev = tuple(hist[-L:]) if L > 0 else ()

        this_nexts = chain.get(this_prev, {})
        #print typ, this_prev, this_nexts
        sample_size = sum(v for v in this_nexts.values())
        if sample_size == 0:
            continue

        this_weight = chain_weights[L] * chain_type_weights[typ]
        if sample_size < 4:
            this_weight /= 4.0 - sample_size

        for choice in "SVPLR":
            ev = 0
            for which, count in this_nexts.items():
                if which == choice:
                    # push
                    continue
                elif which in beats[choice]:
                    ev += float(count)/sample_size
                elif which in beaten_by[choice]:
                    ev -= float(count)/sample_size
                else:
                    raise ValueError()
            #print "According to %s of length %d, picking %s gives EV %.3f" % (typ, L, choice, ev)
            weighted_evs[choice] += ev * this_weight

#pprint.pprint(weighted_evs)
print max("SPRLV", key=lambda choice: weighted_evs[choice])

```
> 3 votes

# Answer
# LoopholeAbuser

**I'm withdrawing this bot from the tourney now that the rules have been patched--without the sneakiness, it's basically a slightly worse version of Bart.**

```
@rules = {

  'L' => %w[V P],
  'P' => %w[V R],
  'R' => %w[L S],
  'S' => %w[P L],
  'V' => %w[R S]
}

@moves = @rules.keys

def defeats?(move1, move2)
  @rules[move1].include?(move2)
end

def score(move1, move2)
  if move1 == move2
    0
  elsif defeats?(move1, move2)
    1
  else
    -1
  end
end

def move
  player, opponent = ARGV

  case player.to_s.size
  when 0
    'P'
  when 1
    'R'*100
  when 2
    'L'
  when 3
    'S'
  when 4
    'V'
  else
    extrapolate(player, opponent)
  end

end

def extrapolate(player,opponent)
  likelihoods = Hash.new {0}

  opponent_last_move = opponent[-1]
  @moves.each { |m| likelihoods[m] += opponent.scan(opponent_last_move + m).size }

  my_last_move = player[-1]
  reactions = player.chars.zip(opponent.chars.drop(1))
  @moves.each { |m| likelihoods[m] += reactions.count([my_last_move, m]) }

  @moves.shuffle.max_by do |m|
    likelihoods.map{ |n,c| score(m,n) * c }.reduce(:+)
  end
end

puts move

```

Just doing these because for once I want to get to the loopholes before other people. If you consider this to be legal (it doesn't throw an error or cause an opponent to throw an error, but it does forfeit a round), run with `ruby loophole_abuser.rb`.
> 3 votes

# Answer
CounterPreference bot PHP

First response on this site, lets hope I get it right.

First round it responds randomly. From there it analyses the opponents hand and plans a counter, but if the opponents has a history of predicting this correctly, it will try to avoid falling for that trap again.

Thanks Martin for pointing out my oversight. I have to admit I do not have any experience with command-line and php. But if I understand it correctly it should work as this. Il test it out when I am on a machine I can access the command line with.

Well, this is turning out to be quite educative. Sadly still not able to test. So I apologize if it still does not work.

```
<?php

$input = $argv;

counterPreferenceBot($input[1], $input[2]);

function counterPreferenceBot($myHandHistory = null, $opponentHandHistory = null)
{

//No Arugments supplied
    if($myHandHistory == null)
    {
        //Random!
        $choices = array("R", "P", "S", "L", "V");
        echo $choices[rand(0, 4)];
    }
    else
    {
        //Arguments supplied
        //Make list of avaiable options
        $r = 0;
        $p = 0;
        $s = 0;
        $l = 0;
        $v = 0;
        foreach($opponentHandHistory as $round => $oppentChoice)
        {
            //Find opponents weaknesses on which it used most.
            if($oppentChoice == "R"){$p++; $v++;}
            else if($oppentChoice == "P"){$s++; $l++;}
            else if($oppentChoice == "S"){$v++; $r++;}
            else if($oppentChoice == "L"){$s++; $r++;}
            else if($oppentChoice == "V"){$l++; $p++;}

            //But avoid falling into whatever clever trap the enemy uses.
            if($myHandHistory[$round] == "R" AND ($oppentChoice == "P" OR $oppentChoice == "V"))
            {   $r--;
            }else if($myHandHistory[$round] == "P" AND ($oppentChoice == "S" OR $oppentChoice == "L"))
            {   $p--;
            }else if($myHandHistory[$round] == "S" AND ($oppentChoice == "V" OR $oppentChoice == "R"))
            {   $s--;
            }else if($myHandHistory[$round] == "L" AND ($oppentChoice == "S" OR $oppentChoice == "R"))
            {   $l--;
            }else if($myHandHistory[$round] == "V" AND ($oppentChoice == "L" OR $oppentChoice == "P"))
            {   $v--;
            }
        }

        $result = array("R" => $r, "P" => $p, "S" => $s, "L" => $l, "V" => $v);
        //Handsomely stolen code from Micheal Angel to sort those 5 ints into the highest for the right choice.
        $maxvalue = max($result);
        while(list($key,$value)=each($result)){
            if($value==$maxvalue)$maxindex=$key;
        }
        $choice = array("m"=>$maxvalue,"i"=>$maxindex);

        echo $choice['i'];
    }
}

?>

```
> 3 votes

# Answer
# Uniform (Ruby)

```
BotName: Uniform
Run:     ruby uniform.rb [Mine] [Theirs]

```

Code

```
@counters = { "R" => [ "P", "V" ], "P" => [ "S", "L" ], "S" => [ "V", "R" ], "L" => [ "R", "S" ], "V" => [ "P", "L" ] }
@counts = { "R" => 0, "S" => 0, "P" => 0, "V" => 0, "L" => 0 }

choices = []

if( ARGV != nil && ARGV[0] != nil )

  mine = ARGV[0].split("")
  theirs = ARGV[1].split("")

  c = @counts.clone

  if( mine.length < 50 )
    if( mine.length.even? )
      mine.values_at(* mine.each_index.select {|i| i.even?}).each {|x| c[x]+=1}
      @counts.keys.each {|x| if( c[x]>4 ) then c.delete(x) end}
    else
      mine[0..-1].each_index.select {|i| i.even?}.each {|x| if( mine[x]==mine[-1] ) then c.delete(mine[x+1]) end}
    end
    choices = c.keys
  else
    c2 = @counts.clone
    for i in 0 .. mine.length - 3
      if( mine[i..i+1].join == mine[-2..-1].join ) then c[theirs[i+2]]+=1 end
    end
    bestCount = 0
    @counters.keys.each {|x| @counters[x].each {|y| c2[y]+=c[x];c2[x]+=c[x]*0.4}}
    @counters.keys.each {|x| if( c2[x] > bestCount ) then bestCount = c2[x] end}
    @counters.keys.each {|x| if( c2[x] == bestCount ) then choices.push( x ) end}
  end
else
  choices = @counters.keys
end

puts choices.sample

```
> 3 votes

# Answer
## LemmingBot

Yep, this is a lemming and his only goal is to die (lose each game). But because he isn't that smart, he always hopes for the other player to make the last move again.

```
import sys, random

def totallyRandomStarterPick() :
    return "P"    ### Chosen by fair dice roll

picks = { "S" : "PL", "P" : "RV", "R" : "LS", "L" : "VP", "V" : "SR" }
confused = lambda p : random.choice(picks[p])

try :
    opn = sys.argv[-1][-1]
    print(confused(opn))    ### Kill me!
except Exception :
    print(totallyRandomStarterPick())

```

Written in Python 2.7, run with `python LemmingBot.py [args1] [args2]` (args1 = own hands, args2 = opponents hands).

Please help him, he really wants to die :(

**EDIT:** LemmingBot goes mad. Added a bit of randomness for confusing his opponents (and himself).
> 3 votes

# Answer
# Java - SelfHatingBot

```
BotName: SelfHatingBot
Compile: Save as 'SelfHatingBot.java'; compile.
Run:     java SelfHatingBot [me] [them]

```

Bot starts randomly, then always plays a winning move against its own prior move with 50% choice of tactic.

```
import java.util.Random;

public class SelfHatingBot {

    static final Random RANDOM = new Random();

    private static char randomPlay() {

        switch (RANDOM.nextInt(5)) {

            case 0 : return 'R';

            case 1 : return 'P';

            case 2 : return 'S';

            case 3 : return 'L';

            default : return 'V';
        }
    }

    private static char antiPlay(String priorPlayString) {

        char[] priorPlays = priorPlayString.toCharArray();

        int choice = RANDOM.nextInt(2);

        switch (priorPlays[priorPlays.length - 1]) {

            case 'R' : return choice == 0 ? 'P' : 'V';

            case 'P' : return choice == 0 ? 'S' : 'L';

            case 'S' : return choice == 0 ? 'V' : 'R';

            case 'L' : return choice == 0 ? 'R' : 'S';

            default : return choice == 0 ? 'L' : 'P'; // V
        }
    }

    public static void main(String[] args) {

        char play;

        if (args.length == 0) {

            play = randomPlay();

        } else {

            play = antiPlay(args[0]);
        }

        System.out.print(play);
        return;
    }
}

```
> 3 votes

# Answer
## Edward Scissorhands

No one had made a Scissor spam bot, so I did.

```
puts 'S'

```

Run as

```
ruby EdwardScissorhands.rb

```

---

## Daenerys Targaryen

No one had made a Lizards spam bot either, so I did that too. Rains fire down on her enemies.

```
puts 'L'

```

Run as

```
ruby Khaleesi.rb

```
> 3 votes

# Answer
# Gazzr

This bot looks at the played games and tries to guess how to beat the enemy:

```
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;

public class Gazzr {

    private static final int DEPTH = 3;
    private final List<String> moves = Arrays.asList(new String[] { "R", "L", "V", "S", "P" });
    private final String[] beatIndex = new String[] { "PV", "RS", "PL", "RV", "LS" };
    private final List<String> loseFromIndex = Arrays.asList(new String[] { "LS", "PV", "RS", "PL", "RV" });
    private final Random random = new Random();

    public static void main(final String[] args) {
        System.out.println(new Gazzr().play(args));;
    }

    public String play(final String[] args) {
        if (args == null || args.length == 0 || args[0].length() < DEPTH) {
            return moves.get(random.nextInt(moves.size()));
        }
        final Map<String, float[]> oppHistDb = new HashMap<String, float[]>();
        final Map<String, float[]> myHistDb = new HashMap<String, float[]>();
        final char[] oppMoves = args[1].toCharArray();
        int i = DEPTH;
        while(i < args[0].length()) {
            updateDB(args[0].substring(i-DEPTH, i), oppMoves[i], myHistDb);
            updateDB(args[1].substring(i-DEPTH, i), oppMoves[i], oppHistDb);
            i++;
        }
        //Predict based on own and opponent moves:
        Integer p1 = predict(args[0].substring(i-DEPTH, i), myHistDb);
        Integer p2 = predict(args[1].substring(i-DEPTH, i), oppHistDb);
        if(p1 == null && p2 == null) {
            return moves.get(random.nextInt(moves.size()));
        }
        if(p2 == null) {
            return "" + beatIndex[p1].charAt(random.nextInt(2));
        } else if(p1 == null) {
            return "" + beatIndex[p2].charAt(random.nextInt(2));
        }
        String s1 = moves.get(p1)+moves.get(p2);
        String s2 = moves.get(p2)+moves.get(p1);
        if(loseFromIndex.contains(s1)) {
            return moves.get(loseFromIndex.indexOf(s1));
        }
        if(loseFromIndex.contains(s2)) {
            return moves.get(loseFromIndex.indexOf(s2));
        }
        if(random.nextBoolean()) {
            return ""+ beatIndex[p1].charAt(random.nextInt(2));
        } else {
            return ""+ beatIndex[p2].charAt(random.nextInt(2));
        }
    }

    private void updateDB(String lastMoves, char nextMove, Map<String, float[]> database) {
        int oppIndex = moves.indexOf("" + nextMove);
        float[] distr = database.get(lastMoves);
        if(distr == null) {
            distr = new float[5];
        }
        distr[oppIndex] += 1.0f;
        database.put(lastMoves, distr);
    }

    public Integer predict(String historicMoves, Map<String, float[]> database) {
        final float[] distr = database.get(historicMoves);
        if(distr == null) {
            return null;
        }
        return predictFromArray(distr);
    }

    private Integer predictFromArray(final float[] distr) {
        float total = 0f;
        for(int i = 0;i<distr.length;i++) {
            total += distr[i];
        }
        float target = total * random.nextFloat();
        total = 0f;
        for(int i = 0;i<distr.length;i++) {
            total += distr[i];
            if(total > target) {
                return i;
            }
        }
        return distr.length - 1;
    }
}

```

Bug fixes:

* Tournament round #1: Bot came in last, a bug was causing it to try to lose instead of win
* (X beats Y, bot predicts opponent plays X, play Y!) #epic
> 3 votes

# Answer
## YAAR (Yet Another Arcane Run-time)

If Google's V8 JavaScript Engine is installed (this all depends how far is @eoin-campbell willing to go? ;) )

jsBot.js:

```
var HAND=["R", "P", "S", "L", "V"];
print(HAND[Math.floor(Math.random() * 5)]);

```

and run it like so:

```
d8 jsBot.js

```

---

If compiling V8 is too much effort, Node.JS would also be able to run this, provided that `print` is changed to `console.log`.

The Spidermonkey jsshell would also work without modifications (precompiled builds on Mozilla's FTP server).
> 2 votes

# Answer
# RandomlyWeighted (Ruby)

Bot name: `RandomlyWeighted`.

Run it with `ruby randomly_weighted_rpslv.rb`. Tested to work with Ruby versions 1.8.7, 2.0.0, and 2.1.2.

In the first round, this bot randomly decides which of the options it likes most and least – you can think of it as choosing its personality or its priorities. The bot assigns each of the five options a unique probability from the list `[0.1, 0.1, 0.2, 0.2, 0.4]`. In all rounds after the first, it sticks to those same probabilities when choosing what option to throw.

The bot stores its chosen probabilities in a file `priorities.marshal-rb` in the `Data` folder.

`randomly_weighted_rpslv.rb`
```
DATA_FOLDER_PATH = begin
  dir_of_this_program = File.expand_path(File.dirname(__FILE__))
  File.join(dir_of_this_program, "Data")
end

module Priorities
  PRIORITIES_FILE_PATH = File.join(DATA_FOLDER_PATH, "priorities.marshal-rb")

  def self.priorities
    begin
      load_saved_priorities
    rescue Errno::ENOENT => e
      # file doesn't exist yet; it's the first round
      chosen_priorities = choose_priorities_randomly
      save_priorities(chosen_priorities)
      chosen_priorities
    rescue IOError => e
      $stderr.puts "Error: priorities file exists, but could not read it."
      $stderr.puts "Fix its permissions or something."
      exit(1)
    end
  end

  private

  def self.choose_priorities_randomly
    probability_spread = [0.1, 0.1, 0.2, 0.2, 0.4]
    options = ['R', 'P', 'S', 'L', 'V']
    paired_options_and_probs = options.shuffle.zip(probability_spread)
    Hash[paired_options_and_probs]
  end

  def self.load_saved_priorities
    File.open(PRIORITIES_FILE_PATH, 'r') do |priorities_file|
      Marshal.load(priorities_file)
    end
  end

  def self.save_priorities(priorities_to_save)
    Dir.mkdir(DATA_FOLDER_PATH)
    File.open(PRIORITIES_FILE_PATH, 'w') do |priorities_file|
      Marshal.dump(priorities_to_save, priorities_file)
    end
  end
end

def prioritized_random_choice(priorities)
  # precondition: the probabilities in `priorities` add up to 1

  remaining_probability_needed = rand
  priorities.to_a.shuffle.each do |option, probability|
    remaining_probability_needed -= probability
    if remaining_probability_needed < 0
      return option
    end
  end
end

puts prioritized_random_choice(Priorities.priorities)

```
> 2 votes

# Answer
# Might As Well Be Random

Yeah, I wouldn't expect much from this guy. ~~Never have I ever written a perl script this long before.~~ That's because I wasn't using half of the code :P

```
use strict;
use warnings;
use Carp qw(croak);

###Stolen from List::Util::ChooseWeighted (with love)
sub choose_weighted{
    my ($objects, $weightsArg ) = @_;
    my $calcWeight = $weightsArg if 'CODE' eq ref $weightsArg;
    my @weights;        # fix wasteful of memory
    if( $calcWeight){
    @weights =  map { $calcWeight->($_) } @$objects;
    }
    else{
    @weights =@$weightsArg;
    if ( @$objects != @weights ){
        croak "given arefs of unequal lengths!";
    }
    }

    my @ranges = ();        # actually upper bounds on ranges
    my $left = 0;
    for my $weight( @weights){
    $weight = 0 if $weight < 0; # the world is hostile...
    my $right = $left+$weight;
    push @ranges, $right;
    $left = $right;
    }
    my $weightIndex = rand $left;
    for( my $i =0; $i< @$objects; $i++){
    my $range = $ranges[$i];
    return $objects->[$i] if $weightIndex < $range;
    }
}
###Credit to Danny Sadinof for choose_weighted code

sub getmove {
    my (@opponenthistory) = @_;
    if(~~@opponenthistory == 0) {
        return ~~(5*rand());
    }
    my %mapper = qw(R 0 P 1 S 2 V 3 L 4);
    @opponenthistory = map {$mapper{$_}} @opponenthistory;
    my %counts = (
        0 => 0,
        1 => 0,
        2 => 0,
        3 => 0,
        4 => 0);
    $counts{$_}++ for @opponenthistory;
    my @keys = keys %counts;
    my @values = values %counts;
    my $choice = choose_weighted(\@keys, \@values);
    return ($choice + 1) % 4;
}

if(~~@ARGV == 0) {
    print qw/R P S V L/[~~(5*rand())];
    exit;
}
my ($myhistory, $opponenthistory) = @ARGV;

print qw/R P S V L/[getmove(split //, $opponenthistory)];

```

run as

```
perl mightaswellberandom.pl

```
> 2 votes

# Answer
# Herpetologist

This one's in Python 3. He really likes lizards for some reason.

```
from sys import argv
from random import choice
print("PLSVR"[len(argv)<2 or "RVPSL".index(sorted([choice(argv[2]) for i in range(12)], key=lambda *a:argv[1].count(a[0]))[choice([0, 1])])])

```
> 2 votes

# Answer
## CasinoShakespeare

Description:

Shakespeare wants to be famous so he feels ok with playing your game. He needs a moment to recall something wise from memory(aka website with quotes) so please don't be too hard on him.

Code:

```
using System;
using System.Linq;
using System.Net;

namespace CasinoShakespeare
{
    class CasinoShakespeare
    {
        private static void Main()
        {
            try
            {
                char[] ar = {'R', 'P', 'S', 'L', 'V'};
                var a = new WebClient().DownloadString("http://www.iheartquotes.com/api/v1/random").Select(char.ToUpperInvariant).FirstOrDefault(ar.Contains);
                Console.WriteLine(a == default(char) ? 'S' : a);
            }
            catch (Exception)
            {
                Console.WriteLine("R");
            }
        }
    }
}

```

First compile with: `csc.exe CasinoShakespeare.cs` then run: `CasinoShakespeare.exe`
> 2 votes

# Answer
# GitGudBot

```
class Progressive
    def main
        args = CobraCore.commandLineArgs
        rng = Random()
        if args.count == 1, Console.write('RPSLV'[rng.next(5)])
        else
            them = List<of char>(args[2].toCharArray)
            me = List<of char>(args[1].toCharArray)
            options = List<of char>()
            for num in me.count
                if '[me[num]][them[num]]' in ['SP','PR','RL','LV','VS','SL','PV','RS','LP','VR'], options.add(me[num])
                else if '[them[num]][me[num]]' in ['SP','PR','RL','LV','VS','SL','PV','RS','LP','VR'], options.add(them[num])
                else, pass
            while options.count > 1
                options.reverse
                if rng.next(3) == 0, break
                else, options.pop
            Console.write(if(options.count,options.last,'RPSLV'[rng.next(5)]))

```

Written in Cobra, which should be easy to install if you've already got a Visual Studio package on the machine. If not, install any VS package, then install Cobra, then add `C:\Cobra\bin` to your %PATH%. If you don't feel like changing your %PATH%, simply copy `cobra.bat` from `C:\Cobra\bin` to the directory with the source file in it.

Compile & Run: `cobra GitGudBot -- [arg1] [arg2]`

-OR-

Compile: `cobra GitGudBot`

Run: `GitGudBot [arg1] [arg2]`
> 2 votes

# Answer
# Bart

```
@rules = {

  'L' => %w[V P],
  'P' => %w[V R],
  'R' => %w[L S],
  'S' => %w[P L],
  'V' => %w[R S]
}

@moves = @rules.keys

def defeats?(move1, move2)
  @rules[move1].include?(move2)
end

def score(move1, move2)
  if move1 == move2
    0
  elsif defeats?(move1, move2)
    1
  else
    -1
  end
end

def move
  player, opponent = ARGV

  case player.to_s.size
  when 0..19
    'R'
  when 20..30
    opponent.count('P') > opponent.count('V') ? 'S' : 'L'
  else
    extrapolate(player, opponent)
  end

end

def extrapolate(player,opponent)
  likelihoods = Hash.new {0}

  opponent_last_move = opponent[-1]
  @moves.each { |m| likelihoods[m] += opponent.scan(opponent_last_move + m).size }

  my_last_move = player[-1]
  reactions = player.chars.zip(opponent.chars.drop(1))
  @moves.each { |m| likelihoods[m] += reactions.count([my_last_move, m]) }

  @moves.shuffle.max_by do |m|
    likelihoods.map{ |n,c| score(m,n) * c }.reduce(:+)
  end
end

puts move

```

Ruby, run with `ruby bart.rb`. Good old rock, nothing beats it.
> 2 votes

# Answer
# Alternator

`ruby alternator.rb`

```
@rules = {

  'L' => %w[V P],
  'P' => %w[V R],
  'R' => %w[L S],
  'S' => %w[P L],
  'V' => %w[R S]
}

@moves = @rules.keys

def defeats?(move1, move2)
  @rules[move1].include?(move2)
end

def score(move1, move2)
  if move1 == move2
    0
  elsif defeats?(move1, move2)
    1
  else
    -1
  end
end

def move
  player, opponent = ARGV
  i = player.to_s.size
  case
  when i < 5
    @moves[player.to_s.size]
  when i.even?
    @moves.shuffle.min_by{|m|player.count(m)}
  else
    extrapolate(player, opponent)
  end

end

def extrapolate(player,opponent)
  likelihoods = Hash.new {0}

  opponent_last_move = opponent[-1]
  @moves.each { |m| likelihoods[m] += opponent.scan(opponent_last_move + m).size }

  my_last_move = player[-1]
  reactions = player.chars.zip(opponent.chars.drop(1))
  @moves.each { |m| likelihoods[m] += reactions.count([my_last_move, m]) }

  @moves.shuffle.max_by do |m|
    likelihoods.map{ |n,c| score(m,n) * c }.reduce(:+)
  end
end

puts move

```

On odd numbered moves, tries to predict the opponent. On even numbered moves, tries to be unpredictable.
> 2 votes

# Answer
# Q - Cobra

Named after the near-omnipotent being(s) in the Star Trek universe, Q plays the long game, makes no mistakes, and watches everything.

For the first game in a tournament run, it will choose a random option.

For the first game in each round, it will choose the option most likely to win against all moves previously played in the tournament. If two options are equal in likelihood, it will choose the least used one. If there is still a tie, it will randomly select from the remaining choices.

For every other game in each round, the following selection algorithm is used:

```
A = Chance of the current opponent choosing the given move in response to my last move
B = Certainty that the opponent's choices of the given move are dependent on my moves
X = Chance of any opponent choosing the given move in response to my last move
Y = Certainty that any opponent's choices of the given move are dependent on my moves
M = Current game number
N = Win/lose/tie against the given choice (+2,+1,-2)

Move weighting = A*B*N*M/10 + X*Y*N

```

Breaking ties with the least selected option, and breaking secondary ties with `Random()`

(uses uint64 in case the round-lengths become rather large)

```
@number float
class Bot
    def main
        index = {c'R':0,c'P':1,c'S':2,c'L':3,c'V':4}
        win = @[@[2,3],@[0,4],@[1,3],@[1,4],@[0,2]]
        lose = @[@[1,4],@[2,3],@[0,4],@[0,2],@[1,3]]
        args = CobraCore.commandLineArgs
        rng = Random()
        path = CobraCore.exePath.split('\\')[:-1].join('\\')+'\\data'
        if not Directory.exists(path), Directory.createDirectory(path)
        past_history = [List<of uint64>(uint64[](5)),List<of uint64>(uint64[](5)),List<of uint64>(uint64[](5)),List<of uint64>(uint64[](5)),List<of uint64>(uint64[](5))]
        past_frequency = List<of uint64>(uint64[](5))
        if File.exists(path+'\\history.txt')
            new_game = false
            for num, line in File.readAllLines(path+'\\history.txt').numbered
                for n in 5
                    past_history[num][n] = uint64.parse(line.split[n])
                    past_frequency[n] += uint64.parse(line.split[n])
        else, new_game = true
        if new_game, Console.write('RPSLV'[rng.next(5)])
        else if args.count <> 3 or if(args.count<>3,false,args[2].length<2)
            options = List<of float>(float[](5))
            for n in 5
                all_weight = past_frequency[n]/if(.sum(past_frequency),.sum(past_frequency),1)
                for m in win[n]
                    options[m] += all_weight*2
                options[n] += all_weight
                for m in lose[n]
                    options[m] -= all_weight*2
            temp_selection = List<of int>()
            for num, o in options.numbered
                if o == options.sorted.last
                    temp_selection.add(num)
            Console.write('RPSLV'[temp_selection[rng.next(temp_selection.count)]])
        else
            this_history = [List<of uint64>(uint64[](5)),List<of uint64>(uint64[](5)),List<of uint64>(uint64[](5)),List<of uint64>(uint64[](5)),List<of uint64>(uint64[](5))]
            this_frequency = List<of uint64>(uint64[](5))
            old_history = [List<of uint64>(uint64[](5)),List<of uint64>(uint64[](5)),List<of uint64>(uint64[](5)),List<of uint64>(uint64[](5)),List<of uint64>(uint64[](5))]
            old_frequency = List<of uint64>(uint64[](5))
            if args[1].length > 10
                for num, move in args[1][:args[1].length-11].numbered
                    old_history[index[move]][index[args[2][num+1]]] += 1
                    old_frequency[index[args[2][num+1]]] += 1
                for num, move in args[1][args[1].length-11:-1].numbered
                    this_history[index[move]][index[args[2][num+1]]] += 1
                    this_frequency[index[args[2][num+1]]] += 1
            else
                for num, move in args[1][:-1].numbered
                    this_history[index[move]][index[args[2][num+1]]] += 1
                    this_frequency[index[args[2][num+1]]] += 1
            me_last = index[args[1][args[1].length-1]]
            them_last = index[args[2][args[2].length-1]]
            turns = args[1].length
            options = List<of float>(float[](5))
            for n in 5
                this_rchan = this_history[me_last][n]/if(.sum(this_history[me_last]),.sum(this_history[me_last]),1)
                this_rcert = this_history[me_last][n]/(if(this_frequency[me_last],this_frequency[me_last],1)/5f)
                this_weight = (this_rchan*this_rcert)*if(turns>10,2f,turns/5)
                old_rchan = old_history[me_last][n]/if(.sum(old_history[me_last]),.sum(old_history[me_last]),1)
                old_rcert = old_history[me_last][n]/(if(old_frequency[me_last],old_frequency[me_last],1)/5f)
                old_weight = (old_rchan*old_rcert)/if(20-turns>0,20-turns,1)
                all_rchan = past_history[me_last][n]/if(.sum(past_history[me_last]),.sum(past_history[me_last]),1)
                all_rcert = past_history[me_last][n]/(if(past_frequency[me_last],past_frequency[me_last],1)/5f)
                all_weight = (all_rchan*all_rcert)/(Math.log(turns)/1.5f)
                for m in win[n]
                    options[m] -= this_weight*2 + old_weight*2 + all_weight*2
                options[n] -= this_weight + old_weight + all_weight
                for m in lose[n]
                    options[m] += this_weight*2 + old_weight*2 + all_weight*2
            temp_selection = List<of int>()
            for num, o in options.numbered
                if o == options.sorted.last
                    temp_selection.add(num)
            Console.write('RPSLV'[temp_selection[rng.next(temp_selection.count)]])
            past_history[index[args[1][args[1].length-2]]][them_last] += 1

        # write the history file
        record = List<of String>()
        for entry in past_history
            record.add(entry.join(' '))
        File.writeAllLines(path+'\\history.txt',record)

    def sum(list as List<of uint64>) as uint64
        num = 0u64
        for entry in list, num += entry
        return num

```

Written in Cobra, which should be easy to install if you've already got a Visual Studio package on the machine. If not, install any VS package, then install Cobra, then add `C:\Cobra\bin` to your %PATH%. If you don't feel like changing your %PATH%, simply copy `cobra.bat` from `C:\Cobra\bin` to the directory with the source file in it.

Compile & Run: `cobra Q -- [arg1] [arg2]`

-OR-

Compile: `cobra Q`

Run: `Q [arg1] [arg2]`

NOTE: to update to a newer version of the bot, delete the old executable before compiling
> 2 votes

# Answer
## Java - DogeBot

Basically just looks for a pattern of two consecutive hands and beats it. If it can't find a pattern, it just beats whatever the last hand was. And if the number of last hands is less than two or it's a new game, it just prints P.

```
public class DogeBot {
     public static void main(String []args){

        if (args.length < 2) {
            System.out.println("P");
            return;
        }

        String yourHistory = args[1];

        if (yourHistory.length() < 2) {
            System.out.println("P");
            return;
        }

        String possibleHands = "RPSLV";

        for (int i = 0; i < 5; i++) {
            String searchString = "" + possibleHands.charAt(i) + possibleHands.charAt(i);

            if (yourHistory.contains(searchString)) {

                char newHand = possibleHands.charAt((i + 2) % 5);
                System.out.println(newHand == 'S' ? "P" : newHand);

                return;
            } else continue;

        }

        char lastHistoryHand = yourHistory.charAt(yourHistory.length() - 1);
        int i = possibleHands.indexOf(lastHistoryHand);

        char newHand = possibleHands.charAt((i + 2) % 5);
        System.out.println(newHand == 'S' ? "P" : newHand);

        return;
    }
}

```
> 2 votes

# Answer
# Deja\_Q - Cobra

Similar to the first Q, but it doesn't record history of past matches. Fares much better against opponents that attempt to analyse its patterns.

```
@number float
class Bot
    def main
        index = {c'R':0,c'P':1,c'S':2,c'L':3,c'V':4}
        win = @[@[2,3],@[0,4],@[1,3],@[1,4],@[0,2]]
        lose = @[@[1,4],@[2,3],@[0,4],@[0,2],@[1,3]]
        args = CobraCore.commandLineArgs
        rng = Random()
        if args.count <> 3
            Console.write('RPSLV'[rng.next(5)])
        else if args[2].length < 2
            Console.write('RPSLV'[lose[index[args[2][0]]][rng.next(2)]])
            options = List<of float>(float[](5))
        else
            this_history = [List<of uint64>(uint64[](5)),List<of uint64>(uint64[](5)),List<of uint64>(uint64[](5)),List<of uint64>(uint64[](5)),List<of uint64>(uint64[](5))]
            this_frequency = List<of uint64>(uint64[](5))
            old_history = [List<of uint64>(uint64[](5)),List<of uint64>(uint64[](5)),List<of uint64>(uint64[](5)),List<of uint64>(uint64[](5)),List<of uint64>(uint64[](5))]
            old_frequency = List<of uint64>(uint64[](5))
            if args[1].length > 10
                for num, move in args[1][:args[1].length-11].numbered
                    old_history[index[move]][index[args[2][num+1]]] += 1
                    old_frequency[index[args[2][num+1]]] += 1
                for num, move in args[1][args[1].length-11:-1].numbered
                    this_history[index[move]][index[args[2][num+1]]] += 1
                    this_frequency[index[args[2][num+1]]] += 1
            else
                for num, move in args[1][:-1].numbered
                    this_history[index[move]][index[args[2][num+1]]] += 1
                    this_frequency[index[args[2][num+1]]] += 1
            me_last = index[args[1][args[1].length-1]]
            them_last = index[args[2][args[2].length-1]]
            turns = args[1].length
            options = List<of float>(float[](5))
            for n in 5
                this_rchan = this_history[me_last][n]/if(.sum(this_history[me_last]),.sum(this_history[me_last]),1)
                this_rcert = this_history[me_last][n]/(if(this_frequency[me_last],this_frequency[me_last],1)/5f)
                this_weight = this_rchan*this_rcert*2
                old_rchan = old_history[me_last][n]/if(.sum(old_history[me_last]),.sum(old_history[me_last]),1)
                old_rcert = old_history[me_last][n]/(if(old_frequency[me_last],old_frequency[me_last],1)/5f)
                old_weight = old_rchan*old_rcert
                for m in win[n]
                    options[m] -= this_weight*2 + old_weight*2
                options[n] -= this_weight + old_weight
                for m in lose[n]
                    options[m] += this_weight*2 + old_weight*2
            temp_selection = List<of int>()
            for num, o in options.numbered
                if o == options.sorted.last
                    temp_selection.add(num)
            Console.write('RPSLV'[temp_selection[rng.next(temp_selection.count)]])

    def sum(list as List<of uint64>) as uint64
        num = 0u64
        for entry in list, num += entry
        return num

```

Compile & Run: `cobra Deja_Q -- [arg1] [arg2]`

-OR-

Compile: `cobra Deja_Q`

Run: `deja_q [arg1] [arg2]`
> 2 votes

# Answer
# IHaveNoIdeaWhatImDoing - Common Lisp (SBCL-specific)

```
BotName: IHaveNoIdeaWhatImDoing
Compile: sbcl --load rpsvl.lisp --eval "(sb-ext:save-lisp-and-die \"rpsvl.exe\" :toplevel #'main :executable t)"
Run:     rpsvl.exe [MyArgs] [HisArgs]

```

Code:

```
;; Utility ;;
;;;;;;;;;;;;;

(defconstant +possible-moves+ '((paper . #\p) (scissors . #\s) (rock . #\r) (lizard . #\l) (spock . #\v)))

;; Split input string at delim
(defun split-string (string delim)
  (loop for i = 0 then (1+ j)
       as j = (position delim string :start i)
       collect (subseq string i j)
       while j))

(defun get-move (ch)
  (let ((early-move (car (rassoc (char-downcase ch) +possible-moves+))))
    (if (not early-move)
        'forfeit
        early-move)))

;; Take input string and turn into list of symbols for moves
(defun get-moves (string)
  (let ((move-list (coerce string 'list)))
    (loop for ch in move-list
         collect (get-move ch))))

;; Get his moves
(defun get-args ()
  (get-moves (caddar (split-string *posix-argv* #\Space))))

;; Game Logic ;;
;;;;;;;;;;;;;;;;

;; Randomly select move from list
(defun get-random-move ()
  (cdr
   (nth
    (random (list-length +possible-moves+))
    +possible-moves+)))

;; Return list of move counts for input moveset
(defun count-moves (move-set)
  (let ((keys (remove-duplicates move-set)))
    (let ((counts
           (loop for key in keys
                collect (count key move-set))))
      (mapcar #'list keys counts))))

;; Select highest move used from previous moves ignoring ties
(defun max-move (move-list)
  (loop for move in move-list
       with max = (car move-list)
       when (< (cadr max) (cadr move)) do (setf max move)
       finally (return (car max))))

;; Make an educated guess at their next input
(defun parse-input (move-set)
  (let ((move (max-move (count-moves move-set))))
    (cond
      ((eq 'paper    move) #\L)
      ((eq 'scissors move) #\R)
      ((eq 'rock     move) #\V)
      ((eq 'lizard   move) #\S)
      ((eq 'spock    move) #\P)
      (t (get-random-move)))))

;; Main Function ;;
;;;;;;;;;;;;;;;;;;;
(defun main ()
  ;; Reseed RNG
  (setf *random-state* (make-random-state t))
  (let ((input (get-args)))
    (if (< (list-length input) 3)
        (princ (char-upcase (get-random-move)))
        (princ (char-upcase (parse-input input))))))

```

First time submitting, please let me know if I did something not to expectations. You can compile this just using Steel Bank Common Lisp REPL after loading it or by using buildapp. I can also provide a binary if you want.

Let me know what you guys think, thanks!
> 2 votes

# Answer
# QQ - Cobra

```
@number float

class Bot

    def main

        index = {c'R':0,c'P':1,c'S':2,c'L':3,c'V':4}
        win = @[@[2,3],@[0,4],@[1,3],@[1,4],@[0,2]]
        lose = @[@[1,4],@[2,3],@[0,4],@[0,2],@[1,3]]
        args = CobraCore.commandLineArgs
        rng = Random()
        path = CobraCore.exePath.split('\\')[:-1].join('\\')+'\\data'

        #ensure data directory exists
        if not Directory.exists(path), Directory.createDirectory(path)

        #read history from the data directory, and check if it's a new tournament
        past_history = [List<of uint64>(uint64[](5)),List<of uint64>(uint64[](5)),List<of uint64>(uint64[](5)),List<of uint64>(uint64[](5)),List<of uint64>(uint64[](5))]
        past_frequency = List<of uint64>(uint64[](5))
        if File.exists(path+'\\history.txt')
            new_game = false
            for num, line in File.readAllLines(path+'\\history.txt').numbered
                for n in 5
                    past_history[num][n] = uint64.parse(line.split[n])
                    past_frequency[n] += uint64.parse(line.split[n])
        else, new_game = true

        #make the move
        this_history = [List<of uint64>(uint64[](5)),List<of uint64>(uint64[](5)),List<of uint64>(uint64[](5)),List<of uint64>(uint64[](5)),List<of uint64>(uint64[](5))]
        this_frequency = List<of uint64>(uint64[](5))
        if new_game, Console.write('RPSLV'[rng.next(5)])
        else if args.count <> 3
            options = List<of float>(float[](5))
            for n in 5
                all_weight = past_frequency[n]/if(.sum(past_frequency),.sum(past_frequency),1)
                for m in win[n]
                    options[m] += all_weight*2
                options[n] += all_weight
                for m in lose[n]
                    options[m] -= all_weight*2
            temp_selection = List<of int>()
            for num, o in options.numbered
                if o == options.sorted.last
                    temp_selection.add(num)
            Console.write('RPSLV'[temp_selection[rng.next(temp_selection.count)]])
        else
            for num, move in args[1].numbered
                this_history[index[move]][index[args[2][num]]] += 1
                this_frequency[index[move]] += 1
                this_frequency[index[args[2][num]]] += 1
            me_last = index[args[1][args[1].length-1]]
            them_last = index[args[2][args[2].length-1]]
            turns = args[1].length
            options = List<of float>(float[](5))
            for n in 5
                this_rchan = this_history[me_last][n]/if(.sum(this_history[me_last]),.sum(this_history[me_last]),1)
                this_rcert = this_history[me_last][n]/(if(this_frequency[me_last],this_frequency[me_last],1)/5f)
                this_weight = this_rchan*this_rcert*turns/10
                all_rchan = past_history[me_last][n]/if(.sum(past_history[me_last]),.sum(past_history[me_last]),1)
                all_rcert = past_history[me_last][n]/(if(past_frequency[me_last],past_frequency[me_last],1)/5f)
                all_weight = all_rchan*all_rcert
                for m in win[n]
                    options[m] -= this_weight*2 + all_weight*2
                options[n] -= this_weight + all_weight
                for m in lose[n]
                    options[m] += this_weight*2 + all_weight*2
            temp_selection = List<of int>()
            for num, o in options.numbered
                if o == options.sorted.last
                    temp_selection.add(num)
            Console.write('RPSLV'[temp_selection[rng.next(temp_selection.count)]])
            past_history[me_last][them_last] += 1

        #update the history file
        record = List<of String>()
        for entry in past_history
            record.add(entry.join(' '))
        File.writeAllLines(path+'\\history.txt',record)

    def sum(list as List<of uint64>) as uint64
        num = 0u64
        for entry in list, num += entry
        return num

```

Plays against it's best guess of the opponent's *last* move. Silly QQ...

Compile & Run: `cobra QQ -- [arg1] [arg2]`

-OR-

Compile: `cobra QQ`

Run: `cobra qq`
> 2 votes

# Answer
# Concession bot - Python 2

The inverse of my other bot. Attempts to predict what move its opponent will play so that it can come up with the worst possible move.

```
import sys
import random

concessions = {"R": "LS", "P": "VR", "S": "PL", "L": "VP", "V": "SR"}
valid_letters = "RPSLV"

# Create a dictionary of all possible patterns of how the cause history could have affected the effect history's next letter
def generate_pattern_dict(cause_history, effect_history):
    dictionary = {}

    # Run through all the rounds so far
    for round in xrange(len(cause_history)):

        history = cause_history[:round][::-1]
        letter = effect_history[round]

        if not letter in dictionary:
            dictionary[letter] = {}

        # Loop through every size of a string that could fit in the history
        for hs_len in range(1, len(history) + 1):

            # Loop through every position a string of that size could be in
            for hs_pos in range(len(history) - hs_len + 1):

                # Add this occurance to the dictionary; noting how long before the letter it occured and what it was
                history_string = history[hs_pos:hs_pos + hs_len]
                dist = hs_pos
                try:
                    dictionary[letter][(dist, history_string)] += 1
                except KeyError:
                    dictionary[letter][(dist, history_string)] = 1
    return dictionary

# Given a pattern dictionary; predict the next letter based on a history
def get_probabilities(patterns, history):
    probs = {}
    history = history[::-1]

    # Look at all the letters that have been used
    for letter in patterns:
        probs[letter] = 0

        # Look at all the known string patterns to have preceded this string and mark this letter as more likely the more strings that point to it
        for key, occurrences in patterns[letter].iteritems():
            dist, history_string = key

            if history[dist: dist + len(history_string)] == history_string:
                probs[letter] += occurrences

    return probs

def get_most_probable(dictionary):
    highest_prob = 0
    hightst_letters = ""

    for letter, prob in dictionary.iteritems():
        if prob >= highest_prob:
            if prob > highest_prob:
                hightst_letters = letter
                highest_prob = prob
            else:
                hightst_letters += letter

    if len(hightst_letters) == 0:
        hightst_letters = valid_letters

    return random.choice(hightst_letters), highest_prob

def get_histories():
    try:
        return (sys.argv[1], sys.argv[2])
    except IndexError:
        return ("", "")

def concede(letter):
    return random.choice(concessions[letter])

def get_hand(my_history, opponent_history):

    # Look at the affect the opponent's moves have on what they choose next
    pattern_dict = generate_pattern_dict(opponent_history, opponent_history)
    pattern_probs = get_probabilities(pattern_dict, opponent_history)
    pattern_letter, pattern_prob = get_most_probable(pattern_probs)

    # Look at what affect my moves have on what the opponent chooses next
    prediction_dict = generate_pattern_dict(my_history, opponent_history)
    prediction_probs = get_probabilities(prediction_dict, my_history)
    prediction_letter, prediction_prob = get_most_probable(prediction_probs)

    if pattern_prob > prediction_prob:
        opponent_letter = pattern_letter
    elif pattern_prob < prediction_prob:
        opponent_letter = prediction_letter
    else:
        opponent_letter = random.choice((pattern_letter, prediction_letter))

    return concede(opponent_letter)

print get_hand(*get_histories())

```

Run with:

```
    python concession_bot.py <args>

```
> 2 votes

# Answer
First time poster I'd like to submit the bot I wrote for this tournament:

## **The Evolver**

```
BotName: Evolver
Compile:
Run:     lua evolver.lua [StoryEvolver] [StoryOpponent]

```

and now the code:

```

-- The Evolver Bot
-- Vittorio "Robotik" Parrella - 01/08/2014
-- Version 3 02/08/2014

--[[
    os.time() gives time in seconds, so the RNG's seed is sometimes
    the same across many executions, so we use os.clock() to mark
    a time offset (in microseconds.) to set the seed.
]]
function random_seed_microseconds()
    local start = os.clock()
    for i=1,math.random(5000000,40000000) do end -- Loop to let some microseconds pass

    local off = (os.clock() - start)*10000
    start = os.time()*1000

    math.randomseed( start+off )
end

DEBUG = false
DATAFILE = "data.lua"
WIN_WEIGHT  = 1.0
DRAW_WEIGHT = 0.2
LOSE_WEIGHT = 0.5
MAX_FITNESS_VALUE = WIN_WEIGHT + DRAW_WEIGHT

my_moves = arg[1] or ""
opponent_moves = arg[2] or "-"

--[[
  Print debug information
]]
function dprint( ... )
    if DEBUG then
        print( "------" )
        print( ... )
    end
end

--[[
    This bot makes use (kind-of) an evolutionary algorithm,
    modifying the ranges used to randomly select the next
    symbol to play.

    The fitness function for the data ranges checks if a
    given set of ranges can create a sequence of symbols
    that is sufficiently good to beat the opponent's plays,
    so that it can be used to actually select a symbol that
    _could_ beat the next unkwown opponent symbol.
]]
function main()
    random_seed_microseconds()

    -- Initializes the bot.
    gen = new( genetic )

    -- Loads the data from the file or in
    -- case generates new data.
    -- FIX: at the start of a new match throws out the last
    -- datafile.
    if #my_moves < 1 or gen:load( DATAFILE ) == false then
        gen:generate( math.random( 10,20 ) )
    end

    -- Updates the fitness data with the new moves.
    gen:calculate_fitness( my_moves, opponent_moves )

    -- Selects and prints the next symbol using the
    -- distribution intervals with maximum fitness.
    print( gen:getSymbol( gen.data[1] , opponent_moves ) )

    dprint( gen:print() )

    -- Saves the calculated evolutionary data.
    gen:save( DATAFILE )
end

--[[
   Matrix graph for the rules:
   0 = draw
   1 = symbol 1 wins
   2 = symbol 2 wins
 ]]
SYMBOLS = { "R","P","S","L","V" }
rules = {
    ["R"] = { ["R"]=0,["P"]=2,["S"]=1,["L"]=1,["V"]=2 },
    ["P"] = { ["R"]=1,["P"]=0,["S"]=2,["L"]=2,["V"]=1 },
    ["S"] = { ["R"]=2,["P"]=1,["S"]=0,["L"]=1,["V"]=2 },
    ["L"] = { ["R"]=2,["P"]=1,["S"]=2,["L"]=0,["V"]=1 },
    ["V"] = { ["R"]=1,["P"]=2,["S"]=1,["L"]=2,["V"]=0 },
}

dprint( my_moves, opponent_moves )

function limit( min, max, value )
    return math.max( min, math.min( max, value ) )
end

--[[
   Very simple object orientation
]]
function new( class )
    local t = {}

    for i,k in pairs( class ) do
        t[i] = k
    end

    return t
end

--[[
   Class for the genetic algorithm
]]
genetic = {
    -- Prints the rows of paramters in the object + the fitness value for the combination
    print = function( self )
        local str = ""
        for i,fit in pairs( self.data ) do
            str = str.."{ "..table.concat(fit, ",", 1, 5).." } [".. fit[6] .."]\n"
        end
        return str
    end,

    --[[
      Writes the bots current data to the file in a format easily
      loadable with Lua.
    ]]
    save = function ( self, filepath )
        local file = io.open( filepath, "w" )
        assert( not(file == nil), "file cannot be opened for write: "..filepath )

        file:write( "return {\n" )
        for _,fit in pairs( self.data ) do
            file:write( "  { " )
            for j=1,#fit do
                file:write( fit[j]..", " )
            end
            file:write( "},\n" )
        end
        file:write( "}\n" )

        file:close()
    end,

    --[[
        Tries to load in memory the evolutionary parameters data table
        from the data.lua file.
    ]]
    load = function( self, filepath )
        result, self.data = pcall( dofile, filepath )

        if result == false then
            self.data = nil
        end

        return result
    end,

    --[[
        Uses the eveolutionary data row (should always be the max fitness one) to
        choose the symbol to print using a non-uniform distribution.
    ]]
    getSymbol = function( self, data )
        local roll = math.random()
        for case=1,5 do
            if roll < data[ case ] then
                return SYMBOLS[ case ]
            end
        end
    end,

    --[[
        Calculates the fitness value for all the data rows in the bot
        in respect to the opponent's previous moves.
    ]]
    calculate_fitness = function( self, my_moves, opp_moves )
        local max_fitness = 0
        local performance = 5

        -- Evaluates the performance of the used data row, counting losses
        for i=#(my_moves:sub(-5)), 1,-1 do
            if rules[ my_moves:sub(-i,-i) ][ opp_moves:sub(-i,-i) ] == 2 then
                performance = performance - 1
            end
        end

        for i,row in pairs( self.data ) do
            -- If first row's perfomance is good, there's no need to mutate it.
            if i > 1 or performance < 3 then
                self:mutate( i )

                local wins = 0
                local draws = 0

                --[[
                    Here we basically check if every row would be capable of defeating
                    the last opponent's moves, so that it can be used to MAYBE
                    defeat it's next moves.
                ]]
                local size = #opp_moves
                for piv=size,1,-1 do
                    local sym = self:getSymbol( row ) -- A possible symbol calculated using this row
                    local opp_sym = opp_moves:sub( piv,piv ) -- The last move used by the opponent

                    local result = rules[ sym ][ opp_sym ]

                    if result == 0 then
                        draws = draws + 1
                    elseif result == 1 then
                        wins = wins + 1
                    end
                end

                local winning_state = (wins+draws) / size
                local draws_state = 1.0-(draws / size)
                local losing_state = (size-wins) / size

                --[[
                    Updates the fitness of the data row maximising victories+draws ( max 1.0 ).
                    Adds a bonus for the number of draws made ( max 0.4 )
                    Adds a malus for the number of losses ( max 0.4 )
                ]]
                self.data[i][6] = winning_state * WIN_WEIGHT
                                + draws_state   * DRAW_WEIGHT
                                - losing_state  * LOSE_WEIGHT

                if self.data[i][6] > max_fitness then
                    max_fitness = self.data[i][6]
                end
                dprint( wins, draws, self.data[i][6] )
            end
        end

        if max_fitness < MAX_FITNESS_VALUE * 0.7 then
            self:generate( math.random( 10, 20 ) )
        else
            -- Orders the rows so that the first row has the highest fitness
            table.sort( self.data, function( a,b ) return a[6] > b[6] end )
        end
    end,

    --[[ Initially generates all the evolutionary data rows ]]
    generate = function( self, size )
        self.data = {}

        for i=1,size do
            self.data[i] = { 0.2, 0.4, 0.6, 0.8 } -- An initial uniform distribution gives good results

            self.data[i][5] = 1 -- High limit for the random symbols intervals
            self.data[i][6] = 0 -- Starting fitness value
        end
    end,

    --[[
        Executes a mutation on the values of a specified data row,
        for now the mutation is just a modification of the values
        to 20% (increase or decrease) of their initial value.
    ]]
    mutate = function( self, index )
        for j=1,4 do
            local plus = 0

            -- randomly picks an increase or a decrease of 20% of the range.
            plus = self.data[index][j] * 0.2

            if math.random() < 0.5 then
                plus = -1 * plus
            end

            self.data[index][j] = limit( 0,1, self.data[index][j] + plus )
        end
        self.data[index][5] = 1 -- the upper limit is always 1

        local tmp = self.data[index][6] -- The fitness value should not be ordered.
        self.data[index][6] = nil
        table.sort( self.data[index] ) -- The values can get mixed and so they're resorted.
        self.data[index][6] = tmp
    end,
}

main()

```

Should it violate any rule let me know and i'll fix it asap.
> 2 votes

# Answer
# qeylIs-bortaS - var'aq

I do believe this is the only one in Klingon...

Chooses a random number and 'translates' the number into R, P, S or L. The program is biased against Spock, because Klingons hate Vulcans (I think...).

Run the following shell script (it is in bash, so you might need to translate it to batch):

```
wget http://www.reocities.com/connorbd/varaq/varaq-current.zip
unzip varaq-current.zip
mv qeylIs-bortaS.vq ./varaq-current
rename varaq-kling varaq-kling.pl

```

To run the program:

```
perl varaq-kling.pl < qeylIs-bortaS.vq [arg1] [arg2] | findstr /R /l "^[RPSL]$"

```

*Note*: The findstr at the end is to get rid of

```
var'aq Reference Edition -- Klingon v0.5
(c)2000 Brian Connors, Chris Pressey, and Mark Shoulson

```

at the start of the program.

## Program

```
(* qeylIs-bortaS.vq *)

6 mIS poD ~ SIq cher (* Generate random number from 0-6 *)

SIq 0 rap'a' { "R" cha' } HIja'chugh
SIq 1 rap'a' { "P" cha' } HIja'chugh
SIq 2 rap'a' { "P" cha' } HIja'chugh
SIq 3 rap'a' { "S" cha' } HIja'chugh
SIq 4 rap'a' { "L" cha' } HIja'chugh
SIq 5 rap'a' { "L" cha' } HIja'chugh
SIq 6 rap'a' { "L" cha' } HIja'chugh

```

# Here's the English version - Kahless' Revenge:

This is just a translation, use qeylIS-bortaS for the tourney.

## Run

```
perl varaq-engl < kahless-revenge.vq [arg1] [arg2] | findstr /R /l "^[RPSL]$"

```

## Code:

```
6 rand clip ~ index set (* Generate random number from 0-6 *)

index 0 eq? { "R" disp } ifyes
index 1 eq? { "P" disp } ifyes
index 2 eq? { "P" disp } ifyes
index 3 eq? { "S" disp } ifyes
index 4 eq? { "L" disp } ifyes
index 5 eq? { "L" disp } ifyes
index 6 eq? { "L" disp } ifyes

```
> 2 votes

# Answer
# The RandomSpockBot, ruby

Simply picks a random move from an array, but it's always the best possible move.

```
puts ['V'].sample

```
> 2 votes

# Answer
# SmarterBot

This one might be smarter.

It has a few more features than its predecessor, including optimizations such as:

* Choosing a move now takes into account the runner up - so that the next move will (some of the time) beat both
* Outputs random move if beaten twice in a row
* If beaten twice in a row, history is effectively cleared for the next hands

```
name - SmarterBot
run with - java SmarterBot.jar

```

code:

```
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;

public class SmarterBot {

public static void main(String[] args){
    if(args.length ==0){
        System.out.print("L");
        return;
    }
    if(args[0].length()<3){
        String[] randLetter = new String[]{"R","P","S","L","V"};
        System.out.print(randLetter[(int) Math.floor(Math.random()*5)]);
        return;
    }
    String myHistory = args[0];
    String otherHistory = args[1];

    double rScore,pScore,sScore,lScore,vScore;//score - highest = highest probability of next opponent move
    rScore = pScore = sScore = lScore = vScore = 0;
    lScore = .001;
    String myUsableHistory = myHistory;
    String otherUsableHistory = otherHistory;
    if(myHistory.length() > 4){
        int startIndex = findLastInstanceOfXLosses(myHistory,otherHistory,3);
        myUsableHistory = myHistory.substring(startIndex);
        otherUsableHistory = otherHistory.substring(startIndex);
    }

    if(lostLastXRounds(myHistory,otherHistory) >= 1){
        String[] randLetter = new String[]{"R","P","S","L","V"};
        System.out.print(randLetter[(int) Math.floor(Math.random()*5)]);
        return;
    }

    ArrayList<ArrayList<Integer>> moveHits = new ArrayList<ArrayList<Integer>>();
    for(int g = 0;g<2;g++){
        for(int i=1;i<(myUsableHistory.length() / 2) + 1;i++){
            if(g==0){
                moveHits.add(findAll(myUsableHistory.substring(myUsableHistory.length() - i),myUsableHistory));
            }
            else{
                moveHits.add(findAll(otherUsableHistory.substring(otherUsableHistory.length() - i),otherUsableHistory));
            }
        }
        for(int i = 0; i < moveHits.size();i++){
            int matchingMoves = i+1;
            ArrayList<Integer> moveIndexes = moveHits.get(i);
            for(Integer index:moveIndexes){
                if(index+matchingMoves +1<= otherUsableHistory.length()){
                    char nextMove = otherUsableHistory.charAt(index + matchingMoves-1);
                    if(nextMove=='R'){rScore = rScore + matchingMoves;}
                    if(nextMove=='P'){pScore = pScore + matchingMoves;}
                    if(nextMove=='S'){sScore = sScore + matchingMoves;}
                    if(nextMove=='L'){lScore = lScore + matchingMoves;}
                    if(nextMove=='V'){vScore = vScore + matchingMoves;}
                }
            }
        }
    }

    HashMap<Character,Double> scores = new HashMap<Character,Double>();
    scores.put('R', rScore);
    scores.put('P',pScore);
    scores.put('S', sScore);
    scores.put('L', lScore);
    scores.put('V', vScore);
    ArrayList<Character> winners = orderHashMap(scores);
    char number1 = winners.get(winners.size() - 1);
    char number2 = winners.get(winners.size() - 2);
    char charToPlay = beatsMove(number1,number2);
    System.out.print(charToPlay);
    return;
}
public static int findLastInstanceOfXLosses(String myHistory,String otherHistory, int losses){
    int index = myHistory.length();
    while(lostLastXRounds(myHistory.substring(0,index),otherHistory.substring(0,index)) < losses && index >1){
        index--;
    }
    return index;
}
public static ArrayList<Character> orderHashMap(HashMap<Character,Double> scores){
    ArrayList<Double> orderedScores = new ArrayList<Double>();
    orderedScores.add(scores.get('R'));
    orderedScores.add(scores.get('P'));
    orderedScores.add(scores.get('S'));
    orderedScores.add(scores.get('L'));
    orderedScores.add(scores.get('V'));
    Collections.sort(orderedScores);

    ArrayList<Character> orderedKeys = new ArrayList<Character>();
    for(Double value:orderedScores){
        for(Character key:scores.keySet()){
            if(value.equals(scores.get(key))){
                orderedKeys.add(key);
            }
        }
    }
    return orderedKeys;
}
public static ArrayList<Integer> findAll(String substring,String realString){
    ArrayList<Integer> ocurrences = new ArrayList<Integer>();
    Integer index = realString.indexOf(substring);
    if(index==-1){return ocurrences;}
    ocurrences.add(index+1);
    while(index!=-1){
        index = realString.indexOf(substring,index + 1);
        if(index!=-1){
            ocurrences.add(index+1);
        }
    }
    return ocurrences;
}
public static int lostLastXRounds(String myHistory,String otherHistory){
    int index = myHistory.length()-1;
    int lost = 0;
    while(ifCharBeatsOther(otherHistory.charAt(index),myHistory.charAt(index)) == true){
        index--;
        lost++;
        if(index == -1){break;}
    }
    return lost;
}
public static boolean ifCharBeatsOther(char char1,char char2){
    ArrayList<Character> beatsRock = new ArrayList<Character>();
    beatsRock.add('V');
    beatsRock.add('P');
    ArrayList<Character> beatsPaper = new ArrayList<Character>();
    beatsPaper.add('S');
    beatsPaper.add('L');
    ArrayList<Character> beatsSissors = new ArrayList<Character>();
    beatsSissors.add('V');
    beatsSissors.add('R');
    ArrayList<Character> beatsLizard = new ArrayList<Character>();
    beatsLizard.add('S');
    beatsLizard.add('R');
    ArrayList<Character> beatsSpock = new ArrayList<Character>();
    beatsSpock.add('P');
    beatsSpock.add('L');

    if(char2 == 'V'){if (beatsSpock.contains(char1)){return true;}}
    if(char2 == 'R'){if (beatsRock.contains(char1)){return true;}}
    if(char2 == 'P'){if (beatsPaper.contains(char1)){return true;}}
    if(char2 == 'S'){if (beatsSissors.contains(char1)){return true;}}
    if(char2 == 'L'){if (beatsLizard.contains(char1)){return true;}}
    return false;
}
public static char beatsMove(char moveToBeBeaten,char runnerUp){
    if(moveToBeBeaten == 'R'){
        if(runnerUp == 'S'){
            return 'V';
        }
        if(runnerUp == 'V'){
            return 'P';
        }
        return 'V';
    }
    if(moveToBeBeaten == 'P'){
        if(runnerUp == 'L'){
            return 'S';
        }
        if(runnerUp == 'V'){
            return 'L';
        }
        return 'L';
    }
    if(moveToBeBeaten == 'S'){
        if(runnerUp == 'R'){
            return 'V';
        }
        if(runnerUp =='L'){
            return 'R';
        }
        return 'V';
    }
    if(moveToBeBeaten == 'L'){
        if(runnerUp == 'P'){
            return 'S';
        }
        if(runnerUp == 'S'){
            return 'R';
        }
        return 'S';
    }
    if(moveToBeBeaten == 'V'){
        if(runnerUp == 'R'){
            return 'P';
        }
        if(runnerUp == 'P'){
            return 'L';
        }
    }
    return 'L';
}
}

```

It has beaten SmartBot more than 50% of the time so it could do quite well.

Or it could crash and burn.
> 1 votes

# Answer
## Java - DogeBot2.0

This is nearly identical to my last submission but it's a little smarter this time. This one only looks at the oppenents last five hands, instead all of them. Also, instead of just printing P when there is less than five hands played, it will beat whatever the last one was.

```
public class DogeBot {
     public static void main(String []args){

        String possibleHands = "RPSLV";

        if (args.length < 2) {
            System.out.println("P");
            return;
        }

        String yourHistory = args[1];

        if (yourHistory.length() < 5) {
            char lastHistoryHand = yourHistory.charAt(yourHistory.length() - 1);
            int i = possibleHands.indexOf(lastHistoryHand);

            char newHand = possibleHands.charAt((i + 2) % 5);
            System.out.println(newHand == 'S' ? "P" : newHand);
            return;
        }

        yourHistory = yourHistory.substring(yourHistory.length() - 5);

        for (int i = 0; i < 5; i++) {
            String searchString = "" + possibleHands.charAt(i) + possibleHands.charAt(i);

            if (yourHistory.contains(searchString)) {

                char newHand = possibleHands.charAt((i + 2) % 5);
                System.out.println(newHand == 'S' ? "P" : newHand);

                return;
            } else continue;

        }

        char lastHistoryHand = yourHistory.charAt(yourHistory.length() - 1);
        int i = possibleHands.indexOf(lastHistoryHand);

        char newHand = possibleHands.charAt((i + 2) % 5);
        System.out.println(newHand == 'S' ? "P" : newHand);

        return;
    }
}

```
> 1 votes

# Answer
# Robotic Oboe Bot Oboe Tuner - Python 2

Goes through each letter its opponent has submitted and looks for any recurring strings in both it and its opponent's history before that point.

Every possible contiguous string before the letter it's checking will be noted in a dictionary along with the distance that string appeared from the letter being checked. This dictionary persists through each letter that is checked and each time the same substring appears the same distance from the letter being checked a counter for that substring in the dictionary is incremented. This process is done separately for both the opponent's history + the opponent's chosen letter and this bot's history + the opponent's chosen letter.

Once each pattern dictionary has been assembled; the bot goes through each letter that was used by the opponent and compares the patterns to the current history. If there is a match with the correct distance from the end then the letter being tested gets a point for every occurrence that substring had had. If the pattern is repeating then the letter will get points separately for each time it had appeared before that as each distance + string combo is considered a distinct dictionary entry.

Once the most probable patternistic next move has been determined - a random countering move is chosen for that move.

In the case where there is a tie; one of the letters in the tie is picked at random. When there are no patterns to work off (before the opponent has repeated any letters) - the bot picks randomly.

The cool thing about this implementation is that because the letters get a flat score for each pattern detected; more recent characters tend to have more weight than older characters as they will have more patterns preceding them and longer patterns will have exponentially more weight as the sub-patterns within them will also be counted as separate patterns. This bot should even deal with bots that periodically alternate strategies once it figures out the pattern.

```
import sys
import random

counters = {"R": "VP", "P": "SL", "S": "VR", "L": "RS", "V": "LP"}
valid_letters = "RPSLV"

# Create a dictionary of all possible patterns of how the cause history could have affected the effect history's next letter
def generate_pattern_dict(cause_history, effect_history):
    dictionary = {}

    # Run through all the rounds so far
    for round in xrange(len(cause_history)):

        history = cause_history[:round][::-1]
        letter = effect_history[round]

        if not letter in dictionary:
            dictionary[letter] = {}

        # Loop through every size of a string that could fit in the history
        for hs_len in range(1, len(history) + 1):

            # Loop through every position a string of that size could be in
            for hs_pos in range(len(history) - hs_len + 1):

                # Add this occurance to the dictionary; noting how long before the letter it occured and what it was
                history_string = history[hs_pos:hs_pos + hs_len]
                dist = hs_pos
                try:
                    dictionary[letter][(dist, history_string)] += 1
                except KeyError:
                    dictionary[letter][(dist, history_string)] = 1
    return dictionary

# Given a pattern dictionary; predict the next letter based on a history
def get_probabilities(patterns, history):
    probs = {}
    history = history[::-1]

    # Look at all the letters that have been used
    for letter in patterns:
        probs[letter] = 0

        # Look at all the known string patterns to have preceded this string and mark this letter as more likely the more strings that point to it
        for key, occurrences in patterns[letter].iteritems():
            dist, history_string = key

            if history[dist: dist + len(history_string)] == history_string:
                probs[letter] += occurrences

    return probs

def get_most_probable(dictionary):
    highest_prob = 0
    hightst_letters = ""

    for letter, prob in dictionary.iteritems():
        if prob >= highest_prob:
            if prob > highest_prob:
                hightst_letters = letter
                highest_prob = prob
            else:
                hightst_letters += letter

    if len(hightst_letters) == 0:
        hightst_letters = valid_letters

    return random.choice(hightst_letters), highest_prob

def get_histories():
    try:
        return (sys.argv[1], sys.argv[2])
    except IndexError:
        return ("", "")

def counter(letter):
    return random.choice(counters[letter])

def get_hand(my_history, opponent_history):

    # Look at the affect the opponent's moves have on what they choose next
    pattern_dict = generate_pattern_dict(opponent_history, opponent_history)
    pattern_probs = get_probabilities(pattern_dict, opponent_history)
    pattern_letter, pattern_prob = get_most_probable(pattern_probs)

    # Look at what affect my moves have on what the opponent chooses next
    prediction_dict = generate_pattern_dict(my_history, opponent_history)
    prediction_probs = get_probabilities(prediction_dict, my_history)
    prediction_letter, prediction_prob = get_most_probable(prediction_probs)

    if pattern_prob > prediction_prob:
        opponent_letter = pattern_letter
    elif pattern_prob < prediction_prob:
        opponent_letter = prediction_letter
    else:
        opponent_letter = random.choice((pattern_letter, prediction_letter))

    return counter(opponent_letter)

print get_hand(*get_histories())

```

Run with:

```
    python robotic_oboe_bot_oboe_tuner.py <args>

```
> 1 votes

# Answer
# Excitingish Bot (Java)

Evolved Boring Bot to take a risk and assume everyone else will try to outsmart him by considering his last move.

```
public class ExcitingishBot
{
    public static void main(String[] args)
    {
        int Rock=0;
        int Paper=0;
        int Scissors=0;
        int Lizard=0;
        int Spock=0;

        if (args.length == 0)
        {
            System.out.print("R");
            return;
        }

        char[] oppPreviousPlays = args[1].toCharArray();
        char[] myPreviousPlays = args[0].toCharArray();

        for (int j=0; j<oppPreviousPlays.length; j++) {
            switch(oppPreviousPlays[j]){
                case 'R': Rock++; break;
                case 'P': Paper++; break;
                case 'S': Scissors++; break;
                case 'L': Lizard++; break;
                case 'V': Spock++;
            }
        }

        if (myPreviousPlays.length()>2){
        for (int j=1; j<3; j++) {
            switch(myPreviousPlays[myPreviousPlays.length()-j]){
                case 'R': Paper+=5; Spock+=5; break;
                case 'P': Scissors+=5; Lizard+=5; break;
                case 'S': Rock+=5; Spock+=5; break;
                case 'L': Scissors+=5; Rock+=5; break;
                case 'V': Paper+=5; Lizard+=5;
              }
        }}

        int Best = Math.max(Math.max(Lizard+Scissors-Spock-Paper,
                                     Rock+Spock-Lizard-Scissors),
                            Math.max(Math.max(Paper+Lizard-Spock-Rock,
                                              Paper+Spock-Rock-Scissors),
                                     Rock+Scissors-Paper-Lizard));

        if (Best== Lizard+Scissors-Spock-Paper){
            System.out.print("R"); return;
        } else if (Best== Rock+Spock-Lizard-Scissors){
            System.out.print("P"); return;
        } else if (Best== Paper+Lizard-Spock-Rock){
            System.out.print("S"); return;
        } else if(Best== Paper+Spock-Rock-Scissors){
            System.out.print("L"); return;
        } else {
            System.out.print("V"); return;
        }
    }
}

```
> 1 votes

# Answer
## Botzinga - Java

```
BotName: Botzinga
Compile: Save as Botzinga.java and compile as usual
Run:     Botzinga [Arg1] [Arg2]

```

The code:

```
public class Botzinga {

private static int curTurn = 0;
private static char[] opHand;
private static char[] myHand;

public static void main(String[] args) {

    if(args.length != 0) {
        int curTurn = args[0].length();
        opHand = args[1].toCharArray();
        myHand = args[0].toCharArray();
    }
    char c = ' ';

    if(curTurn >= 5) {
        if(opHand[curTurn-1] == opHand[curTurn-2] && opHand[curTurn-1] == opHand[curTurn-3])
            c = beater(opHand[curTurn - 1]);
        else {
            if (beats(myHand[curTurn - 1], opHand[curTurn - 1]))
                c = beater(myHand[curTurn - 1]);
            else
                c = beater(opHand[curTurn - 1]);
        }

    }
    else
        c = playRandom();
    System.out.print(c);

}

public static char playRandom() {
    char c = ' ';
    switch((int)(Math.random()*5)) {
        case 0: c = 'R'; break;
        case 1: c = 'P'; break;
        case 2: c = 'S'; break;
        case 3: c = 'L'; break;
        case 4: c = 'V'; break;
    }
    return c;
}

private static char beater(char a) {
    int Rock=0;
    int Paper=0;
    int Scissors=0;
    int Lizard=0;
    int Spock=0;

    for (int j=0; j<curTurn; j++) {
        switch(myHand[j]){
            case 'R': Rock++; break;
            case 'P': Paper++; break;
            case 'S': Scissors++; break;
            case 'L': Lizard++; break;
            case 'V': Spock++;
        }
    }

    switch (a) {
        case 'R': return Paper < Spock ? 'P' : 'V';
        case 'P': return Scissors < Lizard ? 'S' : 'L';
        case 'S': return Rock < Spock ? 'R' : 'V';
        case 'V': return Paper < Lizard ? 'P' : 'L';
        case 'L': return Rock < Scissors ? 'R' : 'S';
        default: return ' ';
    }

}

private static boolean beats(char a, char b) {
    boolean win = false;
    switch (a) {
        case 'R':
            win = b == 'S' || b == 'L';
            break;
        case 'P':
            win = b == 'R' || b == 'V';
            break;
        case 'S':
            win = b == 'P' || b == 'L';
            break;
        case 'V':
            win = b == 'S' || b == 'R';
            break;
        case 'L':
            win = b == 'V' || b == 'P';
            break;
    }
    return win;
}
}

```
> 1 votes

# Answer
# RAMBO\_BOT - PHP

introducing brand new Rambo Bot

fight it by run php 5.4.\*

```
php rambo_bot.php

```

e.g

```
php rambo_bot.php SSVL VLSS

```

i dont know what exactly i did, things got bit obfuscating but my plan was to make it smart, should burst those spammer bots

Update :

from public aplpha to public beta, new features included, better narrow down and dependencies, it got lot more intelligent

```
<?php
/* RamboBot public beta */
class V{
    protected $protected;
    function p(){
        return [get_class($this->protected),"P"];
    }
}

function generateKnowledge($l,$o){

    $j = generateResist();
    $knowledge = [ $j[0][0], $j[1][0], $j[1][1], $j[2], $j[4], mt_rand(0,1), (100/3) ];
    if($l[0] != ""){
        $am = [
            $j[0][0]=>[count(array_keys($l, $j[0][0])),count(array_keys($o, $j[0][0]))],$j[1][0]=>[count(array_keys($l, $j[1][0])),count(array_keys($o, $j[1][0]))],$j[1][1]=>[count(array_keys($l, $j[1][1])),count(array_keys($o, $j[1][1]))],$j[2]=>[count(array_keys($l, $j[2])),count(array_keys($o, $j[2]))],$j[4]=>[count(array_keys($l, $j[4])),count(array_keys($o, $j[4]))]
        ];
        $ma = [];
        $y=0;
        foreach ($am as $key => $value) {
            $ma[]=round(( $value[1]/count($o)) * 100 );
            $y+=round(( $value[1]/count($o)) * 100 );
        }
        $mu=$ma[(array_search(max($ma), $ma))];
        $me=($y / count($am));
        $mo=[];
        foreach ($ma as $key => $value) {
            if($value==0.0){$mo[]=$key;}
        }
        $i=$knowledge;
        unset($i[5]);unset($i[6]);
        foreach ($mo as $no) {
            unset($i[$no]);
        }
        if(($mu-$me)>$knowledge[6]){
            $e=array_search(max($ma), $ma);
        }elseif (count($o) > $knowledge[6]) {
            if(count($mo)>0){
                $e=array_rand($i);
            }else{
                $e=array_search(max($ma), $ma);
            }
        }else {
            $e=array_rand($i);
        }
    }else {
        $e=mt_rand(0,4);
    }
    return array("k"=>$knowledge,"a"=>$e);
}

function generateResist (){
    $t = (string)float;
    $f=["S",'f'];
    $b=(string)$f;
    $z=new V();$u=$z->p();$x = 'u';
    $d=$f[1];
    $resist =[$$d[0][0][0],$$x[0],ucfirst(substr($b, 2,1)),$$x[0][1][0],ucfirst(substr($t, 1,1))  ];
    return $resist;
}

$h=generateKnowledge(str_split($argv[1]),str_split($argv[2]));

switch ($h["k"][$h["a"]]) {
    case $h["k"][0]:
        echo $h["k"][3];
        exit;
    case $h["k"][1]:
        echo $h["k"][2];
        exit;
    case $h["k"][2]:
        echo $h["k"][4];
        exit;
    case $h["k"][3]:
        echo $h["k"][1];
        exit;
    case $h["k"][4]:
        echo $h["k"][3];
        exit;

    default:
        exit;
}
?>

```

i´m excited to see som results

rambo\_bot decides depending on the length of the game if it will beat the opponents move with the highest percentual amount occured if the comparison to the average percentual amount is greater than a certain amount,

rambo\_bot wont fight any moves the opponent has not been played yet starting after the first third of the whole game, if the distance between the lowest percentual amount of occurences but greater than zero and the average percentual amount of occurences is bigger than a certain amount it will exclude to beat that character
> 1 votes

# Answer
# Naan (Ruby)

```
BotName: Naan
Run:     ruby naan.rb [Mine] [Theirs]

```

Code

```
@counters = { "R" => [ "P", "V" ], "P" => [ "S", "L" ], "S" => [ "V", "R" ], "L" => [ "R", "S" ], "V" => [ "P", "L" ] }
@counts = { "R" => 0, "S" => 0, "P" => 0, "V" => 0, "L" => 0 }

choices = []

if( ARGV != nil && ARGV[0] != nil )

  mine = ARGV[0].split("")
  theirs = ARGV[1].split("")

  c2 = @counts.clone
  bestChoice = 100

  mine.each_cons(2) {|a, b| if( a == mine[-1] ) then c2[b]+=1 end}
  c2.keys.each {|x| if( c2[x] < bestChoice ) then bestChoice = c2[x] end}
  c2.keys.each {|x| if( c2[x] == bestChoice ) then choices.push(x) end}

else
  choices = @counters.keys
end

puts choices.sample

```
> 1 votes

# Answer
# NaanViolence (Ruby)

```
BotName: NaanViolence
Run:     ruby naanviolence.rb [Mine] [Theirs]

```

Code

```
@counters = { "R" => [ "P", "V" ], "P" => [ "S", "L" ], "S" => [ "V", "R" ], "L" => [ "R", "S" ], "V" => [ "P", "L" ] }
@counts = { "R" => 0, "S" => 0, "P" => 0, "V" => 0, "L" => 0 }

choices = []

if( ARGV != nil && ARGV[0] != nil )

  mine = ARGV[0].split("")
  theirs = ARGV[1].split("")

  c2 = @counts.clone
  bestChoice = 100

  mine.each {|x| c2[x]+=2}
  theirs.each {|x| c2[@counters[x][0]]-=1; c2[@counters[x][1]]-=1}
  c2.keys.each {|x| if( c2[x] < bestChoice ) then bestChoice = c2[x] end}
  c2.keys.each {|x| if( c2[x] == bestChoice ) then choices.push(x) end}

else
  choices = @counters.keys
end

puts choices.sample

```
> 1 votes

# Answer
# EasyGame, Java

My try at this tournament

```
Bot: EasyGame
Run: java -jar EasyGame.jar [Arg1] [Arg2]

```

Code:

```
public class EasyGame {

    public static String randomLetter(){
        String[] randomLetters = new String[]{"R","P","S","L","V"};
        String character = (randomLetters[(int)Math.floor(Math.random()*5)]);
        return character;
    }

    public static int[] calculateScores(int[] scores, char[] enemyPlays){
        for (int i=0; i != enemyPlays.length; i++){
            if (enemyPlays[i] == 'R') scores[0]++;
            if (enemyPlays[i] == 'P') scores[1]++;
            if (enemyPlays[i] == 'S') scores[2]++;
            if (enemyPlays[i] == 'L') scores[3]++;
            if (enemyPlays[i] == 'V') scores[4]++;
        }
        return scores;
    }

    public static boolean randomPick(int chances, int size){
        if (chances >= (int)Math.floor(Math.random()*size))
            return true;
        return false;
    }

    public static char nextMove(int[] seed, int length){
        if (randomPick(seed[0], length)) return 'P';
        if (randomPick(seed[1], length-(seed[0]))) return 'S';
        if (randomPick(seed[2], length-(seed[0]+seed[1]))) return 'V';
        if (randomPick(seed[3], length-(seed[0]+seed[1]+seed[2]))) return 'R';
        if (randomPick(seed[4], length-(seed[0]+seed[1]+seed[2]+seed[3]))) return 'L';
        return 'V';
    }

    public static void main(String[] args) {

        int[] scores = new int[]{0,0,0,0,0};
        if(args.length == 0 || args[1].length() < 10){
            System.out.print(randomLetter());
            return;
        }

        char[] enemyPlays = args[1].toCharArray();
        scores = calculateScores(scores, enemyPlays);
        System.out.print(nextMove(scores, args[1].length()));
        return;
    }
}

```

This bot picks a seeded randomized option, based on the moves made by the opponent.
> 1 votes

# Answer
## OneBehind, Java

Always one behind... T^T

```
public class OneBehind {

    public static void main(String[] args) {
        if(args.length == 0) {
            System.out.print("L"); //Represent
            return;
        }
        char[] opp = args[1].toCharArray();
        int index = opp.length - 1;
        char choice = opp[index];
        switch(choice) {
            case 'R':
            System.out.print("R");
            break;
            case 'P':
            System.out.print("P");
            break;
            case 'S':
            System.out.print("S");
            break;
            case 'L':
            System.out.print("L");
            break;
            case 'V':
            System.out.print("V");
            break;
        }
        return;
    }

}

```
> 1 votes

# Answer
# The Bot You Could Easily Special Case Against - Python 2

Plays a fixed game that I wrote by hand.

```
import sys

game = "RPSPVPSLSRVVVSVVSLLPPRSLPRRRRVRLLPSSRPRPRSPRPRLLLVSRPSSPRVVRPVVVPPVRRLLLLLRLRPVVSSPRRPSLVLRRRSPRSRRP"

try:
    round = len(sys.argv[1])
except IndexError:
    round = 0

print game[round]

```

Run with:

```
python TheBotYouCouldEasilySpecialCaseAgainst.py <args>

```

Giving your grid formatter a workout.
> 1 votes

# Answer
## Blind Foresight - c#

The obvious flaws of this bot are its strengths.

```
Bot    : Blind Foresight
Compile: csc BlindForesight.cs
Run    : BlindForesight [Arg1] [Arg2]

```

Code:

```
using System;
using System.Collections.Generic;
using System.Diagnostics;

namespace SO.BlindForesight
{

    /// <summary>
    /// Blind Foresight
    /// </summary>
    class Program
    {
        public enum Hand
        {
            Rock,
            Paper,
            Scissors,
            Vulcan,
            Lizard
        }

        public enum Outcome
        {
            Win=1,
            Tie=0,
            Loss=-1,
        }

        static Random rnd=new Random();
        static Dictionary<char, Hand> interpreter;
        static Program()
        {
            interpreter=new Dictionary<char, Hand>();
            foreach(var item in Enum.GetValues(typeof(Hand)))
            {
                Hand hand=(Hand)item;
                char key=hand.ToString()[0];
                interpreter[key]=hand;
            }
        }

        public struct Game
        {
            public Game(Hand mine, Hand other)
            {
                this.mine=mine;
                this.other=other;
                this.result=mine==other?Outcome.Tie:
                    ((int)mine+2)%5==(int)other||((int)mine+4)%5==(int)other?Outcome.Win:
                        Outcome.Loss;
            }
            public Game(char mine, char other) : this(interpreter[mine], interpreter[other]) { }
            public readonly Hand mine, other;
            public readonly Outcome result;
        }

        static void Main(string[] args)
        {
            if(args.Length==0) { Return(rnd.Next(0, 5)); }
            else if(args.Length==1) { throw new ArgumentException(); }
            else
            {
                int n=args[0].Length;
                Game last=new Game(args[0][n-1], args[1][n-1]);
                if(last.result==Outcome.Loss)
                {
                    Return((int)last.other+rnd.Next(0, 2)*2-1);
                }
                else
                {
                    Return((int)last.mine+rnd.Next(0, 2)*2-1);
                }
            }
        }
        static void Return(int hand)
        {
            if(hand<0) { hand+=5*(1-hand/5); }
            Console.WriteLine(((Hand)(hand%5)).ToString()[0]);
        }
    }
}

```
> 1 votes

# Answer
# The Bot That Easily General Cases The Bot You Could Easily Special Case Against - Python 2

**\*BotName: OboeOboeBeater ***

Plays a fixed game that beats the game I wrote by hand.

```
import sys

game = "VLVSLLVSRPLPPRLPRSRSSPRSLPPVPPVSSSVRPSPSPRLPLPRRSPVVLRRSPLPVSPLLSLPPVRSSRRVRVSLLRVLVPSVSLRVVPVSPRVVL"

try:
    round = len(sys.argv[1])
except IndexError:
    round = 0

print game[round]

```

Run with:

```
python TheBotThatEasilyGeneralCasesTheBotYouCouldEasilySpecialCaseAgainst.py <args>

```

Formatting! :D
> 1 votes

# Answer
# Leonard Shelby

Hey, I removed one so I can add one, right? `ruby leonard.rb`

```
@rules = {

  'L' => %w[V P],
  'P' => %w[V R],
  'R' => %w[L S],
  'S' => %w[P L],
  'V' => %w[R S]
}

@moves = @rules.keys

def defeats?(move1, move2)
  @rules[move1].include?(move2)
end

def score(move1, move2)
  if move1 == move2
    0
  elsif defeats?(move1, move2)
    1
  else
    -1
  end
end

def move
  player, opponent = ARGV

  hardcoded_moves = 'PRPSPLPVPRPSPLPV'

  if m = hardcoded_moves[player.to_s.size]
    m
  elsif winning?(player, opponent)
    %w[R P S L V].sample
  else
    extrapolate(player[-16,16],opponent[-16,16])
  end

end

def winning?(player,opponent)
  player.chars.zip(opponent.chars).map{ |move| score(*move) }.inject(0,:+) >= 5
end

def extrapolate(player,opponent)
  likelihoods = Hash.new {0}

  opponent_last_move = opponent[-1]
  @moves.each { |m| likelihoods[m] += opponent.scan(opponent_last_move + m).size }

  my_last_move = player[-1]
  reactions = player.chars.zip(opponent.chars.drop(1))
  @moves.each { |m| likelihoods[m] += reactions.count([my_last_move, m]) }

  @moves.shuffle.max_by do |m|
    likelihoods.map{ |n,c| score(m,n) * c }.reduce(0,:+)
  end

end

puts move

```

Leonard needs a lot of paper because he can't really remember more than the recent (16 rounds) past.

This bot uses a few counter-intuitive ideas. One is that it switches to fully random moves when it's *winning*, just in case the opposing bot is on the verge of figuring out its strategy. It'll have fewer lopsided victories, but hopefully more victories overall.
> 1 votes

# Answer
## **RelaxedBot**

The RelaxedBot doesn't worry about much. If he won last time, then he might as well try what he did again. Otherwise, something random will do just fine.

run with `python RelaxedBot.py [me] [them]`

```
import random
import sys

def pickRand():
    plays = ['R', 'P', 'S', 'L', 'V']
    return random.choice(plays)

def beat(me, them):
    if me==them:
        return 0
    if(me=='V' and (them == 'L' or them == 'P')):
        return -1
    if(me=='S' and (them == 'V' or them == 'R')):
        return -1
    if(me=='P' and (them == 'S' or them == 'L')):
        return -1
    if(me=='R' and (them == 'P' or them == 'V')):
        return -1
    if(me=='L' and (them == 'R' or them == 'S')):
        return -1
    return 1

if len(sys.argv) > 1:
    if beat((sys.argv[1])[-1], (sys.argv[2])[-1]) > 0:
        print(sys.argv[1][-1])

    else:
        print(pickRand())
else:
    print(pickRand())

```
> 1 votes

# Answer
# TobiasFuenke, Python 2.7

Ugly piece of c...ake that analyzes stuff. Basically, an attempted naive Bayes classifier calculates probabilities for the opponents next move, which are used to find the own move with the best expected outcome. I might provide more information and cleaner/commented code. I probably actually will if someone requests for that.

```
Bot: TobiasFuenke
Run: python TobiasFuenke.py [Arg1] [Arg2]

```

Code:

```
import random
import sys

hands = "RPSVL"

def outcome(h1, h2):
    dist = (hands.index(h1)-hands.index(h2)) % 5
    if dist==0:
        return 0
    if dist & 1:
        return 1
    return -1

class EM():
    def __init__(self, predictor):
        self.predictor = predictor

    def hand(self, ours="", theirs=""):
        probs = self.predictor.probs(ours, theirs)

        if not(probs):
            return random.choice(hands)

        expectation = { our : sum([outcome(our, their) * probs[their] for their in hands]) for our in hands }
        winning = max(expectation.values())
        candidates = filter(lambda h: expectation[h]==winning, expectation.keys())
        return random.choice(candidates)

class Predictor:
    def __init__(self):
        self.fnum = 7

    def extract(self, ours, theirs, idx):
        if idx < 2:
            return None

        f1 = ours[idx-1]
        f2 = theirs[idx-1]
        f3 = (f1, f2)
        f4 = (f1, (f1 == ours[idx-2]))
        f5 = (f2, (f2 == theirs[idx-2]))
        f6 = (f1, ours[idx-2])
        f7 = (f2, theirs[idx-2])

        return [f1,f2,f3,f4,f5,f6,f7]

    def probs(self, ours, theirs):
        if not(theirs):
            return None

        idx = 0

        fcount = []
        flcount = []
        for i in range(0, self.fnum):
            fcount.append({})
            flcount.append({})

        lcount = {}
        samples = 0

        while idx < len(theirs):
            label = theirs[idx]

            features = self.extract(ours, theirs, idx)
            if not(features):
                idx +=1
                continue

            samples += 1

            if not(label in lcount):
                lcount[label] = 0

                for feature in flcount:
                    feature[label] = {}

            lcount[label] += 1

            for fi in range(0, self.fnum):
                realz = features[fi]
                fcount_i = fcount[fi]

                if not(realz in fcount_i):
                    fcount_i[realz] = 0

                fcount_i[realz] += 1

                flcount_il = flcount[fi][label]
                if not(realz in flcount_il):
                    flcount_il[realz] = 0

                flcount_il[realz] += 1

            idx+=1

        if not(samples):
            return None

        lprob = {label: float(c) / samples for (label, c) in lcount.items() }
        flprob = [ { label : { realz : float(c) / sum(realizations.values()) for realz, c in realizations.items()} for label, realizations in feature.items()} for feature in flcount ]

        features = self.extract(ours, theirs, idx)

        probs = {}
        for label in hands:
            if not(label in lprob):
                probs[label] = 0
                continue

            prob = lprob[label]
            for fi in range(0, self.fnum):
                realz = features[fi]
                flprob_il = flprob[fi][label]
                if realz in flprob_il:
                    prob *= flprob_il[realz]
                elif flprob_il:
                    prob = 0
                    break

            probs[label] = prob

        return probs

bot = EM(Predictor())

if len(sys.argv) == 3:
    move = bot.hand(sys.argv[1], sys.argv[2])
else:
    move = bot.hand()

sys.stdout.write(move)

```
> 1 votes

# Answer
## Dice Throw Bot, C#

Truly Random

```
using System;
using Microsoft.CSharp;
using Microsoft.Win32.SafeHandles;
using System.Collections.Generic;
using System.Linq;

public static void Main (string[] args)
{
    var computerPlay = GetRandomOption(gameGestures);
    IList<Gesture> gameGestures = GetGestures();

    public static Gesture GetRandomOption (IList<Gesture> options)
    {
        Random rand = new Random();
        var returnVariable = options[rand.Next (0,options.Count)];
        return options[4];  //chosen by fair dice roll.
                            //guaranteed to be random.
    }

    // http://xkcd.com/221/

    static IList<Gesture> GetGestures()
    {
        var v = new Gesture("Spock");
        var l = new Gesture("Lizard");
        var p = new Gesture("Paper");
        var r = new Gesture("Rock");
        var s = new Gesture("Scissors");
    }

    Console.WriteLine(computerPlay.ToString());
}

public class Gesture
{
    public override string ToString()
    {
        return Name;
    }

    public Gesture(string name)
    {
        Name = name;
    }
}

```
> 1 votes

# Answer
# stepAhead Bot: Python 2

```
Name: stepAhead
Run:  python stepAhead.py [my_hist] [op_hist]

```

This bot tries to determine the best moves the opponent can make, based on my hands that have lost in the past, and counter them. To reduce the pool of possible counters, hands that have commonly failed in the past are removed, and hands that counter multiple "best moves" or counter commonly used opponent moves are prioritized.

```
#!/usr/bin/python
# EGYP7
# 08/03/2014
# stepAhead.py: Play to beat the opponent's best move against me.

import sys
from operator import itemgetter

DIV_FACTOR  = 1
HIST_FACTOR = 0.5
DEBUG = True

def beats(hand):
    ''' Return ways to beat "hand".
    '''
    if   hand == 'R':
        return ['P', 'V']
    elif hand == 'P':
        return ['S', 'L']
    elif hand == 'S':
        return ['V', 'R']
    elif hand == 'L':
        return ['R', 'S']
    elif hand == 'V':
        return ['L', 'P']
    else:
        return ValueError

def most_common(in_list):
    ''' Return sorted dictionary of occuring hands and their frequencies.
    '''
    log = [
            ['R', 0],
            ['P', 0],
            ['S', 0],
            ['L', 0],
            ['V', 0]
          ]

    for entry in in_list:
        for sublist in log:
            if entry in sublist:
                sublist[1] += 1

    log = sorted(log, key=itemgetter(1), reverse=True)

    return log

def decide(my_hist, op_hist):
    ''' Reads battle history, analyses and returns best move.
    '''
    global DIV_FACTOR, HIST_FACTOR

    # Find most common losing and winning hands
    wins = []
    loss = []
    for i in range(len(my_hist)):
        if op_hist[i] in beats(my_hist[i]):
            loss.append(my_hist[i])
        elif my_hist[i] in beats(op_hist[i]):
            wins.append(my_hist[i])

    loss_rank = most_common(loss)
    wins_rank = most_common(wins)

    # 1) Find my hands that lose the most
    big_loser = []

    for case in loss_rank:
        # Check for a tie
        if case[1] == loss_rank[0][1]:
            big_loser.append(case[0])
        else:
            break

    counter = []
    for loser in big_loser:
        # Find their likely moves
        for op in beats(loser):
            # Counter those moves
            for count in beats(op):
                counter.append(count)

    # 2) Don't use a counter if it's in the big_loser list
    for count in counter:
        if count in big_loser:
            counter.remove(count)

    # 3) Prioritize reoccuring counters
    counter_num = most_common(counter)

    # 4) Prioritize counters that beat commonly used op_hands
    for candidate in counter_num:
        candidate.append(0)
        for i in range(len(op_hist)):
            if candidate[0] in beats(op_hist[i]):
                candidate[2] += 1

    # 5) Return best counter by weights
    final = sorted(counter_num, key=lambda x: DIV_FACTOR*x[1] + HIST_FACTOR*x[2], reverse=True)

    print final[0][0]
    return

if __name__ == "__main__":
    if len(sys.argv) != 3:
        # First Round: Lizard
        print 'L'
        exit(-1)

    # Not first round
    my_hist = sys.argv[1]
    op_hist = sys.argv[2]

    decide(my_hist, op_hist)

```

PS: Thank you, Eoin, for opening this question back up to novices like myself!
> 1 votes

# Answer
# The Triangulator: Python 3.2

This program takes the previously played moves, analyses for biases and adds biases to its own moves. Throughout the game it is constantly triangulating its play pattern. (This is my serious entry)

Run:

```
python triangulator.py [arg1] [arg2]

```

Code:

```
import sys, random

# Set all biases to zero for first round
biases = {"R": "-",
          "P": "-",
          "S": "-",
          "L": "-",
          "V": "-"}

beating = {"R": "PV",
           "P": "SL",
           "S": "RV",
           "L": "SR",
           "V": "PL"}

numbertimes = {"R": 0,
               "P": 0,
               "S": 0,
               "L": 0,
               "V": 0}

choices = ["R", "P", "S", "L", "V"]

chooser = []

if len(sys.argv) != 3 or len(sys.argv[2]) < 4:
    # Just selects a random choice during first few steps
    print(random.choice(choices))

else:
    oppmoves = sys.argv[2]

    # Finds how many times each move has been played by opponent
    for i in range(0, len(oppmoves)):
        numbertimes[oppmoves[i]] += 1

    # Changes the biases
    for j in range(0, len(choices)):
        if numbertimes[choices[j]]/len(oppmoves) == 1:
            pattern = choices[j]
            moves = beating[choices[j]]
            biases[moves[0]] = "^"
            biases[moves[1]] = "^"

            for k in range(0, len(choices)):
                if not biases[choices[k]] == "^":
                    biases[choices[k]] = "X"

        elif numbertimes[choices[j]]/len(oppmoves) > 0.75:
            pattern = choices[j]
            moves = beating[choices[j]]
            biases[moves[0]] = "!"
            biases[moves[1]] = "!"

        elif numbertimes[choices[j]]/len(oppmoves) > 0.5:
            pattern = choices[j]
            moves = beating[choices[j]]
            biases[moves[0]] = "!"
            biases[moves[1]] = "!"

    # Creates a biased array based upon the previously defined biases
    for a in range(0, len(choices)):
        if biases[choices[a]] == "^":
            it = 16
        elif biases[choices[a]] == "!":
            it = 4
        elif biases[choices[a]] == "-":
            it = 1
        elif biases[choices[a]] == "X":
            it = 0
        for b in range(0, it):
            chooser.insert(len(chooser), choices[a])

    # Prints the move
    print(random.choice(chooser))

```
> 1 votes

# Answer
# Golfscript - CaptainObvious

Chooses the move which, when played against all of the opponent's previous moves, has the highest score. Golfed down to 73 bytes for fun:

**Use this code:**

```
' #'+' '/1=1/:H;"RPSVL"1/.{:x;H{x=},,}%:C;5,{0\{)5%.C=@+~)\}4*;}%.$0=?=

```

**Run with:**

```
echo arg1 arg2 | ruby golfscript.rb CaptainObvious.gs

```

where golfscript.rb is downloaded from golfscript.com 's "Download" tab

**Ungolfed & commented:**

```
' #'+                       #Handles initial case
' '/1=1/       :History;    #Opponent's move history
"RPSVL"1/      :Options     #The 5 moves, strategically ordered
{
  :x History{x=},,\;
}%
               :Counts;     #Count array corresponding to chars
5,
{
  )5%. Counts=-1* \
  )5%. Counts=    \
  )5%. Counts=-1* \
  )5%  Counts=
  ]{+}*
}%
.$)\;
?Options=

```
> 1 votes

# Answer
# PrediKitty - Perl

```
BotName: PrediKitty
Compile: Just save as predikitty.pl
Run: perl predikitty.pl [my moves] [opponent moves]

```

PrediKitty outputs its move to STDOUT as one of `RPSLV`. The data is inputted on the command line (with PrediKitty's move history first), and it does not matter the history size. (If I've made an error, let me know)
Here's the code:

```
    # Accept inputs
@mine = split('', $ARGV[0]);
@yours = split('', $ARGV[1]);
# Initialize hashes
%mine_freq = ();
%your_freq = ();
foreach $sym (['R', 'P', 'S', 'L', 'V']) {
 $mine_freq[$sym] = 0;
 $your_freq[$sym] = 0;
}
# OK, next up, make a possibility pool.
my @possibilities;
$count = 0;
$possibilities[$count][0] = 'R';
$possibilities[$count][1] = 'P';
$possibilities[$count][2] = 'S';
$possibilities[$count][3] = 'L';
$possibilities[$count][4] = 'V';
$count++;
# Now gather data
foreach $sym (@mine) {
 $mine_freq[$sym] = $mine_freq[$sym] + 1;
}
# Here's where it gets fun: Based on earlier predictions, add to the pool!
foreach $sym (@yours) {
 $your_freq[$sym] = $your_freq[$sym] + 1;
 # Add two of each of the things that beat it, and one that ties it (in case we are wrong)
 if ($sym == 'R') {
$possibilities[$count][0] = 'R';
$possibilities[$count][1] = 'P';
$possibilities[$count][2] = 'P';
$possibilities[$count][3] = 'V';
$possibilities[$count][4] = 'V';
 } elsif ($sym == 'S') {
$possibilities[$count][0] = 'S';
$possibilities[$count][1] = 'R';
$possibilities[$count][2] = 'R';
$possibilities[$count][3] = 'V';
$possibilities[$count][4] = 'V';
 } elsif ($sym == 'P') {
$possibilities[$count][0] = 'P';
$possibilities[$count][1] = 'S';
$possibilities[$count][2] = 'S';
$possibilities[$count][3] = 'L';
$possibilities[$count][4] = 'L';
 } elsif ($sym == 'L') {
$possibilities[$count][0] = 'L';
$possibilities[$count][1] = 'S';
$possibilities[$count][2] = 'S';
$possibilities[$count][3] = 'R';
$possibilities[$count][4] = 'R';
 } elsif ($sym == 'V') {
$possibilities[$count][0] = 'V';
$possibilities[$count][1] = 'P';
$possibilities[$count][2] = 'P';
$possibilities[$count][3] = 'L';
$possibilities[$count][4] = 'L';
 } else {
  next; # If somewhere a bot fails, this shouldn't affect us
 }
  $count++;
}
# Now, get a random pool from the meta-pool (which is my new invention)
THROW: {
$pool_num =  int(rand(( scalar @possibilities )));
# And a choice
$choice_num = int(rand(5));
# This is to add some extra random - You never know when you'll need it...
$pick_random = int(rand(50));
if ($pick_random == 0) {
 $pool_num = 0; # Go back to our random pool
}
$redo = int(rand(10));
if ($redo == 0) {
 redo THROW;
}
# Now calculate and output!
$chosen_throw = $possibilities[$pool_num][$choice_num];
print $chosen_throw;
}
# Hey, did you really scroll all the way down here? Good job!
# Have a smiley. ;D

```

I will be happy to update should the terms of the challenge change. But for now, this should rock! Or should I say rock-paper-scissors-lizard-spock? No, I shouldn't.
> 1 votes

# Answer
# UnlimitedMarkovBot (java)

Try to find how the previous steps affected the opponent play and adapt

```
public class UnlimitedMarkovBot{
    public static void main(String[] args){

        char[] plays = new char[]{'R','S','L','P','V'};

        if (args.length == 0){
            System.out.print('V');
            return;
        }

        char[] myHis = args[0].toCharArray();
        char[] opHis = args[1].toCharArray();

        int[] myHis_n = new int[myHis.length];
        int[] opHis_n = new int[opHis.length];

        for (int i = 0; i < myHis.length; i++){
            for (int k = 0; k < 5; k++){
                if (myHis[i] == plays[k])
                    myHis_n[i] = k;
                if (opHis[i] == plays[k])
                    opHis_n[i] = k;
            }
        }

        double [][][] myMarkovMatrix = new double[myHis.length][5][5];
        double [][][] opMarkovMatrix = new double[myHis.length][5][5];

        double[] estProb = new double[5];

        for (int i = 0; i < myHis.length; i++){
            for (int j = 0; j < i; j++){
                    myMarkovMatrix[i-j][myHis_n[j]][opHis_n[i]] +=1;
                    opMarkovMatrix[i-j][opHis_n[j]][opHis_n[i]] +=1;
            }
        }

        double coeff = 0.8;
        double c = 1;
        for (int i = 1; i < myHis.length; i++){
            for (int k = 0; k < 5; k++){

                estProb[k] += c*myMarkovMatrix[i][myHis_n[myHis.length - 1]][k];
                estProb[k] += c*opMarkovMatrix[i][opHis_n[myHis.length - i]][k];
                c*= coeff;
            }
        }
        int best = 0;
        double bestScore = 0;
        for (int k = 0; k < 5; k++){
            if ( estProb[k]+2*estProb[(k+1)%5]+ 2*estProb[(k+2)%5]> bestScore){
                bestScore = estProb[k]+2*estProb[(k+1)%5]+ 2*estProb[(k+2)%5];
                best = k;

            }
        }
        System.out.print(plays[best]);
    }
}

```
> 1 votes

# Answer
# PatternFinder

```
BotName: PatternFinder
Run: python3 patternFinder.py [mine] [his]

```

It's based on the code that's giving me the best results in the Loaded RPS, where it looks for pattern of an opponent taking into account my last play or his (and stick to the one he seems to be using).

```
import sys
import random
import numpy as np

if __name__ == "__main__":

        if len(sys.argv) != 3:
                print("R")
                exit(-1)

        my_history = sys.argv[1]
        opp_history = sys.argv[2]

        t = len(opp_history)
        RPS = ["R","P","S","L","V"]
        if t < 5:
                print(RPS[t])
        elif t == 5:
                print(random.choice(RPS))

        def n(c): return RPS.index(c)

        total_me = np.zeros(shape=(5,5))
        total_opp= np.zeros(shape=(5,5))
        p_me = np.array([[.2]*5]*5)
        p_opp = np.array([[.2]*5]*5)

        for i in range(1, t):
                total_me[n(my_history[i-1]), n(opp_history[i])] += 1
                total_opp[n(opp_history[i-1]), n(opp_history[i])] += 1
        for i in range(3):
                if np.sum(total_me[i,:]) != 0:
                        p_me[i,:] = total_me[i,:] / np.sum(total_me[i,:])
                if np.sum(total_opp[i,:]) != 0:
                        p_opp[i,:] = total_opp[i,:] / np.sum(total_opp[i,:])

        error_me = 0
        error_opp = 0

        for i in range(1, t):
                diff = 1 - p_me[n(my_history[i-1]), n(opp_history[i])]
                error_me += diff * diff
                diff = 1 - p_opp[n(opp_history[i-1]), n(opp_history[i])]
                error_opp += diff * diff

        if error_me < error_opp:
                p = p_me[n(my_history[-1]),:]
        else:
                p = p_opp[n(opp_history[-1]),:]

        win = [[2,3],[0,4],[1,3],[1,4],[0,2]]
        lose = [[1,4],[2,3],[0,4],[0,2],[1,3]]

        best_score = -1000
        for i in range(5):
                E = p[win[i][0]] + p[win[i][1]] - p[lose[i][0]] - p[lose[i][0]]
                if E > best_score:
                        best_idx = i

        print(RPS[best_idx])

```
> 0 votes

---
Tags: king-of-the-hill
---