LOL雲頂之弈人工智障助手
概述
本人云頂新手,好多年不玩LOL了,被朋友安利雲頂之弈,玩了兩天覺得有點意思。但是這個遊戲陣容可搭配太多了,如果不是天天研究這個遊戲的,很難喫雞。所以我就心血來潮想寫個陣容助手(python),給定幾個你想玩的英雄,基於遺傳算法向玩家推薦陣容。目前適配9.19版本,不過後面有新陣容出現的話,改起來也方便。增加鏟子功能,不過只能增加一個(增加兩個的話計算量大,不夠實時性)
爬取相關網站內容獲取英雄信息
這一步是可以自己輸入的,但是作爲一個倔強的程序員,顯然不能做這種事(手動狗頭)
一開始選的是lol官網…搞半天都搞不出來(技術不夠,淚目)
後來發現還是多玩好爬一點
結果如下
另外還保存了英雄的暱稱與其對應的id,方便輸入(有時候真想不起來英雄的真名啊)
陣容搭配與得分
建立一個列表,記錄各種陣容搭配,需要人口數目,記錄鏟子能增加的羈絆
計算英雄陣容與所需金幣總數
def teamtype(hero_ids, heros_info):
'''
查看陣容,金幣
'''
team = {}
gold = 0
for hero_id in hero_ids:
gold += heros_info['gold'][hero_id]
for job in heros_info['info'][hero_id]:
if job in team:
team[job] += 1
else:
team[job] = 1
return team, gold
計算得分時候,不考慮羈絆效果不平衡的情況(我也玩得少…不大瞭解)
另外,默認組成人口越多,羈絆效果增加得越多(採用平方得分函數)
def calculateTeamScore(team, show= 0, shovel= False):
'''
計算隊伍得分(鏟子)
羈絆得分規則:按達成羈絆人數得分,不考慮羈絆效果不平衡
'''
max_score = 0
if shovel:
#計算鏟子
change = 'null'
team_out = {}
for j in shovel_add:
#如果隊伍裏沒有相關職業,跳過(鏟子沒有單獨羈絆)
if j not in team.keys():
continue
team_copy = copy.deepcopy(team)
team_copy[j] +=1
score = calc(team= team_copy, show= 0)
change = change if score <= max_score else j
team_out = team_out if score <= max_score else copy.deepcopy(team_copy)
max_score = max_score if score <= max_score else score
calc(team= team_out, show= show)
return max_score, change
else:
max_score = calc(team= team, show= show)
return max_score, None
遺傳算法設計
編碼的話,就是用的實數編碼
得分函數選擇是上面的陣容得分+所需金幣數(越貴的英雄越強)
選擇策略是得分最高的個體直接複製到下一代,得分最低的9個個體直接全部重抽
上代碼:
def GA(team_pnum, selected_ids, heros_info, heros_info_short,gens = 100, sample = 50, alpha = 0.5, shovel= False):
'''
team_pnum:你想組成多少人隊伍
selected_ids:列表,已經選定哪些英雄
heros_info:英雄信息
heros_info_short:英雄名稱縮寫信息
gens:最大繁殖多少代
sample:每代繁衍個體數
alpha:金錢影響程度(值越大,越偏向便宜的英雄)
'''
selected_ids = getHeroid(selected_ids,heros_info_short= heros_info_short)
hero_info_cp = copy.deepcopy(heros_info)
k = len(selected_ids)
n = team_pnum - k
hero_couldchose = hero_info_cp['hero_id']
for idxs in selected_ids:
hero_couldchose.pop(hero_couldchose.index(idxs))
#生成第一代
scores = {
'chosed_ids':[],
'score':[]
}
for i in range(sample):
hero_thisGenCouldChose = copy.deepcopy(hero_couldchose)
random.shuffle(hero_thisGenCouldChose)
teamChoesd = selected_ids + hero_thisGenCouldChose[:n]
team, gold = teamtype(teamChoesd, hero_info_cp)
score,change = calculateTeamScore(team,shovel= shovel)
# print('<================================>')
score = score * 10 - gold * alpha if score > 0 else 0
scores['chosed_ids'].append(teamChoesd)
scores['score'].append(score)
#開始繁衍
maxscores = []
for gen in range(gens):
scores_thisgen = {
'chosed_ids':[],
'score':[]
}
#最優的個體直接保存
score_max_idx = scores['score'].index(max(scores['score']))
scores_thisgen['chosed_ids'].append(scores['chosed_ids'][score_max_idx])
scores_thisgen['score'].append(scores['score'][score_max_idx])
#最差個體的直接重置掉(重複9次)
for i in range(9):
#重排、重選序號
random.shuffle(hero_thisGenCouldChose)
teamChoesd= selected_ids + hero_thisGenCouldChose[:n]
#重新賦值
score_min_idx = scores['score'].index(min(scores['score']))
scores['chosed_ids'][score_min_idx] = teamChoesd
scores_thisgen['chosed_ids'].append(teamChoesd)
#計算得分
team, gold = teamtype(teamChoesd, hero_info_cp)
score,change = calculateTeamScore(team, shovel= shovel)
score = score * 10 - gold * alpha if score > 0 else 0
scores['score'][score_min_idx] = score
scores_thisgen['score'].append(score)
#計算累積概率
p = [0]
totalScores = sum(scores['score'])
for i in range(2,sample):
p.append(p[-1] + scores['score'][i]/totalScores)
#根據輪盤賭法生成新一代個體
for i in range(sample):
#有莫名bug找不到雙親,所以先賦值,如果後面找到了會被覆蓋
Dad = scores['chosed_ids'][0]
Mom = scores['chosed_ids'][-1]
#選父體
rnd = random.random()
for theone in range(len(p)):
if p[theone] > rnd:
Dad = scores['chosed_ids'][theone - 1]
break
else:
continue
#選母體
rnd = random.random()
for theone in range(len(p)):
if p[theone] > rnd:
Mom = scores['chosed_ids'][theone - 1]
break
else:
continue
#求並集
dadmon = list(set(Dad[k:]) | set(Mom[k:]))
random.shuffle(dadmon)
baby = selected_ids + dadmon[:n]
#求得分
team, gold = teamtype(baby, hero_info_cp)
score,change = calculateTeamScore(team, shovel= shovel)
score = score * 10 - gold * alpha if score > 0 else 0
scores_thisgen['chosed_ids'].append(baby)
scores_thisgen['score'].append(score)
maxscores.append(max(scores_thisgen['score']))
#保存這代信息
scores = copy.deepcopy(scores_thisgen)
#取出最佳個體
besTeam = scores['chosed_ids'][scores['score'].index(max(scores['score']))]
return besTeam, maxscores
運行結果
效果還不錯,大概幾秒鐘就能運行出結果,不影響遊戲進度
同時爲不熟悉python的小夥伴做了個雙擊直接運行版本
雙擊,cmd里根據提示輸入參數即可
(至少需要安裝pandas庫,命令:pip install pandas)