Spot it algorithm - js

ⅰ亾dé卋堺 提交于 2021-02-08 05:17:33

问题


In the game Dobble ("Spot it") , there is a pack of 57 playing cards, each with 8 different symbols on them. The system is that any two cards chosen at random will have just one matching symbol. This spurred me on to the mathematical background behind the system and so I wrote an simple algorithm:

let getCards = function(symbolCount) {
  let n = symbolCount - 1,
    cards = [],
    card = []
  for (i = 0; i < n + 1; i++)
    card.push(i)
  cards.push(card)
  for (j = 1; j <= n; j++) {
    let card = [1]
    for (k = 1; k <= n; k++)
      card.push(n + n * (j - 1) + k)
    cards.push(card)
  }
  for (i = 1; i <= n; i++)
    for (j = 1; j <= n; j++) {
      let card = [i]
      for (k = 1; k <= n; k++)
        card.push(n + 1 + n * (k - 1) + (((i - 1) * (k - 1) + j - 1) % n))
      cards.push(card)
    };
  return cards;
}

let pack = getCards(8).join("\n").split(",").join(", ");
console.log(pack)

The algorithm is working so far for a few days but today I mentioned a bug ( The worst one that could have occurred ): There are two identical pairs on two cards.

0, 1, 2, 3, 4, 5, 6, 7
1, 8, 9, 10, 11, 12, 13, 14
1, 15, 16, 17, 18, 19, 20, 21
1, 22, 23, 24, 25, 26, 27, 28
1, 29, 30, 31, 32, 33, 34, 35       This one ("1", "35")
1, 36, 37, 38, 39, 40, 41, 42
1, 43, 44, 45, 46, 47, 48, 49
1, 50, 51, 52, 53, 54, 55, 56
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       This one ("1", "35")
...

I really get no idea where the bug occurres and I must mention that I've spent hours in finding the bug. So any help would be really appreciated.


回答1:


(While I was working on this, Damien Prot posted links to explanations. I'll post my answer anyway, someone may find it helpful, and it's good to have an answer that doesn't depend on external links.)

If we start off with the first card with 8 symbols, we can number them:

0, 1, 2, 3, 4, 5, 6, 7

All other cards need to have one symbol in common with the first card, so they will fall into eight categories:

0, x, x, x, x, x, x, x  
1, x, x, x, x, x, x, x  
2, x, x, x, x, x, x, x  
3, x, x, x, x, x, x, x  
4, x, x, x, x, x, x, x  
5, x, x, x, x, x, x, x  
6, x, x, x, x, x, x, x  
7, x, x, x, x, x, x, x  

Let's look at the cards which have symbol 0. They cannot share more than one symbol with the first card, so they cannot have symbols 1 to 7. They also cannot share any additional symbols with each other, because they already share symbol 0. This means each card adds 7 new symbols:

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

The maximum number of cards in each category is 7. If there were an eighth card:

1,57,58,59,60,61,62,63  

we would run into trouble when choosing the symbols for the cards in the other categories; they would have a symbol 1 to 7, and share a symbol with each of the cards in category 0 (but not symbol 0, because then they'd share two symbols with the first card). So they can share a symbol with only 7 cards in the other categories.

The cards in category 1 look like this:

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

Each card has symbol 1, and then a symbol from each of the cards in category 0 (but not symbol 0); practically, this means that the columns from category 0 are transformed into rows for category 1. The cards in category 2 are similar:

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

You'll notice that the symbols in the last 6 column are rotated when compared to category 1: the third column up by 1 position, the fourth column up by 2 positions, the fifth column up by 3 positions, and so on. The same is done when going from category 2 to category 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

And we can continue doing this for the other categories:

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

So when using cards with 8 symbols on each card, we can make a total of 57 cards: the first card, plus 8 categories of 8 − 1 = 7 cards.

In general, with N symbols, we can make a maximum of N × (N − 1) + 1 cards. However, this works only when N is a prime number plus one (because otherwise rotating the columns doesn't create unique permutations).

(According to the article linked in Damien's answer, it is also possible to create a Dobble deck when N is a power of a prime plus one (e.g. 32 + 1 = 10), but that would need a different method, or have fewer than N × (N − 1) + 1 cards.)

function DobbleCards(n) { // n-1 must be prime
    var cards = [];

    // first card and first category
    for (var crd = 0; crd < n; crd++) {
        var symbols = [0];
        for (var sym = 1; sym < n; sym++) {
            symbols.push(crd * (n-1) + sym);
        }
        cards.push(symbols.slice());
    }

    // other categories
    for (var cat = 1; cat < n; cat++) {
        for (var crd = 0; crd < n-1; crd++) {
            var symbols = [cat];
            for (var sym = 1; sym < n; sym++) {
                symbols.push(1 + sym * (n-1) + ((cat-1) * (sym-1) + crd) % (n-1));
            }
            cards.push(symbols.slice());
        }
    }
    return cards;
}

var deck = DobbleCards(8);
for (var i in deck) {
    document.write(deck[i] + "<br>");
}



回答2:


First of all, the game is containing only 55 cards, not 58. But this is really strange since it is in fact possible to generate 57 cards with only one matching symbol, I don't know why the creators only put 55...

There are many links explaining how to compute this set of 57 cards, for example:

  • a nice video https://www.youtube.com/watch?v=lhTMr8RzUr8
  • this article: https://www.mathteacherscircle.org/assets/legacy/resources/materials/DSenguptaSpotIt.pdf


来源:https://stackoverflow.com/questions/52822827/spot-it-algorithm-js

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!