游戏开发论坛

 找回密码
 立即注册
搜索
查看: 8793|回复: 21

[求助] 关于多重循环数值的产出估算问题

[复制链接]

1

主题

9

帖子

67

积分

注册会员

Rank: 2

积分
67
发表于 2013-11-21 10:47:14 | 显示全部楼层 |阅读模式
本帖最后由 swd153 于 2013-11-21 11:09 编辑

设定:
技能:共10种技能,每种技能都有相同的经验成长曲线;假定每一级技能升到下一级所需要经验值为:500*当前技能等级,每个技能等级共100级;
体力值:每分钟自动回复1点,上限200点,初始满体力200,每次对任何一个技能的任何一次操作扣除5点体力,获得100点技能经验;
其他:初始默认掌握所有1级技能,体力值可用于对任何一个技能的操作,升级时自动补满体力值

问:如何估算每天大约能获得多少点体力值,多少点技能经验,望各位大神给小的答疑解惑,做好是能有详细的分析过程。


98

主题

784

帖子

4495

积分

版主

Rank: 7Rank: 7Rank: 7

积分
4495
发表于 2013-11-21 11:22:06 | 显示全部楼层
等待编译到手机上的时间(5分钟)给你算了下第一天的结果,假如我每次都升级最低等级的技能,那么第一天:
总获得体力:32090
当前体力:5/200
技能等级状况:
[技能0] 等级:26 经验:100/5200
[技能1] 等级:26 经验:100/5200
[技能2] 等级:26 经验:100/5200
[技能3] 等级:26 经验:100/5200
[技能4] 等级:26 经验:100/5200
[技能5] 等级:26 经验:100/5200
[技能6] 等级:26 经验:100/5200
[技能7] 等级:26 经验:100/5200
[技能8] 等级:25 经验:4800/5000
[技能9] 等级:25 经验:100/5000

思路Delphi版
unit Unit1;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;

Const
SkillCount = 10;
CostStaminaPerTime = 5; //干1次-5体力
RestoreStaminaPerMin = 1; //每分钟恢复1

type
  TSkill = record
    lv:Integer;   //当前技能等级
    expongInt;  //当前技能经验
    need:LongInt; //升级所需经验
  end;

  TForm1 = class(TForm)
    Button1: TButton;
    Memo1: TMemo;
    procedure FormCreate(Sender: TObject);
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
    Stamina:Integer;  //当前体力
    StaminaMax:Integer; //最大体力
    Skill:Array[0..SkillCount-1]of TSkill; //10个技能
    CurMin:Integer; //当前分钟
    StaminaGain:LongInt;  //获得的总体力

    function GetMinLvSkillIndex:Integer;  //获得最低等级武功的下标
    procedure InitGuy;  //初始化一个新角色
    procedure DoSomeThing;  //据说这叫动作
    procedure TextToList; //打出来
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

function GetNeedByLv(lv:Integer):Integer;
begin
result:=lv*200; //升级需要经验
end;

procedure TForm1.TextToList;
var
i:integer;
begin
memo1.Lines.Clear;
memo1.Lines.Add('总获得体力:'+IntToStr(StaminaGain));
memo1.Lines.Add('当前体力:'+IntToStr(Stamina)+'/'+IntToStr(StaminaMax));
memo1.Lines.Add('技能等级状况:');
for i:=0 to SkillCount-1 do
  begin
  memo1.Lines.Add('[技能'+IntToStr(i)+'] 等级:'+IntToStr(Skill[i].lv)+' 经验:'+IntToStr(Skill[i].exp)+'/'+IntToStr(Skill[i].need));
  end;
end;

function TForm1.GetMinLvSkillIndex:Integer;
var
i,minLv,curIndex:Integer;
begin
minLv:=-1;
result:=0;
for i := 0 to SkillCount-1 do
  if (minLv<0) or (Skill[i].lv < minLv) then
    begin
    minLv:= Skill[i].lv;
    result:=i;
    end;
end;

procedure TForm1.Button1Click(Sender: TObject);
const
CalculateTime = 1440; //1天1440分钟
var
getStamina:Integer;
begin
while CalculateTime > CurMin do
  begin
  //体力足够就狂点最低的技能去升级
  while Stamina>=CostStaminaPerTime do
    begin
    DoSomeThing;
    end;
  //不足就待机
  CurMin:=CurMin+1;
  if (Stamina+RestoreStaminaPerMin>StaminaMax) then
    begin
    //恢复后体力超上限
    getStamina:=StaminaMax-Stamina;
    Stamina:=StaminaMax;
    end else begin
    //正常恢复
     Stamina:=Stamina+RestoreStaminaPerMin;
     getStamina:= RestoreStaminaPerMin;
    end;
  StaminaGain:=StaminaGain+getStamina;
  end;
TextToList;
CurMin:=0;  //如果你还想算上第二天的再点我
end;

procedure TForm1.DoSomeThing;
var
addExpToSkillIndex:Integer;
begin
if Stamina >= CostStaminaPerTime then
  begin
  Stamina:=Stamina-CostStaminaPerTime;
  addExpToSkillIndex:=  GetMinLvSkillIndex;
  Skill[addExpToSkillIndex].exp := Skill[addExpToSkillIndex].exp + 100; //说好的1次100。
  if Skill[addExpToSkillIndex].exp > Skill[addExpToSkillIndex].need then
    begin
    //升级
    StaminaGain:=StaminaGain+StaminaMax-Stamina;  //获得体力
    Stamina:=StaminaMax;  //体力满
    Skill[addExpToSkillIndex].lv := Skill[addExpToSkillIndex].lv+1; //升级
    Skill[addExpToSkillIndex].exp := Skill[addExpToSkillIndex].exp - Skill[addExpToSkillIndex].need; //当前经验下降。
    Skill[addExpToSkillIndex].need := GetNeedByLv(Skill[addExpToSkillIndex].lv);  //重算需要经验。
    end;
  end;
end;

procedure TForm1.InitGuy;
var
i:Integer;
begin
Stamina:=200;
StaminaMax:=200;
for i := 0 to SkillCount-1 do
  begin
  Skill[i].lv := 1;
  Skill[i].exp := 0;
  Skill[i].need := GetNeedByLv(Skill[i].lv);
  end;
CurMin:=0;
StaminaGain:=0;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
InitGuy;
end;

end.

21

主题

3926

帖子

5142

积分

论坛元老

索尼已经断气了.jpg

Rank: 8Rank: 8

积分
5142
发表于 2013-11-21 13:00:51 | 显示全部楼层
随便拉张表算一下就好

楼上虎炸天

0

主题

185

帖子

728

积分

高级会员

Rank: 4

积分
728
发表于 2013-11-21 15:20:41 | 显示全部楼层
先问一句:“升级时自动补满体力值”指的是技能升级,还是人物升级?
这点对计算有影响。

在这个设定中,还缺少对于玩家玩游戏时间和习惯的期望假设。即200体力上限造成的体力溢出的体力获取损失。

如果第一问的回答是人物升级补充满体力。那么,这整个模型的计算就几乎完全取决于对玩家玩游戏时间和习惯的期望假设:假设确定了之后,就是很简单的计算。

如果第一问的回答是技能升级补充满体力。那么,操作策略对于体力的获取会产生很大的影响。我们因此就需要找到一个最佳方案,然后再根据该方案计算——实际上也就是计算两个值:一、时间积累的体力获取,与上面类似,这取决于对玩家玩游戏时间和习惯的期望假设;二、技能升级额外获得的体力值,这个值实际就是10*99-1=989次升级(最后一个技能升级补满体力对我们无意义,因此此处减去该次升级)能获取的最大值减去体力溢出。而所谓的最佳方案,则是试图尽量减少体力溢出导致的损失。当这两个值都计算而得后,我们就获得了体力的总获取值,要求每天获取,只需除以天数就行了。

下面,是对于最佳方案的分析:
①首先假设操作不需要消耗时间,即忽视时间积累的体力造成的浪费,简化模型方便计算。
②不可避免的,在技能等级比较低的时候,升级时仍会有体力剩余,从而造成浪费。
③为了减少浪费,我们需要尽量获得更大的消耗体力的方式。
④8级技能的消耗恰好是200体力,升级时不会体力剩余从而造成浪费。

因此,最佳方案的如下:
①用初始的200体力中的195体力将9个技能点到400经验,1个技能点到300经验。然后从9个技能中选择一个,升级;
②将该2级技能点到900经验,并将①中那个例外技能点到400经验。此时,不可避免的面临体力浪费。
分析两种选择的区别:将2级技能升到3级,我们能获得一个需要1500经验升级的3级技能,即能消耗掉75点体力;将1级技能升到2级,我们能获得一个需要1000经验升级的2级技能,即能消耗掉50点体力。
因此,我们选择将2级技能升到3级。
③之后的选择也是如此,直到我们将该技能升到8级。此时,恰好不造成浪费。
④我们继续将该技能升到9级。此时,该技能就能帮助消耗其他技能升级时补满的体力值了。
因此,第一个技能升3级-升8级的体力浪费,就是这个最佳方案的技能升级的体力浪费。
计算这个值:技能升级的体力浪费:(8-3+1)*200-(2+3+…+7)*500/100*5-5=520。
因此,技能升级能获得体力为:(99*10-1)*200-520=197280。

将这个值与时间获取体力模型的体力获取相加,再除以天数,即为每天获取的体力值。

19

主题

197

帖子

1171

积分

金牌会员

实干兴邦,空谈误国

Rank: 6Rank: 6

积分
1171
发表于 2013-11-21 15:51:57 | 显示全部楼层
个人比较倾向于bineye的算法。

因为在猴与花果山的算法中:

function TForm1.GetMinLvSkillIndex:Integer;
var
i,minLv,curIndex:Integer;
begin
minLv:=-1;
result:=0;
for i := 0 to SkillCount-1 do
  if (minLv<0) or (Skill[i].lv < minLv) then
    begin
    minLv:= Skill[i].lv;
    result:=i;
    end;
end;

这个是按照技能列表顺序选取第一个最低等级的技能。

在程序上这个算法没有什么不妥。

但是从用户来看,是秉着“最不浪费”原则,将体力进行最大化运用的,所以我倾向于bineye的算法。

98

主题

784

帖子

4495

积分

版主

Rank: 7Rank: 7Rank: 7

积分
4495
发表于 2013-11-21 16:52:01 | 显示全部楼层
smallcorpse 发表于 2013-11-21 15:51
个人比较倾向于bineye的算法。

因为在猴与花果山的算法中:

那你就带入这个最不浪费原则,去改写这个函数就行了,返回出当前要点的最合理的技能的下标,其他流程完全不需要改进。
不过说到这里,你会发现一个很有趣的问题——如果策划只有想法而不能归纳,那其实程序是无法工作的,这就是很多团队中策划和程序之间合作的鸿沟。
你可以试着按他说的思路coding一个呗,这个工程你直接黏贴,只需要在TForm1上托一个Tbutton和一个TListbox就能工作了,我故意没换控件名字。但是看着他写的“最佳方案”如下,我觉得我是没法动手coding的,因为特殊处理的东西太多了。这种函数中,你必须认为当前技能的等级是a,经验是b,a和b分别等于多少都是不定的,这叫做函数,而他的思路里面全都是定的数字。

点评

是TMemo,我改了一下自己忘了,毕竟是临时随手写写的,为了方便复制粘贴。  发表于 2013-11-21 16:57

19

主题

197

帖子

1171

积分

金牌会员

实干兴邦,空谈误国

Rank: 6Rank: 6

积分
1171
发表于 2013-11-21 17:00:59 | 显示全部楼层
猴与花果山 发表于 2013-11-21 16:52
那你就带入这个最不浪费原则,去改写这个函数就行了,返回出当前要点的最合理的技能的下标,其他流程完全 ...

……我觉得光改写这个函数还不行,bineye的算法应该用另一种模式去编写。

第一步是将当前体力折算成的经验减去100。然后将剩下的经验顺序填充到技能里,填充到缺100经验升级就可以填充下一个技能了。(我们称缺100经验的技能为预升级技能)

第二步就是将最后的100经验填充到第一个预升级技能里面。

这样就可以循环第一步和第二步了,一直到体力不足无法支持第二步便进入等待。

98

主题

784

帖子

4495

积分

版主

Rank: 7Rank: 7Rank: 7

积分
4495
发表于 2013-11-21 17:22:06 | 显示全部楼层
smallcorpse 发表于 2013-11-21 17:00
……我觉得光改写这个函数还不行,bineye的算法应该用另一种模式去编写。

第一步是将当前体力折算成的经 ...

你说的这个逻辑,包含了两点:
1,假如我的体力>=每次动作消耗体力x2(保证这是最后第二次或者更多次),那么我就不去加还差100经验的技能,除非已经没有选择了。
2,最后一次工作的体力优先加入还差100的技能内。
那么随之产生的问题就是:
1,当我的体力>=每次动作消耗体力x2的时候,我应该加入到哪个技能?这个技能如何挑选?规则是什么?我们只知道排除掉的,却不知道需要的。
2,最后一次工作的体力了,我该加哪个技能?如果当前没有差100就升级的技能?这个技能如何挑选?
差的就是这两点逻辑了,不需要额外写什么函数,顶多作为一个程序员的话,要把函数重命名一下,但我是策划。

19

主题

197

帖子

1171

积分

金牌会员

实干兴邦,空谈误国

Rank: 6Rank: 6

积分
1171
发表于 2013-11-21 17:40:12 | 显示全部楼层
猴与花果山 发表于 2013-11-21 17:22
你说的这个逻辑,包含了两点:
1,假如我的体力>=每次动作消耗体力x2(保证这是最后第二次或者更多次), ...

感谢指正

1,因为在本题中,所有技能都有相同的成长经验曲线。所以加体力一开始是一个无差别的顺序过程。而第一步的意义在于额外创造一个“预升级技能序列”。这个“预升级技能序列”可以定义为一个先进先出的队列。那么整体来说,我只需要判断这个“预升级技能序列”里是否有技能,就可以进行第二步了。

2,第二步选取的就是“预升级技能序列”中第一的技能,让它“先出”。这样就可以形成一个比较规范的逻辑了。

98

主题

784

帖子

4495

积分

版主

Rank: 7Rank: 7Rank: 7

积分
4495
发表于 2013-11-21 17:58:57 | 显示全部楼层
smallcorpse 发表于 2013-11-21 17:40
感谢指正

1,因为在本题中,所有技能都有相同的成长经验曲线。所以加体力一开始是一个无差别的顺序过程 ...

我大概了解了这个“预升级技能序列”的工作方式,不知道理解得对不对?
1,把差100经验的技能丢进这个序列,用push的方式也没问题。
2,最后1次工作如果“序列”列表长度大于0,则将first()进行加点。

但是还是有一个问题,这个“预升级技能序列”并不能解释,在体力足够干2次或以上的情况下,我去加哪个技能(如果有2个以上距离升级超过100点经验的技能)。眼下十个技能的等级是a1到a10,这10个数字未必都相等,而当前经验b1到b10也未必相等,只是所需经验可以由c1=a1x200到c10=a10x200获得,这种情况下,已知c1到c10没有一个差比b1到b10中对应的只多100(也就是你这个序列现在是空的),我该把这次工作(还剩余x次工作机会,x>1)投入到几号技能?为什么?
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

作品发布|文章投稿|广告合作|关于本站|游戏开发论坛 ( 闽ICP备17032699号-3 )

GMT+8, 2025-8-27 00:47

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表