人工智能--打飞机游戏
来源:互联网 发布:cf外设淘宝店 编辑:程序博客网 时间:2024/05/17 00:50
代码下载:Here。
很久以前微信流行过一个小游戏:打飞机,这个游戏简单又无聊。在2017年来临之际,我就实现一个超级弱智的人工智能(AI),这货可以躲避从屏幕上方飞来的飞机。本帖只使用纯Python实现,不依赖任何高级库。
本文的AI基于neuro-evolution,首先简单科普一下neuro-evolution。从neuro-evolution这个名字就可以看出它由两部分组成-neuro and evolution,它是使用进化算法(遗传算法是进化算法的一种)提升人工神经网络的机器学习技术,其实就是用进化算法改进并选出最优的神经网络。
使用TPOT自动选择scikit-learn机器学习模型和参数
neuro-evolution
定义一些变量:
import math
import random
神经网络3层, 1个隐藏层; 4个input和1个output
network = [4, [16], 1]
遗传算法相关
population = 50
elitism = 0.2
random_behaviour = 0.1
mutation_rate = 0.5
mutation_range = 2
historic = 0
low_historic = False
score_sort = -1
n_child = 1
定义神经网络:
激活函数
def sigmoid(z):
return 1.0/(1.0+math.exp(-z))
random number
def random_clamped():
return random.random()*2-1
“神经元”
class Neuron():
def init(self):
self.biase = 0
self.weights = []
def init_weights(self, n): self.weights = [] for i in range(n): self.weights.append(random_clamped())def __repr__(self): return 'Neuron weight size:{} biase value:{}'.format(len(self.weights), self.biase)
层
class Layer():
def init(self, index):
self.index = index
self.neurons = []
def init_neurons(self, n_neuron, n_input): self.neurons = [] for i in range(n_neuron): neuron = Neuron() neuron.init_weights(n_input) self.neurons.append(neuron)def __repr__(self): return 'Layer ID:{} Layer neuron size:{}'.format(self.index, len(self.neurons))
神经网络
class NeuroNetwork():
def init(self):
self.layers = []
# input:输入层神经元数 hiddens:隐藏层 output:输出层神经元数def init_neuro_network(self, input, hiddens , output): index = 0 previous_neurons = 0 # input layer = Layer(index) layer.init_neurons(input, previous_neurons) previous_neurons = input self.layers.append(layer) index += 1 # hiddens for i in range(len(hiddens)): layer = Layer(index) layer.init_neurons(hiddens[i], previous_neurons) previous_neurons = hiddens[i] self.layers.append(layer) index += 1 # output layer = Layer(index) layer.init_neurons(output, previous_neurons) self.layers.append(layer)def get_weights(self): data = { 'network':[], 'weights':[] } for layer in self.layers: data['network'].append(len(layer.neurons)) for neuron in layer.neurons: for weight in neuron.weights: data['weights'].append(weight) return datadef set_weights(self, data): previous_neurons = 0 index = 0 index_weights = 0 self.layers = [] for i in data['network']: layer = Layer(index) layer.init_neurons(i, previous_neurons) for j in range(len(layer.neurons)): for k in range(len(layer.neurons[j].weights)): layer.neurons[j].weights[k] = data['weights'][index_weights] index_weights += 1 previous_neurons = i index += 1 self.layers.append(layer)# 输入游戏环境中的一些条件(如敌机位置), 返回要执行的操作def feed_forward(self, inputs): for i in range(len(inputs)): self.layers[0].neurons[i].biase = inputs[i] prev_layer = self.layers[0] for i in range(len(self.layers)): # 第一层没有weights if i == 0: continue for j in range(len(self.layers[i].neurons)): sum = 0 for k in range(len(prev_layer.neurons)): sum += prev_layer.neurons[k].biase * self.layers[i].neurons[j].weights[k] self.layers[i].neurons[j].biase = sigmoid(sum) prev_layer = self.layers[i] out = [] last_layer = self.layers[-1] for i in range(len(last_layer.neurons)): out.append(last_layer.neurons[i].biase) return outdef print_info(self): for layer in self.layers: print(layer)
遗传算法:
“基因组”
class Genome():
def init(self, score, network_weights):
self.score = score
self.network_weights = network_weights
class Generation():
def init(self):
self.genomes = []
def add_genome(self, genome): i = 0 for i in range(len(self.genomes)): if score_sort < 0: if genome.score > self.genomes[i].score: break else: if genome.score < self.genomes[i].score: break self.genomes.insert(i, genome) # 杂交+突变def breed(self, genome1, genome2, n_child): datas = [] for n in range(n_child): data = genome1 for i in range(len(genome2.network_weights['weights'])): if random.random() <= 0.5: data.network_weights['weights'][i] = genome2.network_weights['weights'][i] for i in range(len(data.network_weights['weights'])): if random.random() <= mutation_rate: data.network_weights['weights'][i] += random.random() * mutation_range * 2 - mutation_range datas.append(data) return datas # 生成下一代def generate_next_generation(self): nexts = [] for i in range(round(elitism*population)): if len(nexts) < population: nexts.append(self.genomes[i].network_weights) for i in range(round(random_behaviour*population)): n = self.genomes[0].network_weights for k in range(len(n['weights'])): n['weights'][k] = random_clamped() if len(nexts) < population: nexts.append(n) max_n = 0 while True: for i in range(max_n): childs = self.breed(self.genomes[i], self.genomes[max_n], n_child if n_child > 0 else 1) for c in range(len(childs)): nexts.append(childs[c].network_weights) if len(nexts) >= population: return nexts max_n += 1 if max_n >= len(self.genomes)-1: max_n = 0
NeuroEvolution:
class Generations():
def init(self):
self.generations = []
def first_generation(self): out = [] for i in range(population): nn = NeuroNetwork() nn.init_neuro_network(network[0], network[1], network[2]) out.append(nn.get_weights()) self.generations.append(Generation()) return outdef next_generation(self): if len(self.generations) == 0: return False gen = self.generations[-1].generate_next_generation() self.generations.append(Generation()) return gendef add_genome(self, genome): if len(self.generations) == 0: return False return self.generations[-1].add_genome(genome)
class NeuroEvolution():
def init(self):
self.generations = Generations()
def restart(self): self.generations = Generations()def next_generation(self): networks = [] if len(self.generations.generations) == 0: networks = self.generations.first_generation() else: networks = self.generations.next_generation() nn = [] for i in range(len(networks)): n = NeuroNetwork() n.set_weights(networks[i]) nn.append(n) if low_historic: if len(self.generations.generations) >= 2: genomes = self.generations.generations[len(self.generations.generations) - 2].genomes for i in range(genomes): genomes[i].network = None if historic != -1: if len(self.generations.generations) > historic+1: del self.generations.generations[0:len(self.generations.generations)-(historic+1)] return nndef network_score(self, score, network): self.generations.add_genome(Genome(score, network.get_weights()))
是AI就躲个飞机
import pygame
import sys
from pygame.locals import *
import random
import math
import neuro_evolution
BACKGROUND = (200, 200, 200)
SCREEN_SIZE = (320, 480)
class Plane():
def init(self, plane_image):
self.plane_image = plane_image
self.rect = plane_image.get_rect()
self.width = self.rect[2] self.height = self.rect[3] self.x = SCREEN_SIZE[0]/2 - self.width/2 self.y = SCREEN_SIZE[1] - self.height self.move_x = 0 self.speed = 2 self.alive = Truedef update(self): self.x += self.move_x * self.speeddef draw(self, screen): screen.blit(self.plane_image, (self.x, self.y, self.width, self.height))def is_dead(self, enemes): if self.x < -self.width or self.x + self.width > SCREEN_SIZE[0]+self.width: return True for eneme in enemes: if self.collision(eneme): return True return Falsedef collision(self, eneme): if not (self.x > eneme.x + eneme.width or self.x + self.width < eneme.x or self.y > eneme.y + eneme.height or self.y + self.height < eneme.y): return True else: return Falsedef get_inputs_values(self, enemes, input_size=4): inputs = [] for i in range(input_size): inputs.append(0.0) inputs[0] = (self.x*1.0 / SCREEN_SIZE[0]) index = 1 for eneme in enemes: inputs[index] = eneme.x*1.0 / SCREEN_SIZE[0] index += 1 inputs[index] = eneme.y*1.0 / SCREEN_SIZE[1] index += 1 #if len(enemes) > 0: #distance = math.sqrt(math.pow(enemes[0].x + enemes[0].width/2 - self.x + self.width/2, 2) + math.pow(enemes[0].y + enemes[0].height/2 - self.y + self.height/2, 2)); if len(enemes) > 0 and self.x < enemes[0].x: inputs[index] = -1.0 index += 1 else: inputs[index] = 1.0 return inputs
class Enemy():
def init(self, enemy_image):
self.enemy_image = enemy_image
self.rect = enemy_image.get_rect()
self.width = self.rect[2] self.height = self.rect[3] self.x = random.choice(range(0, int(SCREEN_SIZE[0] - self.width/2), 71)) self.y = 0def update(self): self.y += 6def draw(self, screen): screen.blit(self.enemy_image, (self.x, self.y, self.width, self.height))def is_out(self): return True if self.y >= SCREEN_SIZE[1] else False
class Game():
def init(self):
pygame.init()
self.screen = pygame.display.set_mode(SCREEN_SIZE)
self.clock = pygame.time.Clock()
pygame.display.set_caption(‘是AI就躲个飞机’)
self.ai = neuro_evolution.NeuroEvolution() self.generation = 0 self.max_enemes = 1 # 加载飞机、敌机图片 self.plane_image = pygame.image.load('plane.png').convert_alpha() self.enemy_image = pygame.image.load('enemy.png').convert_alpha()def start(self): self.score = 0 self.planes = [] self.enemes = [] self.gen = self.ai.next_generation() for i in range(len(self.gen)): plane = Plane(self.plane_image) self.planes.append(plane) self.generation += 1 self.alives = len(self.planes)def update(self, screen): for i in range(len(self.planes)): if self.planes[i].alive: inputs = self.planes[i].get_inputs_values(self.enemes) res = self.gen[i].feed_forward(inputs) if res[0] < 0.45: self.planes[i].move_x = -1 elif res[0] > 0.55: self.planes[i].move_x = 1 self.planes[i].update() self.planes[i].draw(screen) if self.planes[i].is_dead(self.enemes) == True: self.planes[i].alive = False self.alives -= 1 self.ai.network_score(self.score, self.gen[i]) if self.is_ai_all_dead(): self.start() self.gen_enemes() for i in range(len(self.enemes)): self.enemes[i].update() self.enemes[i].draw(screen) if self.enemes[i].is_out(): del self.enemes[i] break self.score += 1 print("alive:{}, generation:{}, score:{}".format(self.alives, self.generation, self.score), end='\r')def run(self, FPS=1000): while True: for event in pygame.event.get(): if event.type == QUIT: pygame.quit() sys.exit() self.screen.fill(BACKGROUND) self.update(self.screen) pygame.display.update() self.clock.tick(FPS)def gen_enemes(self): if len(self.enemes) < self.max_enemes: enemy = Enemy(self.enemy_image) self.enemes.append(enemy)def is_ai_all_dead(self): for plane in self.planes: if plane.alive: return False return True
game = Game()
game.start()
game.run()
AI的工作逻辑
假设你是AI,你首先繁殖一个种群(50个个体),开始的个体大都是歪瓜裂枣(上来就被敌机撞)。但是,即使是歪瓜裂枣也有表现好的,在下一代,你会使用这些表现好的再繁殖一个种群,经过代代相传,存活下来的个体会越来越优秀。其实就是仿达尔文进化论,种群->自然选择->优秀个体->杂交、变异->种群->循环n世代。
ai开始时候的表现:
是AI就躲个飞机 - 纯Python实现人工智能图片被拉扁了 sorry
经过几百代之后,ai开始娱乐的躲飞机:
是AI就躲个飞机 - 纯Python实现人工智能
ps.祝大家新年快乐,感觉我又浪费了一年
- 人工智能--打飞机游戏
- C#打飞机游戏
- 【Unity3D 游戏】 打飞机(仿微信打飞机) 源码
- 发布一个打飞机游戏
- 摄像头互动游戏-打飞机
- 开源游戏 “打飞机”
- Python开发打飞机游戏
- Pygame开发打飞机游戏
- 打飞机游戏相关策划
- 汇编写的打飞机游戏
- libgdx 打飞机游戏实现教程
- c++游戏设计五:打飞机
- unity打飞机游戏简单制作
- C/C++ 控制台打飞机游戏
- javascript游戏之打飞机、接礼物
- 练习开发unity3d打飞机游戏
- jQuery打飞机游戏代码下载
- [Unity]2D打飞机游戏
- 变量、窗体、控件用英语命名而不用拼音命名的好处
- swift GPUImage 进行 视频录制 美化 音乐合成等
- 【Keras】DNN神经网络模型
- vijos 弱弱的战壕(树状数组)
- PTA习题 树的同构
- 人工智能--打飞机游戏
- Entity Framework DataSet注入数据分析
- 时区的概念与划分
- 应用层-Ijk-ffmpeg消息实现机制
- 12.9 矩阵变换 2859
- C语言实验——最值
- [R语言爬虫] 豆瓣网,10月图书抓取
- also的位置情况总结(基于材料:“老托福听力93篇”)
- Python学习 第一天任务 (三:Python不止基础学习 继续安装爬虫环境的配置)