【问题标题】:Most elegant way to expand card hand suits扩展牌手套装的最优雅方式
【发布时间】:2010-06-03 22:23:34
【问题描述】:

我存储 4 张牌的方式是对不同花色的牌进行相同处理,例如:

9h 8h 7c 6c

相同
9d 8d 7h 6h

因为您可以将一套西装换成另一套并拥有相同的东西。使用通配符表示花色很容易将它们转换为独特的表示形式。以前的会变成:

9A 8A 7B 6B

我的问题是 - 将后者转回前者列表的最优雅方式是什么?例如,当输入为9A 8A 7B 6B时,输出应为:

9c 8c 7d 6d
9c 8c 7h 6h
9c 8c 7s 6s
9h 8h 7d 6d
9h 8h 7c 6c
9h 8h 7s 6s
9d 8d 7c 6c
9d 8d 7h 6h
9d 8d 7s 6s
9s 8s 7d 6d
9s 8s 7h 6h
9s 8s 7c 6c

我有一些丑陋的代码,根据有多少独特的套装,逐案执行此操作。它不会扩展到拥有更多卡片的手中。同样在这样的情况下:

7A 7B 8A 8B

它会有重复,因为在这种情况下 A=cB=dA=dB=c 相同。

有什么优雅的方法可以有效地解决这个问题?我正在用 C 编写代码,但我可以将高级代码转换为 C。

【问题讨论】:

  • 您的第一个示例是 9A 8A 7B 6C 而第二个示例是 9A 8A 7B 6B - 您的意思可能是 9h 8h 7c 6c 而不是 9h 8h 7c 6d。

标签: algorithm language-agnostic


【解决方案1】:

只有 4 套西装,所以可能的替换空间非常小 - 4! = 24 例。 在这种情况下,我认为不值得尝试想出一些特别聪明的东西。

只需解析“7A 7B 8A 8B”之类的字符串,计算其中不同字母的数量,然后根据该数字,根据预先计算的一组替换生成替换。

1 letter -> 4 possible substitutions c, d, h, or s
2 letters -> 12 substitutions like in Your example.
3 or 4 letters -> 24 substitutions.

然后对替换集进行排序并删除重复项。您已经对每个字符串中的标记进行了排序,例如“7c 8d 9d 9s”,然后对字符串数组进行排序以检测重复项,但这应该不是问题。最好也对“7A 7B 8A 8B”等模式进行排序(“7A”、“8B”等标记按升序排列)。

编辑:

排序的另一种方法可能是,如果等级与两个或多个花色相关联,则检测相同的集合,并在生成替换时将其考虑在内,但我认为它更复杂。您必须为模式字符串中出现的每个字母创建一组等级。

例如,对于字符串“7A 7B 8A 8B”,与字母 A 关联的是集合 {7, 8} 并且相同的集合与字母 B 关联。那么您必须寻找关联的相同集合用不同的字母。在大多数情况下,这些集合只有一个元素,但它们可能有两个,如上例所示。与同一组相关的字母可以互换。你可以有以下几种情况

1 letter no duplicates -> 4 possible substitutions c, d, h, or s
2 letters no duplicates -> 12 substitutions.
2 letters, 2 letters interchangeable (identical sets for both letters) -> 6 substitutions.
3 letters no duplicates -> 24 substitutions.
3 letters, 2 letters interchangeable -> 12 substitutions.
4 letters no duplicates -> 24 substitutions.
4 letters, 2 letters interchangeable -> 12 substitutions.
4 letters, 3 letters interchangeable -> 4 substitutions.
4 letters, 2 pairs of interchangeable letters -> 6 substitutions.
4 letters, 4 letters interchangeable -> 1 substitution.

【讨论】:

  • 我喜欢预先计算潜艇的想法。不过,我认为对潜艇进行排序以检测欺骗行为会太慢 - 还有其他想法吗?
【解决方案2】:

我认为一个通用置换函数接受一个数组 arr 和一个整数 n 并返回该数组中 n 元素的所有可能排列在这里会很有用。

找出手中有多少种独特的花色。然后使用来自实际西装[c, d, h, s] 的许多元素生成所有可能的排列。最后遍历每个花色排列,将手中的每个未知字母[A, B, C, D]分配给排列后的值。

以下 Ruby 代码使用给定的牌并生成所有花色排列。最繁重的工作是由这里的Array.permutation(n) 方法完成的,它也应该为相应的 C 程序简化很多事情。

# all 4 suits needed for generating permutations
suits = ["c", "d", "h", "s"]

# current hand
hand = "9A 8A 7B 6B"

# find number of unique suits in the hand. In this case it's 2 => [A, B]
unique_suits_in_hand = hand.scan(/.(.)\s?/).uniq.length

# generate all possible permutations of 2 suits, and for each permutation
# do letter assignments in the original hand
# tr is a translation function which maps corresponding letters in both strings.
# it doesn't matter which unknowns are used (A, B, C, D) since they 
# will be replaced consistently.
# After suit assignments are done, we split the cards in hand, and sort them.
possible_hands = suits.permutation(unique_suits_in_hand).map do |perm|
   hand.tr("ABCD", perm.join ).split(' ').sort
end

# Remove all duplicates
p possible_hands.uniq

以上代码输出

9c 8c 7d 6d
9c 8c 7h 6h
9c 8c 7s 6s
9d 8d 7c 6c
9d 8d 7h 6h
9d 8d 7s 6s
9h 8h 7c 6c
9h 8h 7d 6d
9h 8h 7s 6s
9s 8s 7c 6c
9s 8s 7d 6d
9s 8s 7h 6h

【讨论】:

  • 7A 7B 8A 8B 的重复问题怎么办?
  • @Claudiu - 您可以对手中的牌进行拆分和排序,以使每手牌具有唯一的表示形式,然后删除重复的牌。使用关联数组将此唯一表示映射为键,因此以后的查找可以在 O(1) 中进行。例如,7c 7d 8c 8d7d 7c 8d 8c 都有键 7c 7d 8c 8d,因此您可以在生成手时避免重复,或者稍后将其删除。
【解决方案3】:

将花色表示为稀疏数组或列表,将数字表示为索引,将手表示为关联数组

在你的例子中

H [A[07080000] B[07080000] C[00000000] D[00000000] ](放置四张牌)

要获得“真正的”手牌,始终应用 24 种排列(固定时间),因此您不必关心手牌 A、B、C、D 有多少张 -> c、d、h, s 带有以下“trick”> 总是按字母顺序存储>

H1 ​​[c[xxxxxx] d[xxxxxx] s[xxxxxx] h[xxxxxx]]

由于手是关联数组,重复排列不会产生两个不同的输出手。

【讨论】:

    【解决方案4】:
    #include <stdio.h>
    #include <stdlib.h>
    
    const int RANK = 0;
    const int SUIT = 1;
    
    const int NUM_SUITS = 4;
    
    const char STANDARD_SUITS[] = "dchs";
    int usedSuits[] = {0, 0, 0, 0};
    
    const char MOCK_SUITS[] = "ABCD";
    
    const char BAD_SUIT = '*';
    
    char pullSuit (int i) {
      if (usedSuits [i] > 0) {
        return BAD_SUIT;
      }
      ++usedSuits [i];
      return STANDARD_SUITS [i];
    }
    
    void unpullSuit (int i) {
      --usedSuits [i];
    }
    
    int indexOfSuit (char suit, const char suits[]) {
      int i;
      for (i = 0; i < NUM_SUITS; ++i) {
        if (suit == suits [i]) {
          return i;
        }
      }
      return -1;
    }
    
    int legitimateSuits (const char suits[]) {
      return indexOfSuit (BAD_SUIT, suits) == -1;
    }
    
    int distinctSuits (const char suits[]) {
      int i, j;
      for (i = 0; i < NUM_SUITS; ++i) {
        for (j = 0; j < NUM_SUITS; ++j) {
          if (i != j && suits [i] == suits [j]) {
            return 0;
          }
        }
      }
      return 1;
    }
    
    void printCards (char* mockCards[], int numMockCards, const char realizedSuits[]) {
      int i;
      for (i = 0; i < numMockCards; ++i) {
        char* mockCard = mockCards [i];
        char rank = mockCard [RANK];
        char mockSuit = mockCard [SUIT];
        int idx = indexOfSuit (mockSuit, MOCK_SUITS);
        char realizedSuit = realizedSuits [idx];
        printf ("%c%c ", rank, realizedSuit);
      }
      printf ("\n");
    }
    
    /*
     * Example usage:
     * char** mockCards = {"9A", "8A", "7B", "6B"};
     * expand (mockCards, 4);
     */
    void expand (char* mockCards[], int numMockCards) {
      int i, j, k, l;
      for (i = 0; i < NUM_SUITS; ++i) {
        char a = pullSuit (i);
        for (j = 0; j < NUM_SUITS; ++j) {
          char b = pullSuit (j);
          for (k = 0; k < NUM_SUITS; ++k) {
            char c = pullSuit (k);
            for (l = 0; l < NUM_SUITS; ++l) {
              char d = pullSuit (l);
              char realizedSuits[] = {a, b, c, d};
              int legitimate = legitimateSuits (realizedSuits);
              if (legitimate) {
                int distinct = distinctSuits (realizedSuits);
                if (distinct) {
                  printCards (mockCards, numMockCards, realizedSuits);
                }
              }
              unpullSuit (l);
            }
            unpullSuit (k);
          }
          unpullSuit (j);
        }
        unpullSuit (i);
      }
    }
    
    int main () {
      char* mockCards[] = {"9A", "8A", "7B", "6B"};
      expand (mockCards, 4);
      return 0;
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2010-10-12
      • 2011-08-06
      • 2012-05-28
      • 1970-01-01
      • 2018-04-01
      • 1970-01-01
      • 2011-08-02
      • 1970-01-01
      相关资源
      最近更新 更多