如何为N骰子生成“Go First”骰子?

时间:2012-09-07 21:44:29

标签: python math dice

背景

如此处所述http://www.ericharshbarger.org/dice/#gofirst_4d12,“Go First”骰子是一组四个骰子,每个骰子都有唯一的编号,因此:

  • 两个或两个以上骰子的任何一卷都不会产生平局。
  • 任何与模组中任何其他模具相对的模具都有相同的机会对所述模具“输赢”。

这是所提到的四个骰子的编号:

DICE COUNT: 4
FACE COUNT: 12
D1: 1,8,11,14,19,22,27,30,35,38,41,48
D2: 2,7,10,15,18,23,26,31,34,39,42,47
D3: 3,6,12,13,17,24,25,32,36,37,43,46
D4: 4,5, 9,16,20,21,28,29,33,40,44,45

(via)

问题

我很擅长数学。我很难过。鉴于以上信息,我希望能够在给定多个骰子的情况下生成整数列表(“骰子”)。这样,示例输出可能看起来像这样(格式化,python控制台) :

    >>> generate_dice(players=4)
    [[1,8,11,14,19,22,27,30,35,38,41,48],
     [2,7,10,15,18,23,26,31,34,39,42,47],
     [3,6,12,13,17,24,25,32,36,37,43,46],
     [4,5,9,16,20,21,28,29,33,40,44,45]]    

此处选择的边数仅用于示例目的,因为它与给定的另一个示例相匹配。每个模具的“公平性”确实是我正在寻找的。

我向你保证这不是功课。这只是一个坚定的极客,被一个看似微不足道的谜题所困扰,这个谜题不会让我孤单......而且出于某种原因,我似乎无法做到这一点。

我确信这里有一些相对简单的数学,这里涉及一个基本的算法,这就是我正在寻找的东西。如果这对您来说很明显,我应该搜索哪些术语?因为对我而言,事实并非如此。

理想情况下,解决方案将在Python中,但我也可以阅读PHP,Javascript,一些Ruby。

2 个答案:

答案 0 :(得分:5)

这是一个(计算上的)难题。 它首先看起来是不够的,每个骰子的预期值是相同的(尽管奇怪的是,在你给出的例子中)。每个模具必须在每个模具元件的点积的所有实例的50%中“赢”。

这篇文章提到数学家生成了“手工”给出的例子这一事实使我在建议以下蛮力方法时更加舒服:

import itertools

nplayers=4
nsides=2
max_number=8

assert nplayers*nsides <= max_number
assert nsides % 2 == 0 #otherwise x^x (dot product) is not even, so half_wins_fairness always fails

iterations=[]
def half_wins_fairness( dice1,dice2 ):
    dice1_wins= map( lambda x: x[0]>x[1], itertools.product(dice1,dice2) )
    dice_wins_prob= float(sum(dice1_wins))/len(dice1_wins)
    #probs.append(dice_wins_prob)
    return dice_wins_prob==0.5

def fair( all_dice ):
    all_fair= True
    for d1,d2 in itertools.combinations( all_dice, 2):
        if not half_wins_fairness(d1,d2):
            all_fair=False
    return all_fair

for i,dice_pattern in enumerate(itertools.permutations(range(max_number), nplayers*nsides)):
    #cut dice pattern into dices
    dice= [dice_pattern[p*nsides:(p+1)*nsides] for p in range(nplayers)]
    if fair(dice):
        print dice
        iterations.append(i)

def discrete_derivative(l):
    last=0
    for i,x in enumerate(l):
        tmp= x
        l[i]=x-last
        last=tmp

#discrete_derivative(iterations)
#import pylab
#pylab.plot(iterations)
#pylab.show()

这里的复杂性是n ^ n,所以这本身只能解决你的nplayers和nsides数量非常少的问题。 但是,通过取消注释注释行,您可以检查骰子沿着dot产品迭代的公平性图,这似乎有很多模式,表明可以使用几种启发式来加速此搜索,甚至可能找到一般解决方案。

修改

更改了改进图表的代码。 这是一些照片,以防有人特别擅长发现模式。

nplayers = 2,nsides = 2,max_number = 8 nplayers=2, nsides=2, max_number=8 nplayers = 2,nsides = 4,max_number = 8 nplayers=2, nsides=4, max_number=8 nplayers = 4,nsides = 2,max_number = 8 nplayers=4, nsides=2, max_number=8

一些初步观察:

  1. 它是对称的
  2. “清洁”图表似乎是在生成时生成的     max_number%(nplayers * nsides)== 0

答案 1 :(得分:0)

为了记录,codegolf上的这个答案有一个简单的算法,似乎至少在骰子上的边数均为偶数时起作用:https://codegolf.stackexchange.com/a/7238/5376

def generate_dice(count, sides = 12):
  dice = []
  for i in range(count):
    dice.append([])

  value = 0
  for sindex in range(sides):
    if sindex % 2:
      for dindex in range(count):
        value += 1
        dice[dindex].append(value)
    else:
      for dindex in reversed(range(count)):
        value += 1
        dice[dindex].append(value)
  return dice