# ​Python人工智能在贪吃蛇游戏中的运用与探索（下）

## 设置规则

```if a == 0:
self.X = deque([x_start, x_start - 1, x_start - 2, x_start - 3])
self.Y = deque([y_start, y_start, y_start, y_start])
init_dir = 1
```

```def eat_food(self, x_food, y_food):
self.X.appendleft(x_food)
self.Y.appendleft(y_food)
self.LENGTH += 1
self.MOVES += 100

def update(self, x_change, y_change):
# 更新贪吃蛇身体位置
for i in range(self.LENGTH - 1, 0, -1):
self.X[i] = self.X[i - 1]
self.Y[i] = self.Y[i - 1]

# 更新贪吃蛇头部位置
self.X[0] = self.X[0] + x_change
self.Y[0] = self.Y[0] + y_change

self.MOVES -= 1
```
```if new_head_x == self.FOOD_X and new_head_y == self.FOOD_Y:
self.SNAKE.eat_food(self.FOOD_X, self.FOOD_Y)  # 确认吃了食物
reward = 50  # 给予吃食物的奖励
food_eaten = True
```
```def reset(self):
......
......
self.FOOD_X, self.FOOD_Y = self.get_randoms()```

```def bit_itself(self):
for i in range(1, self.LENGTH):
if self.X[0] == self.X[i] and self.Y[0] == self.Y[i]:
return True
return False

def is_on_body(self, check_x, check_y, remove_last=True):
X, Y = self.X.copy(), self.Y.copy()

if remove_last:  # 不考虑尾部
Y.pop()
for x, y in zip(X, Y):
if x == check_x and y == check_y:
return True
return False
```
```if new_head_x < x1 or new_head_x > x2 or new_head_y < y1 or new_head_y > y2:
reward = -50
done = True
self.SNAKE.kill()```
```def kill(self):
self.is_alive = False
```

```if action == 0:
if self.VELOCITY == 1:  # 向右移动
x_change = 1
else:
x_change = -1  # 向左移动
update = True
......
```

## 初始化环境

##### 神经网络参数的设置
```HIDDEN_UNITS = (32, 16, 32)  # 神经网络隐藏层神经元数目
NETWORK_LR = 0.001  # 神经网络学习率
BATCH_SIZE = 64  # 训练批次
UPDATE_EVERY = 5  # 本地模型每训练5次更新
GAMMA = 0.95  # 强化学习中的折扣因子
NUM_EPISODES = 5000  # 最大迭代次数
def train():
agent = DeepQ_agent(env, hidden_units=HIDDEN_UNITS, network_LR=NETWORK_LR,
batch_size=BATCH_SIZE, update_every=UPDATE_EVERY,                               gamma=GAMMA)  # 深度学习环境
......
```

##### 环境状态设定
```def reset(self):

# 初始化贪吃蛇和食物的位置
snake_x, snake_y = self.get_randoms(length=4)
self.SNAKE = Snake(snake_x, snake_y, self.WIDTH, self.HEIGHT)
self.VELOCITY = self.SNAKE.INITIAL_DIRECTION
self.FOOD_X, self.FOOD_Y = self.get_randoms()
self.STATE = self.SNAKE.look(self.FOOD_X, self.FOOD_Y,
self.get_boundaries())
return self.STATE
```

## 设定训练模型和张量

##### 判断蛇和与环境的关系，生成环境张量

```def look(self, x_food, y_food, boundaries):
# 往上观察
up = self.lookInDirection(boundaries, y=-1, x=0)
......#左右等剩余七个观察
......
aa = np.hstack((food_position, up, up_right, right, down_right, down, down_left, left, up_left))
return np.hstack((food_position, up, up_right, right, down_right, down, down_left, left, up_left))

def lookInDirection(self, boundaries, y, x):
tail_distance = 0  # 0如果尾部不在这个方向
distance = 1  # 1是离墙的最小距离
check_x, check_y = curr_x + x, curr_y + y  # 按照方向变化头部位置
x1, x2, y1, y2 = boundaries
while y1 <= check_y <= y2 and x1 <= check_x <= x2:
if tail_distance == 0 and (self.is_on_body(check_x, check_y,
remove_last=False)):
tail_distance = (1 / distance)
# 持续迭代
check_y += y
check_x += x
distance += 1
return np.array([1 / distance, tail_distance])
```

## 开始训练

##### 建立本地和目标模型，并预估动作
```self.qnetwork_local = QNetwork(input_shape=self.env.STATE_SPACE,
output_size=self.nA,
learning_rate=self.NETWORK_LR)
#print(self.qnetwork_local.model.summary())

#一个模型用于本地训练，另外一个模型随之更新权重
self.qnetwork_target = QNetwork(input_shape=self.env.STATE_SPACE,
output_size=self.nA,
learning_rate=self.NETWORK_LR)

self.memory = ReplayMemory(self.MEMORY_CAPACITY, self.BATCH_SIZE)
```
```#使用本地模型估计下一个动作
target = self.qnetwork_local.predict(states, self.BATCH_SIZE)
#使用目标模型估计下一个动作
target_val = self.qnetwork_target.predict(
next_states, self.BATCH_SIZE)
target_next = self.qnetwork_local.predict(
next_states, self.BATCH_SIZE)```

##### 计算分数
```for i in range(self.BATCH_SIZE):
if dones[i]:
target[i][actions[i]] = rewards[i]
else:
target[i][actions[i]] = rewards[i] + self.GAMMA * \
target_val[i][max_action_values[i]
```

## 执行训练

##### 开始移动
```def act(self, state, epsilon):  #设置epsilon默认为0
state = state.reshape((1,)+state.shape)
action_values = self.qnetwork_local.predict(
state)
if random.random() > epsilon:
#选择最好的行动
action = np.argmax(action_values)
else:
#选择随机的行动
action = random.randint(0, self.nA-1)
return action
```

##### 存储与提取经验
```def add_experience(self, state, action, reward, next_state, done):

def add(self, state, action, reward, next_state, done):
'''把经验存储起来'''
e = tuple((state, action, reward, next_state, done))
```
```def sample(self, state_shape):
experiences = random.sample(self.memory, k=self.BATCH_SIZE)
# 提取反馈信息
states, actions, rewards, next_states, dones = zip(*experiences)
```
```def learn(self):
if self.memory.__len__() > self.BATCH_SIZE:
states, actions, rewards, next_states, dones = self.memory.sample(
self.env.STATE_SPACE)```

```model_arch = '2019816'
resume_model_path = model_out_dir + '/snake_dqn_2019815_final.h5'
```
```agent.qnetwork_local.model = load_model('F://贪吃蛇//SnakeAI-master//agents_models//snake_dqn_2019816_3000.h5')
```

「参考文献：」

0 条评论

• ### 强化学习DQN玩转FlappyBird｜前景提要

强化学习是机器学习大家族中的一大类, 使用强化学习能够让机器学着如何在环境中拿到高分, 表现出优秀的成绩. 而这些成绩背后却是他所付出的辛苦劳动, 不断的试错,...

• ### 干货 | 时间序列数据的对齐和数据库的分批查询

在机器学习里，我们对时间序列数据做预处理的时候，经常会碰到一个问题：有多个时间序列存在多个表里，每个表的的时间轴不完全相同，要如何把这些表在时间轴上进行对齐，从...

• ### 10分钟教你用Python做个打飞机小游戏超详细教程

这次还是用python的pygame库来做的游戏。关于这个库的内容，读者可以上网了解一下。本文只讲解用到的知识。代码参考自网上，自己也做了一点代码简化。尽量把最...

• ### Tiknter例子3

============================================

• ### Python魔术方法-Magic Method

目录[-] 介绍 在Python中，所有以“__”双下划线包起来的方法，都统称为“Magic Method”,例如类的初始化方法 __init__ ,Pyt...

• ### python写一个简单的俄罗斯方块

self.color = ['red','orange','yellow','purple','blue','green','pink']

• ### 从item-base到svd再到rbm多种协同过滤算法从原理到实现

一.引入 一直想写一篇关于推荐系统的文章总结下，这次借着完善DML写一下，权当是总结了。不过真正的推荐系统当然不会这么简单，往往是很多算法交错...

• ### Python魔法方法指南

什么是魔法方法呢？它们在面向对象的Python的处处皆是。它们是一些可以让你对类添加“魔法”的特殊方法。 它们经常是两个下划线包围来命名的（比如 __init_...

• ### 你的童年有俄罗斯方块吗？教你用 Python 实现俄罗斯方块！

还是为数不多的游戏类电子产品，对小孩子更是有着不可抗拒的魔力，在当时如果哪个小孩买了一个小游戏机，大伙一定迅速围上去...