首先是事实。
在桥牌比赛中有4个 球员名叫北,南,东和 西方。
所有52张牌都配有13张牌 每个球员。
有一个荣誉计数系统。 Ace = 4分,King = 3分,Queen = 2分 积分和杰克= 1分。
我正在制造一个有限制的“卡片经销商”,例如你可能会说北方的手必须有5个黑桃,13到16个荣誉计数点,其余的手是随机的。 / p>
如何在不影响“随机性”的情况下以最佳方式完成此任务并获得有效代码?
我在C#和.Net中编码,但伪代码中的一些想法会很好!
答案 0 :(得分:4)
由于这里的数字非常小,你可以采用启发式方法:随机处理你的牌,评估约束,如果不满足则再次处理。
答案 1 :(得分:4)
由于有人已经提到我的Deal 3.1,我想指出我在该代码中做出的一些优化。
首先,为了获得最灵活的约束,我想为我的经销商添加一个完整的编程语言,因此您可以使用不同类型的评估者和规则生成整个约束库。我使用Tcl作为那种语言,因为我已经在学习它的工作了,并且在1994年发布了Deal 0.0时,Tcl是最容易嵌入C语言的语言。
其次,我需要约束语言才能运行得相当快。约束在循环内部深入运行。我的经销商中的相当多的代码都是使用查找表等进行的优化。
最令人惊讶和简单的优化之一是在座位上检查约束之前不将卡片交给座位。例如,如果您希望north匹配约束A和south以匹配约束B,则约束代码为:
match constraint A to north
match constraint B to south
然后只有当你到达第一行时,你才会填写北手。如果失败,您拒绝完成交易。如果它通过,接下来填写南手并检查其约束。如果它失败了,就扔掉整个交易。否则,完成交易并接受它。
我在进行一些分析时发现了这种优化,并注意到大部分时间花在了随机数生成器上。
有一种奇特的优化,在某些情况下可以起作用,称为“智能堆叠”。
deal::input smartstack south balanced hcp 20 21
这会为南手生成一个“工厂”,这需要一些时间来构建,但是可以非常快速地填写一方以符合此标准。由于条件概率问题,智能堆叠一次只能应用于每个交易的一只手。 [*]
智能堆叠采用“形状类” - 在这种情况下,“平衡”,“保持评估器”,在这种情况下,“hcp”,以及保持评估器的一系列值。 “持有评估者”是适用于每个诉讼然后总计的任何评估者,因此hcp,控制,输家和hcp_plus_shape等都持有诽谤者。
为了使智能堆叠有效,持有评估者需要采用一组相当有限的值。智能堆叠如何工作?这可能比我在这里发布时间要多一些,但它基本上是一组庞大的表格。
最后一条评论:如果你真的只想要这个程序进行竞标,而不是模拟,很多这些优化可能都是不必要的。这是因为实践的本质使其不值得花时间来进行非常罕见的投标。因此,如果您的条件只出现在十亿次交易中,那么您真的可能不想担心它。 :)
[编辑:添加智能堆叠详细信息。]
好的,一套西装中可能存在8192 = 2 ^ 13个。按长度和荣誉计数对它们进行分组:
Holdings(length,points) = { set of holdings with this length and honor count }
所以
Holdings(3,7) = {AK2, AK3,...,AKT,AQJ}
然后让
h(length,points) = |Holdings(length,points)|
现在列出符合您的形状条件的所有形状(spades = 5):
5-8-0-0
5-7-1-0
5-7-0-1
...
5-0-0-8
请注意,所有可能的手形的集合大小为560,因此此列表并不大。
对于每个形状,列出通过列出每件套装的荣誉点,您可以获得所需的总荣誉点数的方式。例如,
Shape Points per suit
5-4-4-0 10-3-0-0
5-4-4-0 10-2-1-0
5-4-4-0 10-1-2-0
5-4-4-0 10-0-3-0
5-4-4-0 9-4-0-0
...
使用我们的集合持有(长度,点数),我们可以计算获得这些行的方式的数量。 例如,对于第5-4-4-0行10-3-0-0,您将拥有:
h(5,10)*h(4,3)*h(4,0)*h(0,0)
因此,随机选择其中一行,相对概率基于计数,然后,对于每个诉讼,从正确的Holdings()集合中随机选择一个持有。
显然,手形和点的范围越宽,预计需要的行数就越多。多一点代码,你仍然可以通过预先确定的一些卡片来做到这一点 - 如果你知道黑桃的王牌或西方的整个手牌或其他什么。
[*]从理论上讲,你可以用多手来解决智能堆叠的这些条件概率问题,但问题的解决方案只能使它对极少数类型的交易有效。这是因为工厂表中的行数大致是用于堆叠一只手的行数乘以用于堆叠另一只手的行数的乘积。此外,h()表必须键入在手1,手2和其他手之间划分n个卡的方式的数量,这将值的数量从大约2 ^ 13改变为3 ^ 13个可能的值,这大约要大两个数量级。
答案 2 :(得分:2)
根据计算机的速度,可能足以执行此操作:
与所有表现问题一样,要做的就是试试看!
编辑我试过了,看到了:
done 1000000 hands in 12914 ms, 4424 ok
这没有考虑优化 - 它每秒产生342只手,符合你的标准“北方有5个黑桃和13-16个荣誉点”。我不知道您申请的详细信息,但在我看来,这可能已经足够了。
答案 3 :(得分:1)
我会选择这个流程,我认为这不会影响随机性(除了通过修剪不符合约束的解决方案):
您可以编写一个程序来生成我的第一个点的组合,或者只是硬编码它们同时考虑颜色对称性以减少代码行数:)
答案 4 :(得分:1)
由于你想练习竞价,我想你将来可能会遇到各种形式的限制(而不仅仅是1S开放,正如我猜这个当前的问题)。试图提出适合约束的最佳手部生成可能是一个巨大的时间下沉,并不值得努力。
我建议您使用拒绝抽样:生成随机交易(没有任何约束)并测试它是否满足您的约束条件。
为了使这个可行,我建议你尽可能快地集中精力制作随机交易(没有任何限制)。
为此,将每只手映射到12字节整数(桥接手的总数适合12个字节)。生成一个随机的12字节整数可以在3,4字节的随机数调用中完成,当然由于指针的数量不是完全拟合12个字节,你可能需要做一些处理在这里,但我希望它不会太多。
Richard Pavlicek有一个很好的页面(有算法)可以将交易映射到一个数字并返回。
见这里:http://www.rpbridge.net/7z68.htm
我还建议您查看现有的桥牌交易软件(如免费提供的Deal 3.1)。 Deal 3.1还支持进行双重虚拟分析。也许你可以让它为你工作,而不必自己动手。
希望有所帮助。