Python 我不知道';我不能让我的AI玩Tictatcoe。如何提高其性能?
AI是用整洁的python构建的。输入是游戏板上的字段列表(0:Unoccubied,1:player1,2:player2)。AI产生9个输出,最大值(输出)的索引被选为要执行的字段。它针对随机选择田地的机器人进行训练。如果要转到的字段已被占用,则第一个空闲字段将被设置为要转到的字段Python 我不知道';我不能让我的AI玩Tictatcoe。如何提高其性能?,python,pygame,neat,Python,Pygame,Neat,AI是用整洁的python构建的。输入是游戏板上的字段列表(0:Unoccubied,1:player1,2:player2)。AI产生9个输出,最大值(输出)的索引被选为要执行的字段。它针对随机选择田地的机器人进行训练。如果要转到的字段已被占用,则第一个空闲字段将被设置为要转到的字段 import neat import pygame import os import json import random import checkpoint import winsound import tim
import neat
import pygame
import os
import json
import random
import checkpoint
import winsound
import time
import matplotlib.pyplot as plt
pygame.init()
cloud = checkpoint.Checkpointer()
p = None
GEN = 0
screen = None
pygame.display.set_caption("Tic Tac Toe")
o_icon = pygame.image.load("o.png")
x_icon = pygame.image.load("x.png")
class Field:
def __init__(self):
self.field = [0,0,0, 0,0,0, 0,0,0]
self.winner = None
def reset(self):
self.field = [0,0,0, 0,0,0, 0,0,0]
self.winner = None
def display(self):
screen.fill([0,0,0])
self.display_pieces()
self.display_board()
pygame.display.update()
def display_pieces(self):
pos_to_pix = {
0: (0,0),
1: (100,0),
2: (200,0),
3: (0,100),
4: (100,100),
5: (200,100),
6: (0, 200),
7: (100, 200),
8: (200, 200)
}
for pos in range(len(self.field)):
if self.field[pos] == 1:
screen.blit(x_icon, pos_to_pix[pos])
elif self.field[pos] == 2:
screen.blit(o_icon, pos_to_pix[pos])
@staticmethod
def pos_to_field(pos):
x = pos[0]
y = pos[1]
if x < 100:
x = 0
elif x < 200:
x = 1
else:
x = 2
if y < 100:
y = 0
elif y < 200:
y = 1
else:
y = 2
return x+y*3
@staticmethod
def display_board():
pygame.draw.rect(screen, "White", [0,99, 300,2])
pygame.draw.rect(screen, "White", [0,199, 300,2])
pygame.draw.rect(screen, "White", [99,0, 2,300])
pygame.draw.rect(screen, "White", [199,0, 2,300])
def action(self, field_id, player_id):
self.field[field_id] = player_id
def field_is_free(self, field):
if self.field[field] == 0:
return True
return False
def check_winner(self):
for line in range(3):
# check horizontal
if self.field[line*3] == self.field[line*3+1] == self.field[line*3+2] != 0:
self.winner = self.field[line*3]
return True, self.winner
if self.field[line] == self.field[line+3] == self.field[line+6] != 0:
self.winner = self.field[line]
return True, self.winner
if self.field[0] == self.field[4] == self.field[8] != 0:
self.winner = self.field[0]
return True, self.winner
if self.field[2] == self.field[4] == self.field[6] != 0:
self.winner = self.field[2]
return True, self.winner
return False
def first_free(self):
for index, value in enumerate(self.field):
if value == 0:
return index
class Player:
def __init__(self, id, being, brain=None):
self.id = id
self.being = being
self.brain = brain
class Graph:
def __init__(self):
self.gens = []
self.maxs = []
self.losts = []
self.drawns = []
self.wons = []
self.average = []
self.last_gens = 50
self.vmax = None
def add(self, gen, vmax_round, lost, drawn, won):
self.gens.append(gen)
self.maxs.append(vmax_round)
self.losts.append(lost)
self.drawns.append(drawn)
self.wons.append(won)
self.average.append(sum(self.maxs[-min(self.last_gens,gen):]) / min(self.last_gens,gen))
self.vmax = max(self.maxs)
def display(self):
plt.figure(figsize=(10,6))
plt.plot(self.gens, self.maxs, label="Best Fitness")
plt.plot(self.gens, self.average, label="Average Fitness last " + str(self.last_gens) + " generations")
plt.plot(self.gens, self.losts, label="Lost")
plt.plot(self.gens, self.drawns, label="Drawn")
plt.plot(self.gens, self.wons, label="Won")
plt.legend(bbox_to_anchor=(1.05, 1), loc="upper left")
plt.grid("on")
plt.tight_layout()
plt.show()
def save(self):
with open('gens.txt', 'w') as filehandle:
json.dump(self.gens, filehandle)
with open('maxs.txt', 'w') as filehandle:
json.dump(self.maxs, filehandle)
with open('average.txt', 'w') as filehandle:
json.dump(self.average, filehandle)
with open('losts.txt', 'w') as filehandle:
json.dump(self.losts, filehandle)
with open('drawns.txt', 'w') as filehandle:
json.dump(self.drawns, filehandle)
with open('wons.txt', 'w') as filehandle:
json.dump(self.wons, filehandle)
def load(self):
with open('gens.txt', 'r') as filehandle:
self.gens = json.load(filehandle)
with open('maxs.txt', 'r') as filehandle:
self.maxs = json.load(filehandle)
with open('average.txt', 'r') as filehandle:
self.average = json.load(filehandle)
with open('losts.txt', 'r') as filehandle:
self.losts = json.load(filehandle)
with open('drawns.txt', 'r') as filehandle:
self.drawns = json.load(filehandle)
with open('wons.txt', 'r') as filehandle:
self.wons = json.load(filehandle)
graph = Graph()
board = Field()
def place_piece(player, field):
board.field[field] = player.id
def sound():
winsound.Beep(440,200)
def train(genomes, config):
global GEN
GEN += 1
best_fitness = 0
players = [None, None]
best_lost, best_drawn, best_won = 0,0,0
for index, genome in genomes:
index -= 1
genome.fitness = 0
net = neat.nn.FeedForwardNetwork.create(genome, config)
players[0] = Player(1, "random")
players[1] = Player(2, "ai")
lost, drawn, won = 0,0,0
for round in range(100):
if round == 50:
players[0] = Player(1, "ai")
players[1] = Player(2, "random")
field_to_go = -1
placed = 0
player = players[0]
while True:
if player.being == "random":
field_to_go = random.randint(0,8)
elif player.being == "ai":
output = net.activate(board.field)
field_to_go = output.index(max(output))
elif player.being == "human":
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
break
elif event.type == pygame.MOUSEBUTTONUP:
field_to_go = board.pos_to_field(pygame.mouse.get_pos())
if field_to_go > -1:
if board.field_is_free(field_to_go):
board.action(field_to_go, player.id)
else:
board.action(board.first_free(), player.id)
if player == players[0]:
player = players[1]
else:
player = players[0]
placed += 1
if shown:
board.display()
time.sleep(1)
if board.check_winner() or placed == 9:
if board.winner is None:
genome.fitness += 1
drawn += 1
elif players[board.winner-1].being == "ai":
genome.fitness += 2
won += 1
else:
genome.fitness -= 0
lost += 1
board.reset()
break
if genome.fitness > best_fitness:
best_fitness = genome.fitness
best_lost = lost
best_drawn = drawn
best_won = won
graph.add(GEN, best_fitness, best_lost, best_drawn, best_won)
def test(genome):
result = [0,0,0]
players = [None, None]
for round in range(1000):
placed = 0
if round % 2 == 0:
players[0] = Player(1, "ai")
players[1] = Player(2, "human")
else:
players[0] = Player(1, "human")
players[1] = Player(2, "ai")
player = players[0]
while True:
field_to_go = -1
if player.being == "random":
field_to_go = random.randint(0,8)
elif player.being == "ai":
output = genome.activate(board.field)
field_to_go = output.index(max(output))
elif player.being == "human":
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
break
elif event.type == pygame.MOUSEBUTTONUP:
field_to_go = board.pos_to_field(pygame.mouse.get_pos())
if field_to_go > -1:
if board.field_is_free(field_to_go):
board.action(field_to_go, player.id)
else:
board.action(board.first_free(), player.id)
if player == players[0]:
player = players[1]
else:
player = players[0]
placed += 1
if shown:
pygame.event.get()
board.display()
time.sleep(0.75)
if board.check_winner() or placed == 9:
if board.winner is None:
result[1] += 1
elif players[board.winner-1].being == "ai":
result[2] += 1
else:
result[0] += 1
if shown:
if board.winner is None:
print("None")
else:
print(players[board.winner-1].being + " " + str(player.id))
board.reset()
break
print(result)
def run(config_path):
global shown
global GEN
global screen
config = neat.config.Config(neat.DefaultGenome, neat.DefaultReproduction,
neat.DefaultSpeciesSet, neat.DefaultStagnation, config_path)
nc_name = "population"
testing = False
shown = False
new = True
if testing:
if shown:
screen = pygame.display.set_mode((300, 300))
pygame.display.set_caption("Tic Tac Toe")
test(neat.nn.FeedForwardNetwork.create(cloud.restore_checkpoint("population").population.best_genome, config))
quit()
if new:
p = neat.Population(config)
p.add_reporter(neat.StdOutReporter(True))
p.add_reporter(neat.StatisticsReporter())
else:
p = cloud.restore_checkpoint(nc_name).population
graph.load()
GEN = p.generation
p.run(train,250)
print(time.strftime("%H:%M:%S", time.localtime()))
cloud.save_checkpoint(config, p, p.species, GEN, nc_name)
graph.save()
graph.display()
sound()
if __name__ == "__main__":
local_dir = os.path.dirname(__file__)
config_path = os.path.join(local_dir, "config_feedforward")
run(config_path)
导入整洁
导入pygame
导入操作系统
导入json
随机输入
导入检查点
导入winsound
导入时间
将matplotlib.pyplot作为plt导入
pygame.init()
cloud=checkpoint.Checkpointer()
p=无
GEN=0
屏幕=无
pygame.display.set_标题(“Tic-Tac-Toe”)
o_icon=pygame.image.load(“o.png”)
x_icon=pygame.image.load(“x.png”)
类别字段:
定义初始化(自):
self.field=[0,0,0,0,0,0,0]
self.winner=无
def重置(自):
self.field=[0,0,0,0,0,0,0]
self.winner=无
def显示(自):
屏幕填充([0,0,0])
self.display_件()
自显示板()
pygame.display.update()
def显示部件(自身):
位置到像素={
0: (0,0),
1: (100,0),
2: (200,0),
3: (0,100),
4: (100,100),
5: (200,100),
6: (0, 200),
7: (100, 200),
8: (200, 200)
}
对于范围内的位置(len(self.field)):
如果自身字段[pos]==1:
屏幕.blit(x_图标,位置到pix[pos])
elif自身字段[pos]==2:
屏幕.blit(o_图标,位置到位置[pos])
@静力学方法
def pos_至_字段(pos):
x=位置[0]
y=位置[1]
如果x<100:
x=0
elif x<200:
x=1
其他:
x=2
如果y<100:
y=0
elif y<200:
y=1
其他:
y=2
返回x+y*3
@静力学方法
def显示板():
pygame.draw.rect(屏幕,“白色”[0,99300,2])
pygame.draw.rect(屏幕,“白色”[0199300,2])
pygame.draw.rect(屏幕,“白色”[99,02300])
pygame.draw.rect(屏幕,“白色”[199,02300])
def动作(自我、场号、球员号):
self.field[field\u id]=玩家\u id
def field_是自由的(自我,字段):
如果self.field[field]==0:
返回真值
返回错误
def检查优胜者(自我):
对于范围(3)中的行:
#水平检查
如果self.field[line*3]==self.field[line*3+1]==self.field[line*3+2]!=0:
self.winner=self.field[第*3行]
回归真实,自我胜利
如果self.field[line]==self.field[line+3]==self.field[line+6]!=0:
self.winner=self.field[行]
回归真实,自我胜利
如果self.field[0]==self.field[4]==self.field[8]!=0:
self.winner=self.field[0]
回归真实,自我胜利
如果self.field[2]==self.field[4]==self.field[6]!=0:
self.winner=self.field[2]
回归真实,自我胜利
返回错误
def第一自由(自我):
对于索引,枚举中的值(self.field):
如果值==0:
回报指数
职业球员:
定义初始(自我、身份、存在、大脑=无):
self.id=id
自我存在
self.brain=大脑
类图:
定义初始化(自):
self.gens=[]
self.maxs=[]
self.losts=[]
self.drawns=[]
self.wons=[]
self.average=[]
自身最后一个发电机组=50
self.vmax=None
def添加(自我、一般、最大轮、损失、平局、赢得):
self.gens.append(gen)
self.maxs.append(vmax\u轮)
self.losts.append(丢失)
self.drawns.append(已绘制)
self.wons.append(won)
self.average.append(总和(self.maxs[-min(self.last\u gens,gen):])/min(self.last\u gens,gen))
self.vmax=max(self.maxs)
def显示(自):
plt.图(figsize=(10,6))
plt.plot(self.gens、self.maxs、label=“最佳适合度”)
plt.plot(self.gens,self.average,label=“平均适合度最后一代”+str(self.last_gens)+“世代”)
plt.plot(self.gens,self.losts,label=“Lost”)
plt.绘图(self.gens,self.drawns,label=“Drawn”)
plt.plot(self.gens、self.wons、label=“Won”)
plt.图例(bbox_to_anchor=(1.05,1),loc=“左上”)
公共电网(“on”)
plt.紧_布局()
plt.show()
def保存(自我):
以open('gens.txt','w')作为文件句柄:
json.dump(self.gens,filehandle)
以open('maxs.txt','w')作为文件句柄:
json.dump(self.maxs,filehandle)
以open('average.txt','w')作为文件句柄:
json.dump(self.average,filehandle)
以open('losts.txt','w')作为文件句柄:
dump(self.losts,filehandle)
以open('drawns.txt','w')作为文件句柄:
dump(self.drawns,filehandle)
以open('wons.txt','w')作为文件句柄:
json.dump(self.wons,filehandle)
def加载(自):
以open('gens.txt','r')作为文件句柄:
self.gens=json.load(filehandle)
以open('maxs.txt','r')作为文件句柄:
self.maxs=json.load(文件句柄)
以open('average.txt','r')作为文件句柄:
self.average=json.load(filehandle)
以open('losts.txt','r')作为文件句柄:
self.losts=json.load(filehandle)
以open('drawns.txt','r')作为文件句柄:
self.drawns=json.load(filehandle)
以open('wons.txt','r')作为文件句柄:
self.wons=json.load(filehandle)
图=图()
board=字段()
def place_工件(球员、场地):
board.field[字段]=player.id
def sound():
winsound.Beep(440200)
def序列(基因组,配置):
全球发电机
发电机+=1
最佳适配度=0
玩家=[无,无]