查看: 2708|回复: 5

[胡扯] 让我们来制作一个简单的资源占有模拟

[复制链接]
梦石
0
星屑
9687
在线时间
3224 小时
注册时间
2011-3-24
回帖
616

开拓者

发表于 2021-2-5 09:55:12 | 显示全部楼层 |阅读模式

加入我们,或者,欢迎回来。

您需要 登录 才可以下载或查看,没有账号?注册会员

×
本帖最后由 Mr.Jin 于 2021-2-5 09:59 编辑

今天我们来做一个简单有趣的小试验吧!
[pre lang="ruby"]Unit = Struct.new(:asset)[/pre]
首先我们来定义一个Struct,表示一个"单元",它占有一定量的资源
我们可以通过观察不同"单元"之间的互动关系(资源量的传递),得到一些有趣的现象……

那么,现在我们来设计一套"单元"互动的规则
为了观察"单元",我们可能需要把它们画在一个区域里,这样就可以直观地看到结果了
所以为此我们首先需要传入一个尺寸:
[pre lang="ruby"]def game(width, height)[/pre]

然后我们要设定每个"单元"初始拥有的资源量,这个量我们可以认为是随机的,所以也要设定一个上限
[pre lang="ruby"]unit_initval_max = 100[/pre]

现在,我们就可以构建一个"单元"表了,你可以理解成它们就是一个小社会里的所有人。
考虑到完全的随机化可能会导致某些"单元"刚出生就陷入资源极度匮乏的情况,因此我们使其最少也可以拥有半数的初始资源量最大值
[pre lang="ruby"]units = Array.new(width * height) do
        init_asset = rand(unit_initval_max) / 2 + unit_initval_max / 2
        Unit.new(init_asset)
end[/pre]

好!布置完成了,我们现在来设计一轮游戏的规则,首先来搞一个循环吧。
[pre lang="ruby"]loop do[/pre]

我们现在要遍历所有的"单元"去和其它"单元"进行交互,所以来用一个双重循环编写
注意,为了不让id优先的"单元"获得先天优势,我们可以特意用shuffle把这个顺序给随机化
这是外层循环:
[pre lang="ruby"](0...units.size).to_a.shuffle.each do |i|[/pre]
这是内层循环,代表着每个i去向其它的j发起互动:
[pre lang="ruby"](0...units.size).to_a.shuffle.each do |j|[/pre]

接下来编写循环的内容,也就是交互的规则

首先写这样的一个东西避免自己跟自己交互(虽然交互规则大致决定了自己跟自己交互也没什么关系,但至少可以让你的程序跑的快一点点点点)
[pre lang="ruby"]next if i == j[/pre]

我们设定一个交互值,使得i"单元"的资源转移给j"单元",这个转移也是有限度的,不能超过i"单元"已有的资源量
(另外在i已经耗尽所有资源的情况之下,就不必再继续和其它的"单元"进行互动了,因此可以用break提前结束内层循环来让你的程序跑的快一点)
[pre lang="ruby"]interact = [units.asset, rand(unit_initval_max)].min
units.asset -= interact
units[j].asset += interact
break if units.asset <= 0[/pre]

好,简单的规则完成了,我们来把这一切呈现出来,回到我们的loop循环之外去写几个熟悉的RGSS对象吧
[pre lang="ruby"]sprite = Sprite.new
canvas = sprite.bitmap = Bitmap.new(width, height)
sprite.zoom_x = sprite.zoom_y = 16[/pre]
搞出一个精灵,上面挂一个Bitmap作为我们的画布,画布的长和宽自然就是我们传入的长和宽了
当然我们做的实验可能会把长和宽做得很小,因此请用zoom把显示结果放大一些,我这里是16x

然后,我们需要在loop循环内,双层循环之后(也就是游戏逻辑处理完毕)的部分,写上我们呈现结果的部分:
先清空画布:
[pre lang="ruby"]canvas.clear[/pre]

为了观察每个"单元"的资源占有情况,我们可以把代表"单元"的点绘制成红色的,越亮的点越富有,越暗的点越贫穷
这个亮度的计算,自然是以 [资源占有量 / 资源占有的理论总量(也就是所有单元的初始财富之和) * 100%] 来计算的,但是考虑到这样的话可能大多数的"单元"都会显示不清,
因此我们把这个总量乘以10%(当然你想更少或更多都可以)
[pre lang="ruby"]unit_display_max = width * height * unit_initval_max * 0.1[/pre]

把每个"单元"画到画布上的对应位置去:
[pre lang="ruby"](0...units.size).each do |i|
        c = units.asset / unit_display_max
        canvas.set_pixel i % width, i / height, Color.new(c * 255, 0, 0)
end[/pre]

最后更新画面显示:
[pre lang="ruby"]Graphics.update[/pre]

好!现在来到def外面,我们来跑一下这个模拟:
(为了节省性能,开个8x8的就可以了)
[pre lang="ruby"]game(8, 8)[/pre]

我们可以看到,这些点的闪烁非常地频繁,呈现一种比较混乱的状态:
sim1.gif

现在,我们来更改一下两个"单元"之间交互的规则:

我们不再保护i"单元"了,就算使其资源量变为负值(是负债吗?),也可以让它继续参与和其它"单元"的交互当中:
[pre lang="ruby"]interact = rand(unit_initval_max)
units.asset -= interact
units[j].asset += interact[/pre]

结果会如何呢?

我们可以看到,这次的结果呈现出了完全不一样的局面:有一些点似乎变成了"常亮"的!只有其它的一些点处于类似于上图的闪烁状态。
sim2.gif

考虑到我们曾经在计算unit_display_max来观测显示结果时,为它乘以了10%,可能会使得一些超出该资源值的"单元"显示地过于亮,而没有办法显示比较"富有"的"单元"之间的差距
现在我们把这个10%去掉,让它以100%显示:
[pre lang="ruby"]unit_display_max = width * height * unit_initval_max * 1.0[/pre]

可以看到,情况变得类似允许"负债"之前那样了,不过你还是可以很容易分辨出来一些"常亮"的点。
sim3.gif

实际上,我们可以把亮度的显示曲线用pow函数操作一下,你可以更清楚地看到那些"常亮"的点。
sim3bb.gif

好啦,胡扯就到这里,简单粗糙的代码放上:
试验代码全部代码[pre lang="ruby"]module LanzaSim
  # 允许负债的设定
  ALLOW_DEBT = false
  # 允许显示细节的设定,打开这个开关可以更好看到
  # 比较贫穷的单元的状况
  ALLOW_DISPLAY_DETAIL = false
  # 允许显示pow曲线的设定,打开这个开关可以更好看到
  # 比较富有的单元的状况
  ALLOW_DISPLAY_POW = false
  
  Unit = Struct.new(:asset)
  
  class << self
    def game(width, height)
      unit_initval_max = 100
      unit_display_max = width * height * unit_initval_max * (ALLOW_DISPLAY_DETAIL ? 0.1 : 1.0)
      units = Array.new(width * height) do
        init_asset = rand(unit_initval_max) / 2 + unit_initval_max / 2
        Unit.new(init_asset)
      end
      sprite = Sprite.new
      sprite.zoom_x = sprite.zoom_y = 16
      canvas = sprite.bitmap = Bitmap.new(width, height)
      
      processor = ALLOW_DEBT ? Proc.new { |i, j|
        interact = rand(unit_initval_max)
        units.asset -= interact
        units[j].asset += interact
        false
      } : Proc.new { |i, j|
        interact = [units.asset, rand(unit_initval_max)].min
        units.asset -= interact
        units[j].asset += interact
        units.asset <= 0
      }
      
      loop do
        (0...units.size).to_a.shuffle.each do |i|
          (0...units.size).to_a.shuffle.each do |j|
            next if i == j
            break if processor.call i, j
          end
        end
        canvas.clear
        (0...units.size).each do |i|
            c = units.asset / unit_display_max
            next if c <= 0.0
            c = c ** 2.0 if ALLOW_DISPLAY_POW
            canvas.set_pixel i % width, i / height, Color.new(c * 255, 0, 0)
        end
        Graphics.update
      end
    end
  end
end

LanzaSim.game(8, 8)
[/pre]

sim3b.gif

评分

参与人数 1赞 +1 收起 理由
百万HP + 1 精品文章

查看全部评分

>>→Lanza Games 2020←<<
Lanza Schneider
浪子心,孤星梦永远流浪……
~不会放弃,我的精力永远充沛~
>>>>>Lanza Adventure<<<<<
>>>>>Lanza的新年派对!<<<<<
>>>>>Lanza的口袋心脏病!<<<<<

老鹰

梦石
40
星屑
37812
在线时间
7091 小时
注册时间
2012-5-26
回帖
3297

极短24评委极短23参与极短22参与极短21评委老司机慢点开短篇十吟唱者组别冠军开拓者剧作品鉴家

发表于 2021-2-5 10:56:30 | 显示全部楼层
这是要做甚么.jpg
回复

使用道具 举报

梦石
0
星屑
35248
在线时间
4171 小时
注册时间
2007-12-15
回帖
9489
发表于 2021-2-5 11:07:28 | 显示全部楼层
楼主的意思是,不进行宏观调控,资本总会集中到少数点手中?

点评

感觉是大型计算机,会去拿去运行一些更复杂的模资源分配拟实验以供人参考吧XD  发表于 2021-2-5 11:29
我倒没有特意表达这个这个意思,主要看每个人怎么想;就像如果有人喜欢一个很亮的点,那么这种调控也会阻碍亮点的出现,就会变成另一个问题 :-)  发表于 2021-2-5 11:11
回复

使用道具 举报

梦石
0
星屑
8026
在线时间
1051 小时
注册时间
2012-4-3
回帖
1270

开拓者

发表于 2021-2-5 15:33:16 来自手机 | 显示全部楼层
是否也在暗示着,随机化不能单纯地依赖rand本身。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册会员

本版积分规则

Powered by Discuz! X5.0 © 2001-2026 Discuz! Team.

在本版发帖返回顶部