`
realfun
  • 浏览: 25731 次
  • 性别: Icon_minigender_1
  • 来自: 北京
文章分类
社区版块
存档分类
最新评论

猜数字(xAxB)游戏的八步以内求解程序

阅读更多
Python代码 : 猜数字游戏的八步以内求解程序
001 #coding=utf-8
002
003 #猜数字游戏8步以内的求解程序
004 #每次给出结果,要求输入xAyB,比如2A0B这样的结果,不分大小写
005 #
006 #解题思路很简单:
007 #1. 生成所有的四位不重复的0-9的数字组合的集合
008 #2. 随便找四个数字,比如0123
009 #3. 根据用户返回结果(xAyB),砍掉集合里面不符合结果的
010 #4. 根据现有数字组合,猜下一个,主要技术含量在这里:
011 #   a. 贪心算法,每次都找当前步骤里最优的
012 #   b. “最优”的定义:
013 #      b1. 选择一个组合
014 #      b2. 把这个组合和剩下的组合进行匹配,统计xAyB出现的次数,
015 #          比如0A0B出现了10次,1A3B出现了0次等等
016 #      b3. 如果xAyB的所有可能出现的机会最为均等,那么这个选择的“区分度”就很大
017 #          这个可以通过信息量理论进行衡量,也可以简化为通过“最小标准差”来衡量
018 #      b4. 遍历所有组合,找出“区分度”最大的
019 #5. 重复步骤3, 4,直到用户给出4A0B或者集合里面只剩下一个元素
020 #
021
022 #生成所有的四位不重复的0-9的数字组合
023 #  by Leo Jay
024 #  灭掉了所有的判断语句,同时用展开的方法灭掉了set,目前已知最快的
025 #  应该不能更快了,因为这个版本已经没有多余的操作了
026 #其他方法参见:http://www.fayaa.com/code/view/114/
027 def init_set ():
028     ret = []
029     for i in xrange ( 0 , 10 ):
030        for j in xrange ( i + 1 , 10 ):
031            for k in xrange ( j + 1 , 10 ):
032                for l in xrange ( k + 1 , 10 ):
033                    ret . append (( i , j , k , l ))
034                    ret . append (( i , j , l , k ))
035                    ret . append (( i , k , j , l ))
036                    ret . append (( i , k , l , j ))
037                    ret . append (( i , l , j , k ))
038                    ret . append (( i , l , k , j ))
039                    ret . append (( j , i , k , l ))
040                    ret . append (( j , i , l , k ))
041                    ret . append (( j , k , i , l ))
042                    ret . append (( j , k , l , i ))
043                    ret . append (( j , l , i , k ))
044                    ret . append (( j , l , k , i ))
045                    ret . append (( k , i , j , l ))
046                    ret . append (( k , i , l , j ))
047                    ret . append (( k , j , i , l ))
048                    ret . append (( k , j , l , i ))
049                    ret . append (( k , l , i , j ))
050                    ret . append (( k , l , j , i ))
051                    ret . append (( l , i , j , k ))
052                    ret . append (( l , i , k , j ))
053                    ret . append (( l , j , i , k ))
054                    ret . append (( l , j , k , i ))
055                    ret . append (( l , k , i , j ))
056                    ret . append (( l , k , j , i ))
057     return ret
058
059 #对给定的两组数,计算xAyB
060 #不知道能不能更快些
061 def get_match_ab ( target , source ):
062     la , lb = 0 , 0
063     for ( i , t ) in enumerate ( target ):
064         for ( j , s ) in enumerate ( source ):
065             if s == t :
066                 if i == j :
067                     la += 1
068                 else :
069                     lb += 1
070                 #break this loop since we already found match
071                 break
072     return ( la , lb )
073
074 #检查target与source是否符合aAbB
075 def match_guess ( target , source , a , b ):
076     ( la , lb ) = get_match_ab ( target , source )
077     return la == a and lb == b
078
079 #nums: the number_set list to be checked
080 #guess: last guess
081 #a, b: the number of aAbB
082 #@return: the rest number_sets which matche last guess
083 def check_and_remove ( nums , guess , a , b ):
084     rest_nums = []
085     for num_set in nums :
086         if match_guess ( num_set , guess , a , b ):
087             rest_nums . append ( num_set )
088     return rest_nums
089
090 #计算一个选择相对于选择集的“标准差”
091 def calc_standard_deviation ( target , nums ):
092     #a * 10 + b is used to indicate an "a & b" combination
093     ab_map = {}
094     #init ab_map
095     abs = ( 0 , 1 , 2 , 3 , 4 , 10 , 11 , 12 , 13 , 20 , 21 , 22 , 30 , 31 , 40 )
096     for ab in abs :
097         ab_map [ ab ] = 0
098     #let's do the calculation
099     for num_set in nums :
100         ( a , b ) = get_match_ab ( num_set , target )
101         ab_map [ a * 10 + b ] += 1
102     ab_counts = [ ab_map [ ab ] for ab in abs ]
103     total = sum ( ab_counts )
104     avg = float ( total ) / len ( abs )
105     sd = sum ([( abc - avg ) ** 2 for abc in ab_counts ])
106     return sd
107
108 #根据现有集合寻找下一个集合
109 #采用“最小标准差”作为衡量标准
110 def next_guess ( nums ):
111     min_sd = 0
112     min_set = ()
113     touched = False
114     for num_set in nums :
115         sd = calc_standard_deviation ( num_set , nums )
116         if not touched or min_sd > sd :
117             touched =
2
2
分享到:
评论
6 楼 realfun 2009-01-20  
梁利锋 写道

完全统计确实比较慢,不过,程序已经做了优化,使用数据文件进行提速。具体记不清了,太久以前的程序了。

多谢回复
5 楼 梁利锋 2008-07-16  
完全统计确实比较慢,不过,程序已经做了优化,使用数据文件进行提速。具体记不清了,太久以前的程序了。
4 楼 realfun 2008-07-16  
@梁利峰
看了你的代码,全basic的,好多的代码呀。
完全统计需要多久?
我想尝试一下使用信息量做前四次猜测,然后使用完全枚举的方式做后面的猜测。
3 楼 梁利锋 2008-07-16  
7步之内需要随机数中的数字不重复,没试过有重复数字的情况。
没有推理过程。
我是使用5040个数字枚举的。
源程序:
http://llf.hanzify.org/llf/show.asp?ID=428
以单次步数最少为例,最好的结果是:

真正完全统计电脑猜数字(27450)
共进行了 5040 次猜测
1 次就猜中的有 1 次
2 次就猜中的有 2 次
3 次就猜中的有 30 次
4 次就猜中的有 377 次
5 次就猜中的有 2124 次
6 次就猜中的有 2315 次
7 次就猜中的有 191 次
8 次就猜中的有 0 次
9 次就猜中的有 0 次
10 次就猜中的有 0 次
2 楼 realfun 2008-07-15  
@梁利锋
有推理过程可供参考吗?
1 楼 梁利锋 2008-07-15  
7步之内可以猜到的。

相关推荐

Global site tag (gtag.js) - Google Analytics