首謀者の戦略


19

私は、Mastermindのコードゴルフチャレンジしか見つけることができなかったので、ここに、自分が挑戦したいコードチャレンジバージョンを示します。

通常の首謀者ゲームの最適な戦略であるMM(4,6)は、1993年に小山とライによって発見され、平均推測数= 5625/1296〜4.34でした。MM(5,8)はまだ解決されていませんが、推測の平均数は5.5であると推定されます。

あなたの仕事は、MM(5,8)戦略を作成することです。これは、5つの穴と8つの色に対応し、すべてのpow(8,5) = 32768可能な個別のソリューションをカバーします。明らかに、最適なものである必要はありません。次の2つの選択肢があります。

  1. 戦略を生成する決定論的プログラムを投稿します。このプログラムは、Windows 7、Mac OS X、またはLinux上で、フリーでないソフトウェアを追加せずにコンパイル/実行できる必要があります。
  2. 戦略を(StackExchange名とともに)インターネット上のどこかに公開し、ここにURLを投稿します。

どちらの場合も、回答のヘッダーにスコア(以下を参照)を明記してください。

戦略は、次の文法に従ってエンコードする必要があります。

strategy : guessing-strategy | known-solution-strategy
guessing-strategy : '{' guess ':' branches '}'
known-solution-strategy : guess
guess : color color color color color
color : 'A'..'H'
branches : '{' branch (',' branch)* '}'
branch : reply ':' strategy
reply : number-of-blacks number-of-whites
number-of-blacks : number-of-key-pegs
number-of-whites : number-of-key-pegs
number-of-key-pegs : '0'..'5'

ブラック/ホワイトキーペグの数を決定するために使用されるアルゴリズムは、http://en.wikipedia.org/wiki/Mastermind_(board_game)で説明されています

応答「50」(つまり、正しい推測)が暗示されており、文法の一部ではないことに注意してください。

スコアリング:N = 32768の各パス/ソリューションの推測数の合計。Nが最小の戦略が勝利します。最初のタイブレーク:推測の最小最大数。2番目のタイブレーク:最初に投稿された回答。コンテストは2014年8月1日0:00 GMTに終了します。


スコア= 21のMM(2,3)の戦略の例:

{AB:{10:{AC:{10:AA,01:CB,00:BB}},02:BA,01:{BC:{01:CA}},00:CC}}

この戦略を使用すると、9つの可能なゲームは次のようになります。

  • AB 20
  • AB 10、AC 20
  • AB 10、AC 10、AA 20
  • AB 10、AC 01、CB 20
  • AB 10、AC 00、BB 20
  • AB 02、BA 20
  • AB 01、BC 20
  • AB 01、BC 01、CA 20
  • AB 00、CC 20

便宜上、JavaベースのMM(5,8)戦略検証ツールをすぐに投稿します。


MM(2,3)の例の戦略がどのように適用されるかを理解するのは困難です。戦略を説明するサンプルゲームを投稿できますか?

@tolos私はすべて9を追加しました:)
MrBackend 14年

検証者がスコアを出力できれば素晴らしいと思います!
チャールズではない14

@チャールズはやる!
MrBackend 14年

2
複数のキーペグの組み合わせに対して同じ応答を許可するように文法を変更してもよろしいですか?好き{AB:{10|01:BB}}?私は削減可能性がある、私は答えを持っていますが、それはそれは、すべての(4つの穴、3色でうまくスケールしない文法のツリー構造にかなりナイーブと原因だ、147メガバイトの戦略を生成し、大幅の部品を組み合わせることにより、ツリー)。
マーティンエンダー

回答:


6

Java

MM(5,8)のアルゴリズムは、最大深度8 9の177902 178006 182798 182697でスコア付けされ、数秒しかかかりません(遅いコンピューターで)。

このアルゴリズムで見つかったスコア= 21のMM(2,3)の戦略の出力例は次のようになります。

{BC:{00:AA,01:AB:{01:CA},02:CB,10:AC:{00:BB,01:BA,10:CC}}}

私のアルゴリズムには刺激的なものはありません。発明なし。ネットで見つかったレシピに従って、このJavaコードに圧縮しました。私が行った唯一の最適化は、コードの行を(ある意味で)最適化しようとすることです。こんなふうになります:

  1. すべての可能なコードの初期セットS0を作成して、現在のセットSにします。
  2. CodebreakerはSの(貪欲な)良い推測を見つけます。各推測はSのパーティションPにつながり、各サブセットS 'は(Sからの)推測で同じ応答を持つすべてのコードを収集します。推測のためのほとんどの情報を提供するパーティションとして、適切な推測には適切なパーティションがあります。
  3. 適切な推測とそのPを使用します。Pの空でない各S 'に対して、コードブレーカーを再帰的に適用します(ステップ2)。

@MrBackend:検証者を書くのは難しいと思います。;-)

import java.util.TreeMap;
import java.util.Vector;

public class MM {
    Vector<String> codeset = new Vector<String>();
    String guess;
    TreeMap<Integer, MM> strategy = new TreeMap<Integer, MM>();

    public String toString() {
        String list="";
        for (Integer reply: strategy.keySet()) {
            if (strategy.get(reply)!=null) list+=(list.length()>0?",":"")+(reply<10?"0":"")+reply+":"+strategy.get(reply);
        }
        if (list.length()>0) return guess+":{"+list+"}"; else return guess;
    }

    MM() { }

    MM(int h, int c) {
        for (int i = 0; i < Math.pow(c, h); i++) {
            String code = "";
            for (int j = 0, p=i; j < h; j++) {
                code+="ABCDEFGH".charAt(p%c);
                p/=c;
            }
            codeset.add(code);
        }
    }

    int replyAccordingToDonaldKnuth(String secret, String guess) {
        int black=0;
        int totalHitsBlackAndWhite=0;
        for (char n = 'A'; n <= 'H'; n++) {
            int a=0, b=0;
            for (int i = 0; i < secret.length(); i++) {
                if (secret.charAt(i)==n) a++;
                if ( guess.charAt(i)==n) b++;
            }
            totalHitsBlackAndWhite+=Math.min(a, b);
        }
        for (int i = 0; i < secret.length(); i++) {
            if (secret.charAt(i) == guess.charAt(i)) black++;
        }
        return 10 * black + (totalHitsBlackAndWhite-black);
    }

    int reply(String secret, String guess) {
        return replyAccordingToDonaldKnuth(secret, guess);
    }

    MM codebreaker(Vector<String> permuts) {
        int fitness=0;
        MM protostrategy=null;
        for (int greedy = 0; greedy < Math.min(permuts.size(), 200); greedy++) {
            MM tmp=partition(permuts, permuts.get(greedy));
            int value=tmp.strategy.size();
            if (fitness<=value) {
                fitness=value;
                protostrategy=tmp;
                protostrategy.guess=permuts.get(greedy);
            }
        }
        if (protostrategy!=null) {
            for (Integer reply: protostrategy.strategy.keySet()) {
                protostrategy.strategy.put(reply, codebreaker(protostrategy.strategy.get(reply).codeset));
            }
        }
        return protostrategy;
    }

    MM partition(Vector<String> permuts, String code) {
        MM protostrategy=new MM();
        for (int c = 0; c < permuts.size(); c++) {
            int reply=reply(permuts.get(c), code);
            if (!protostrategy.strategy.containsKey(reply)) protostrategy.strategy.put(reply, new MM());
            if (permuts.get(c)!=code) protostrategy.strategy.get(reply).codeset.add(permuts.get(c));
        }
        return protostrategy;
    }

    public static void main(String[] args) {
        MM mm = new MM(5,8);
        System.out.println("{"+mm.codebreaker(mm.codeset)+"}");
    }
}

いくつかのコメント:

  1. セットSとそのパーティションは(自動)一貫性のある方法で構築されるため、一貫性チェックは不要です。
  2. (Sではなく)S0から適切な推測を選択することは理にかなっています。しかし、現在のコードではこのアプローチに従っていません。
  3. 私の貪欲な検索は、200試行まで人為的に除去されます。
  4. 「推測のためにほとんどの情報を与える」ことはあまり正確ではありません。シンプルなアイデアは、サブセットの数が最も多いパーティションを選択することです。
  5. 結果は、応答の計算方法(..)に大きく依存します。最後に、ドナルドクヌースの表現を採用しました。

の戦略についてMM(5,8) は、こちらをご覧ください。GitHubには長い行の表示に問題があるため、Rawボタンをクリックします。


こんにちは 、結果を検索ガイドに変換できるようにgithubテキストをきれいに印刷する方法..最初の開始点「HHCAA」から..そして返信に応じて次のステップ...そして次へなど 現在の生のテキスト形式は手動スキャンでは簡単ではありません。私が望んでいるテクニックは、ネストされたブラケットを解析し、質問の箇条書きリストのように最後まで簡単にフォローできる素敵なテーブルレイアウトを取得する方法ですMM(2,3)の場合。ありがとうございました。私が何を求めているのか理解していただければ幸いです。(strを解析するにはpythonをお
勧めし

2

ルビー

編集:不可能な推測を排除するためにいくつかのロジックを追加しました。したがって、戦略は現在、指定された形式に準拠し、はるかに管理しやすくなっています。

そのため、これを実現するための1つの試みがあります。それはかなり単純です(あまり読みにくいです-if / elsif / elseブランチを下から上に読むのに役立ちます)。

Holes, Colors = ARGV.map &:to_i

ColorChars = ('A'..'H').to_a

def is_possible(guess, blacks, result)
    blacks == guess.chars.zip(result.chars).count {|chars| chars[0] == chars[1]}
end

def print_strategy(known_colors, remaining_permutations, next_color)
    char = ColorChars[next_color]
    if remaining_permutations
        guess = remaining_permutations[0]
        print guess
        if remaining_permutations.length > 1
            print ':{'
            (Holes-1).times do |i|
                new_permutations = (remaining_permutations - [guess]).select { |perm| is_possible(guess, i, perm) }
                next if new_permutations.empty?
                print "#{i}#{Holes-i}:"                
                print '{' if new_permutations.length > 1
                print_strategy(known_colors, new_permutations, next_color)
                print '}' if new_permutations.length > 1
                print ',' if i < Holes-2
            end
            print '}'
        end
    elsif known_colors.length == Holes
        print_strategy(known_colors, known_colors.chars.permutation.map(&:join).uniq, next_color)
    elsif next_color == Colors-1
        print_strategy(known_colors+char*(Holes - known_colors.length), remaining_permutations, next_color+1)
    else
        print char*Holes, ':{'

        (Holes - known_colors.length + 1).times do |i|
            break if i == Holes
            print "#{i}0:"
            print '{' if next_color < Colors-2 || i > 0 || known_colors.length > 0
            print_strategy(
                known_colors+char*i,
                remaining_permutations,
                next_color+1
            )
            print '}' if next_color < Colors-2 || i > 0 || known_colors.length > 0
            print ',' if i < (Holes - known_colors.length) && i < Holes-1
        end
        print '}'
    end
end

print '{'
print_strategy('', nil, 0)
puts '}'

まず、各色の5つを試します:AAAAABBBBBなど。パターンから実際にどの色が使用されているかを判断します。そして、私は単に与えられた色のすべての順列を試して、すでに黒いペグによって除外されているものを除外します。

ここでMM(2,3)の戦略は:

{AA:{00:{BB:{00:CC,10:{BC:{02:CB}}}},10:{BB:{00:{AC:{02:CA}},10:{AB:{02:BA}}}}}}

の戦略MM(5,8)は376KBで、ここにあります。GitHubには長い行の表示に問題があるため、Rawボタンをクリックします。

ベリファイアを取得したら、実際のスコアが何であるかを伝えることもできます。:)


まだ公開されていない検証ツールについては気分が悪いが、進行中です...(最初の)MM(2,3)戦略に問題があります。たとえば、ソリューションがABの場合:Guess = AA; reply = 10; guess = BB; reply = 10、これには戦略はありません。返信のグループ化の提案を検討しますが、適切な戦略には必要ではないはずです。考えられるソリューションのセットは、異なる返信に対して互いに素です。
MrBackend

@MrBackend良いキャッチ、私はそこでケースをスキップしました。今すぐ修正する必要があります。文法については、もちろん良い戦略には必要ありませんが、少しレベルを下げても構わないと思ったかもしれません。;)単純なエントリ(私のようなエントリ)を送信できる場合は、最初からすべての組み合わせを含める必要がなく、徐々に改善される興味深いサブミッションを取得できる可能性があります。
マーティンエンダー14

取引は次のとおりです。現在の検証ツールを終了して公開します(Webアプリとして-ここに貼り付けるには大きすぎます)。残念なことに、不可能な応答はエラーであると見なされるため、厳密すぎる可能性があります。その後、複数の応答をサポートするように調整し、不可能な応答については警告を発します。そうは言っても、適切なMM(5,8)戦略の推定サイズはほんの一握りであるため、1.3G MM(4,4)戦略には多くの不可能な応答および/または非削減の推測を含める必要があります。
MrBackend

@MrBackendもちろん、私の戦略には無数の不可能な返信が含まれています。それが、「組み合わせ論をやっていない」という意味です。;)それをサポートし、返信をグループ化するのが面倒な場合は、心配しないでください。不可能な推測を省略することを検討します。
マーティンエンダー14

@MrBackend良いニュース、私はそれを修正しました。:)戦略が現在有効であることを願っています。問題がまだあるかどうか教えてください。
マーティンエンダー14
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.