ロック、ペーパー、はさみ、トカゲ、壮大なスポックトーナメント


98

最新のリーダーボード@ 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

トーナメントノート

除外されたボット

  • BashRocksBot-cygwin bashスクリプトを実行する.netにはまだ喜びがありません
  • CounterPreferenceBot-バグ修正待ち
  • RandomlyWeighted-バグ修正待ち
  • CasinoShakespeare-アクティブなインターネット接続が必要なため除外

元の投稿された質問

友達の家に行って、ロック、ペーパー、はさみ、トカゲ、スポックの最も壮大な対決バトルに参加しました。真のBigBangオタクスタイルでは、どのプレイヤーも自分自身をプレイしていませんが、代わりにプレイするコンソールボットを作成しています。USBキーを取り出して、ショーダウンに含めるためにSheldor the Conqueror引き渡します。ペニーは失神します。あるいは、ハワードが失神するかもしれません。レナードのアパートではここでは判断しません。

ルール

標準のロック、ペーパー、はさみ、トカゲ、スポックのルールが適用されます。

  • はさみカット紙
  • 紙が岩を覆っている
  • 岩がトカゲをつぶす
  • トカゲはスポックを毒する
  • スポックはハサミを粉砕します
  • はさみはトカゲを断頭します
  • トカゲは紙を食べる
  • 紙はスポックを反証する
  • スポックがロックを蒸発させる
  • 岩はさみ

RPSLVルール

各プレイヤーのボットは、トーナメントで他のボットに対して1つのマッチをプレイします。

各試合は、RPSLVゲームの100回の反復で構成されます。

各試合の後、勝者は100の中で最も多くのゲーム/ハンドに勝ったプレーヤーです。

試合に勝った場合、リーグテーブルで1ポイントが割り当てられます。ドローマッチの結果、どちらのプレイヤーもポイントを獲得できません。

ボットの要件

ボットはコマンドラインから実行可能でなければなりません。

Sheldorの* nixボックスはなくなったため、彼のwindows 8 Gaming Laptopから実行しているので、提供されたソリューションがWindowsで実行できることを確認してください。Sheldorは、ソリューションを実行するために必要なランタイムを(理由の範囲内で)インストールすることを丁寧に提案しました。(.NET、Java、PHP、Python、Ruby、Powershell ...)

インプット

各試合の最初のゲームでは、ボットに引数は提供されません。各試合の以降の各ゲームでは、次のようになります。-Arg1には、この試合のボットのハンド/決定の履歴が含まれます。-Arg2には、この試合の対戦相手のハンド/決定の履歴が含まれます。

歴史は、あなたがプレイできるハンドを表す単一の大文字のシーケンスによって表されます。

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

例えば

  • ゲーム1:MyBot.exe
  • ゲーム2:MyBot.exe SV
  • ゲーム3:MyBot.exe SS VL
  • ゲーム4:MyBot.exe SSR VLS

出力

ボットは、各ゲームの「手」を表す1つのキャラクターレスポンスを記述する必要があります。結果はSTDOUTに書き込まれ、ボットは終了します。有効な単一の大文字は次のとおりです。

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

ボットが有効なハンドを返さない場合(つまり、上記の5つの大文字のうち1つがあれば、そのハンドは自動的に没収され、試合が続行されます)。

両方のボットが有効なハンドを返さない場合、ゲームは引き分けと見なされ、試合が続行されます。

マッチ形式

提出された各ボットは、トーナメントで他のボットと1試合します。

各試合はちょうど100ゲーム続きます。

対戦は匿名で行われ、対戦している特定のボットに関する高度な知識はありませんが、現在の試合の履歴中に彼の意思決定から得られるあらゆる情報を使用して、あなたに対する戦略を変更することができます相手。また、以前のゲームの履歴を追跡して、パターン/ヒューリスティックなどを構築することもできます...(以下のルールを参照)

単一のゲーム中、オーケストレーションエンジンはボットと対戦相手のボットを100ミリ秒間隔で実行し、結果を比較して同じ言語/ランタイムでのPRNG衝突を回避します。(これは実際にテスト中に私に起こりました)。

判断と制約

Sheldor the Conquerorを装ったDr. Sheldon Cooperは、トーナメントの運営を監督することを親切に申し出ました。Sheldor the Conquerorは公正で、ちょうど監督です(ほとんど)。Sheldorによるすべての決定は最終的なものです。

ゲームは公正かつ適切な方法で実施されます。

  • ボットスクリプト/プログラムは、サブフォルダーの下のオーケストレーションエンジンに保存されます Players\[YourBotName]\
  • サブフォルダーPlayers\[YourBotName]\dataを使用して、進行中の現在のトーナメントのデータまたはゲーム履歴を記録できます。データディレクトリは、各トーナメントの開始時に消去されます。
  • トーナメントの他のプレイヤーのプレイヤーディレクトリにアクセスすることはできません
  • ボットは、別の特定のボットの動作をターゲットとする特定のコードを持つことができません
  • 各プレイヤーは、相互に対話したり支援したりしない限り、複数のボットを送信できます。

編集-追加の制約

  • 没収に関しては、サポートされません。ボットは5つの有効なハンドのいずれかをプレイする必要があります。トーナメント以外の各ボットをランダムデータでテストして、動作を確認します。エラー(つまり、エラーを失った)を投げたボットは、バグが修正されるまでトーナメントから除外されます。
  • ボットは、動作が簡潔に異なる限り、派生物である場合があります。既存のボットとまったく同じ動作をするボット(他の言語を含む)は失格となります
  • 次のスパムボットは既に存在するため、再送信しないでください
    • ロック-BartSimpson
    • ペーパー-LisaSimpson
    • シザー-EdwardScissorhands
    • スポック-バルカン
    • トカゲ-Khaleesi
    • 擬似ランダム-SimpleRandomBotおよびFairBot
    • 擬似ランダムRPS-ConservativeBot
    • 擬似ランダムLV-バーニー・スティンソン
  • ボットは、サードパーティのサービスまたはWebリソース(または、試合の時間/意思決定の速度を大幅に低下させるその他のもの)を呼び出すことはできません。CasinoShakespeareこの制約が追加される前にそのボットが送信されたため、唯一の例外です。

Sheldorは、より多くのボットが送信されるたびに、トーナメント結果でこの質問をできる限り頻繁に更新します。

オーケストレーション/制御プログラム

オーケストレーションプログラムと各ボットのソースコードは、githubで入手できます。

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

提出の詳細

提出には以下を含める必要があります

  • ボットの名前
  • あなたのコード
  • へのコマンド
    • 例えば、シェルからボットを実行します
    • ルビーmyBot.rb
    • python3 myBot.py
    • または
    • 最初に両方をコンパイルしてから実行します。例えば
    • csc.exe MyBot.cs
    • MyBot.exe

サンプル提出

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

コード:

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

明確化

質問がある場合は、以下のコメントで質問してください。


7
プレイヤーがハンドを失ったときの履歴はどのように見えますか?
histocrat

1
私は分析的アプローチで全面的に取り組むつもりでしたが、ここのボットのほとんどは、スマートAIを打ち負かすほど愚かです。
ふわふわ14

1
私はちょうどので、決してためのリードで午前どの私が競ってきたケートの挑戦、私は記念品として、スクリーンショットを撮影しました。
カイルカノス14

3
今夜、別のトーナメントを開催し、完全な試合結果をpastebinに投稿します。次のバッチには約450のゲームがありますが、コントロールプログラムに並列化機能を実装したため、実行が少し速くなります
Eoin Campbell

3
誤解していない場合、オーケストレーションスクリプトに重大なバグがあるようです。プレーヤー1と2の履歴は、それぞれ第1と第2の引数として常にボットに渡されますが、ルールに従って、ボットは常に最初に自分の歴史。プレイヤー2は、効果的に自分自身を打ち負かそうとしています。(ボットがプレーヤー1であるすべての試合で勝ち、他の試合の半分を失ったため、少し疑わしくなりました。)
エミール14

回答:


26

ポニー(Python 2)

これは、先ほどUdacityオンラインクラスの終わりにプログラミングの課題のために書いたじゃんけんボットに基づいています。スポックとトカゲを含めるように変更し、いくつかの改善を行いました。

このプログラムには11の異なる単純な戦略があり、それぞれに5つのバリアントがあります。前回のラウンドでどれだけうまくいったかによって、これらの中から選択します。

強い敵とランダムに対戦するフォールバック戦略を削除しました。このようにもっと楽しいと思います。

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]

として実行:

python Pony.py

編集:不確実な場合に最も単純な戦略(つまり、常に同じ動きをする)にバイアスをかけることにより、小さな変更を加えました。これは、ConservativeBotのようなボットなど、存在しない過度に複雑なパターンを見つけようとしないようにするのに役立ちます。

:他のボットDienstagの投稿で、このボットが使用する基本的な履歴マッチング戦略を説明しようとしました。


3
96%の勝率は傑出しています。
AndoDaan

非常に素晴らしい。まだ見ていなければ、あなたはIocaine Powderを好むかもしれません。
wchargin 14

もちろん、@ WChargin。:)元のコードを書いたとき、私は数年前にIocaine Powderについて読んでいたので、一般的な考えを漠然と覚えていました。それで、ポニーは、非常に直接的ではないにしても、確かにそれに触発されています。結局のところ、それらは非常に似ています。Iocaine Powderには含まれていないメタメタ推論の巧妙なレベルがありますが、鉱山には戦略のより広いレパートリーがあると思います。
エミール14

20

マルコフ、ルビー

相手の最後の2つの動きを見て、可能な(そして最も可能性の高い)フォローアップを決定します。組み合わせが以前に選択されていなかった場合、代わりに(これまでの)相手のすべての動きを使用します。次に、彼はこれらの可能な応答をすべて収集し、ランダムな応答を選択します。

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

のように走る

markov.rb

そして、このプログラムを使用して、次に実行する最も可能性のある動きを判断し、次に何をするかを見つけ、最後に何をするかを打ち負かし、全体を何度も何度も無限ループさせる方法を見つけます。
ジェイミー14

@ジェイミーあなたはこの男のような意味ですか?codegolf.stackexchange.com/a/35295/8478
マーティン・エンダー

あなたはそれを推測します。(コメントは投稿するのに十分な長さではありませんでした)
ジェイミー14


13

スターウォーズファン-ルビー

ネジ止め、スポック

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

次のように実行します:

ruby starwarsfan.rb

コントローラーに追加
Eoin Campbell 14

回答編集でロールバックできます-それらを追加したら、ここでコメントします。
エオインキャンベル14

なぜRとSなのか?:P
cjfaure 14

@mardaviスポックを使用していないため、スターウォーズのファンです。
ウィリアムバルボサ14

ああ、あなたは正しい(もちろん)。私は、それはあまりにも速く私のミス(幸いにも影響なし)読み
mardavi

13

バーニースティンソン-ルア

ルールは1つだけです。新しいものは常に優れています。古いジョーケンポーまたはあなたがそれを呼ぶものは何でもねじ込みます。

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

次のように実行します:

lua legenwaitforitdary.lua

8

退屈なボット(Java)

彼は誰もが常に同じことをしていると想定し、それに応じて計画します。彼は通常、他の誰もが正しいので、結束して岩を選びます。

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

これが他の誰かがすでに使用している戦略である場合はお知らせください。削除します。それは私がまだ見なかった明らかなもののように感じます。
ケイン14

これはC#です。あなたは.lengthプロパティが間違っています。方法はありませんmax
キャンベル14

@EoinCampbellこれはjavaであり、私は両方で遊んでおり、どのコマンドがどのコマンドに属しているかを忘れているようです。
ケイン14

ああクール。それを私に残して、私はそれを含めます
エオインキャンベル14

まだ壊れています。jre8の実行-java BoringBot.java-エラー:メインクラスD:\ My Software Dev \ big-bang-game \ BigBang.Orchestrator \ bin \ Debug \ Players \ BoringBot \ BoringBot.javaが見つからないかロードできませんでした
Eoin Campbell

8

IocainePowder、Ruby

ここに画像の説明を入力してください

ここで RPS戦略に基づいて(恥知らずに盗まれました)。ボットの外観は、マルコフボットと同じ推測を選択しますが、対戦相手が何を選択するかを推測したと想定し、それに応じてその1つを倒す動きを選択します。

リンクされた戦略の基本的な考え方を適応させただけであり、詳細には従わないことに注意してください。

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

のように走る

iocaine.rb

5
その言葉を使い続けます。私はそれがあなたがそれが意味すると思うものを意味するとは思わない。
JoshDM 14

2
Iocaine Powderの真の力は、markovとbeating-markovの使用を切り替えることでした。スマートマルコフとして開始しますが、一度検知すると(負け始めると)ビートマルコフモードにジャンプします。追加しやすいはずです。
ロイヴァンレイン

ああ、賢い!嘘をつくつもりはありませんが、私はイオカインが私に説明されているのを聞いただけで、実際にはそれを詳しく見ていませんでした。ご希望の場合は自由にコードを変更するか、独自のコードを送信してクレジットを取得してください!
jmite 14

8

HuddleWolfTheConqueror-C#

HuddleWolfが戻ってきて、かつてないほど良くなりました。彼は自分の愚かなゲームで征服者シェルダーを倒します。HuddleWolfは、スパマーボットを特定して対処するのに十分なほどスマートです。より知的な対戦相手の場合、HuddleWolfは基本的な5年生統計の知識を活用し、対戦相手のプレイの履歴に基づいた重み付きダイスロールを利用します。

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

幼児証明

このかなり馬鹿なボットは、動きを「追いかける」幼児を演じていると想定し、常に最後に投げられたものを打ち負かそうとします。ボットが連続して数回叩かれた場合、パターン内の新しいポイントにジャンプします。それは、私のずっと弟を常に打ち負かすという私の戦略に基づいています。:)

編集::ランダムスローにジャンプするために必要な損失ストリークの長さを変更しました。また、ランダムジャンプに関する主要なバグを修正しました。

として保存しToddlerProof.java、コンパイルしてから実行します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;
    }
}

1
printまたはprintlnを使用する必要がありますか?...わかりませんでした。
ケイン14

うーん。両方とも機能すると思いますが、制御プログラムが文字ではなく改行を取得すると、printlnが混乱するのを見ることができました。それを指摘してくれてありがとう、私は念のために私のコードを編集します
Stranjyr

@Stranjyr、最後の実行でいくつかのバグがありました。制御プログラムを爆撃しませんでしたが、「ToddlerProof plays n」の履歴を検索すると、ボットが特定のハンドに対してnullを返し、ハンドをオートロスしているように見えます。例のゲームは「Echo&ToddlerProof」で、Echoがボットを開始する前に「LVSPRLV」をプレイしました。
エオインキャンベル14

@Eion Campbell言及してくれてありがとう。失敗したトーナメントのログを投稿したとき、私はそれを以前に見ました、そして私はそれを直したと思います。エラーが発生し、5を超えるストレートを失うと、ランダムプレイにジャンプする代わりに、無効な値がスローされました。そして、それによりそれが失われたため、別の無効な値をスローしました。悪循環。
Stranjyr 14

クール。制御プログラムで今すぐ更新してください。
エオインキャンベル14

8

バートシンプソン

「古き良き岩!岩に勝るものはない!」

puts 'R'

として実行

ruby DoTheBartman.rb

リサ・シンプソン

「悪い、予測可能なバート。常にロックを選択します。」

puts 'P'

として実行

ruby LisaSimpson.rb

ベターリサシンプソン

私はリサをとても馬鹿にするのが嫌だと思ったので、彼女に、岩を打つ手のうちのどちらかをランダムに選択させました。まだ愚かですが、彼女は結局シンプソンです。たぶんクレヨンが彼女の脳に引っかかったのでしょうか?

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

として実行

ruby BetterLisaSimpson.rb


@MartinBüttnerくそー、気づかなかった。しかし、プログラムはまだ別のことをしているようです-そして少なくともここのリサは、彼女の兄弟の2つの異なるバージョンを破ることによって、より優れていると感じることができます。
博士Rディズル14

1
Sheldorは同意します... BartBotとBartSimpsonがあります:)
Eoin Campbell 14

3
BortBotのみがあります。
JoshDM 14

1
これらは、マルコフ:)によって虐殺されます
たけ

7

エコー

C#で書かれています。でコンパイルしcsc Echo.csます。のように実行しますEcho.exe ARG1 ARG2

最初の実行であるEchoはランダムオプションを取ります。エコーは、最初の実行の後、毎回、相手の最新のアクションを繰り返します。

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

バルカン、ルビー

指が接着されています。

puts 'V'

のように走る

ruby vulcan.rb

(これがあなたの背景設定のための唯一のキャラクター内戦略であると思います。)


エピソードを振り返って、分岐した舌で生まれた人がいるかどうかを確認する必要があります。LizardMan FTW !!!
エオインキャンベル14

3
しかし、これはビッグバンのみんながとにかくプレーする方法ではありませんか?
ケイン14

2
@anotherguest「これが唯一のキャラクター内戦略です」という意味です。
マーティンエンダー14

6

ティラノサウルス、ゴジラ、バーニー...トカゲのルール。時折、彼らはトラブルに巻き込まれ、スポックに電話するか、ロックを投げる必要があります

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

BayesianBot、Perl(現在v2!)

他の何よりも、これはユニークなプログラムです。そこには、統計と恐ろしいプログラミング形式の素晴らしい融合が見られるでしょう。また、このボットはおそらくベイジアン統計の多くの規則を破りますが、名前はもっとクールに聞こえます。

このボットの本質は、250の異なる予測モデルの作成です。各モデルは、「前のターンにロックをプレイし、2ターン前に対戦相手がハサミをプレイしたことを考えると、これは対戦相手の次の動きの確率分布です」という形をとります各確率分布は、多次元ディリクレ分布の形を取ります。

各ターンでは、適用可能なすべてのモデル(通常10)の予測が乗算されて全体的な予測が形成され、これを使用してどの動きが最も高い見返りを得るかが決定されます。

編集1:このバージョンでは、以前の配布を変更し、ボットが失われたときにボットをよりランダム化しました。

モデルの数(250は3桁の数字のみ)、事前分布の選択(現在はDir(3,3,3,3,3))など、改善の余地があるものがいくつかあります。予測を融合する方法。また、確率分布を正規化することは一切ありませんでしたが、今はそれを掛けているので大丈夫です。

私はそれほど高い期待はしていませんが、このボットがうまくいくことを願っています。

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

私はこのプログラムを次のように実行しています:

perl BayesianBot.plx

5

DynamicBot

動的ボットはほとんど常に変化しています。繰り返すのが本当に嫌い

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

言語:Python 3.4.1

コマンド:python dynamicbot.py <history>またはpython3 dynamicbot.py <history>システムに応じて


ええ、それについて考えました。
seequ 14

5

SmartBot-Java

このサイトにあるものの私の最初のエントリー!

あまり創造的な名前ではありませんが...

SmartBotは、相手や自分自身の動きが最後に行われた動きと似ている動きのシーケンスを見つけ、それに応じて計画します。

name = SmartBot

私はそれを実行すると思う、私が間違っている場合は修正してください。

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

同様のパターンが発生した回数ごとに、可能な次の動きごとにスコアを割り当てます。

トカゲをわずかに好む。


最初にjarした場合、それが実行されると思います。最初にコンパイルするだけであれば、動作するjava ABotはずです(ファイルにパブリッククラスと同じ名前を付けることを忘れないでください)
Justin

ありがとう!比較的新しいプログラマーとして、私はこれを知りませんでした。
ストレッチマニアック14

5

SpockOrRock-PHP

SpockOrRock

現実の世界でプレーするとき、ほとんどの人は本能的にはさみを選びます。このボットは、平均的なプレイヤーを倒すためにスポックまたはロックを選択します。前のラウンドについては気にしません。

と走る php spockorrock.php

<?php

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


?>

4

SlowLizard、Ruby

リザードで始めた後、それは常に相手の前の動きを打つランダムな動きを選びます。

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

のように走る

ruby slowlizard.rb

4

LexicographicBot

このボットは手紙を注文するのが好きなので、前のラウンドで相手が与えた応答よりも1高い応答を選択します-相手がバルカンを選択した場合を除き、彼はランダムに応答を選択します。

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

これは、相手のハンドが2番目に配られることを期待しています:

                           me
                            v
python LexicographicBot.py SR RV
                              ^
                            opponent

@MartinBüttner:コマンドが追加されました!私は何かを出版しようとして仕事でかなり忙しかったので、失disappearしました。
カイルカノス14

引数なしで最初の実行時に中断します。トレースバック(最新の呼び出しの最後):[2]はIndexError <モジュール>相手= sys.argvの中で、 "LexicographicBot \ LexicographicBot.py"、行10ファイル:範囲外のリストインデックス
Eoinキャンベル

@EoinCampbell:最初の実行時にexit句を忘れてしまいました。これは追加され、今は正常に動作するはずです。
カイルカノス14

4

ウェレブルカン-ルビー

として実行 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

ワルバルカンは日中は正常に見えますが、月が昇ると耳がとがり、動きがより論理的になります。


4

アナログ化-Ruby

で実行しruby analogizer.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

  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

相手のボットは常に私の前の動きに反応し、それを打ち負かすもの、負けるもの、または可能性のある制限された動きのセットから同じ動きを選ぶと仮定します。次に、その仮定に基づいて最適な動きを選択します。

最初の10の動きがハードコードされていることを除いて、最初はトカゲしか知らないふりをしてから、適切な分析に十分なデータが得られるまで、相手が常に最後に投げたものを打ち負かすために何かを投げると仮定します。


4

Java-SelfLoathingBot

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

ボットはランダムに開始し、次に〜33%がランダムに、または〜33%が直前のプレイのいずれかに対して勝利戦術をプレイし、50%の勝利戦術を選択します。

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

アナリスト

アナリストはいくつかのことを分析し、あなたを打ち負かすためにいくつかのことをします。

でコンパイルしjavac Analyst.javaて実行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

ギャンブラー-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)

名前に反して、このプログラムでランダム性が使用されるのは、情報がない最初のラウンドのみです。その代わり、ギャンブラーの誤acyにちなんで名付けられました。これは、過去にランダムなイベントがあまり頻繁に発生していなければ、将来的に発生する可能性が高いという信念です。たとえば、フェアコインを20回フリップし、最初の15がヘッドである場合、ギャンブラーの誤acyは、残りのフリップがテールであるオッズが増加すると述べています。もちろん、これは真実ではありません。前のフリップに関係なく、フェアコインのテールのオッズは常に50%です。

このプログラムは、対戦相手の履歴を分析し、これまでに使用した回数が最も少ない2つの動きを見つけ、今回の対戦相手の動きはその2つのうちの1つであると想定します。2を勝利に、1を引き分けに、0を負けに割り当て、これら2つの予測された動きに対して最大スコアの動きを見つけ、それをスローします。

ギャンブラーの兄弟-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)

MODE変数を0に切り替えることにより、このプログラムは、ギャンブラーの誤acyとも呼ばれる関連する誤acyに基づいて動作します。これは、過去にランダムなイベントがより頻繁に発生した場合、将来発生する可能性が高いと述べています。たとえば、コインを20回フリップし、最初の15がヘッドである場合、この誤acyは、現在連続しているため、残りのフリップがヘッドである可能性が高いことを示しています。モード0では、このプログラムは同じように動作しますが、これまでに最も頻繁に投げられた2つの動きのうちの1つを対戦相手が投げることを想定しています。

そのため、これら2つのプログラムは1文字しか離れていません。:)


TheGamblerはどのような条件でモードを変更しますか?
博士Rディズル

@DrRDizzleそうではありませんが、これは2つのボットを1つにまとめたもののようです。
パエロエベルマン14

2
連続して特定の時間を超えて損失した場合にモードが切り替わると、このプログラムはより効果的ではないでしょうか?
Rディズル博士14

4

Dienstag(Python 2)

私の最初のエントリーPonyは、2番目の推測(トリプル推測、...)とメタ推論ですべてうまくいくようです。しかし、それは必要ですか?

ですから、ポニーの小さな友達であるディエンスタグは、55の戦略のうちの1つだけです:相手の次の動きを予測して、それを打ちます。

長期的には、Dienstagは、現在のリーダーボードのトップ10のすべてのボットと勝つか結びつきます。つまりポニーを除いて。

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]

として実行:

python Dienstag.py

コードが少し難読化されていることを認めます。誰かがそれについてもっと知りたいと思うなら、私は説明を加えるかもしれません。

編集:これは、アイデアを説明するための簡単なチュートリアル例です:

  • プログラムは、自身の履歴と対戦相手の動きを取得します。

    sys.arg[1] = 'LLVLLVL', sys.arg[2] = 'RPSPSSP'

  • 履歴はペアのリストに結合され、移動は数字に変換されます(R = 0、...):

    hist = [[4, 0], [4, 1], [3, 2], [4, 1], [4, 2], [3, 2], [4, 1]]

  • これまでにプレイされたラウンドの数が決定されます。

    N = 7

  • 現在の基本的な考え方は、以前の履歴の最後の動きとまったく同じで最も長いチェーンを探すことです。プログラムは、そのようなチェーンがリストのどこで終わるかを追跡しますcand(「候補」の場合)。最初は、チェックせずに、最後の1つを除く履歴内のすべての位置が考慮されます。

    cand = [0, 1, 2, 3, 4, 5]

  • 現在、可能なチェーンの長さは段階的に増加しています。チェーンの長さについてl = 1は、前回の移動ペアの以前の出現を探し[4, 1]ます。これは、履歴の位置1およびで確認できます3。これらのみがcandリストに保持されます。

    cand = [1, 3]

  • 次に、l = 2可能性のある候補のうち、最後から2番目の移動ペアが先行した候補をチェックします[3, 2]。これは位置の場合のみです3

    cand = [3]

  • 以下のためにl = 3、よりそこにその長さの以前の鎖ではなく、cand空になります。この場合、の最後の要素candが保持されます。

    cand = [3]

  • ボットは、履歴が繰り返されると想定しています。カイン[3, 2], [4, 1]が最後に発生したとき、その後に続きました[4, 2]。そのため、対戦相手は2(ハサミ)をプレイしましたが、これは(2+1)%5 = 3(スポック)または(2+3)%5 = 0(ロック)で打つことができます。ボットは、N何らかの差異を導入するために奇数か偶数かによって、最初の選択肢または2番目の選択肢を選択します。

  • ここで移動3が選択され、次に翻訳されます:

    print 'V'

注: Dienstagには、Nラウンド後に次の動きを返すための時間計算量O(N 2)があります。ポニーには時間の複雑さO(N 3)があります。したがって、この側面では、おそらく他のほとんどのエントリよりもはるかに悪いでしょう。


してください。これは私にとって素晴らしい学習体験です。私は通常C#/ Javaの土地に住んでいるので、lua、ruby、python、haskellの狂気はすべて私にとって非常に興味深いものです。
エオインキャンベル14

また、ゲームにポニーの追加インスタンスを追加したいと思っています。これは、3番目から最後のMortal Combatレベルでミラーセルフと戦わなければならないようなものです;
Eoin Campbell 14

@EoinCampbell :-)少なくとも直接一致のポニー対ポニーは完璧な引き分けになります。両方のボットにランダム性の要素はありません。
エミール14

3

バッシュロックス

cygwinはランタイムとして尋ねるには多すぎますか?

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 ]}

そして次のように実行します:

sh bashrocks.sh

5
タイトルを読んだ後、あなたが他に何もしないことに少し失望していますR。;)
マーティン・エンダー14

@mccannf。これにいくつか問題があります... cygwinをインストールし、od.exe、xargs.exe、echo.exeのC:\ Cygwin \ binへの完全修飾パスでスクリプトを変更しました。まだ次のエラーが発生します。C:/ Cygwinの/ binに/ xargsの:エコー:いいえそのようなファイルやディレクトリは%5 ")構文エラー:オペランド予想(エラー・トークンがある"
Eoinキャンベル

@EoinCampbell-Windowsでファイルを作成するとき、dos2unix実行する前にcygwinのファイルで実行できますか?
mccannf 14

承知しました。それを試してみます。
Eoinキャンベル

私はこの問題では、/ dev / urandomのステートメントを使用してかもしれないと思う
Eoinキャンベル

3

アルゴリズム

持っているためのアルゴリズム。

Cuz '常に何かをする方が安全だと感じ、複雑なほど良い。

まだ本格的な数学を行っていないため、このアルゴリズムはそれほど効果的ではないかもしれません。

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プログラム: python algorithm.py


1
このアルゴリズムの要約:対戦相手が最後にプレイしたものを見てから、対戦相手が再びプレイした場合に最後の手に対して負ける2つの動きのうちの1つをランダムにプレイします。したがって、同じ動きを連続して2回プレイしないボットには向いています。
ロリーオケイン14

ハハ。そのようにしたかどうかは本当にわかりません。私が間違っていない場合、それは実際には5つの動きのいずれかをランダムに選択する複雑な方法です。;)
2014

3

FairBot、Ruby

簡単に始めましょう。

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

のように走る

ruby fairbot.rb

最後の「V」パラメータの小さなタイプミス。完全性のために更新したい場合は私の側でそれを修正しました
Eoinキャンベル14

@EoinCampbellありがとう、修正!
マーティンエンダー14

1
おもしろいことに、これはすべての戦略に対して勝利する確率がまったく等しいということです。
ランチャー14

3

ViolentBot

このボットは、対戦相手の以前の選択に基づいて最も暴力的なオプションを選択します。

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

として実行

python ViolentBot.py (me) (opp)

パラメータなしでブレークします。トレースバック(最新の呼び出しの最後):[2]はIndexError <モジュール>相手= sys.argvの中で、 "ViolentBot \ ViolentBot.py"、9行目のファイル:範囲外のリストインデックス
Eoinキャンベル

paramsで中断します。トレースバック(最新の最後の呼び出し):ファイル「ViolentBot \ ViolentBot.py」、12行目、<module> print(choice_dict [opponent_last])KeyError: 'S'
Eoin Campbell 14

@EoinCampbell:最初の実行にexit句を追加しました。今すぐ実行できるはずです。
カイルカノス14

3

Haskell-MonadBot

ghcが「理由の範囲内」であると考えられるかどうかはわかりませんが、それが正しいと仮定しましょう。このボットの戦略は、相手の最も人気のある動きに対抗することです。

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

コード:

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'
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.