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

我的孩子们有这个有趣的游戏叫做Spot It! 游戏约束(我可以描述的最好的)是:

  • 这是一副55张牌
  • 在每张卡上有8张独特的照片(即一张卡不能有2张相同的照片)
  • 鉴于从甲板上选择的任何2张牌,有1张和1张相符的照片
  • 匹配的图片可能在不同的卡片上有不同的缩放比例,但这只是为了让游戏更难(即小树仍然匹配更大的树)
  • 游戏的原理是:翻转两张牌,并且首先挑选匹配图片的人得到一个点。

    这是澄清的图片:

    发现它

    (例如:从上面的2张卡片可以看出,匹配的图片是绿色的恐龙,在右下角和中间右侧的图片之间,这是一个小丑的头。)

    我试图了解以下内容:

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

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

  • 更新:

    每张卡片的确出现两次以上的画面(与一些人猜测的相反)。 看到这张3张卡片,每张都有一个闪电: 3张牌


    有限投影几何

    投影(平面)几何的公理与欧几里德几何稍有不同:

  • 每两个点有一条直线穿过它们(这是相同的)。
  • 每两条线恰好相交一点(这与欧几里得有点不同)。
  • 现在,添加“有限”到汤,你有问题:

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

    关于这个问题仍然存在悬而未决的问题,但我们知道这一点:

  • 如果存在具有Q点的几何,则Q = n^2 + n + 1并且n称为几何的order数。
  • 每行有n+1个点。
  • 从每一点开始,通过n+1行。
  • 总行数也是Q

  • 最后,如果n是素数,那么确实存在n阶几何。


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

    card而不是pointpicture而不是line和公理成为:

  • 每两张卡片都有一张共同的照片。
  • 对于每两张照片,都有一张拥有两张照片的卡片。
  • 现在让我们取n=7并得到Q = 7^2 + 7 + 1 order-7有限几何。 这使Q=57行(图片)和Q=57点(卡片)。 我猜谜题制作者决定55比57更圆,剩下2张牌。

    我们也得到n+1 = 8 ,所以从每个点(卡片)开始,8行通过(出现8张图片),每行(图片)有8个点(出现在8张卡片中)。


    下面是最着名的有7个点的有限投影(2阶)平面(几何)表示,称为Fano平面 ,从Noelle Evans复制 - 有限几何问题页面

    我正在考虑创建一张图片来解释如何将上述2号飞机与7张卡片和7张图片拼成一个类似的拼图,但从math.exchange双胞胎问题中得出的链接恰恰就是这样一张图: Dobble-et- LA-几何学,finie

    法诺飞机


    因此,总共有n张图片的池中有k = 55张包含m = 8张图片的卡片。 我们可以重申“我们需要多少张照片?”,以便我们可以在任意一张卡片之间构建一组只有一张共享图片的k卡片? 相当于问:

    给定一个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
    

    由此产生的最大数量的兼容卡对于m =每张卡8张图片来说,对于前几个n从n中选择的不同数量的图片看起来像这样:

    尽管由于组合爆炸,这个蛮力方法并没有得到很大的进展。 但我认为它可能仍然很有趣。

    有趣的是,似乎对于给定的m,k随着n的增加而增加,直到某个n,之后它保持不变。

    这意味着,对于每张卡片的每张照片数量,都有一定数量的照片可供选择,从而可以获得最大数量的合法卡片。 添加更多图片以选择过去的最佳数字不会增加合法卡片的数量。

    前几个最优k是:


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

    这里是生成ypercube所谈论的全部57张卡片的代码。 它采用完全相同57图片,对不起家伙的我已经写了实际的C ++代码,但我们知道, vector <something>是包含的类型值的数组something很容易理解这个代码的作用。 并且该代码使用每个包含P+1图片的P^2+P+1图片并且仅共享1个图片来针对每个素数P值生成P^2+P+1卡片。 这意味着我们可以使用7张图片,每张图片有3张图片(对于p = 2),13张图片使用13张图片(对于p = 3),31张图片使用31张图片(对于p = 5) (对于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();
        }
    }
    

    再次抱歉延迟的代码。

    链接地址: http://www.djcxy.com/p/6835.html

    上一篇: What are the mathematical/computational principles behind this game?

    下一篇: Solving for Big Theta Notation