-
Notifications
You must be signed in to change notification settings - Fork 47
/
brain.py
156 lines (145 loc) · 6.68 KB
/
brain.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
import random
import numpy as np
class brain:
def __init__(self, layers, width, height, block, random_weights=True, random_bases=True):
self.nextFood = None
self.outputs = []
self.weights = []
self.prev_result = 1
self.bases = []
self.prev_food_cost = 1.0
self.block = block
self.width = width
self.height = height
if random_weights == True:
for i in range(len(layers) - 1):
theta = np.random.uniform(low=-0.5, high=.5, size=(layers[i], layers[i+1]))
self.weights.append(theta)
if random_bases == True:
for i in range(len(layers) - 1):
base = np.random.uniform(low=-0.1, high=0.1, size=(1, layers[i+1]))
self.bases.append(base)
# returns true if x, y is the part of the snake else false
def isBody(self, x, y, snake):
for i in range(3, len(snake) - 1):
if snake[i][0] == x and snake[i][1] == y:
return True
return False
# next position and direction based on the result passed
def next_position_direction(self, x, y, direction, result):
l = self.block
if direction == 'north':
if result == 1:
return (x, y - l), 'north'
elif result == 2:
return (x - l, y), 'west'
else:
return (x + l, y), 'east'
elif direction == 'east':
if result == 1:
return (x + l, y), 'east'
elif result == 2:
return (x, y - l), 'north'
else:
return (x, y + l), 'south'
elif direction == 'south':
if result == 1:
return (x, y + l), 'south'
elif result == 2:
return (x + l, y), 'east'
else:
return (x - l, y), 'west'
else:
if result == 1:
return (x - l, y), 'west'
elif result == 2:
return (x, y + l), 'south'
else:
return (x, y - l), 'north'
# returns an list with three element indicating the food, body part and boundary based on the direction passed
def look_in_direction(self, x, y, dirx, diry, fx, fy, snake):
distance = 1
input = [0, 0, 0]
food_found = False
body_found = False
while((x != 0) and (x != self.width-self.block) and (y != 0) and (y != self.height-self.block)):
x, y = x + dirx, y + diry
distance += 1
if(not food_found and fx == x and fy == y):
input[0] = 1
food_found = True
if(not body_found and self.isBody(x, y, snake)):
input[1] = 1 / distance
body_found = True
input[2] = 1 / distance
return input
# makes the input for the neural network by passing all 8 directions to look_in_direction
def make_input(self, x, y, fx, fy, snake, direction):
input = []
# look in direction where snake is moving
(new_x, new_y), _ = self.next_position_direction(x, y, direction, 1)
dir_x, dir_y = new_x - x, new_y - y
input.extend(self.look_in_direction(x, y, dir_x, dir_y, fx, fy, snake))
# look in 90 degree left of direction where snake is moving
(new_x, new_y), _ = self.next_position_direction(x, y, direction, 2)
dir_x, dir_y = new_x - x, new_y - y
input.extend(self.look_in_direction(x, y, dir_x, dir_y, fx, fy, snake))
# look in 90 degree right of direction where snake is moving
(new_x, new_y), _ = self.next_position_direction(x, y, direction, 3)
dir_x, dir_y = new_x - x, new_y - y
input.extend(self.look_in_direction(x, y, dir_x, dir_y, fx, fy, snake))
# look in 45 degree left of direction where snake is moving
(tempx, tempy), new_dir = self.next_position_direction(x, y, direction, 1)
(new_x, new_y), _ = self.next_position_direction(tempx, tempy, new_dir, 2)
dir_x, dir_y = new_x - x, new_y - y
input.extend(self.look_in_direction(x, y, dir_x, dir_y, fx, fy, snake))
# look in 45 degree right of direction where snake is moving
(tempx, tempy), new_dir = self.next_position_direction(x, y, direction, 1)
(new_x, new_y), _ = self.next_position_direction(tempx, tempy, new_dir, 3)
dir_x, dir_y = new_x - x, new_y - y
input.extend(self.look_in_direction(x, y, dir_x, dir_y, fx, fy, snake))
# look in opposite to the direction where snake is moving
(tempx, tempy), new_dir = self.next_position_direction(x, y, direction, 2)
(new_x, new_y), new_dir = self.next_position_direction(tempx, tempy, new_dir, 2)
(new_x, new_y), _ = self.next_position_direction(new_x, new_y, new_dir, 2)
dir_x, dir_y = new_x - x, new_y - y
input.extend(self.look_in_direction(x, y, dir_x, dir_y, fx, fy, snake))
# look in 135 degree right of direction where snake is moving
(tempx, tempy), new_dir = self.next_position_direction(x, y, direction, 3)
(new_x, new_y), _ = self.next_position_direction(tempx, tempy, new_dir, 3)
dir_x, dir_y = new_x - x, new_y - y
input.extend(self.look_in_direction(x, y, dir_x, dir_y, fx, fy, snake))
# look in 135 degree left direction where snake is moving
(tempx, tempy), new_dir = self.next_position_direction(x, y, direction, 2)
(new_x, new_y), _ = self.next_position_direction(tempx, tempy, new_dir, 2)
dir_x, dir_y = new_x - x, new_y - y
input.extend(self.look_in_direction(x, y, dir_x, dir_y, fx, fy, snake))
return input
# feed forward using neural network
def decision_from_nn(self, x, y, snake, direction):
closer_to_food = True
fx, fy = self.nextFood
input = self.make_input(x, y, fx, fy, snake, direction)
input = np.array(input)
# feed forward
output = input
for i in range(len(self.weights) - 1):
output = self.relu(np.dot(output, self.weights[i]) + self.bases[i])
self.outputs.append(output)
output = self.softmax(np.dot(output, self.weights[i+1]) + self.bases[i+1])
self.outputs.append(output)
result = np.argmax(self.outputs[-1]) + 1
return result
# set the next food variable
def setNextFood(self, food):
self.nextFood = food
# sigmoid activation functions
def sigmoid(self, mat):
return 1.0 / (1.0 + np.exp(-mat))
# relu activation function
def relu(self, mat):
return mat * (mat > 0)
# softmax function
def softmax(self, mat):
mat = mat - np.max(mat)
return np.exp(mat) / np.sum(np.exp(mat), axis=1)