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