用递归的方式分析白色相簿2 coda篇各结局概率
作者:互联网
感谢:https://blog.csdn.net/applebananac123/article/details/59253642
这里是白色相簿2 coda篇选项对各参数的影响:https://www.3dmgame.com/gl/3710683_7.html
上面那位朋友用栈的方式来分析概率。我这里提供另一种思路:用递归的方式来分析。这样代码量会更少,更简洁,也更容易理解。
先放代码:
#include<stdio.h>
#include<string.h>
#include<math.h>
int SETZUNANormalEnd=0;
int SETZUNATrueEnd=0;
int KAZUSANormalEnd=0;
int KAZUSATrueEnd=0;
int SETZUNANEweight=0;
int SETZUNATEweight=0;
int KAZUSANEweight=0;
int KAZUSATEweight=0;
void A(int SETZUNA,int KAZUSA,int fq,int QuestionNum,bool NEflag,bool SETZUNAflag,int ChooseNum)
{//雪菜好感度,和纱好感度,浮气值,当前选择支,跳过选项,已做过选择次数(莫得选择时不会增加)
if(QuestionNum==999)
{
return;
}
else
{
if(QuestionNum==1)//选择支1
{
A(SETZUNA+1,KAZUSA,fq,2,NEflag,SETZUNAflag,ChooseNum+1);//选1:雪菜好感度+1
A(SETZUNA,KAZUSA,fq,2,NEflag,SETZUNAflag,ChooseNum+1); //选2:无
}
if(QuestionNum==2)//选择支2
{
A(SETZUNA,KAZUSA,fq,5,true,SETZUNAflag,ChooseNum+1);//选1:NEflag开(跳11、12),跳3、4
A(SETZUNA+1,KAZUSA,fq,3,false,SETZUNAflag,ChooseNum+1);//选2:雪菜好感度+1
}
if(QuestionNum==3)//选择支3
{
A(SETZUNA,KAZUSA,fq,4,NEflag,SETZUNAflag,ChooseNum+1);//选1:无
A(SETZUNA+1,KAZUSA,fq,5,NEflag,SETZUNAflag,ChooseNum+1);//选2:跳选择支4,雪菜好感度+1
}
if(QuestionNum==4)//选择支4
{
A(SETZUNA,KAZUSA,fq+1,5,NEflag,SETZUNAflag,ChooseNum+1);//选1:浮气+1
A(SETZUNA,KAZUSA+1,fq,5,NEflag,SETZUNAflag,ChooseNum+1);//选2:和纱好感度+1
}
if(QuestionNum==5)//选择支5
{
A(SETZUNA+1,KAZUSA,fq+1,7,NEflag,SETZUNAflag,ChooseNum+1);//选1:雪菜好感+1,浮气+1,跳选择支6
A(SETZUNA,KAZUSA,fq,6,NEflag,SETZUNAflag,ChooseNum+1);//选2:无
}
if(QuestionNum==6)//选择支6
{
A(SETZUNA,KAZUSA+1,fq,7,NEflag,SETZUNAflag,ChooseNum+1);//选1:和纱好感+1
A(SETZUNA+1,KAZUSA,fq,7,NEflag,SETZUNAflag,ChooseNum+1);//选2:雪菜好感+1
}
if(QuestionNum==7)//选择支7
{
A(SETZUNA+1,KAZUSA,fq,8,NEflag,SETZUNAflag,ChooseNum+1);//选1:雪菜好感+1
A(SETZUNA,KAZUSA,fq+1,8,NEflag,SETZUNAflag,ChooseNum+1);//选2:浮气+1
}
if(QuestionNum==8)//选择支8
{
A(SETZUNA,KAZUSA+1,fq+1,9,NEflag,SETZUNAflag,ChooseNum+1);//选1:和纱好感+1,浮气+1
A(SETZUNA+1,KAZUSA,fq,9,NEflag,SETZUNAflag,ChooseNum+1);//选2:雪菜好感+1
}
if(QuestionNum==9)//选择支9
{
A(SETZUNA+1,KAZUSA,fq,11,NEflag,SETZUNAflag,ChooseNum+1);//选1:雪菜好感+1,跳选择支10
A(SETZUNA,KAZUSA,fq,10,NEflag,SETZUNAflag,ChooseNum+1);//选2:无
}
if(QuestionNum==10)//选择支10
{
A(SETZUNA,KAZUSA+1,fq,11,NEflag,SETZUNAflag,ChooseNum+1);//选1:和纱好感+1
A(SETZUNA,KAZUSA,fq+1,11,NEflag,SETZUNAflag,ChooseNum+1);//选2:浮气+1
}
if(QuestionNum==11)//选择支11
{
if(NEflag==true)//NEflag开时跳过
{
A(SETZUNA,KAZUSA,fq,13,NEflag,SETZUNAflag,ChooseNum);
}
else
{
A(SETZUNA+1,KAZUSA,fq,12,NEflag,SETZUNAflag,ChooseNum+1);//选1:雪菜好感+1
A(SETZUNA,KAZUSA+1,fq,12,NEflag,SETZUNAflag,ChooseNum+1);//选2:和纱好感+1
}
}
if(QuestionNum==12)//选择支12
{
if(NEflag==true)//NEflag开时跳过
{
A(SETZUNA,KAZUSA,fq,13,NEflag,SETZUNAflag,ChooseNum);
}
else
{
if(SETZUNA>KAZUSA+fq)//不能选1
{
SETZUNAflag=true;
A(SETZUNA,KAZUSA,fq,13,NEflag,SETZUNAflag,ChooseNum);//选2:雪菜flag开
}
else
{
A(SETZUNA,KAZUSA+1,fq,13,NEflag,SETZUNAflag,ChooseNum+1);//选1:和纱好感+1
SETZUNAflag=true;
A(SETZUNA,KAZUSA,fq,13,NEflag,SETZUNAflag,ChooseNum+1);//选2:雪菜flag开
}
}
}
if(QuestionNum==13)//选择支13
{
if(SETZUNAflag==true)//雪菜flag开时不能选1
{
A(SETZUNA,KAZUSA,fq,14,NEflag,SETZUNAflag,ChooseNum);//选2:无
}
else
{
A(SETZUNA,KAZUSA,fq,999,NEflag,SETZUNAflag,ChooseNum+1);//选1:浮气END
KAZUSANormalEnd++;
KAZUSANEweight+=pow(2,14-(ChooseNum+1));
A(SETZUNA,KAZUSA,fq,14,NEflag,SETZUNAflag,ChooseNum+1);//选2:无
}
}
if(QuestionNum==14)//选择支14
{
if(KAZUSA<6)//和纱好感度没到6时不能选2
{
if(SETZUNAflag==true)
{
SETZUNATrueEnd++;
SETZUNATEweight+=pow(2,14-ChooseNum);
A(SETZUNA,KAZUSA,fq,999,NEflag,SETZUNAflag,ChooseNum);
}
else
{
SETZUNANormalEnd++;
SETZUNANEweight+=pow(2,14-ChooseNum);
A(SETZUNA,KAZUSA,fq,999,NEflag,SETZUNAflag,ChooseNum);
}
}
else
{
if(SETZUNAflag==true)//根据雪菜flag是不是开了来决定
{//开
A(SETZUNA,KAZUSA,fq,999,NEflag,SETZUNAflag,ChooseNum+1);//选1:雪菜END
SETZUNATrueEnd++;
SETZUNATEweight+=pow(2,14-(ChooseNum+1));
A(SETZUNA,KAZUSA,fq,999,NEflag,SETZUNAflag,ChooseNum+1);//选2:雪菜END
SETZUNATrueEnd++;
SETZUNATEweight+=pow(2,14-(ChooseNum+1));
}
else
{//关
A(SETZUNA,KAZUSA,fq,999,NEflag,SETZUNAflag,ChooseNum+1);//选1:腰斩END
SETZUNANormalEnd++;
SETZUNANEweight+=pow(2,14-(ChooseNum+1));
A(SETZUNA,KAZUSA,fq,999,NEflag,SETZUNAflag,ChooseNum+1);//选2:和纱END
KAZUSATrueEnd++;
KAZUSATEweight+=pow(2,14-(ChooseNum+1));
}
}
}
}
}
int main()
{
A(0,0,0,1,false,false,0);
printf("腰斩%d 雪菜TE%d 浮气%d 和纱TE%d\n",SETZUNANormalEnd,SETZUNATrueEnd,KAZUSANormalEnd,KAZUSATrueEnd);
printf("腰斩%.4f%% ",(float)SETZUNANEweight*100/16384);
printf("雪菜TE%.4f%% ",(float)SETZUNATEweight*100/16384);
printf("浮气%.4f%% ",(float)KAZUSANEweight*100/16384);
printf("和纱TE%.4f%%",(float)KAZUSATEweight*100/16384);
return 0;
}
这里自定义了一个函数A,将选择支编号、雪菜好感度、和纱好感度、浮气值作为参数,根据选择支编号进入选择支,对当前的两种选择支进行选择并根据情况分别对参数进行影响,然后再次调用A进入下一选择支,以此类推。直到接下来没有选择支之后返回。
对于游戏中存在的跳过选择支的行为,直接在调用A函数时设置好进入的题号就行了。如果跳过的不是临近的选择支的话,这里为函数加入了bool类型的flag参数,当选择了特定的选择支后将flag设为true,表示开启,否则默认是false关闭状态。然后到了对应的选择支对该flag进行判定,如果开启就直接进入下一选择支,没开启就正常做选择。
上述是递归搜索进行的过程,下面说说结局统计。这里设置了四个全局变量,分别表示雪菜TE、和纱TE、浮气线、腰斩线的情况数,每次选择进入该结局后令对应的变量+1即可。
以下是结局数:
雪菜TE 432种
和纱TE 4种
浮气线 299种
腰斩线 299种
下面说说概率的问题。需要注意的时概率的分布不是平均的。就像掷两枚硬币,会有三种情况:一正一反,两正,两反。显然不是一共有三种情况所以概率都是1/3,概率分布不是平均的,是1/2、1/4、1/4。
所以怎么去分析概率呢?我的思路是:当每次做出了一次二选一的选择时,选到每个选项的概率都是1/2。所以当你在一种情况里做了X次二选一的选择后,顺着这条选择链走的概率应为(1/2)X。
所以这里加入了一个ChooseNum的参数,代表做出的二选一的次数。如果有二选一时就+1,莫得选择时就不变。假设最后选了X次,那选到这种选择情况的概率就是(1/2)X。将总权重值设为214=16384(一共14个选择支),每种情况分到的权重值为16384*(1/2)X。再设置4个全局变量记录每种结局的权重值,每次选择结束即将返回时增加对应的权重值,最后将总权重值除以16384即可得到概率。乘以100转化为百分比值。
以下是各个结局的概率:
雪菜TE 39.2578%
和纱TE 0.0244%
浮气线 30.3711%
腰斩线 30.3467%
当然了这是随机乱选的情况,真正玩游戏的时候都是根据剧情去思考的。
和纱TE这么点的概率能选进来的都是真爱了。
(看了下,只有第1题第7题可随意选其他12题一个都不能选错)
一些闲谈:
①刚开始写的时候我把可能被跳的题设置了个bool数组,将其作为参数传入函数。但之后我才知道数组丢进自定义函数是把数组头的指针丢进去而不是形参,也就是直接对变量的本体动手而不是产生分身,就说怎么一直改都改不对(草)。后面发现被跳的题除了一个NEflag控制的11、12,都是相邻的选择支,就直接改进入的下一题的题号就好了
②其实上面那篇文章我看不太懂,因为我栈没学好,除了个先进后出就不懂别的了(手动捂脸)
③关于白2这个游戏,一开始是因为“你为什么这么熟练”的梗去看了番剧(番剧讲序章部分),然后为了后续剧情去下了游戏。我其实是直接上网找攻略通的,我主要是看剧情而不是玩游戏hhhhh。这剧情写的挺好的,情感很细腻,特别令人胃疼纠结,希望所有人都幸福,但总有人要受伤,怎么选好像都不对,又好像都对。
雪菜TE应该是一个相对比较圆满的结局。
丸户老贼不愧是三十禁作家。
以及游戏内立绘的作画真是X了狗了!!
标签:SETZUNAflag,递归,coda,KAZUSA,fq,NEflag,ChooseNum,相簿,SETZUNA 来源: https://blog.csdn.net/weixin_43311658/article/details/105776917