# 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.

• 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

• 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)
{
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

-
What does the history look like when a player has forfeited a hand? – histocrat Jul 25 '14 at 17:41
I was going to go all-out with an analytic approach, but most of the bots here are stupid enough to defeat smart AI. – fluffy Jul 25 '14 at 21:23
Just because I never am in the lead for any KotH challenge I've competed in, I've taken a screenshot as a memento. – Kyle Kanos Jul 26 '14 at 2:55
I'll run another tourney tonight and post the full match results on pastebin... next batch will have about 450 games but should be a bit quicker to run as I've implemented some parallelization stuff in the control prog – Eoin Campbell Jul 28 '14 at 7:55
If I'm not mistaken, there seems to be a serious bug in the orchestration script: The histories of player 1 and 2 are always passed to the bots as first and second argument respectively, while according to the rules the bots should always get their own history first. Now player 2 is effectively trying to beat itself. (I got a bit suspicious because my bot won every single match where it was player 1 while losing half of the other matches.) – Emil Jul 29 '14 at 7:07

# 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.

-
A 96 percent win ratio is outstanding. – AndoDaan Jul 31 '14 at 0:56
Very nice. You may like Iocaine Powder, if you haven't seen it already. – WChargin Jul 31 '14 at 5:14
@WChargin, of course. :) When I wrote my original code, I had read about Iocaine Powder some years earlier and vaguely remembered the general idea. So, Pony is indeed inspired by it, if not very directly. As it turns out, they are very similar. I think mine has a wider repertoire of strategies while Iocaine Powder has a clever level of meta-meta reasoning that I did not include. – Emil Jul 31 '14 at 6:00

## 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

-
And then I use this program to determine the most possible move that I will do next then find out what you will do and finally find a way to beat what you will do and infinite-loop the whole thing again, again and again. – Jamie Jul 29 '14 at 0:35
@Jamie You mean like this guy? codegolf.stackexchange.com/a/35295/8478 – Martin Büttner Jul 29 '14 at 6:51
you guess it. (the comment was not long enough to be posted) – Jamie Jul 29 '14 at 23:22

## ConservativeBot, Ruby

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


Run like

ruby conservative.rb

-
OG version is the best version. – maxywb Jul 25 '14 at 16:25
Added to Controller – Eoin Campbell Jul 25 '14 at 17:51
@EoinCampbell I don't think it's necessary to inform everyone in a comment. It just clutters the page. I suggest that you instead just mention which bots didn't make it into a leaderboard, although they were already posted, like Doorknob does here. – Martin Büttner Jul 25 '14 at 18:09
sure. good suggestion. – Eoin Campbell Jul 25 '14 at 18:17

## 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

-

## Star Wars Fan - Ruby

Screw you, Spock

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


Run it like:

ruby starwarsfan.rb

-
Added to Controller – Eoin Campbell Jul 25 '14 at 17:50
you can rollback by answer edit - I'll just comment here when I've added them. – Eoin Campbell Jul 25 '14 at 17:50
Why R and S? :P – cjfaure Jul 26 '14 at 13:48
@mardavi It is a Star Wars fan because it does not use Spock. – William Barbosa Jul 28 '14 at 10:47
ah, you are right (of course). I read it too fast, my mistake (but without consequences luckily) – mardavi Jul 28 '14 at 11:05

# 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;
}
}
}

-
Note tht if this is a strategy that someone else is already using let me know and I'll delete. It just feels like the obvious one I didn't already see. – kaine Jul 25 '14 at 18:15
is this C#. you're .length properties are wrong. and theres no method max – Eoin Campbell Jul 25 '14 at 18:46
@EoinCampbell It is java, i've been playing with both and apparently forgot which commands belong to which. – kaine Jul 25 '14 at 19:09
ah cool. leave it with me and I'll get it included. – Eoin Campbell Jul 25 '14 at 19:12
still broken. running jre8 - java BoringBot.java - Error: Could not find or load main class D:\My Software Dev\big-bang-game\BigBang.Orchestrator\bin\Debug\Players\BoringBot\BoringBot.jav‌​a - – Eoin Campbell Jul 26 '14 at 0:24

## 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)
{
}
}

// 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)
{
}
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];
}
}

-

# 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;
}
}

-
Should we be using print or println?... I wasn't certain. – kaine Jul 25 '14 at 20:31
Hmmm. I would imagine both would work, but I could see println messing up if the control program grabbed the newline instead of the character. Thanks for pointing that out, I'll edit my code just in case – Stranjyr Jul 25 '14 at 20:34
@Stranjyr there were some bugs in your last run. It didn't bomb the control program but if you search the history for "ToddlerProof plays n" it looks like your bot was returning null for certain hands and then autolosing the hand. Example game is "Echo & ToddlerProof" where Echo played "LVSPRLV" before your bot started to crap out. – Eoin Campbell Jul 30 '14 at 13:09
@Eion Campbell Thanks for mentioning it. I saw that earlier when you posted the logs from the failed tourney, and I think I have it fixed. It was running into an error where if it lost more than 5 straight, instead of jumping to a random play it just threw an invalid value. And then, because that made it lose, it threw another invalid value. A vicious cycle. – Stranjyr Jul 30 '14 at 13:32
Cool. Have it updated in the control prog now. – Eoin Campbell Jul 31 '14 at 17:09

## 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

-
Minor name clash. +1 anyway. – Martin Büttner Jul 28 '14 at 14:06
@MartinBüttner Damn, didn't notice that. The programs still seem to do different things though - and at least Lisa here can feel more superior by beating two different versions of her brother. – Dr R Dizzle Jul 28 '14 at 14:17
Sheldor agrees... there shall be a BartBot and a BartSimpson :) – Eoin Campbell Jul 28 '14 at 15:36
We only have BortBot. – JoshDM Jul 28 '14 at 18:42
These will get slaughtered by markov :) – Cruncher Jul 29 '14 at 19:03

# 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]);
}
}
}
}

-

## 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.)

-
Need to look back at the episodes to see if anyone was born with a forked tongue. LizardMan FTW !!! – Eoin Campbell Jul 25 '14 at 17:05
But isn't this how everyone on big bang plays anyways? – kaine Jul 25 '14 at 17:24
@anotherguest That's what I meant by "this is the only in-character strategy". – Martin Büttner Jul 25 '14 at 17:24

## 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

-
You keep using that word. I do not think it means what you think it means. – JoshDM Jul 28 '14 at 20:25
The real power of Iocaine Powder was that is switches between using the markov and beating-markov. It starts out as smart markov, but once it senses (starts losing) it jumps into beating-markov mode. Should be easy to add. – Roy van Rijn Jul 30 '14 at 14:39
Ahh, clever! Not gonna lie, I had only heard Iocaine described to me, not actually looked at it in detail. Feel free to modify my code if you'd like or submit your own and get the credit! – jmite Jul 30 '14 at 17:11

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");
}
}

-

# 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  - Updated.......... – Eoin Campbell Jul 29 '14 at 17:04 ## 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 - Yeah, thought about that. – Seeq Jul 28 '14 at 8:15 # 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. - I believe that's how you run it if you jar it first. If you simply compile it first, then java ABot should work (remember to name the file the same as the public class) – Justin Jul 26 '14 at 4:49 Thanks! As a relatively new programmer I was not aware of this. – Stretch Maniac Jul 26 '14 at 13:39 # 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"); ?>  - ## 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  - # 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  - @MartinBüttner: Command added! I have been pretty busy at work trying to get something published, hence the disappearance. – Kyle Kanos Jul 25 '14 at 16:31 breaks on first run with no args. Traceback (most recent call last): File "LexicographicBot\LexicographicBot.py", line 10, in <module> opponent = sys.argv[2] IndexError: list index out of range – Eoin Campbell Jul 25 '14 at 19:30 @EoinCampbell: I forgot the exit clause on first run, it's been added & should work fine now. – Kyle Kanos Jul 25 '14 at 19:55 yep. fixed now. thanks – Eoin Campbell Jul 25 '14 at 20:05 # 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. - # 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; } }  - # 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; } } }  - # 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. :) - On what condition does TheGambler change MODE? – Dr R Dizzle Jul 29 '14 at 14:50 @DrRDizzle It doesn't, it looks like this is a submit of two bots in one. – Paŭlo Ebermann Jul 29 '14 at 16:17 Would this program not be more effective if MODE switched if you lose more than a certain amount of times in a row? – Dr R Dizzle Jul 31 '14 at 9:00 ## 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  - After reading the title, I'm slightly disappointed that you do anything but R. ;) – Martin Büttner Jul 25 '14 at 16:53 @mccannf. having some problems with this one... I've installed cygwin and modified your scripts with fully qualified paths to C:\Cygwin\bin for od.exe, xargs.exe & echo.exe. still getting the following error. C:/Cygwin/bin/xargs: echo: No such file or directory % 5 ")syntax error: operand expected (error token is " – Eoin Campbell Jul 27 '14 at 20:44 @EoinCampbell - when you create the file in windows, can you then run dos2unix on the file in cygwin before executing it? – mccannf Jul 27 '14 at 21:00 sure. I'll give that a try. – Eoin Campbell Jul 27 '14 at 21:13 I think the problem might be with the /dev/urandom statement – Eoin Campbell Jul 27 '14 at 21:20 # 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 - Summary of this algorithm: look at what the opponent last played, and then randomly play one of the two moves that would lose against the opponent's last move if they played it again. So it's better against bots that don't play the same move twice in a row. – Rory O'Kane Jul 26 '14 at 4:23 Haha. I don't really know if I did made it that way. If I am not wrong, it is actually just a convoluted way of randomly selecting any of the 5 moves. ;) – bitpwner Jul 26 '14 at 6:35 ## FairBot, Ruby Let's start simple. puts ['R','P','S','L','V'].sample  Run like ruby fairbot.rb  - small typo on that last 'V' param. have fixed it on myside if you wanna update for completeness – Eoin Campbell Jul 25 '14 at 18:50 @EoinCampbell thanks, fixed! – Martin Büttner Jul 25 '14 at 18:56 The interesting thing is that this has exactly equal odds of winning against ALL strategies. – Cruncher Jul 29 '14 at 18:58 # 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)  - breaks with no params. Traceback (most recent call last): File "ViolentBot\ViolentBot.py", line 9, in <module> opponent = sys.argv[2] IndexError: list index out of range – Eoin Campbell Jul 25 '14 at 19:26 breaks with params. Traceback (most recent call last): File "ViolentBot\ViolentBot.py", line 12, in <module> print(choice_dict[opponent_last]) KeyError: 'S' – Eoin Campbell Jul 25 '14 at 19:27 @EoinCampbell: I've added an exit clause for the first run, you should be able to run it now. – Kyle Kanos Jul 25 '14 at 19:55 # 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. - # 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'

-

# 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])

-