策划策略


19

我只能找到Mastermind的代码挑战,所以这是我想承担的代码挑战版本。

普通的Mastermind游戏的最佳策略MM(4,6)由Koyama和Lai于1993年发现,平均猜测数= 5625/1296〜4.34。MM(5,8)仍未解决,但估计平均猜测数约为5.5。

您的任务是创建一个MM(5,8)策略,该策略适用于5个孔和8种颜色,涵盖所有pow(8,5) = 32768可能的不同解决方案。显然,它不一定是最佳选择。您有两种选择:

  1. 发布确定性程序以生成策略。该程序必须在Windows 7,Mac OS X或Linux上可编译/运行,且没有任何其他非自由软件。
  2. 在Internet上的某个位置发布您的策略(以及您的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最低的策略获胜。抢七局:最低的最大猜数。第二次抢七:第一个发布的答案。比赛于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
  • 公元前20年AB 01
  • AB 01,BC 01,CA 20
  • AB 00,抄送20

为了您的方便,我将很快发布一个基于Java的MM(5,8)策略验证程序。


我很难理解MM(2,3)的示例策略是如何应用的。您可以发布一个示例游戏来说明该策略吗?

@tolos我添加了所有9 :)
MrBackend

如果您的验证者也可以输出分数,那就太好了!
不是查尔斯(Charles)

@查尔斯会做!
MrBackend 2014年

2
您是否愿意更改语法以允许对多个键组合进行相同的响应?喜欢{AB:{10|01:BB}}吗?我确实有一个答案,但是它很幼稚,由于语法的树状结构,它根本无法很好地扩展(4孔,3种颜色,生成147MB的策略,我可以通过合并以下内容的一部分来显着减少该策略那个树)。
Martin Ender

Answers:


6

爪哇

我的MM(5,8)算法得分为177902 178006 182798 182697,最大深度为8 9,并且只需要几秒钟(在我的慢速计算机上)。

该算法找到的分数为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. 密码破译者找到了一个对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. 从S0(而不是S)中选择一个好的猜测是有道理的。但是我在当前代码中不遵循这种方法。
  3. 我贪婪的搜索被人为地修剪了200次。
  4. 我知道,“提供大多数信息以供猜测”不是很精确。简单的想法是选择子集数量最多的分区。
  5. 结果在很大程度上取决于您如何计算reply(..)。最后,我适应了唐纳德·克努斯(Donald Knuth)的表情。

的策略MM(5,8) 可以在这里找到。GitHub在显示行太长时存在一些问题,因此请单击Raw按钮。


嗨,如何漂亮地打印github 文本,以便可以将结果转换为查找指南..从第一个起点“ HHCAA” ..到下一步,具体取决于回复...等等。当前的原始文本格式对于手动扫描而言并不容易。.我所追求的技术是如何解析嵌套的方括号并获得一个很好的表格布局,使其更容易理解到最后,类似于问题中的项目符号列表对于MM(2,3)。谢谢。希望你能理解我的追求。(更喜欢python来解析str)
ihightower

2

红宝石

编辑:添加了一些逻辑以排除不可能的猜测。因此,这些策略现在符合给定格式,并且更易于管理。

因此,这是实现这一目标的一种尝试。这非常幼稚(而且不是很清晰-它有助于从底部到顶部读取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; 回复= 10; 猜= BB; 答复= 10,没有策略。我将研究您关于对答复进行分组的建议,但是对于好的策略来说,这不是必需的,因为对于不同的答复,可能的解决方案集是不相交的。
MrBackend

@MrBackend很好,我在那儿跳过了一个案例。现在应该修复。至于语法,当然没有必要采取好的策略,但我认为您可能愿意稍微降低标准。;)如果人们可以提交更简单的条目(例如我的),那么您可能会有些运气,因为有趣的提交逐渐得到了改善,而不必从一开始就包含所有组合。
Martin Ender 2014年

达成协议:完成当前的验证程序并将其发布(作为网络应用程序-太大了,无法粘贴到此处)。不幸的是,它可能太严格了,因为它认为不可能回答错误。之后,我将对其进行修改以支持多个答复,并且仅对可能的答复发出警告。话虽如此,您的1.3G MM(4,4)策略必须包含许多不可能的答复和/或不可减少的猜测,因为一个体面的MM(5,8)策略的估计大小很少。
MrBackend

@MrBackend当然,我的策略包含很多不可能的答复。这就是我所说的“我没有在做组合”。;)如果您对支持和分组答复太麻烦了,请不要担心,那么我将着眼于消除不可能的猜测。
马丁·恩德

@MrBackend好消息,我已修复它。:)我希望该策略现在有效。让我知道它是否仍然有任何问题。
Martin Ender 2014年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.