C# 如何在不存储一副卡的情况下实现经销商类?

C# 如何在不存储一副卡的情况下实现经销商类?,c#,language-agnostic,algorithm,math,permutation,C#,Language Agnostic,Algorithm,Math,Permutation,问题 即使只有52张卡片,排列索引(我在解释部分中描述)也将是一个巨大的数字;它是52中的一个数字,需要存储29个字节 因此,我不知道一种简单的方法来计算大范围的排列索引,并以最小的成本存储索引,或者也可以进行计算。我认为这个问题的解决方案应该是三种算法: 一种算法,用于计算正确的排列索引,以实现处理方法 一种算法,用于计算正确的排列索引,以实现收集方法 一种以最小代价存储(或计算)排列索引的算法 解释 我最初尝试使用置换实现一个整数句柄生成器,范围从int.MinVale到int.MaxVa

问题

即使只有52张卡片,
排列索引
(我在解释部分中描述)也将是一个巨大的数字;它是
52中的一个数字,需要存储29个字节

因此,我不知道一种简单的方法来计算大范围的
排列索引
,并以最小的成本存储索引,或者也可以进行计算。我认为这个问题的解决方案应该是三种算法:

  • 一种算法,用于计算正确的
    排列索引
    ,以实现
    处理
    方法

  • 一种算法,用于计算正确的
    排列索引
    ,以实现
    收集
    方法

  • 一种以最小代价存储(或计算)排列索引的算法

  • 解释

    我最初尝试使用置换实现一个整数句柄生成器,范围从
    int.MinVale
    int.MaxValue

    因为范围非常大,所以我从实现一个包含52张卡的交易商
    类开始,这个类实际上不存储一副卡,比如hashset或array,甚至也不需要随机的(除了首字母)

    一个给定的序数范围,我认为一个全排列的每个序列都有一个索引,并将其命名为“代码> PrimeTodeIndex <代码>。我使用索引来记住它是哪个排列,而不是真正存储序列。序列是卡片组的可能顺序之一

    这是一个动画图形仿真的例子,展示了我的想法。

    每次发牌时,我都会更改
    排列索引
    已发牌
    (已发牌数),以确定哪些牌已发,哪些牌仍在手。当我收回一张已发的卡时,我会知道卡号,并将其放在顶部,它也会成为下次交易的卡。在动画中,
    colleted
    是卡号


  • 有关更多信息,请参见下文

    • 代码说明

      仅针对三个3的概念性示例
      Dealer
      类如下所示。 代码是用英文写的,我也在考虑任何解决方案

      下面是对示例代码的一些描述

      public static class Dealer {
          public static void Collect(int number) {
              if(1>dealt)
                  throw new IndexOutOfRangeException();
      
              switch(permutationIndex) {
                  case 5:
                  case 0:
                      switch(number) {
                          case 3:
                              break;
      
                          case 2:
                              permutationIndex=1;
                              break;
      
                          case 1:
                              permutationIndex=4;
                              break;
                      }
      
                      break;
      
                  case 4:
                  case 3:
                      switch(number) {
                          case 3:
                              permutationIndex=5;
                              break;
      
                          case 2:
                              permutationIndex=2;
                              break;
      
                          case 1:
                              break;
                      }
      
                      break;
      
                  case 2:
                  case 1:
                      switch(number) {
                          case 3:
                              permutationIndex=0;
                              break;
      
                          case 2:
                              break;
      
                          case 1:
                              permutationIndex=3;
                              break;
                      }
      
                      break;
              }
      
              --dealt;
          }
      
          public static int Dealing() {
              if(dealt>2)
                  throw new IndexOutOfRangeException();
      
              var number=0;
      
              switch(permutationIndex) {
                  case 5:
                      permutationIndex=3;
                      number=3;
                      break;
      
                  case 4:
                      permutationIndex=0;
                      number=1;
                      break;
      
                  case 3:
                      permutationIndex=1;
                      number=1;
                      break;
      
                  case 2:
                      permutationIndex=4;
                      number=2;
                      break;
      
                  case 1:
                      permutationIndex=5;
                      number=2;
                      break;
      
                  case 0:
                      permutationIndex=2;
                      number=3;
                      break;
              }
      
              ++dealt;
              return number;
          }
      
          static int[,] sample=
              new[,] {
                  { 1, 2, 3 }, // 0
                  { 1, 3, 2 }, // 1
                  { 3, 1, 2 }, // 2
                  { 3, 2, 1 }, // 3
                  { 2, 3, 1 }, // 4
                  { 2, 1, 3 }, // 5
              };
      
          static int permutationIndex;
          static int dealt;
      }
      
      • 通过方法
        交易()
        ,我们可以得到一些被视为已交易的牌。它总是返回最右边的编号(与数组相关),然后通过更改排列索引将编号从左边(比如下一个可用的编号)滚动到最右边的位置

      • 收集(int)
    的方法是收集并将已发牌放回牌组。 它还将根据返回给经销商的卡的数量更改排列索引

  • 整数
    已发
    表示我们已发多少张牌;从最左边的到存储在
    已发
    中的计数都是已发卡。通过
    排列索引
    ,我们知道卡片的顺序

  • 示例代码中的
    int[,]
    数组没有使用,只是为了帮助想象排列。switch语句被认为是通过计算
    置换索引
    的算法实现的

  • 排列索引

    的回答中描述的内容相同

  • 示例代码

    public static class Dealer {
        public static void Collect(int number) {
            if(1>dealt)
                throw new IndexOutOfRangeException();
    
            switch(permutationIndex) {
                case 5:
                case 0:
                    switch(number) {
                        case 3:
                            break;
    
                        case 2:
                            permutationIndex=1;
                            break;
    
                        case 1:
                            permutationIndex=4;
                            break;
                    }
    
                    break;
    
                case 4:
                case 3:
                    switch(number) {
                        case 3:
                            permutationIndex=5;
                            break;
    
                        case 2:
                            permutationIndex=2;
                            break;
    
                        case 1:
                            break;
                    }
    
                    break;
    
                case 2:
                case 1:
                    switch(number) {
                        case 3:
                            permutationIndex=0;
                            break;
    
                        case 2:
                            break;
    
                        case 1:
                            permutationIndex=3;
                            break;
                    }
    
                    break;
            }
    
            --dealt;
        }
    
        public static int Dealing() {
            if(dealt>2)
                throw new IndexOutOfRangeException();
    
            var number=0;
    
            switch(permutationIndex) {
                case 5:
                    permutationIndex=3;
                    number=3;
                    break;
    
                case 4:
                    permutationIndex=0;
                    number=1;
                    break;
    
                case 3:
                    permutationIndex=1;
                    number=1;
                    break;
    
                case 2:
                    permutationIndex=4;
                    number=2;
                    break;
    
                case 1:
                    permutationIndex=5;
                    number=2;
                    break;
    
                case 0:
                    permutationIndex=2;
                    number=3;
                    break;
            }
    
            ++dealt;
            return number;
        }
    
        static int[,] sample=
            new[,] {
                { 1, 2, 3 }, // 0
                { 1, 3, 2 }, // 1
                { 3, 1, 2 }, // 2
                { 3, 2, 1 }, // 3
                { 2, 3, 1 }, // 4
                { 2, 1, 3 }, // 5
            };
    
        static int permutationIndex;
        static int dealt;
    }
    

  • 如果我理解正确,下面的代码实现了这一点:

    public class Dealer {
        public int Dealing() {
            var number=
                _freeCards.Count>0
                    ?_freeCards.Dequeue()
                    :_lastNumber++;
    
            _dealtCards.Add(number);
            return number;
        }
    
        public void Collect(int number) {
            if(!_dealtCards.Remove(number))
                throw new ArgumentException("Card is not in use", "number");
    
            _freeCards.Enqueue(number);
        }
    
        readonly HashSet<int> _dealtCards=new HashSet<int>();
        readonly Queue<int> _freeCards=new Queue<int>(); // "Pool" of free cards.
        int _lastNumber;
    }
    
    公共类经销商{
    公开交易{
    变量数=
    _免费卡。计数>0
    ?_freeCards.Dequeue()
    :_lastNumber++;
    _dealtCards.Add(编号);
    返回号码;
    }
    公开作废收款(整数){
    如果(!\u dealtCards.Remove(数字))
    抛出新参数异常(“卡未使用”、“编号”);
    _免费卡。排队(编号);
    }
    只读哈希集_dealtCards=new HashSet();
    只读队列_freeCards=新队列();/“池”中的空闲卡。
    int_lastNumber;
    }
    
    这并不完全是你想要完成的,但是如果你想从一副牌的随机排列中进行交易,你可以使用洗牌算法。典型的洗牌算法是。洗牌算法将创建一个数组,以随机顺序(13,5,7,18,22等)列出卡号。要进行处理,请从数组中的第一个元素开始,然后继续前进。

    我也很难看到这里的全貌,但您可以将每个排列转换为base(52),用一个字符表示每个卡片,用一个字符串表示每个排列

    所以黑桃可以是
    1-9(ace-9)
    0ABC(10,jqk)
    ,然后
    DEFG
    。。。启动心脏等等

    因此,一副由3张牌组成的牌,2张黑桃(2),3张心形(F)和2张菱形(比如e),将有以下排列数字:

    2Fe
    2eF
    F2e
    Fe2
    eF2
    e2F
    
    您可以通过执行从基52到基10的转换,将它们来回转换为int/long/bigint

    因此e2F将是
    F+2*52+e*52^2
    ,这将是
    16+2*52+43*52*52=116392

    所以116392是你的排列数


    (顺便说一句,我猜2钻石是‘e’和43,你可以把它数一数,看看它到底是什么)

    解决这个问题的一种方法是使用(伪)随机数生成器(如a),然后只存储每笔交易的种子数。由于每次从同一种子中获得相同的随机数序列,因此它可以代表整个交易(使用该种子生成的随机数来驱动所发的牌)

    [编辑…]

    一些pse abcdefghijklm nopqrstuvwxyz ♥ A234567890JQK ♦ A234567890JQK ABCDEFGHIJKLM NOPQRSTUVWXYZ ♣ A234567890JQK ♠ A234567890JQK
    public enum Cards : byte
    {
        HeartsAce
        HeartsTwo
        // ...
        HeartsTen
        HeartsJack
        HeartsQueen
        HeartsKing
        DiamondsAce
        DiamondsTwo
        // ...
        SpadesTen
        SpadesJack
        SpadesQueen
        SpadesKing
    }
    
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace ConsoleApplication12
    {
        class Program
        {
            static void Main(string[] args)
            {
                // Because each card is unique you could use Flag attributed Enum see the enum below and set each item a unique value I used 2 to the power of 52
                Cards cardsdealt = Cards.Clubs_10 | Cards.Clubs_2 | Cards.Diamonds_3;
    
                if ((cardsdealt & Cards.Clubs_10) == Cards.Clubs_10)
                {
                    Console.WriteLine("Card.Clubs_10 was dealt");
                }
    
                // Storage would always be 8 bytes for the long data type
            }
    
            [Flags]
            public enum Cards : long
            {
                Spades_Ace = 1,
                Spades_2 = 2,
                Spades_3 = 4,
                Spades_4 = 8,
                Spades_5 = 16,
                Spades_6 = 32,
                Spades_7 = 64,
                Spades_8 = 128,
                Spades_9 = 256,
                Spades_10 = 512,
                Spades_Jack = 1024,
                Spades_Queen = 2048,
                Spades_King = 4096,
                Hearts_Ace = 8192,
                Hearts_2 = 16384,
                Hearts_3 = 32768,
                Hearts_4 = 65536,
                Hearts_5 = 131072,
                Hearts_6 = 262144,
                Hearts_7 = 524288,
                Hearts_8 = 1048576,
                Hearts_9 = 2097152,
                Hearts_10 = 4194304,
                Hearts_Jack = 8388608,
                Hearts_Queen = 16777216,
                Hearts_King = 33554432,
                Diamonds_Ace = 67108864,
                Diamonds_2 = 134217728,
                Diamonds_3 = 268435456,
                Diamonds_4 = 536870912,
                Diamonds_5 = 1073741824,
                Diamonds_6 = 2147483648,
                Diamonds_7 = 4294967296,
                Diamonds_8 = 8589934592,
                Diamonds_9 = 17179869184,
                Diamonds_10 = 34359738368,
                Diamonds_Jack = 68719476736,
                Diamonds_Queen = 137438953472,
                Diamonds_King = 274877906944,
                Clubs_Ace = 549755813888,
                Clubs_2 = 1099511627776,
                Clubs_3 = 2199023255552,
                Clubs_4 = 4398046511104,
                Clubs_5 = 8796093022208,
                Clubs_6 = 17592186044416,
                Clubs_7 = 35184372088832,
                Clubs_8 = 70368744177664,
                Clubs_9 = 140737488355328,
                Clubs_10 = 281474976710656,
                Clubs_Jack = 562949953421312,
                Clubs_Queen = 1125899906842620,
                Clubs_King = 2251799813685250,
    
            }
        }
    }