Javascript Spot-it算法-js

Javascript Spot-it算法-js,javascript,algorithm,loops,math,Javascript,Algorithm,Loops,Math,在Dobble(“Spot it”)游戏中,有一副57张扑克牌,每张牌上有8个不同的符号。系统是随机选择的任何两张卡将只有一个匹配符号。这促使我了解了系统背后的数学背景,因此我写了一个简单的算法: let getCards=函数(symbolCount){ 设n=symbolCount-1, 卡片=[], 卡片=[] 对于(i=0;i

在Dobble(“Spot it”)游戏中,有一副57张扑克牌,每张牌上有8个不同的符号。系统是随机选择的任何两张卡将只有一个匹配符号。这促使我了解了系统背后的数学背景,因此我写了一个简单的算法:

let getCards=函数(symbolCount){
设n=symbolCount-1,
卡片=[],
卡片=[]
对于(i=0;i对于(j=1;j首先,游戏只包含55张牌,而不是58张。但这真的很奇怪,因为事实上可以生成57张只有一个匹配符号的牌,我不知道创造者为什么只放55张

有许多链接解释如何计算这组57张卡片,例如:

  • 一段精彩的视频
  • 本文:
(当我在做这项工作时,Damien Prot发布了解释的链接。无论如何,我会发布我的答案,有人可能会觉得它很有用,并且有一个不依赖外部链接的答案是很好的。)

如果我们从第一张有8个符号的卡片开始,我们可以对它们进行编号:

0,1,2,3,4,5,6,7
所有其他卡都需要有一个与第一张卡相同的符号,因此它们将分为八类:

0,x,x,x,x,x,x,x,x
1,x,x,x,x,x,x,x,x
2,x,x,x,x,x,x,x,x
3,x,x,x,x,x,x,x,x
4,x,x,x,x,x,x,x,x
5,x,x,x,x,x,x,x,x
6,x,x,x,x,x,x,x,x
7,x,x,x,x,x,x,x,x
让我们看看符号为0的卡。它们不能与第一张卡共享多个符号,因此它们不能有符号1到7。它们也不能彼此共享任何其他符号,因为它们已经共享符号0。这意味着每张卡添加7个新符号:

0,8,9,10,11,12,13,14
0,15,16,17,18,19,20,21
0,22,23,24,25,26,27,28
0,29,30,31,32,33,34,35
0,36,37,38,39,40,41,42
0,43,44,45,46,47,48,49
0,50,51,52,53,54,55,56
每个类别中的最大卡数为7张。如果有第八张卡:

1,57,58,59,60,61,62,63
在为其他类别的牌选择符号时,我们会遇到麻烦;它们会有一个符号1到7,并与类别0中的每一张牌共享一个符号(但不是符号0,因为这样它们会与第一张牌共享两个符号)。因此,它们只能与其他类别中的7张牌共享一个符号

类别1中的卡片如下所示:

1,8,15,22,29,36,43,50
1, 9,16,23,30,37,44,51
1,10,17,24,31,38,45,52
1,11,18,25,32,39,46,53
1,12,19,26,33,40,47,54
1,13,20,27,34,41,48,55
1,14,21,28,35,42,49,56
每张卡都有符号1,然后是类别0中每张卡的符号(但不是符号0);实际上,这意味着类别0中的列被转换为类别1的行。类别2中的卡类似:

2,8,16,24,32,40,48,56
2, 9,17,25,33,41,49,50
2,10,18,26,34,42,43,51
2,11,19,27,35,36,44,52
2,12,20,28,29,37,45,53
2,13,21,22,30,38,46,54
2,14,15,23,31,39,47,55
您会注意到,与类别1相比,最后6列中的符号是旋转的:第三列向上移动1个位置,第四列向上移动2个位置,第五列向上移动3个位置,依此类推。从类别2到类别3时也是如此:

3,8,17,26,35,37,46,55
3, 9,18,27,29,38,47,56
3,10,19,28,30,39,48,50
3,11,20,22,31,40,49,51
3,12,21,23,32,41,43,52
3,13,12,24,33,42,44,53
3,14,16,25,34,36,45,54
我们可以继续对其他类别进行此操作:

4,8,18,28,31,41,44,54
4, 9,19,22,32,42,45,55
4,10,20,23,33,36,46,56
4,11,21,24,34,37,47,50
4,12,15,25,35,38,48,51
4,13,16,26,29,39,49,52
4,14,17,27,30,40,43,53
5,8,19,23,34,38,49,53
5, 9,20,24,35,39,43,54
5,10,21,25,29,40,44,55
5,11,15,26,30,41,45,56
5,12,16,27,31,42,46,50
5,13,17,28,32,36,47,51
5,14,18,22,33,37,48,52
6,8,20,25,30,42,47,52
6, 9,21,26,31,36,48,53
6,10,15,27,32,37,49,54
6,11,16,28,33,38,43,55
6,12,17,22,34,39,44,56
6,13,18,23,35,40,45,50
6,14,19,24,29,41,46,51
7,8,21,27,33,39,45,51
7, 9,15,28,34,40,46,52
7,10,16,22,35,41,47,53
7,11,17,23,29,42,48,54
7,12,18,24,30,36,49,55
7,13,19,25,31,37,43,56
7,14,20,26,32,38,44,50
因此,当使用每张卡上有8个符号的卡时,我们总共可以制作57张卡:第一张卡,加上8类8− 1=7张卡

通常,对于N个符号,我们可以使最大值为N×(N− 1) +1卡片。但是,这只在N是素数加1时有效(因为旋转列不会产生唯一的排列)

(根据Damien答案中的链接文章,当N是素数加1的幂(例如32+1=10)时,也可以创建一个双音组,但这需要一个不同的方法,或者小于N×(N)− 1) +1张卡。)

函数DobbleCards(n){//n-1必须是素数
var卡=[];
//第一张牌和第一类
对于(变量crd=0;crd”;

}
下面有一个精彩的逻辑解释

//生成唯一图片或字母的数组。
函数生成(n){
让输入=[],总计=n*--n+1;
对于(设i=0;i// Generate array of unique pictures or letters.

function generate(n){
    let inputs = [], total = n * --n + 1;
    for (let i = 0; i < total; i++) inputs[i] = i;
    return createCards(inputs, n);
    }
    
// `inputs` is an array of (prime * (prime + 1) + 1) values.
// eg. a list of images (['file1.png', 'img2.png'...])
function createCards(inputs, prime){
    let cards = [];

    // Split inputs into multi-dim array of length prime.
    while (inputs.length) cards.push(inputs.splice(0, prime));

    // `last` is the `angle` for horizontal (ie. the original) rows.
    let last = cards.pop()[0]
    cards.map(i => i.push(last))

    // The last row of pictures is used to match sets of cards which have the same angle.
    let angles = cards[cards.length - 1];

    // The `angle` is the amount we move to the right on each row to create a set.
    // Cards with the same angle will not overlap, so they are given the corresponding card from the last row.
    for (let angle = 0; angle < prime; angle++){
        for (let start = 0; start < prime; start++){
            let row = [];
            for (let col = 0; col < prime; col++){
                let inc = (col * angle + start) % prime;
                row.push(cards[col][inc]);
                }
            cards.push([...row, angles[angle]])
            }
        }

    return cards;
    }

let results = generate(8); // where 8 is one more than a prime.
console.log(results)