old_blog 剑圣无敌斩的编程模型

来源:互联网 发布:淘宝图文编辑软件 编辑:程序博客网 时间:2024/04/29 17:29
  想必大家都jugg都是十分了解的,其大招无敌斩更是他享有“河道杀手”的称号。但是随机性攻击也成为jugg不稳定击杀的隐患。下面我们来考虑一个问题,jugg追杀敌方单位,准备开大,这时突然冒出来一坨小兵(很常见的情形)。这时jugg是否应该继续放大呢?或者放大后有多大的概率击杀对手呢?
  显然我们将会通过编程来处理这个问题。在此之前,我想介绍关于面向对象的编程(因为我和我们一些同学正在学习Java以及Android开发,了解面向对象的机制还是很有帮助的)。
  面向过程的程序设计我们为了简洁代码量,以函数的方式进行封装,来实现相同的功能。与面向过程的程序设计不同,面向对象的程序设计是以数据而不是功能为核心,将数据以及这些数据的操作以“类”的形式封装为一个整体,以“类”的对象作为程序的基本元素,通过对象发送消息,进而由对象启动相关的方法完成各种功能。形象的说,“类”就是一个包裹,里面放置着数据和函数(方法)。数据与函数分为动态和静态,动态的数据、函数必须实例化才能访问或者运行,而静态的数据、函数至只与类有关,与对象无关。静态函数类似于面向过程,此时类的作用仅仅是归类、打包。
  下面来讲讲开始提出的例子,如果我们现在是面向过程,那么我们需要写一个函数,它的参数是jugg剩余攻击次数、近程小兵个数、远程小兵个数,经过函数内部的模拟或者计算,可以通过返回值的形式传出概率结果,也可以通过指针、引用参数的方式为形参赋值。但是,如果我们现在是面向对象,我们需要写一个“概率模拟器”或者是“概率计算器”,实例化“模拟器”或“计算器”对象并设置必要参数、运行得到概率结果。大家可以参考我们现实当中的计算器,通过键入数据、点击运行按钮,从而获得相应的结果,当然前提是你必须先买一个计算器,即实例化计算器对象。
  为了解决jugg的无敌斩问题,我们提出几点必要的假设,使之完全成为数学问题:
  1.jugg在无敌斩期间忽略普通攻击;
  2.jugg无敌斩的劈斩对象概率均相等(这一点假设是必要的,其实jugg是随机一个角度在进行角度劈斩,不能保证劈斩每个人的概率相等);
  3.随机数的产生视为真随机数(其实C++模拟随机数、魔兽软件产生的随机数都是伪随机数);
  4.jugg的第一次攻击也是随机的(其实是必中的,我们可以通过将剩余次数、劈斩次数同时减一的方法模拟或计算)
  4.近程兵能够承受3次攻击,远程兵能够承受2次攻击(实验得来的,但是随着小兵的成长承受次数会增加)。

  下面我们编写“概率模拟器”类,保存在文件simulate.h中:

#include<iostream.h>#include<stdlib.h>#include<time.h>class Simulator{private: int anum; int bnum; int leftattack; int *p1,*p2; int times; int cut; int p;public: Simulator(int a,int b,int lefta) {  anum=a;  bnum=b;  leftattack=lefta;  times=1000;  p1=new int[a];  p2=new int[b];  for(int i=0;i<anum;i++)   p1[i]=0;  for(i=0;i<bnum;i++)   p2[i]=0;  p=leftattack;  cut=6; } void setTimes(int t) {  times=t; } void setCut(int c) {  cut=c; } double run() {  int x,count=0;  int n;  for(int i=0;i<times;i++)  {   n=0;   while(p&&n!=cut)   {    x=rand()%(anum+bnum+1);    if(x<anum)    {     if(p1[x]==3)      continue;     else p1[x]++;    }    else if(x<anum+bnum)    {     if(p2[x-anum]==2)      continue;     else p2[x-anum]++;    }    else    {     p--;    }    n++;   }   if(!p) count++;   for(int i=0;i<anum;i++)    p1[i]=0;   for(i=0;i<bnum;i++)    p2[i]=0;   p=leftattack;  }  cout<<"simulate probability=\t"<<(double)count/times*100<<"%"<<endl;  return (double)count/times; }};

  我们规定在构造函数当中传入必要参数(近程小兵个数、远程小兵个数、剩余攻击次数),并可以人为地设置劈斩次数、模拟次数。最后通过run()函数获得模拟成功概率。
  下面我们编写“概率计算器”类,保存在文件calculate.h中:

#include<iostream.h>#include<stdlib.h>#include<time.h>#include<string.h>class Node{public: char *ar; Node *next; int pro; bool success; Node(int c,char *a) {  ar=new char[c];  int l=strlen(a);  strcpy(ar,a);  next=NULL;  pro=1;  success=false; }};class Calculator{private: Node* first; char* temp; int anum; int bnum; int leftattack; int cut; int n; int *array; double getRes() {  double res=0;  for(Node* p=first;p;p=p->next)  {   if(p->success)    res+=1.0/p->pro;  }  return res; } void calSuccess() {  for(Node* p=first;p;p=p->next)  {   int i=0;   for(int j=0;j<(int)strlen(p->ar);j++)    if(p->ar[j]-'0'==anum+bnum) i++;   if(i==leftattack)    p->success=true;  } } void visitLink() {  for(Node* p=first;p;p=p->next)   cout<<p->ar<<"\tpro="<<p->pro<<"\t"<<p->success<<endl; } int calLive(int *p) {  int s=0;  for(int i=0;i<anum+bnum+1;i++)  {   if(i<anum)    {    if(p[i]<3) s++;   }   else if(i<anum+bnum)    {    if(p[i]<2) s++;   }   else    {    if(p[i]<cut) s++;   }  }  return s; } void calProbability() {  int *alive=new int[anum+bnum+1];  for(Node* p=first;p;p=p->next)  {   int s=1;   for(int i=0;i<anum+bnum+1;i++)    alive[i]=0;   for(int j=0;j<(int)strlen(p->ar);j++)   {    s*=calLive(alive);    alive[p->ar[j]-'0']++;   }   p->pro=s;  } } void Insert(int *a,int l) {  char *str=new char[cut];  for(int i=0;i<l;i++)   str[i]=a[i]+'0';  str[i]=0;  if(strcmp(temp,str)!=0)  {   if(n==0)    first=new Node(cut,str);   else   {    Node* q=new Node(cut,str);    q->next=first;    first=q;   }   strcpy(temp,str);  }  else strcpy(temp,str);  n++; } bool pass(int *a,int step) {  int count=0;  for(int i=0;i<step;i++)   if(a[i]==a[step])    count++;  count++;  if(a[step]<anum)  {   if(count==4)    return false;   else return true;  }  else if(a[step]<anum+bnum)   {   if(count==3)    return false;   else return true;  }  else    return true; } void print(int *a,int l) {  for(int i=0;i<l;i++)   cout<<a[i]<<" ";  cout<<endl; } void print(int *a) {  for(int i=0;i<cut;i++)   cout<<a[i]<<" ";  cout<<endl; } void fillArray(int *a,int step) {  int count=0;  for(int j=0;j<step-1;j++)   if(a[j]==anum+bnum) count++;  if(!pass(a,step-1))   return;  if(count==leftattack)  {   Insert(a,step-1);   return;  }  if(step==cut)  {   Insert(a,cut);   return;  }  for(int i=0;i<anum+bnum+1;i++)  {   a[step]=i;   fillArray(a,step+1);  } }public: Calculator(int a,int b,int lefta) {  anum=a;  bnum=b;  leftattack=lefta;  times=1000;  cut=6;  n=0;  temp=new char[cut];  first=NULL; } ~Calculator() {  for(Node *p=first->next;p;p=p->next)  {   delete first;   first=p;  } } void setCut(int c) {  cut=c; } double run() {  array=new int[cut];  fillArray(array,0);  calProbability();  calSuccess();//  visitLink();  double x=getRes();  cout<<"calculate probability=\t"<<x*100<<"%"<<endl;  return x; }};
  我们规定在构造函数当中传入必要参数(近程小兵个数、远程小兵个数、剩余攻击次数),并可以人为地设置劈斩次数。最后通过run()函数获得计算成功概率。程序通过链表的存储方式存储劈斩次序,变量pro存放的是某一种情况概率的倒数值。
  最后,我们通过main()函数进行测试,由于类的封装性,用户不需详知类的工作原理只要会使用就行了。
#include"simulate.h"#include"calculate.h"#include<math.h>void main(){ Simulator sim(3,1,1); Calculator cal(3,1,1); sim.setCut(6); cal.setCut(6); srand((unsigned)time(NULL)); double ps=sim.run(); double pc=cal.run(); cout<<"accuracy of simulating:\t"<<100-fabs(ps-pc)/pc*100<<"%"<<endl; system("pause");}

  这里我们实例化对象并初始化、设置、运行。当然还计算出模拟准确度。
  如果jugg可以劈6下,劈到就死(如程序设置),那么运行结果如下:
simulate probability=   76%
calculate probability=  75.974%
accuracy of simulating: 99.9658%
请按任意键继续. . .
  如果jugg可以劈9下,那么
simulate probability=   90.9%
calculate probability=  91.4825%
accuracy of simulating: 99.3632%
请按任意键继续. . .
  如果只能劈三下。。。。
simulate probability=   45.5%
calculate probability=  49%
accuracy of simulating: 92.8571%
请按任意键继续. . .
  可见,模拟概率与计算概率的吻合度还是很高的,证明程序基本正确。
  jugg的大招模型可以运用到很多相似的地方:
  1.与弹射有关的模型:如lich的大招、WD的弹弹乐
  2.准弹射模型:三国杀陆伯言的技能烧营
  3.很多概率模型:如多次抽签、判定、拼点等
  4.其实jugg的大招概率计算是一个NP问题,经过恰当的算法改造,可以定义公钥密码体制。
  等等。

0 0
原创粉丝点击