从信任的进化到遗传算法

记得小时候玩过一个手机上的游戏,让我感触挺深的,游戏名字叫做叫“信任的进化”。
信任的进化
在这里插入图片描述

这个游戏就是将一群小人装进一个沙箱里面,让他么相互博弈,角逐胜负,观察具有神秘品质的人能够获得最终胜利
昨晚在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



结果

这是没有进化过的结果
1

这是进化10次的结果
10
这是进化100次的结果
在这里插入图片描述
哎,数据放不上去,我就直接说结论吧。
进化的次数越多。“聪明蛋”(选择独吞的人)所占的比例就越多,而其他人的淘汰的几率就则相对来说很大,所以聪明蛋的有更多的机会留下后代;而且如果在每轮进化的时候不将父辈积攒的分数归10,那么”聪明蛋“们积累的分数将成为天文数字,而且长久地存在下去~~(果然还是自私的人活得长久呀)~~
在这里插入图片描述
还有一个现象就是随机选择的个体在很早的时候就全部被淘汰了,到最后一个随机选择的也没有了。
不知道将惩罚系数拉大一点结果会不会有变化…

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值