记得小时候玩过一个手机上的游戏,让我感触挺深的,游戏名字叫做叫“信任的进化”。
信任的进化
这个游戏就是将一群小人装进一个沙箱里面,让他么相互博弈,角逐胜负,观察具有神秘品质的人能够获得最终胜利
昨晚在B站偶然刷到一个关于遗传算法的视频,手痒痒,所以也做一个信任的进化算法吧!
先把遗传算法的框图放在这里
讲故事嘛,肯定要先说好游戏规矩呀
场景:
有一个机器,上面显示一个数值(a = 2),两人(小A,小B)选择独吞或者平分。
若双方都选择独吞的话,则同时失去{b = 3}分;
若一方选择平分,另一方选择独吞,则分全部归选择独吞方,平分方不失分;
若双方均选择平分,则分数平均分于双方;
初始值为10,输光的人出局。
10人逐次比较9!次为一轮,无人因输光分数而淘汰则保底每轮淘汰分数最低的一人
探究最后剩下的是谁
然后就是这几种人
1.憨憨:总是选择平分
2.复读机:选择上次对手选择,不针对人,默认为平分
3.复读机:选择上次对手选择,不针对人,默认为独吞
4.不稳定者:随机选择平分和独吞
5.复仇者:骗我一次永远不合作,不针对人,默认平分
6.聪明蛋:总是选择独吞
想要直接看结果的直接拉到最下面吧,不知道是哪里的问题,结果是挺令人唏嘘的
前言
环境就是python 软件是pycharm
成品 是这样的
好了,下一步就是搭建沙盒
main.py是这样子的
#函数
import fun,choose,papapa
#库
import random
import numpy as np
#初始值
year = 10 #进化次数
getp = 2 #每轮平分分数
losep = 3 #每轮惩罚分数
sheyv = 2 #剩余几分之一的人口
tubian = 5 #突变机会
hanpi = 100 #憨憨:总是选择平分
fuduji = 100 #复读机:选择上次对手选择,不针对人,默认为平分
fuduji_ = 100 #复读机:选择上次对手选择,不针对人,默认为独吞
shenjingbing = 100 #不稳定者:随机选择平分和独吞
matherfuker = 100 #复仇者:骗我一次永远不合作,不针对人,默认平分
sb = 100 #聪明蛋:总是选择独吞
families = hanpi+fuduji_+fuduji+shenjingbing+matherfuker+sb #种群个体数
families_shuxing = 8 #个体属性数(个体编号,是否存活,个体分数,是否随机,默认选择,是否变通,变通行为模式,上轮对手选择)
no_ = 0 #个体序号
families_ = families #剩余种群个体数
#创建一个种群
par = np.ones((families,families_shuxing),dtype=np.int64)
no_ -= 1
for i in range(hanpi):
no_ +=1
i = no_
par[i] = i,1,10,0,1,0,0,0
pass
for i in range(fuduji):
no_ +=1
i = no_
par[i] = i,1,10,0,1,1,0,1
pass
for i in range(fuduji_):
no_ +=1
i = no_
par[i] = i,1,10,0,0,1,0,0
pass
for i in range(shenjingbing):
no_ +=1
i = no_
par[i] = i,1,10,1,0,0,0,0
pass
for i in range(matherfuker):
no_ +=1
i = no_
par[i] = i,1,10,0,1,1,1,0
pass
for i in range(fuduji):
no_ +=1
i = no_
par[i] = i,1,10,0,0,0,0,0
pass
#主循环
for i in range(year):
families_ = families #剩余种群个体数
list0 = list(range(families))
while families_> int(families/sheyv+1):
families_ = 0
for i in range(families-1): # 存活存货人数
if par[i, 1] == 1:
families_ += 1
pass
pass
if families_ % 2 == 1: # 存活人数求偶
families_ -= 1
pass
print(families_)
list1 = list0[0:int(families_ / 2)] # pk顺序
list2 = list0[int(families_ / 2 ): int(families_)]
random.shuffle(list1)
random.shuffle(list2)
minp,minn = 1000000,0
for i in range(int(families_/2)):
a = list2[i]
b = list1[i]
x1,x2,x3,x4,x5,x6,x7,x8 = par[a]
x = choose.whatido(x1,x2,x3,x4,x5,x6,x7,x8 )
y1,y2,y3,y4,y5,y6,y7,y8 = par[b]
y = choose.whatido(y1,y2,y3,y4,y5,y6,y7,y8)
x3,y3 = fun.pk(x3,y3,x,y, getp, losep)
#比较后的数据处理
x8 = y
y8 = x
par[a] = x1,x2,x3,x4,x5,x6,x7,x8
par[b] = y1,y2,y3,y4,y5,y6,y7,y8
if x3>y3|x3 == y3:
if y3 < minp:
minp = y3
minn = b
pass
else:
if x3 < minp:
minp = x3
minn = a
pass
pass
pass
par[minn,1] = 0 ##规定最小值死亡
list0.remove(minn)
pass
#计算剩余父辈并求偶(防止出现小数)
parents_num = int(families / sheyv)
if parents_num % 2 ==1:
parents_num -=1
pass
par_ = par[np.lexsort(-par.T[:2,:])]##排序,将已经死亡的人堆在下面
par_ = par_[:int(families / sheyv),:]##切割表格,将死亡的人排除
for i in range(int(families / sheyv)):##这个是一个将父辈积攒的分数归10的一个功能,为的是给子辈一个较为公平的竞争平台
par_[i,2] = 10 ##父辈分数全部置10
pass
##切割表格并进行“杂交”同时也有一定的变异风险
list3 = list(range(parents_num))
list4 = list3[:int(parents_num/2)]
list5 = list3[int(parents_num/2):]
random.shuffle(list4)
random.shuffle(list5)
for i in range(int(parents_num/2)):##产生子代并并列到父辈之后
p = list4[i]
q = list5[i]
x1, x2, x3, x4, x5, x6, x7, x8 = par[p]
y1, y2, y3, y4, y5, y6, y7, y8 = par[q]
s = random.randint(0,4)
d = random.randint(0, 4)
x4, x5, x6, x7, x8,y4, y5, y6, y7, y8 = papapa.yichuan(x4, x5, x6, x7, x8,y4, y5, y6, y7, y8,tubian,s,d)
par_1 = np.array([[no_+1, 1, 10, x4, x5, x6, x7, x8],[no_+2, 1, 10, y4, y5, y6, y7, y8]])
no_ +=2
par_ = np.concatenate((par_,par_1))
pass
par = par_##传递表格
print(par)
np.savetxt("ans.txt",par,fmt="%d",delimiter="------")##保存结果,写到文件里面
# for i in range(60):
# x1,x2,x3,x4,x5,x6,x7,x8 = par[i]
# x = choose.whatido(x1,x2,x3,x4,x5,x6,x7,x8 )
# print(x)
# print(par)
# print(families)
# for i in range(1000):
# one,two = fun.pk(one,two,random.randint(0,1),random.randint(0,1),2,3)
# print(one,two)
python说实话在大学也就选修了半个学期,都是一边百度一边用的,大佬们看出错来直接说,孩子一定改
然后下面就是调用的几个函数了
fun.py ——相当于那个机器,判断两个人平分分数还是让一个崽独吞
def pk(a,b,x1,x2,y,z): #a的分数,b的分数,a的选择,b的选择,决策级的分数,惩罚系数
if x1 == x2 :
if x1 == 0:
a = a + y / 2
b = b + y / 2
pass
else:
a = a-z
b = b-z
pass
pass
else:
if x1==0:
b = b + y
pass
else:
a =a + y
pass
pass
return int(a),int(b)
choose.py——这几种人的行为模式,选择独吞还是平分
import random
def whatido(no1,alive,point,a,b,c,d,e): #序号,是否存活,分数,a是否随机,b默认选择,c是否变通,d变通行为模式,e上轮对手选择
ans = 0
if a == 1:
ans = random.randint(0,1)
pass
else:
if c == 0:
ans = b
pass
else:
if d == 0:
ans = e
pass
else:
ans = b
pass
pass
pass
pass
return int(ans)
papapa.py ——交叉遗传和变异
import random
def yichuan(x1,x2,x3,x4,x5,y1,y2,y3,y4,y5,z,s,d):
list1 = [x1,x2,x3,x4,x5]
list2 = [y1,y2,y3,y4,y5]
zan = list2[s]
list2[s] = list1[s]
list1[s] = zan
zan = list2[d]
list2[d] = list1[d]
list1[d] = zan
if random.randint(0,10) < z:
list1[random.randint(0,4)] = random.randint(0,1)
pass
return x1,x2,x3,x4,x5,y1,y2,y3,y4,y5
结果
这是没有进化过的结果
这是进化10次的结果
这是进化100次的结果
哎,数据放不上去,我就直接说结论吧。
进化的次数越多。“聪明蛋”(选择独吞的人)所占的比例就越多,而其他人的淘汰的几率就则相对来说很大,所以聪明蛋的有更多的机会留下后代;而且如果在每轮进化的时候不将父辈积攒的分数归10,那么”聪明蛋“们积累的分数将成为天文数字,而且长久地存在下去~~(果然还是自私的人活得长久呀)~~
还有一个现象就是随机选择的个体在很早的时候就全部被淘汰了,到最后一个随机选择的也没有了。
不知道将惩罚系数拉大一点结果会不会有变化…