於是乎,這就是學校教的C++能派上用場的時候啦!因為寫程式能力有點生疏,所以花了一整個晚上才寫好。
但是!!!非常令人驚訝,機率竟然不到1%!
以下是執行結果:
舉例來說:
0 1 1 0
0.015873 1201
是指:“沒換牌前,龍鰻0張、學徒至少1張、鏡像至少1張”的情況— 在總共的27405個組合中,一共出現了1201次。
而在這種特定的情況下,前兩回合就有抽齊“兩張龍鰻、一張學徒、和一張鏡像”的條件機率是0.015873。
那麼,就只好把程式碼貼上來,和大家討論實際的機率啦~
#include <iostream>
#include <stdlib.h>
#include <stdio.h>
#include <array>
#include <vector>
using namespace std;
//returns all (-1) if having no other ways to choose
void selection_changeToNextState(int numOfThingsToChooseFrom, int numOfThingsChosen, int nowState[]);
int main(int argc, const char * argv[]) {
const int MaxCards = 30;
int rounds = 2;
array<int,MaxCards> cards={};
cards[0]=2;
cards[1]=2;
cards[2]=2;
cards[3]=24;
array<int,MaxCards> goal={};
goal[0]=2;
goal[1]=1;
goal[2]=1;
goal[3]=0;
array<int,MaxCards> deck={};
int nowCard=0;
int importantTypes=0;
for(int nowType=0; nowType<MaxCards; ++nowType){
if(cards[nowType]>0){
importantTypes = nowType+1;
for(int j=nowCard; j< nowCard+cards[nowType]; ++j){
deck[j]=nowType;
}
nowCard+=cards[nowType];
}
}
int totalCards = nowCard;
cout<<"totalCards:\t"<<totalCards<<"\n";
cout<<"importantTypes:\t"<<importantTypes<<"\n";
//for testing: show the entire deck
/*for(int i=0;i<totalCards;++i){
cout<<i<<":\t"<<deck[i]<<"\n";
}*/
bool isFirst = false;
int firstDrawNum;
if(isFirst)
firstDrawNum=3;
else
firstDrawNum=4;
//hand starts from "choosing the first <firstDrawNum> number of cards"
array<int,MaxCards> hand = {};
for(int i=0;i<firstDrawNum;++i){
hand[i]=i;
}
bool testShow_cardTypeDrawn = false;
bool testShow_possible_hands = false;
bool testShow_possible_afterHands = false;
bool testShow_unfulfilledGoal = false;
bool testShow_finalGoal = false;
bool testShow_cardsLaterDrawn = false;
bool testShow_count = true;
bool testShow_finishProbability = false;
int count=1;
struct cardTypesKept_to_probability{
array<int,MaxCards> cardTypesKept;
double probability;
int count;
};
vector<cardTypesKept_to_probability> record;
while(true){
int cardsKept = 0;
int cardsToRedraw = 0;
array<int,MaxCards> unfulfilledGoal = goal;
array<int,MaxCards> cardTypesKept = {};
array<bool,MaxCards> cardIsKept = {};
for(int j=0;j<firstDrawNum;++j){
int cardDrawn = deck[hand[j]];
// for testing: show card type drawn
if(testShow_cardTypeDrawn)
cout<<cardDrawn<<"\n";
if(unfulfilledGoal[ cardDrawn ]>0){
unfulfilledGoal[ cardDrawn ]--;
cardTypesKept[ cardDrawn ]++;
cardIsKept[ hand[j] ] = true;
++cardsKept;
}
else{
++cardsToRedraw;
}
}
// for testing: show card type drawn
if(testShow_cardTypeDrawn){
cout<<"\n";
for(int j=0;j<importantTypes;++j){
cout<<cardTypesKept[j]<<"\t";
}
cout<<"\n";
}
bool inRecord = false;
for(int j=0;j<record.size();++j){
if(cardTypesKept == record[j].cardTypesKept){
++record[j].count;
inRecord = true;
}
}
if(!inRecord){
int cardsLaterDrawn = cardsToRedraw + (rounds-1) +1;
array<int,MaxCards> calcHandsAfter = {};
for(int i=0;i<cardsLaterDrawn;++i){
calcHandsAfter[i]=i;
}
int afterCount = 1;
int finishCount = 0;
while(true){
// for testing: show all the possible hands after drawing again
if(testShow_possible_afterHands){
cout<<"\t\t";
cout<<afterCount<<"~ ";
for(int j=0;j<cardsLaterDrawn;++j){
cout<<calcHandsAfter[j]<<" ";
}
cout<<"\n";
}
array<int,MaxCards> finalGoal = unfulfilledGoal;
bool goalFinished = true;
int nowPlace=0;
int nowAfterCode=0;
for(int stepsMoved=0; nowPlace<totalCards;++nowPlace){
if(cardIsKept[nowPlace]){
if(testShow_possible_afterHands)
cout<<nowPlace<<" ";
}
else{
if(stepsMoved == calcHandsAfter[nowAfterCode]){
if(testShow_possible_afterHands)
cout<<nowPlace<<" ";
int cardDrawnAfter = deck[nowPlace];
if(finalGoal[ cardDrawnAfter ]>0){
finalGoal[ cardDrawnAfter ]--;
}
++nowAfterCode;
}
++stepsMoved;
}
}
if(testShow_possible_afterHands)
cout<<"\n";
for(int j=0;j<importantTypes;++j){
if(finalGoal[j]>0){
goalFinished=false;
}
}
if(goalFinished)
++finishCount;
// for testing: show finalGoal
if(testShow_finalGoal){
for(int j=0;j<importantTypes;++j){
cout<<finalGoal[j]<<" ";
}
cout<<"\n";
}
selection_changeToNextState(totalCards-cardsKept, cardsLaterDrawn, calcHandsAfter.data());
//if having no other ways to choose
if(calcHandsAfter[0]<0)
break;
++afterCount;
}
double finishProbability = (finishCount * 1.0)/afterCount;
struct cardTypesKept_to_probability c_p={cardTypesKept,finishProbability,1};
record.push_back(c_p);
//cout<<finishProbability<<"\n";
}
// for testing: show all the possible hands
if(testShow_possible_hands){
cout<<count<<": ";
for(int j=0;j<firstDrawNum;++j){
cout<<hand[j]<<" ";
}
cout<<"\n";
}
// for testing: show unfulfilledGoal
if(testShow_unfulfilledGoal){
cout<<count<<"– ";
for(int j=0;j<importantTypes;++j){
cout<<unfulfilledGoal[j]<<" ";
}
}
selection_changeToNextState(totalCards, firstDrawNum, hand.data());
//if having no other ways to choose
if(hand[0]<0)
break;
++count;
}
//for testing
if(testShow_count)
cout<<count<<"\n";
double sumOfProbability = 0.0;
for(int i=0;i<record.size();++i){
sumOfProbability += (record[i].probability)*(record[i].count);
for(int j=0;j<importantTypes;++j){
cout<<record[i].cardTypesKept[j]<<"\t";
}
cout<<"\n";
cout<<record[i].probability<<"\t"<< record[i].count <<"\n";
cout<<"\n";
}
cout<<"\n"<< sumOfProbability/count <<"\n";
return 0;
}
//returns all (-1) if having no other ways to choose
void selection_changeToNextState(int numOfThingsToChooseFrom, int numOfThingsChosen, int nowState[]){
int lastDigit = numOfThingsChosen-1;
int lastNum = numOfThingsToChooseFrom-1;
int carryDigits = 0;
while(nowState[lastDigit - carryDigits] >= lastNum-carryDigits){
++carryDigits;
if(lastDigit - carryDigits<0)
break;
}
//return all (-1) if having no other ways to choose
if(lastDigit - carryDigits<0){
for(int j= 0; j<=lastDigit; ++j){
nowState[j]= -1;
}
return;
}
nowState[lastDigit - carryDigits]++;
for(int j= lastDigit - carryDigits+1; j<=lastDigit; ++j){
nowState[j]=nowState[j-1]+1;
}
}
跑出來的結果比我預期中小很多。大家覺得,這一種情況的機率是多少呢?