这个游戏背后的数学/计算原理是什么?


196

我的孩子有一个有趣的游戏,名为Spot It!游戏约束(据我所描述)是:

  • 它是一副55张卡片
  • 每张卡上有8张独特的图片(即一张卡上不能有2张相同的图片)
  • 给定从套牌中选择的任意两张卡,则只有1张,只有1张匹配的图片
  • 匹配的图片在不同的卡上可能会有不同的缩放比例,但这只是使游戏变得更困难(即,一棵小树仍然匹配一棵大树)

游戏的原理是:翻转2张牌,谁先选择匹配的图片就可以得到一个点。

这是用于澄清的图片:

发现它

(示例:您可以从上方的底部两张卡片中看到匹配的图片是绿色恐龙。在右下和右中图片之间是一个小丑的头。)

我试图了解以下内容:

  1. 满足这些标准所需的最少不同图片数量是多少,您将如何确定?

  2. 使用伪代码(或Ruby),如何从N张图片的阵列中生成55张游戏卡(其中N是问题1中的最小数量)?

更新:

每个甲板上确实发生了两次以上的图片(与某些推测相反)。看到这张3张卡片的图片,每张卡片都有一个闪电:3张


64
将游戏变成伤害我的大脑的+1。
歌舞表演

3
每张卡的最小图片数量,或者每张卡有8张图片的最小图片数量?另外,每个图片都必须匹配吗?
真实性2011年

7
我认为您需要添加更多约束。否则,您可以在每张卡上放置一个苹果,然后向每张卡添加任意数量的唯一图像。每对卡片只会在苹果的图片上匹配。
mbeckish 2011年

8
@cabaret:在这种情况下,您将喜欢set。令人难以置信的乐趣和加剧。
dmckee ---前主持人小猫,

4
尽管这是一个很好的问题,但它已经在数学站点上被问到(我)。这里似乎没什么话题。- math.stackexchange.com/questions/36798/...
Javid詹美回教堂

Answers:


148

有限射影几何

所述公理射影(平面)的几何形状比欧几里德几何稍有不同:

  • 每两个点都有一条直线穿过它们(这是相同的)。
  • 每两条线恰好在一个点相遇(这与欧几里得有点不同)。

现在,将“有限”添加到汤中,您会遇到一个问题:

我们可以有一个只有2个点的几何吗?有3分?用4?与7?

关于此问题仍然存在未解决的问题,但是我们知道这一点:

  • 如果存在带点的几何图形Q,则Q = n^2 + n + 1n称为order几何图形的。
  • n+1在每一行分。
  • 从每一点开始,精确地通过n+1直线。
  • 总行数也是Q

  • 最后,如果n为素数,则确实存在阶的几何n


有人可能会问,这与难题有什么关系。

放置card代替pointpicture代替,line公理变为:

  • 每两张卡共有一张相同的图片。
  • 对于每两张图片,只有一张卡片同时包含了这两张卡片。

现在,让n=7我们取,我们有的order-7有限几何形状Q = 7^2 + 7 + 1。这样就形成了Q=57线(图片)和Q=57点(卡)。我猜拼图制造者认为55比57多了一半,剩下2张卡了。

我们也得到n+1 = 8,因此从每个点(卡)开始,经过8行(出现8张图片),并且每行(图片)具有8个点(出现在8张卡中)。


下面是最有名的有限射影(阶2)面(几何形状)的7分,被称为一个表示的Fano平面,从复制诺勒埃文斯-有限几何问题页

在此处输入图片说明

我当时正在考虑创建一张图像,用来解释如何用7张卡片和7张图片将上述2阶飞机做成一个类似的谜题,但是math.exchange twin问题的一个链接正是这样一个示意图:Dobble-et-几何精确度

法诺飞机


9
那么,这款游戏表现出非欧几里得几何形状吗?说“卡片正确”是否正确?
RMorrisey 2011年

2
这听起来很棒,但我无法确定它实际上可以很好地模拟问题。@ypercube,您能再解释一下为什么您认为卡/图片与点/线之间的类比有效吗?
Nate Kohl

@Nate:第一个类比every two cards have exactly one picture in common,在问题中陈述。第二for every two pictures there is exactly one card that has both of them,OP可以告诉我们游戏设置是否满足要求。
ypercubeᵀᴹ

4
很棒的答案!深刻的洞察力,使他意识到游戏与7阶投影飞机的属性相匹配,再加上我所见过的关于投影飞机的最佳解释之一。
RBarryYoung 2011年

3
辉煌。我将需要再读100遍,以弄清楚如何在Python中生成卡集...
Jared 2013年

22

对于那些难以用57点描绘投影平面几何图形的人,有一种非常不错的直观方法,可以用57张牌和57个符号构造游戏(基于Yuval Filmus这个问题的回答):

  1. 对于带有8个符号的卡,请创建一个7x7的唯一符号网格。
  2. 为从0到6的“坡度”添加其他8个符号,为无穷大坡度添加一个符号。
  3. 每张卡是网格上的一条线(7个符号),再加上从该线的斜率设置的斜率起的一个符号。线有一个偏移量(即,左边的起点)和一个斜率(即,每个步骤右边要增加多少个符号)。当线条从顶部离开网格时,在底部重新输入。请参见此示例图(boardgamegeek的图片)中的两张这样的卡:

从网格中将两个示例卡(红色和绿色)作为线

在示例中,我采用斜率为零的线(红色),而斜率为1的线(绿色)。它们在一个共同点(猫头鹰)处相交。

此方法可确保任意两张卡都有一个共同的符号,因为

  1. 如果斜率不同,则直线将始终在恰好一个点处相交。
  2. 如果斜率相同,则直线将不相交,并且网格中将不会有公共符号。在这种情况下,斜率符号将相同。

这样,我们可以构造7x7卡(7个偏移和7个斜率)。

我们还可以从垂直线穿过网格构造七个额外的卡(即,取每一列)。对于那些,使用无限斜率图标。

因为每张卡都由网格中的七个符号和一个“斜率”符号组成,所以我们可以创建一张附加卡,该卡仅由所有8个斜率符号组成。

这样我们剩下7x8 + 1 = 57个可能的卡,以及7 x 7 + 8 = 57个必需的符号。

(自然,这仅适用于素数大小的网格(例如n = 7)。否则,如果斜率是网格大小的除数,则不同斜率的线可能具有零个或多个交点。)


18

因此,从总共n张图片的池中有k = 55张卡片,每张包含m = 8张图片。我们可以列出这样一个问题:有多少图片ñ做我们需要的,这样我们就可以构造一个集ķ卡与任何一对牌之间只有一个共享的照片吗?“ 等效地通过询问:

给定一个n维向量空间和所有向量的集合,这些向量恰好包含等于一个且所有其他零的m个元素,因此n会有多少,因此我们可以找到一组k个向量,其成对点积为全部等于1

正好有(n个选择m个)可能的向量可用于构建对。因此,我们至少需要一个足够大的n,以便(n选择m)> = k。这只是一个下限,因此为了满足成对兼容性约束,我们可能需要高得多的n

只是为了做一点实验,我写了一个小的Haskell程序来计算有效的卡组:

编辑:在看到Neil和Gajet的解决方案后,我才意识到,我使用的算法并不总是能找到最佳的解决方案,因此下面的内容不一定有效。我将尝试尽快更新代码。

module Main where

cardCandidates n m = cardCandidates' [] (n-m) m
cardCandidates' buildup  0  0 = [buildup]
cardCandidates' buildup zc oc
    | zc>0 && oc>0 = zerorec ++ onerec
    | zc>0         = zerorec
    | otherwise    = onerec
    where zerorec = cardCandidates' (0:buildup) (zc-1) oc
          onerec  = cardCandidates' (1:buildup) zc (oc-1)

dot x y = sum $ zipWith (*) x y
compatible x y = dot x y == 1

compatibleCards = compatibleCards' []
compatibleCards' valid     [] = valid
compatibleCards' valid (c:cs)
  | all (compatible c) valid = compatibleCards' (c:valid) cs
  |                otherwise = compatibleCards'    valid  cs

legalCardSet n m = compatibleCards $ cardCandidates n m

main = mapM_ print [(n, length $ legalCardSet n m) | n<-[m..]]
  where m = 8

对于前几张n可以从n个图像中选择不同数量的图像,每张卡m = 8张图像所产生的兼容卡最大数量如下所示:

尽管由于组合爆炸,这种蛮力方法还没有走得很远。但我认为这可能仍然很有趣。

有趣的是,似乎对于给定的mk仅随着n的增加而增加到某个n,之后它保持恒定。

这意味着,每张卡上的每张照片都有一定数量的图片可供选择,这将导致最大数量的合法卡。添加更多图片以从过去的最佳数量中进行选择不会进一步增加合法卡的数量。

前几个最佳k为:

最佳k表


那只是初步尝试,对吗?您尚未纳入“等于1的成对点积”的要求...
Nemo

显然,这里的语法高亮真的不支持哈斯克尔meta.stackexchange.com/questions/78363/...),但我会在提示只是它在未来的情况下折腾。
BoltClock

@BoltClock感谢您的编辑!我不知道您可以提示特定于语言的语法。
Thies Heidecke

这还不是很知名:)
BoltClock

9

其他人则描述了设计的一般框架(有限投影平面),并展示了如何生成素数阶的有限投影平面。我只想填补一些空白。

可以为许多不同的阶生成有限的投影平面,但是对于素数阶,它们最简单p。然后,以整数为模p的有限域可用于描述平面中点和线的坐标。有3种不同的点坐标:(1,x,y)(0,1,x),和(0,0,1),其中xy可以采取的值从0p-1。3种不同的点说明p^2+p+1了系统中点数的公式。我们也可以形容线同为3种不同的坐标:[1,x,y][0,1,x],和[0,0,1]

我们通过它们的坐标的点积是否等于0 mod来计算点和线是否入射p。因此,例如,点(1,2,5)和线[0,1,1]从时p=7起入射1*0+2*1+5*1 = 7 == 0 mod 7,但点(1,3,3)和线从时起[1,2,6]不入射1*1+3*2+3*6 = 25 != 0 mod 7

翻译成卡片和图片的语言,这意味着具有坐标的卡片(1,2,5)包含具有坐标的图片[0,1,1],但是具有坐标的卡片(1,3,3)不包含具有坐标的图片[1,2,6]。我们可以使用此过程来开发一张完整的卡片清单以及其中包含的图片。

顺便说一句,我认为将图片视为点,将卡视为线是容易的,但是点和线之间的投影几何结构存在双重性,所以这实际上没有关系。但是,接下来我将在图片中使用点,在卡片中使用线。

相同的构造适用于任何有限域。我们知道,q当且仅当q=p^k素数幂存在一个有限的阶域。该字段称为GF(p^k)“加洛瓦字段”。在原始功率情况下,这些字段不像在原始情况下那样容易构造。

幸运的是,辛苦的工作已经在免费软件Sage中完成并实现了。例如,要获得第4阶的投影平面设计,只需键入

print designs.ProjectiveGeometryDesign(2,1,GF(4,'z'))

然后您将获得如下输出

ProjectiveGeometryDesign<points=[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
11, 12, 13, 14, 15, 16, 17, 18, 19, 20], blocks=[[0, 1, 2, 3, 20], [0,
4, 8, 12, 16], [0, 5, 10, 15, 19], [0, 6, 11, 13, 17], [0, 7, 9, 14,
18], [1, 4, 11, 14, 19], [1, 5, 9, 13, 16], [1, 6, 8, 15, 18], [1, 7,
10, 12, 17], [2, 4, 9, 15, 17], [2, 5, 11, 12, 18], [2, 6, 10, 14, 16],
[2, 7, 8, 13, 19], [3, 4, 10, 13, 18], [3, 5, 8, 14, 17], [3, 6, 9, 12,
19], [3, 7, 11, 15, 16], [4, 5, 6, 7, 20], [8, 9, 10, 11, 20], [12, 13,
14, 15, 20], [16, 17, 18, 19, 20]]>

我对以上内容的解释如下:从0到20标记了21张图片。每个块(投影几何中的线)告诉我哪些图片出现在卡上。例如,第一张卡片的图片为0、1、2、3和20;第二张卡上将显示图片0、4、8、12和16;等等。

订单7的系统可以通过以下方式生成

print designs.ProjectiveGeometryDesign(2,1,GF(7)) 

产生输出

ProjectiveGeometryDesign<points=[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28,
29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46,
47, 48, 49, 50, 51, 52, 53, 54, 55, 56], blocks=[[0, 1, 2, 3, 4, 5, 6,
56], [0, 7, 14, 21, 28, 35, 42, 49], [0, 8, 16, 24, 32, 40, 48, 50], [0,
9, 18, 27, 29, 38, 47, 51], [0, 10, 20, 23, 33, 36, 46, 52], [0, 11, 15,
26, 30, 41, 45, 53], [0, 12, 17, 22, 34, 39, 44, 54], [0, 13, 19, 25,
31, 37, 43, 55], [1, 7, 20, 26, 32, 38, 44, 55], [1, 8, 15, 22, 29, 36,
43, 49], [1, 9, 17, 25, 33, 41, 42, 50], [1, 10, 19, 21, 30, 39, 48,
51], [1, 11, 14, 24, 34, 37, 47, 52], [1, 12, 16, 27, 31, 35, 46, 53],
[1, 13, 18, 23, 28, 40, 45, 54], [2, 7, 19, 24, 29, 41, 46, 54], [2, 8,
14, 27, 33, 39, 45, 55], [2, 9, 16, 23, 30, 37, 44, 49], [2, 10, 18, 26,
34, 35, 43, 50], [2, 11, 20, 22, 31, 40, 42, 51], [2, 12, 15, 25, 28,
38, 48, 52], [2, 13, 17, 21, 32, 36, 47, 53], [3, 7, 18, 22, 33, 37, 48,
53], [3, 8, 20, 25, 30, 35, 47, 54], [3, 9, 15, 21, 34, 40, 46, 55], [3,
10, 17, 24, 31, 38, 45, 49], [3, 11, 19, 27, 28, 36, 44, 50], [3, 12,
14, 23, 32, 41, 43, 51], [3, 13, 16, 26, 29, 39, 42, 52], [4, 7, 17, 27,
30, 40, 43, 52], [4, 8, 19, 23, 34, 38, 42, 53], [4, 9, 14, 26, 31, 36,
48, 54], [4, 10, 16, 22, 28, 41, 47, 55], [4, 11, 18, 25, 32, 39, 46,
49], [4, 12, 20, 21, 29, 37, 45, 50], [4, 13, 15, 24, 33, 35, 44, 51],
[5, 7, 16, 25, 34, 36, 45, 51], [5, 8, 18, 21, 31, 41, 44, 52], [5, 9,
20, 24, 28, 39, 43, 53], [5, 10, 15, 27, 32, 37, 42, 54], [5, 11, 17,
23, 29, 35, 48, 55], [5, 12, 19, 26, 33, 40, 47, 49], [5, 13, 14, 22,
30, 38, 46, 50], [6, 7, 15, 23, 31, 39, 47, 50], [6, 8, 17, 26, 28, 37,
46, 51], [6, 9, 19, 22, 32, 35, 45, 52], [6, 10, 14, 25, 29, 40, 44,
53], [6, 11, 16, 21, 33, 38, 43, 54], [6, 12, 18, 24, 30, 36, 42, 55],
[6, 13, 20, 27, 34, 41, 48, 49], [7, 8, 9, 10, 11, 12, 13, 56], [14, 15,
16, 17, 18, 19, 20, 56], [21, 22, 23, 24, 25, 26, 27, 56], [28, 29, 30,
31, 32, 33, 34, 56], [35, 36, 37, 38, 39, 40, 41, 56], [42, 43, 44, 45,
46, 47, 48, 56], [49, 50, 51, 52, 53, 54, 55, 56]]>

8

我刚刚找到了处理57或58张图片的方法,但是现在我头疼得很厉害,我睡得很好后,会在8-10个小时内发布红宝石代码!这只是我的解决方案的一个提示,每7张卡片共享相同的标记,使用我的解决方案可以构建总共56张卡片。

这是生成ypercube所讨论的全部57张卡片的代码。它只使用了57张图片,对不起,我已经编写了实际的C ++代码,但是知道这vector <something>是一个包含类型值的数组,something因此很容易理解该代码的作用。并且此代码会P^2+P+1使用P^2+P+1图片生成卡片,每个图片包含一个P+1图片,并且每个素数P值仅共享一张图片。这意味着我们可以有7张卡使用7张图片,每张包含3张图片(对于p = 2),13张卡使用13张图片(对于p = 3),31张卡使用31张图片(对于p = 5),57张卡用于57张图片(对于p = 7),依此类推...

#include <iostream>
#include <vector>

using namespace std;

vector <vector<int> > cards;

void createcards(int p)
{
    cards.resize(0);
    for (int i=0;i<p;i++)
    {
        cards.resize(cards.size()+1);
        for(int j=0;j<p;j++)
        {
            cards.back().push_back(i*p+j);
        }
        cards.back().push_back(p*p+1);
    }

    for (int i=0;i<p;i++)
    {
        for(int j=0;j<p;j++)
        {
            cards.resize(cards.size()+1);
            for(int k=0;k<p;k++)
            {
                cards.back().push_back(k*p+(j+i*k)%p);
            }
            cards.back().push_back(p*p+2+i);
        }
    }

    cards.resize(cards.size()+1);

    for (int i=0;i<p+1;i++)
        cards.back().push_back(p*p+1+i);
}

void checkCards()
{
    cout << "---------------------\n";
    for(unsigned i=0;i<cards.size();i++)
    {
        for(unsigned j=0;j<cards[i].size();j++)
        {
            printf("%3d",cards[i][j]);
        }
        cout << "\n";
    }
    cout << "---------------------\n";
    for(unsigned i=0;i<cards.size();i++)
    {
        for(unsigned j=i+1;j<cards.size();j++)
        {
            int sim = 0;
            for(unsigned k=0;k<cards[i].size();k++)
                for(unsigned l=0;l<cards[j].size();l++)
                    if (cards[i][k] == cards[j][l])
                        sim ++;
            if (sim != 1)
                cout << "there is a problem between cards : " << i << " " << j << "\n";

        }
    }
}

int main()
{
    int p;
    for(cin >> p; p!=0;cin>> p)
    {
        createcards(p);
        checkCards();
    }
}

再次对延迟的代码表示歉意。


37
我对此有很好的证明,但是可惜这个注释框太小,无法容纳它。
sarnold 2011年

@Gajet:您运行它了p=4吗?(21卡/图象)
ypercubeᵀᴹ

4不是在我的算法中不起作用,因为4不是质数,在我的算法中,p应该是质数很重要。
Ali1S232 2011年

@ypercube再次检查后,我的算法中有一些小错误,但我检查了2、3、5、7,并且我可以证明它可以工作的任何其他素数,所以这是我的完整代码(但在c ++中)
Ali1S232 2011年

1
@Gajet:很酷的解决方案!现在我明白了为什么我的贪婪算法并不总是产生最佳解决方案的原因。
Thies Heidecke

6

这是Gajet在Python中的解决方案,因为我发现Python更具可读性。我已经对其进行了修改,以便它也可以与非素数一起使用。我使用Thies洞察力生成了一些更容易理解的显示代码。

from __future__ import print_function
from itertools import *

def create_cards(p):
    for min_factor in range(2, 1 + int(p ** 0.5)):
        if p % min_factor == 0:
            break
    else:
        min_factor = p
    cards = []
    for i in range(p):
        cards.append(set([i * p + j for j in range(p)] + [p * p]))
    for i in range(min_factor):
        for j in range(p):
            cards.append(set([k * p + (j + i * k) % p
                              for k in range(p)] + [p * p + 1 + i]))

    cards.append(set([p * p + i for i in range(min_factor + 1)]))
    return cards, p * p + p + 1

def display_using_stars(cards, num_pictures):
    for pictures_for_card in cards:
        print("".join('*' if picture in pictures_for_card else ' '
                      for picture in range(num_pictures)))

def check_cards(cards):
    for card, other_card in combinations(cards, 2):
        if len(card & other_card) != 1:
            print("Cards", sorted(card), "and", sorted(other_card),
                  "have intersection", sorted(card & other_card))

cards, num_pictures = create_cards(7)
display_using_stars(cards, num_pictures)
check_cards(cards)

输出:

***      *   
   ***   *   
      ****   
*  *  *   *  
 *  *  *  *  
  *  *  * *  
*   *   *  * 
 *   **    * 
  **   *   * 
*    * *    *
 * *    *   *
  * * *     *
         ****

2
我认为您示例中的最后三张卡无效,因为它们与第五张卡不共享图片。刚刚检查了我的代码一个多小时之后,我才意识到它:)有趣的是,似乎合法卡集的最大大小为每张卡4张图片5张,即使选择更多图片也不会增加。
Thies Heidecke

1
@Thies与我使用Gajet的代码制作的图表相比,更容易理解为什么有确切的(p) + (p * p) + (1)配置。
尼尔·G

1
@Neil:感谢您提供更新的图表,它使您轻松了解Gajet解决方案的工作原理!
Thies Heidecke

1
@Gajet:我认为您错了all p except 4 and 6。如果要在p*p+p+1有点和线(卡和图片)的地方生成有限平面,则它与finite fields和不相关ringsp当p为prime或a 时,存在有限阶域prime power。您的代码可以正确地处理素数,因为类似k * p + (j + i * k) % p的表达式是k*p + j + i*k在阶数有限的字段中以乘法和加法来表示的p
ypercubeᵀᴹ

1
它会正常工作的主要力量也一样,如果你能表达这些操作(多个并添加)的顺序为有限域p^2p^3等等。因此,它会连续工作4, 8, 9, 16, 25, 27, ...
ypercubeᵀᴹ

4

使用z3定理证明者

P每卡符号的数量。根据本文ypercubeᵀᴹ答案N = P**2 - P + 1,分别有卡和符号。一副纸牌可以用其发生矩阵表示,该矩阵对每张纸牌有一行,对每个可能的符号有一列。它的(i,j)元素是1卡片上是否i有符号j。我们只需要考虑以下约束来填充此矩阵:

  • 每个元素都是零或一个
  • 每行的总和正好 P
  • 每列的总和正好 P
  • 任何两行必须有一个完全相同的符号

这意味着N**2变量和 N**2 + 2*N + (N choose 2)约束。z3对于较小的输入,它似乎可以在很短的时间内完成管理。

编辑:不幸的是P = 8对于此方法似乎太大。经过14小时的计算时间,我终止了该过程。

from z3 import *
from itertools import combinations

def is_prime_exponent(K):
    return K > 1 and K not in 6  # next non-prime exponent is 10, 
                                 # but that is too big anyway

def transposed(rows):
    return zip(*rows)

def spotit_z3(symbols_per_card):
    K = symbols_per_card - 1
    N = symbols_per_card ** 2 - symbols_per_card + 1
    if not is_prime_exponent(K):
        raise TypeError("Symbols per card must be a prime exponent plus one.")

    constraints = []

    # the rows of the incidence matrix
    s = N.bit_length()
    rows = [[BitVec("r%dc%d" % (r, c), s) for c in range(N)] for r in range(N)]

    # every element must be either 1 or 0
    constraints += [Or([elem == 1, elem == 0]) for row in rows for elem in row]

    # sum of rows and cols must be exactly symbols_per_card
    constraints += [Sum(row) == symbols_per_card for row in rows]
    constraints += [Sum(col) == symbols_per_card for col in transposed(rows)]

    # Any two rows must have exactly one symbol in common, in other words they
    # differ in (symbols_per_card - 1) symbols, so their element-wise XOR will
    # have 2 * (symbols_per_card - 1) ones.
    D = 2 * (symbols_per_card - 1)
    for row_a, row_b in combinations(rows, 2):
        constraints += [Sum([a ^ b for a, b in zip(row_a, row_b)]) == D]

    solver = Solver()
    solver.add(constraints)

    if solver.check() == unsat:
        raise RuntimeError("Could not solve it :(")

    # create the incidence matrix
    model = solver.model()
    return [[model[elem].as_long() for elem in row] for row in rows]


if __name__ == "__main__":
    import sys
    symbols_per_card = int(sys.argv[1])
    incidence_matrix = spotit_z3(symbols_per_card)
    for row in incidence_matrix:
        print(row)

结果

$python spotit_z3.py 3
[0, 0, 1, 1, 0, 1, 0]
[0, 0, 0, 0, 1, 1, 1]
[0, 1, 0, 1, 0, 0, 1]
[1, 1, 0, 0, 0, 1, 0]
[0, 1, 1, 0, 1, 0, 0]
[1, 0, 0, 1, 1, 0, 0]
[1, 0, 1, 0, 0, 0, 1]
python spotit_z3.py 3  1.12s user 0.06s system 96% cpu 1.225 total

$ time python3 spotit_z3.py 4
[0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0]
[0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0]
[0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 1]
[0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0]        
[0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1]
[0, 0, 1, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0]
[0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1]
[0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0]
[0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0]
[1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1]
[1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0]
[1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0]
[1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0]
python spotit_z3.py 4  664.62s user 0.15s system 99% cpu 11:04.88 total

$ time python3 spotit_z3.py 5
[1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0]
[0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0]
[0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0]
[0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0]
[0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0]
[0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0]
[0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1]
[0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0]
[0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
[0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0]
[0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0]
[0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1]
[1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0]
[0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0]
[0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0]
[0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1]
[1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]
[1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0]
[0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0]
[0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1]
[1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0]
python spotit_z3.py 5  1162.72s user 20.34s system 99% cpu 19:43.39 total

$ time python3 spotit_z3.py 8
<I killed it after 14 hours of run time.>


3

我写了一篇文章,介绍如何使用Perl中的代码生成这种套牌。该代码没有经过优化,但至少能够生成“合理”订单的牌组等等。

这是一个8阶示例,它必须考虑稍微复杂一点的基础数学,因为8并不是素数,尽管这是生成此类牌组的有效顺序。如果您只是想生成稍微困难一点的Spot-It,请参见上文或文章中的详细说明,:-)

$ time pg2 8
elements in field: 8
  0. (1, 9, 17, 25, 33, 41, 49, 57, 65)
  1. (0, 9, 10, 11, 12, 13, 14, 15, 16)
  2. (2, 9, 18, 27, 36, 45, 54, 63, 72)
  3. (6, 9, 22, 26, 37, 43, 56, 60, 71)
  4. (7, 9, 23, 32, 34, 46, 52, 59, 69)
  5. (8, 9, 24, 30, 35, 42, 55, 61, 68)
  6. (3, 9, 19, 29, 39, 44, 50, 64, 70)
  7. (4, 9, 20, 31, 38, 48, 53, 58, 67)
  8. (5, 9, 21, 28, 40, 47, 51, 62, 66)
  9. (0, 1, 2, 3, 4, 5, 6, 7, 8)
 10. (1, 10, 18, 26, 34, 42, 50, 58, 66)
 11. (1, 14, 22, 30, 38, 46, 54, 62, 70)
 12. (1, 15, 23, 31, 39, 47, 55, 63, 71)
 13. (1, 16, 24, 32, 40, 48, 56, 64, 72)
 14. (1, 11, 19, 27, 35, 43, 51, 59, 67)
 15. (1, 12, 20, 28, 36, 44, 52, 60, 68)
 16. (1, 13, 21, 29, 37, 45, 53, 61, 69)
 17. (0, 17, 18, 19, 20, 21, 22, 23, 24)
 18. (2, 10, 17, 28, 35, 46, 53, 64, 71)
 19. (6, 14, 17, 29, 34, 48, 51, 63, 68)
 20. (7, 15, 17, 26, 40, 44, 54, 61, 67)
 21. (8, 16, 17, 27, 38, 47, 50, 60, 69)
 22. (3, 11, 17, 31, 37, 42, 52, 62, 72)
 23. (4, 12, 17, 30, 39, 45, 56, 59, 66)
 24. (5, 13, 17, 32, 36, 43, 55, 58, 70)
 25. (0, 49, 50, 51, 52, 53, 54, 55, 56)
 26. (3, 10, 20, 30, 40, 43, 49, 63, 69)
 27. (2, 14, 21, 32, 39, 42, 49, 60, 67)
 28. (8, 15, 18, 28, 37, 48, 49, 59, 70)
 29. (6, 16, 19, 31, 36, 46, 49, 61, 66)
 30. (5, 11, 23, 26, 38, 45, 49, 64, 68)
 31. (7, 12, 22, 29, 35, 47, 49, 58, 72)
 32. (4, 13, 24, 27, 34, 44, 49, 62, 71)
 33. (0, 57, 58, 59, 60, 61, 62, 63, 64)
 34. (4, 10, 19, 32, 37, 47, 54, 57, 68)
 35. (5, 14, 18, 31, 35, 44, 56, 57, 69)
 36. (2, 15, 24, 29, 38, 43, 52, 57, 66)
 37. (3, 16, 22, 28, 34, 45, 55, 57, 67)
 38. (7, 11, 21, 30, 36, 48, 50, 57, 71)
 39. (6, 12, 23, 27, 40, 42, 53, 57, 70)
 40. (8, 13, 20, 26, 39, 46, 51, 57, 72)
 41. (0, 65, 66, 67, 68, 69, 70, 71, 72)
 42. (5, 10, 22, 27, 39, 48, 52, 61, 65)
 43. (3, 14, 24, 26, 36, 47, 53, 59, 65)
 44. (6, 15, 20, 32, 35, 45, 50, 62, 65)
 45. (2, 16, 23, 30, 37, 44, 51, 58, 65)
 46. (4, 11, 18, 29, 40, 46, 55, 60, 65)
 47. (8, 12, 21, 31, 34, 43, 54, 64, 65)
 48. (7, 13, 19, 28, 38, 42, 56, 63, 65)
 49. (0, 25, 26, 27, 28, 29, 30, 31, 32)
 50. (6, 10, 21, 25, 38, 44, 55, 59, 72)
 51. (8, 14, 19, 25, 40, 45, 52, 58, 71)
 52. (4, 15, 22, 25, 36, 42, 51, 64, 69)
 53. (7, 16, 18, 25, 39, 43, 53, 62, 68)
 54. (2, 11, 20, 25, 34, 47, 56, 61, 70)
 55. (5, 12, 24, 25, 37, 46, 50, 63, 67)
 56. (3, 13, 23, 25, 35, 48, 54, 60, 66)
 57. (0, 33, 34, 35, 36, 37, 38, 39, 40)
 58. (7, 10, 24, 31, 33, 45, 51, 60, 70)
 59. (4, 14, 23, 28, 33, 43, 50, 61, 72)
 60. (3, 15, 21, 27, 33, 46, 56, 58, 68)
 61. (5, 16, 20, 29, 33, 42, 54, 59, 71)
 62. (8, 11, 22, 32, 33, 44, 53, 63, 66)
 63. (2, 12, 19, 26, 33, 48, 55, 62, 69)
 64. (6, 13, 18, 30, 33, 47, 52, 64, 67)
 65. (0, 41, 42, 43, 44, 45, 46, 47, 48)
 66. (8, 10, 23, 29, 36, 41, 56, 62, 67)
 67. (7, 14, 20, 27, 37, 41, 55, 64, 66)
 68. (5, 15, 19, 30, 34, 41, 53, 60, 72)
 69. (4, 16, 21, 26, 35, 41, 52, 63, 70)
 70. (6, 11, 24, 28, 39, 41, 54, 58, 69)
 71. (3, 12, 18, 32, 38, 41, 51, 61, 71)
 72. (2, 13, 22, 31, 40, 41, 50, 59, 68)
errors in check: 0

real    0m0.303s
user    0m0.200s
sys 0m0.016s

0到的每个标识符72都可以读取为卡标识符和图片标识符。例如,最后一行表示:

  • 72包含图片21322,..., ,5968
  • 图片72显示卡21322,...,5968
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.