本人很喜欢一款叫做白色相簿2的游戏,最近闲得无聊研究了一下coda中各结局的概率,在这里和各位喜欢二次元和算法的朋友交流

首先,coda篇中选项好感度变化大家可以看这一篇贴吧帖子https://tieba.baidu.com/p/3716041711。我把它画成了流程图(字比较潦草),这里上传上来给大家简单看一下。

可以看到整个过程非常错综复杂。如果只有选项或者判定那么计算概率还会容易一些,但这里还有一些选项会由于好感度不同而被屏蔽,鄙人深感自己数学功力不足,于是决定借助计算机来帮助解决问题。

接下来说说鄙人是怎么设计算法的:

我将每一个选项,判定或者结局用结构体Choice来表示。Choice主要起到两个作用,其一便是存储到当前Choice的各种数值,我这里定义了三个变量kazusa,setsuna,fq分别存储到当前Choice为止的冬马好感度,雪菜好感度以及浮气度,接着定义两个布尔类型neFlag,setsunaFlag分别表示NE的flag和雪菜TE的flag;其二便是要为下一个Choice做指引,这里就相对比较复杂。我这里定义了好多变量,首先定义了三个int变量deltaKazusa,deltaSetsuna,deltaFq分别来表示选项对于冬马好感度,雪菜好感度以及浮气度的变化关系,这三个变量可以分别取0,1,2,比如deltaKazusa取0表示没有选项会对冬马好感度起作用,deltaSetsuna取1表示选项A会对雪菜好感度起作用,取2表示选项B会对雪菜好感度起作用,接着定义两个int类型openNEFlag,openSetsunaFlag来表示选项对于开启flag的作用,取值和前面三个一样,不多做叙述了。每个Choice要包含两个指针( 或者也可以是两个序号),分别表示选A和选B(或者判定的是,否)所对应的后一个Choice应该是什么。

现在该说说整体算法设计思路了。我觉得这个问题应该用栈解决,这里我提供两种思路(其实是大同小异)。第一种,选项1的Choice入栈。每次栈顶元素tmp出栈(注意是出栈, 移出去了),然后把它的两个儿子复制之后得到tmpA,tmpB,利用tmp计算出tmpA和tmpB的各项好感度以及flag是否开启,然后将tmpA和tmpB入栈。重复这样做直到栈空。第二种,我这里给Choice添加了一个int变量status,可以取0,1,2分别用来标识它是准备选A选项,还是准备选B选项,还是A,B都选过了。选项1的Choice入栈,每次判断栈顶元素的status,如果是0,代表准备选A,将status加一,然后修改A儿子的各个数值之后将其入栈;如果是1,代表准备选B,status再加一,然后修改B儿子的各个数值之后将其入栈;如果是2,代表A,B都选过了,将其出栈。我个人推荐第二种方法,因为占用空间少,第一种需要复制大量的Choice同时压到栈里,第二个等于只有十几个Choice,我们做的只是在修改它的值而已。至于选项A,B能不能选,就另外加条件判断,这里贴出代码。

#include<iostream>
#include<stack>using namespace std;struct Choice {Choice* A;Choice* B;int type;//-1代表结局,0代表正常选项,1代表NE判定,2代表TE判定int endingType;//0代表雪菜TE,1代表雪菜NE,2代表冬马NE,3代表冬马TEint status;//0代表下一个选A,1代表下一个选Bint num;//选项序号,用于屏蔽选项int weight;int kazusa;//冬马好感度int setsuna;//雪菜好感度int fq;//浮气度//增加好感度,0,1,2分别代表不增加,A选项增加,B选项增加int deltaKazusa;//冬马好感度+1int deltaSetsuna;//雪菜好感度+1int deltaFq;//浮气度+1bool neFlag;//雪菜NE,冬马NE flagbool setsunaFlag;//雪菜TE flag//打开flag,0,1,2分别代表不打开,A选项打开,B选项打开int openNEFlag;//打开NE flagint openSetsunaFlag;//打开雪菜TE flagChoice* chooseA(bool weightFlag) {A->status = 0;if (weightFlag) {A->weight = weight;}else {A->weight = weight / 2;}//冬马好感度+1if (deltaKazusa==1) {A->kazusa = kazusa + 1;}else {A->kazusa = kazusa;}//雪菜好感度+1if (deltaSetsuna==1) {A->setsuna = setsuna + 1;}else {A->setsuna = setsuna;}//浮气度+1if (deltaFq==1) {A->fq = fq + 1;}else {A->fq = fq;}//打开NE flagif (openNEFlag==1) {A->neFlag = true;}else {A->neFlag = neFlag;}//打开雪菜TE flagif (openSetsunaFlag==1) {A->setsunaFlag = true;}else {A->setsunaFlag = setsunaFlag;}return A;}Choice* chooseB(bool weightFlag) {B->status = 0;if (weightFlag) {B->weight = weight;}else {B->weight = weight / 2;}//冬马好感度+1if (deltaKazusa==2) {B->kazusa = kazusa + 1;}else {B->kazusa = kazusa;}//雪菜好感度+1if (deltaSetsuna==2) {B->setsuna = setsuna + 1;}else {B->setsuna = setsuna;}//浮气度+1if (deltaFq==2) {B->fq = fq + 1;}else {B->fq = fq;}//打开NE flagif (openNEFlag == 2) {B->neFlag = true;}else {B->neFlag = neFlag;}//打开雪菜TE flagif (openSetsunaFlag == 2) {B->setsunaFlag = true;}else {B->setsunaFlag = setsunaFlag;}return B;}Choice(int dK , int dS , int dF , int oNF,int oSF,Choice* cA,Choice *cB,int n,int t=0,int eT=0) {status = 0;kazusa = setsuna = fq = 0;neFlag = setsunaFlag  = false;deltaKazusa = dK;deltaSetsuna = dS;deltaFq = dF;openNEFlag = oNF;openSetsunaFlag = oSF;A = cA;B = cB;num = n;type = t;endingType = eT;}
};int main() {int endingNumber = 0;int endingTypeNumber[4] = { 0 };int endingWeightNumber[4] = { 0 };bool flagA, flagB;Choice *setsunaTrueEnding = new Choice(0, 0, 0, 0, 0, 0, 0, 0, -1, 0), *setsunaNormalEnding = new Choice(0, 0, 0, 0, 0, 0, 0, 1, -1, 1), *kazusaNormalEnding = new Choice(0, 0, 0, 0, 0, 0, 0, 2, -1, 2), *kazusaTrueEnding = new Choice(0, 0, 0, 0, 0, 0, 0, 3, -1, 3);Choice *pd4 = new Choice(0, 0, 0, 0, 0, setsunaTrueEnding, kazusaTrueEnding, 4, 2),*pd3 = new Choice(0, 0, 0, 0, 0, pd4, setsunaNormalEnding, 3, 2);Choice *choice14 = new Choice(0, 0, 0, 0, 0, pd3, pd4, 14),*choice13 = new Choice(0, 0, 0, 0, 0, kazusaNormalEnding, choice14, 13),*choice12 = new Choice(1, 0, 0, 0, 2, choice13, choice13, 12);Choice *pd2 = new Choice(0, 0, 0, 0, 0, choice13, choice12, 2, 1);Choice *choice11 = new Choice(2, 1, 0, 0, 0, pd2, pd2, 11);Choice *pd1 = new Choice(0, 0, 0, 0, 0, choice13, choice11, 1, 1);Choice *choice10 = new Choice(1, 0, 2, 0, 0, pd1, pd1, 10),*choice9 = new Choice(0, 1, 0, 0, 0, pd1, choice10, 9),*choice8 = new Choice(1, 2, 1, 0, 0, choice9, choice9, 8),*choice7 = new Choice(0, 1, 2, 0, 0, choice8, choice8, 7),*choice6 = new Choice(1, 2, 0, 0, 0, choice7, choice7, 6),*choice5 = new Choice(0, 1, 1, 0, 0, choice7, choice6, 5),*choice4 = new Choice(2, 0, 1, 0, 0, choice5, choice5, 4),*choice3 = new Choice(0, 2, 0, 0, 0, choice4, choice5, 3),*choice2 = new Choice(0, 2, 0, 1, 0, choice5, choice3, 2),*choice1 = new Choice(0, 1, 0, 0, 0, choice2, choice2, 1);choice1->weight = 16384;stack<Choice*> choiceStack;choiceStack.push(choice1);while (!choiceStack.empty()) {Choice* tmp = choiceStack.top();if (tmp->type==0) {flagA = false;flagB = false;if ((tmp->num == 13 && tmp->setsunaFlag) || (tmp->num == 12 && tmp->setsuna > tmp->kazusa + tmp->fq)) {flagA = true;}if (tmp->num == 14 && tmp->kazusa < 6) {flagB = true;}if (tmp->status==0) {tmp->status = tmp->status + 1;if (flagA) {continue;}choiceStack.push(tmp->chooseA(flagB));}else if (tmp->status == 1) {tmp->status = tmp->status + 1;if (flagB) {continue;}choiceStack.push(tmp->chooseB(flagA));}else {choiceStack.pop();}}else if(tmp->type==1){choiceStack.pop();if (tmp->neFlag) {choiceStack.push(tmp->chooseA(true));}else {choiceStack.push(tmp->chooseB(true));}}else if(tmp->type==2){choiceStack.pop();if (tmp->setsunaFlag) {choiceStack.push(tmp->chooseA(true));}else {choiceStack.push(tmp->chooseB(true));}}else if (tmp->type == -1) {choiceStack.pop();endingNumber++;endingTypeNumber[tmp->endingType] = endingTypeNumber[tmp->endingType] + 1;endingWeightNumber[tmp->endingType] = endingWeightNumber[tmp->endingType] + tmp->weight;}}cout << "endingNumber:" << endingNumber << endl;cout << "雪菜TE:" << endingTypeNumber[0] << endl;cout << "雪菜NE:" << endingTypeNumber[1] << endl;cout << "冬马NE:" << endingTypeNumber[2] << endl;cout << "冬马TE:" << endingWeightNumber[3] << endl;cout << "雪菜TE:" << endingWeightNumber[0] << endl;cout << "雪菜NE:" << endingWeightNumber[1] << endl;cout << "冬马NE:" << endingWeightNumber[2] << endl;cout << "冬马TE:" << endingWeightNumber[3] << endl;return 0;
}

我们最后计算出雪菜TE总共有432种情况,雪菜NE总共有299种情况,冬马NE总共有299种情况,冬马TE总共有4种情况,全局共有1034种情况。很多人到这里可能松一口气,我们拿各个种类的结局数除以1034不就能得到每个结局出现的概率了吗?

这种想法显然是错误的。我给大家举个例子,我们玩抛硬币游戏,我说给你抛两次,你两次都抛反面算你赢,请问你赢的概率是多少?这个是小学数学对吧,是个人都知道4种 情况所以是1/4。这里我再加个条件,我说你只要抛一到一次正面就算我赢,你不用抛了,那么你赢的概率是多少?这个时候其实只有3种情况,就是1正,1反2正,1反2反,但你肯定不会说1/3吧?因为这三个结果概率并不相等,1正的概率是后面两个的两倍,所以依然是1/4。

那么放到我们这里的问题怎么计算呢?我这里提出一个思路,我加入一个名为权重weight的变量,这个weight的值我们这个Choice底下潜在的能选的值是多少(注意,weight值 不代表真实能选的数量,但是与weight总量的比值依然能反映出该到选项有多大概率),选项1的Choice我给它的weight赋值为16384(2的14次方),每次如果是2选1的选项,A,B两个Choice的权值取为当前Choice的一半;如果是判定,由于判定结果具有唯一性,它的下一个Choice权值不变;如果是两个选项有一个被屏蔽掉,那么余下的那个获得当前Choice的全部权值。然后把每个结局获得的所有weight累加起来,最后再除以16384,就是当前结局的概率。

最后贴出结果:

雪菜TE概率:39.3%

雪菜NE概率:30.3%

冬马NE概率:30.4%

冬马TE概率:0.024%

(以上结果是基于每次都是等概率地选两个选项,如果不是概率那么就要复杂很多)

好了,洋洋洒洒写了这么多,也不知道自己说清楚了没有,有问题欢迎随时和我交流。最后告诉大家,我是雪菜党哦,欢迎大家有空来百度的小木曾雪菜吧坐坐!

白色相簿2 coda篇各结局概率分析相关推荐

  1. 用递归的方式分析白色相簿2 coda篇各结局概率

    感谢:https://blog.csdn.net/applebananac123/article/details/59253642 这里是白色相簿2 coda篇选项对各参数的影响:https://ww ...

  2. 《圈子圈套3》终局篇没有结局的结局

    <?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />     10月 ...

  3. react ui框架_Web开发 React 学习(二十)连载基础篇大结局

    系列文章: 测开技能--Web开发 React 学习(一) 测开技能--Web开发 React 学习(二)环境搭建 测开技能--Web开发 React 学习(三)元素的渲染 测开技能--Web开发 R ...

  4. java寂静岭 攻略,GBA版《寂静岭》HARRY篇图文流程攻略

    "Play Novel: Silent Hill"是KONAMI于2001年3月21日在GBA上推出的一款文字冒险游戏,剧情内容取自同社的恐怖冒险游戏--Silent Hill(& ...

  5. ldd导出html,教学 | 乐高虚拟建模软件LDD教程(大结局)— 步骤图和零件表

    本期LDD教程来到了最后一篇大结局. 本期介绍两个主题-步骤图的零件表的制作方法. 制作搭建步骤图 LDD中制作完成模型之后,点击界面右上角的Buliding gudie mode按钮,或快捷键F7, ...

  6. 小说的逻辑与反逻辑_以理性的数学逻辑构筑推理小说

    亚历克斯·帕维西(Alex Pavesi)出道作<第八个侦探>(美版:The Eighth Detective:英版:Eight Detectives)出版于2020年8月.根据其在麦克米 ...

  7. 钗黛双收:若你也同Vim难割舍,却又看Emacs情切切

    作者: C. Minos Niu 原文:请猛击. 1 钗黛双收:若你也同Vim难割舍,却又看Emacs情切切 (引子) 这篇文章分享我的一些经历,写给和我一样对娇小的Vim难以割舍,又在抱上Emacs ...

  8. 长乐未央——记高桥留美子的辉煌三十年

    (初稿于2005年8月) "虽然一直都在画漫画,但是我却没有特地去研究过漫画的画法,所以到现在还搞不太清楚,画漫画究竟是怎么一回事--" 很难想象,说这句话的人,竟会是被公认为在分 ...

  9. 【日本动漫推荐】十一长假动画推荐情报~

    续作补救篇     在十月新番的搜罗中,我们看见了许多新番续作的身影.不管是商家的分期诈钱还是什么原因,如果你不想在新的一季开始后成为小白,在长假期间,补救下这些动漫是最好的选择了~ 完美结局篇    ...

最新文章

  1. ros-kinetic install error: sudo rosdep init ImportError: No module named 'rosdep2'
  2. 算法与数据结构(冒泡排序)
  3. k8s与CICD--将drone部署到kubernetes中,实现agent动态收缩
  4. 单体 soa 微服务 区别_漫谈何时从单体架构迁移到微服务?
  5. python钻石数据分析_数据分析该用什么工具?
  6. 结语|日拱一卒无有尽,功不唐捐终入海
  7. 管理工作中的50点感悟
  8. 【数据库系统设计】关系数据库标准语言SQL(3)
  9. java实现菱形的打印java实现菱形的输出
  10. 函数的基本用法c语言,C语言(函数基本用法).ppt
  11. MVVM框架的了解与使用
  12. 静态类型语言、动态类型语言、强类型定义语言、弱类型定义语言、编译型语言、解释型语言...
  13. Paypal快速支付接口参数的含义
  14. html自动补位的功能,js中位数不足自动补位扩展padLeft、padRight实现代码
  15. 【软件测试】测试员vs测试工程师,你是测试员还是测试工程师?
  16. openlayers官方教程(三)Basics——Zooming to your location
  17. 安装 tez-0.10.1
  18. MySQL基础--MySQL数据库基本操作
  19. mouseover和mouseenter的异同
  20. Unitary matrix 幺正矩阵

热门文章

  1. python 脚本梦幻西游_GitHub - U200915104/mhxy_fz: 一个基于计算机视觉开发的梦幻西游辅助脚本...
  2. 想知道自己30分钟能“走”多远嘛?
  3. flutter web h5微信授权与支付
  4. 谷歌地图街景服务涉嫌侵犯隐私遭起诉
  5. 计算机游戏者战略编写员教程
  6. [fuzz论文阅读] Symbolic execution for software testing: three decades later
  7. 阿里云“无影”云电脑,究竟是不是桌面云?!
  8. 只有那些疯狂到以为自己能够改变世界的人, 才能真正的改变世界
  9. 字节测开秋招面经(一面+二面凉经)
  10. android4以下的音乐播放器,动静(音乐播放器)