-
Notifications
You must be signed in to change notification settings - Fork 1
/
jogodavelha.py
396 lines (257 loc) · 9.74 KB
/
jogodavelha.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
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
"""
Curso de IA - Jogo da velha
Robo que aprende a jogar o Jogo da Velha por RL
"""
import numpy as np
import grafico
def main():
"""Ambiente"""
dim = 3 # Dimenssão do tabuleiro
dim2 = dim * dim
possibilidades = 3 # quantas formas eu tenho para preencher um espaço do tabuleiro
empty = 0 # digito 0 na base ternária
o = 1 # digito 1 na base ternária
x = -1 # digito 2 na base ternária
p1 = o
p2 = x
Q = 0.4 * np.ones((possibilidades**dim2, dim2)) # Inicializa Tabela Q
# Parâmetros
N_episodes = 100000 # Quantidade de vezes que o robo ira jogar
alpha = 0.1
gamma = 0.90
max_epsilon = 1
min_epsilon = 0
decay_rate = 0.0005
epsilon = 1
robo_começar = grafico.select_player()
if robo_começar == "s":
quem_comeca = p2
elif robo_começar == "n":
quem_comeca = p1
if quem_comeca == p2:
try:
arquivo = open("data/tabelaq2.txt", "r")
Q = puxar_inteligencia(arquivo, possibilidades, dim2, quem_comeca)
except Exception:
for episode in range(N_episodes):
Q = play_one_episode(Q, o, x, epsilon, dim2, empty, alpha, gamma, dim, quem_comeca)
epsilon = min_epsilon + (max_epsilon - min_epsilon) * np.exp(-decay_rate * episode)
if episode % 1000 == 0:
print(epsilon)
guardar_inteligencia(Q, dim2, quem_comeca, p1, p2)
elif quem_comeca == p1:
try:
arquivo = open("data/tabelaq1.txt", "r")
Q = puxar_inteligencia(arquivo, possibilidades, dim2, quem_comeca)
except Exception:
for episode in range(N_episodes):
Q = play_one_episode(Q, o, x, epsilon, dim2, empty, alpha, gamma, dim, quem_comeca)
epsilon = min_epsilon + (max_epsilon - min_epsilon) * np.exp(-decay_rate * episode)
if episode % 1000 == 0:
print(epsilon)
guardar_inteligencia(Q, dim2, quem_comeca, p1, p2)
while True:
play_teste(Q, dim2, empty, x, o, dim, quem_comeca)
def play_one_episode(Q, o, x, epsilon, dim2, empty, alpha, gamma, dim, quem_comeca):
""" Joga uma partida do jogo da velha"""
vet_board = np.zeros(dim2)
gameover = False
p2 = x
p1 = o
current_player = []
recorded_s_a_r = []
quem_ncomeca = []
if quem_comeca == p1:
quem_ncomeca = p2
elif quem_comeca == p2:
quem_ncomeca = p1
state = take_state(dim2, vet_board, empty, o, x)
while not gameover:
if current_player == quem_comeca: # alterna entre os players
current_player = quem_ncomeca
else:
current_player = quem_comeca
# player atual faz uma jogada
if current_player == p1: # robo aprendiz
action = take_action(Q, state, epsilon, dim2, vet_board, empty)
else: # robo com açoes totalmente aleatórias
action = take_action(Q, state, 1, dim2, vet_board, empty) # 1 no epsilon pq ele nunca vai pegar experiencias e sempre jogadas aleatorias
# Preenchimento do tabuleiro
vet_board[action] = current_player
# A Partida terminou?
gameover, winner = game_over(vet_board, dim, x, o)
# Recebe a recompensa
reward = get_reward(gameover, winner, p1)
# Passo para o novo estado
new_state = take_state(dim2, vet_board, empty, o, x)
# Geralmente a atualização da tabela Q eh aqui, porem
# como se trata de um problema de dois agentes, não pode ser aqui
# Armazenamento da sequencia de state-action-reward do robo aprendiz
if current_player == p1:
recorded_s_a_r.append((state, action, reward))
# Atualização estado
state = new_state
maximun = 0
for s_a_r in reversed(recorded_s_a_r):
s = s_a_r[0]
a = s_a_r[1]
r = s_a_r[2]
Q[s, a] = (1 - alpha) * Q[s, a] + alpha * (r + gamma * maximun)
maximun = np.max(Q[s, :])
return Q
def play_teste(Q, dim2, empty, x, o, dim, quem_comeca):
""" Função para testar nosso robo"""
vet_board = np.zeros(dim2)
gameover = False
p2 = x
p1 = o
current_player = []
quem_ncomeca = []
if quem_comeca == p1:
quem_ncomeca = p2
elif quem_comeca == p2:
quem_ncomeca = p1
state = take_state(dim2, vet_board, empty, o, x)
draw_board(vet_board) # desenha o tabuleiro inicial
while not gameover:
if current_player == quem_comeca: # alterna entre os players
current_player = quem_ncomeca
else:
current_player = quem_comeca
# player atual faz uma jogada
if current_player == p1: # robo aprendiz
action = take_action(Q, state, 0, dim2, vet_board, empty) # robo utiliza somente das suas experiencias
else: # Humano
nao_liberado = True
while nao_liberado:
action = None
print("Faça sua jogada")
while action == None:
action = grafico.mouse_posicao(grafico.rects)
if action == -1:
vet_board = [-1, -1, -1, -1, -1, -1, -1, -1, -1]
break
elif vet_board[action] == empty:
nao_liberado = False
# Preenchimento do tabuleiro
if action != -1:
vet_board[action] = current_player
else:
pass
# desenha o novo tabuleiro
draw_board(vet_board)
# A Partida terminou?
gameover, winner = game_over(vet_board, dim, x, o)
if gameover:
while action != -1:
action = grafico.mouse_posicao(grafico.rects)
# Passo para o novo estado
new_state = take_state(dim2, vet_board, empty, o, x)
# Atualização estado
state = new_state
def take_action(Q, state, epsilon, dim2, vet_board, empty):
"""Tomada de decição"""
r = np.random.rand() # numero aleatorio entre 0 e 1
possible_actions = []
for i in range(dim2):
if vet_board[i] == empty:
possible_actions.append(i)
if r <= epsilon: # ação aleatória
n = len(possible_actions)
index = np.random.choice(n)
action = possible_actions[index]
return action
else: # uso da experiencias
Q_vals = Q[state, :]
Q_possible = [Q_vals[i] for i in possible_actions] # valores de Q das açoes possiveis
max_Q_possible = np.max(Q_possible) # maximo valor de Q dentro das açoes possiveis
actions_max = [i for i in possible_actions if Q_vals[i] == max_Q_possible]
action = np.random.choice(actions_max)
return action
def take_state(dim2, vet_board, empty, o, x):
"""Representação dos Estados possíveis do tabuleiro"""
somatorio = 0
for i in range(dim2):
if vet_board[i] == empty:
digit = 0
elif vet_board[i] == o:
digit = 1
else:
digit = 2
somatorio = somatorio + digit * (3**i)
state = somatorio
return state
def get_reward(gameover, winner, p1):
"""Estratégia de Recompensa"""
if gameover and winner == p1:
reward = 1
return reward
elif gameover and winner == "tie":
reward = 0.5
return reward
else:
reward = 0
return reward
def game_over(vet_board, dim, x, o):
mat_board = np.reshape(vet_board, (dim, dim))
if np.all((mat_board == -1) == True): # todos os campos não estão vazios?
winner = 'desistencia'
return True, winner
# verifica linhas e colunas
for player in (x, o):
for i in range(dim):
if mat_board[i, :].sum() == player * dim: # verifica linhas
winner = player
return True, winner
elif mat_board[:, i].sum() == player * dim: # verifica colunas
winner = player
return True, winner
# verifica diagonais
for player in (x, o):
if np.sum(np.diag(mat_board)) == player * dim: # diagonal principal
winner = player
return True, winner
elif np.sum(np.diag(np.fliplr(mat_board))) == player * dim: # diagonal oposta
winner = player
return True, winner
# verifica se deu empate
if np.all((mat_board == 0) == False): # todos os campos não estão vazios?
winner = 'tie'
return True, winner
# Jogo ainda não terminou
winner = None
return False, winner
def draw_board(vet_board):
grafico.atualiza_tela(vet_board)
def guardar_inteligencia(Q, dim2, quem_comeca, p1, p2):
"""Grava um arquivo .txt com a tabela Q e as informações obtidas no treinamento """
if quem_comeca == p2:
arquivo = open("data/tabelaq2.txt", "w")
elif quem_comeca == p1:
arquivo = open("data/tabelaq1.txt", "w")
for i in Q:
lista = ""
for j in range(dim2):
valor = i[j]
valor = str(valor)
if j == (dim2 - 1):
valor = valor + "\n"
else:
valor = valor + " "
lista = lista + valor
arquivo.write(lista)
arquivo.close()
def puxar_inteligencia(arquivo, possibilidades, dim2, quem_comeca):
"""Pega as informações para preencher a tabela Q a partir de um arquivo .txt """
Q = 0.4 * np.ones((possibilidades**dim2, dim2))
for i in range(possibilidades**dim2):
linha_str = arquivo.readline()
linha_str = linha_str.strip()
linha_str = linha_str.split()
for j in range(dim2):
valor = linha_str[j]
valor = np.float(valor)
Q[i, j] = valor
arquivo.close()
return Q
main()