需要找出洗牌方法中的逻辑错误
我正在尝试编写一个方法,该方法接受一个整数数组(0-51,按顺序),将其切成两个单独的数组(下面函数中的 A 和 B 使用 cut 方法,我知道它确实有效),然后通过从 A 或 B 的底部随机选择 0、1 或 2 张牌并将它们添加到牌堆中,将两个阵列重新融合在一起。
(ps-“数组”我的意思是链接列表,我只是说数组是因为我认为它在概念上会更容易)
这是我到目前为止的代码,它有效,但是当涉及到卡片落地的位置时,存在明显的偏差。有人能发现我的逻辑错误吗?
[code]
void Deck::shuffle(){
IntList *A = new IntList();
IntList *B = new IntList();
cut(A, B);
IntListNode *aMarker = new IntListNode;
aMarker = A->getSentinel()->next;
//cout<< A->getSentinel()->prev->prev->data <<'\n'<<'\n';
IntListNode *bMarker = new IntListNode;
bMarker = B->getSentinel()->next;
//cout<< B->getSentinel()->prev->data;
deckList.clear();
srand(time(NULL));
int randNum = 0, numCards = 0, totalNumCards = 0;
bool selector = true, aisDone = false, bisDone = false;
while(totalNumCards < 52){
randNum = rand() % 3;
if(randNum == 0){
selector = !selector;
continue;
}
numCards = randNum;
if(!aisDone && !bisDone){
if(selector){
for(int i = 0; i < numCards; i++){
deckList.push_back(aMarker->data);
aMarker = (aMarker->next);
if(aMarker == A->getSentinel()){
aisDone = true;
break;
}
}
selector = false;
}else{
for(int i = 0; i < numCards; i++){
deckList.push_back(bMarker->data);
bMarker = (bMarker->next);
if(bMarker == B->getSentinel()){
bisDone = true;
break;
}
}
selector = true;
}
}
if(aisDone && !bisDone){
for(int i = 0; i < (52 - totalNumCards); i++){
deckList.push_back(bMarker->data);
bMarker = (bMarker->next);
if(bMarker == B->getSentinel()){
bisDone = true;
break;
}
}
//return;
}
if(bisDone && !aisDone){
for(int i = 0; i < (52 - totalNumCards); i++){
deckList.push_back(aMarker->data);
aMarker = (aMarker->next);
if(aMarker == A->getSentinel()){
aisDone = true;
break;
}
}
//return;
}
totalNumCards += numCards;
}
int tempSum = 0;
IntListNode *tempNode = deckList.head();
for(int j = 0; j < 52; j++){
//cout<< (tempNode->data) << '\n';
tempSum += (tempNode->data);
tempNode = (tempNode ->next);
}
if(tempSum != 1326)
system("PAUSE");
return;
}
[/code]
I'm trying to write a method that takes an array of integers (0-51, in that order), cuts it into two separate arrays (A and B in the below function by using the cut method, which I know for sure works) and then re-fuses the two arrays together by randomly selecting 0, 1 or 2 cards from the BOTTOM of either A or B and then adding them to the deck.
(ps- by "array" I mean linked list, I just said array because I thought it would be conceptually easier)
This is my code so far, it works, but there's a definite bias when it comes to where the cards land. Can anybody spot my logic error?
[code]
void Deck::shuffle(){
IntList *A = new IntList();
IntList *B = new IntList();
cut(A, B);
IntListNode *aMarker = new IntListNode;
aMarker = A->getSentinel()->next;
//cout<< A->getSentinel()->prev->prev->data <<'\n'<<'\n';
IntListNode *bMarker = new IntListNode;
bMarker = B->getSentinel()->next;
//cout<< B->getSentinel()->prev->data;
deckList.clear();
srand(time(NULL));
int randNum = 0, numCards = 0, totalNumCards = 0;
bool selector = true, aisDone = false, bisDone = false;
while(totalNumCards < 52){
randNum = rand() % 3;
if(randNum == 0){
selector = !selector;
continue;
}
numCards = randNum;
if(!aisDone && !bisDone){
if(selector){
for(int i = 0; i < numCards; i++){
deckList.push_back(aMarker->data);
aMarker = (aMarker->next);
if(aMarker == A->getSentinel()){
aisDone = true;
break;
}
}
selector = false;
}else{
for(int i = 0; i < numCards; i++){
deckList.push_back(bMarker->data);
bMarker = (bMarker->next);
if(bMarker == B->getSentinel()){
bisDone = true;
break;
}
}
selector = true;
}
}
if(aisDone && !bisDone){
for(int i = 0; i < (52 - totalNumCards); i++){
deckList.push_back(bMarker->data);
bMarker = (bMarker->next);
if(bMarker == B->getSentinel()){
bisDone = true;
break;
}
}
//return;
}
if(bisDone && !aisDone){
for(int i = 0; i < (52 - totalNumCards); i++){
deckList.push_back(aMarker->data);
aMarker = (aMarker->next);
if(aMarker == A->getSentinel()){
aisDone = true;
break;
}
}
//return;
}
totalNumCards += numCards;
}
int tempSum = 0;
IntListNode *tempNode = deckList.head();
for(int j = 0; j < 52; j++){
//cout<< (tempNode->data) << '\n';
tempSum += (tempNode->data);
tempNode = (tempNode ->next);
}
if(tempSum != 1326)
system("PAUSE");
return;
}
[/code]
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
发布评论
评论(4)
如果你的老师有道德教你如何编程,那么他们会鼓励你像这样用四行代码解决问题:
#include<algorithm>
#include<vector>
// ...
std::vector<int> cards; // fill it in ...
std::random_shuffle(cards.begin(), cards.end());
使用标准库是<正确的做事方式。当您可以使用标准库解决问题时,自己编写代码是错误的做事方式。你的老师没有教你正确的方法。如果他们想表达一个观点(例如,让你练习使用指针),那么他们应该更加注意选择他们给你的练习。
在演讲中,这里有一个比上面的解决方案更糟糕但比你的老师的更好的解决方案:
执行以下操作 52 次:
- 在 [0,52) 范围内选择两个随机的不相等整数。
- 交换数组中与这些位置对应的值。
注释:
srand(time(NULL));
这应该在应用程序运行期间只调用一次。通常最好在开始时在 main() 中调用它。
int randNum = 0, numCards = 0, totalNumCards = 0;
bool selector = true, aisDone = false, bisDone = false;
每行一个标识符。每个编写的编码标准都有这条规则。它还可以防止使用指针时可能出现的一些细微错误。习惯它。
randNum = rand() % 3;
rand 的底部位是最不随机的。
rand Num = rand() / (MAX_RAND / 3.0);
问:
if(!aisDone && !bisDone)
{
This can execute
and set one of the above to isDone
Example:
Exit state aisDone == false bsiDone == false // OK
Exit state aisDone == true bsiDone == false // Will run below
Exit state aisDone == false bsiDone == ture // Will run below
}
if(aisDone && !bisDone)
{
Is this allowed to run if the first block above is run?
}
if(bisDone && !aisDone)
{
Is this allowed to run if the first block above is run?
}
剩下的太复杂了,看不懂。
我可以想到更简单的技术来很好地洗牌一副牌:
for(loop = 0 .. 51)
{
rand = rand(51 - loop);
swap(loop, loop+rand);
}
上面模拟从牌组 A 中随机挑选一张牌并将其放在牌组 B 的顶部(牌组 B 最初是空的)。当循环完成时,B 现在是 A(因为它已就地完成)。
因此,每张牌(来自 A 的牌)被放置在 B 中任何位置的概率都是相同的。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
只使用 std::random_shuffle 怎么样?是的,它不适用于链表,但你可以将其更改为
vector
:)What about just using
std::random_shuffle
? Yeah, it won't work for linked list, but you can change it tovector
:)