-
Notifications
You must be signed in to change notification settings - Fork 1
/
utils.py
112 lines (87 loc) · 3.11 KB
/
utils.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
import random
import pygame as pg
import numpy as np
# from initializers import *
from classes import *
'''
a new state simply means the changed position of the
rectangle and the circle. the rectangle would move according
to the optimal action, the circle falls freely.
'''
def new_state_after_action(s, act):
updatedPlayer = None
if act == 2: # 0 == stay, 1 == left, 2 == right
if s.player.right + s.player.width > WIDTH:
rct = s.player
else:
rct = pg.Rect(s.player.left + s.player.width, s.player.top, s.player.width,
s.player.height) # Rect(left, top, width, height)
elif act == 1: # action is left
if s.player.left - s.player.width < 0:
rct = s.player
else:
rct = pg.Rect(s.player.left - s.player.width, s.player.top, s.player.width,
s.player.height) # Rect(left, top, width, height)
else: # action is 0, means stay where it is
updatedPlayer = s.player
s.enemy.top += SPEED
updatedEnemy = s.enemy
return State(updatedPlayer, updatedEnemy)
'''
almost similar to a new state, separating because of some easiness
'''
def new_rect_after_action(rect, act):
if act == 2: # 0 == left, 1 == right
if rect.right + rect.width > windowWidth:
return rect
else:
return pg.Rect(rect.left + rect.width, rect.top, rect.width,
rect.height) # Rect(left, top, width, height)
elif act == 1: # action is left
if rect.left - rect.width < 0:
return rect
else:
return pg.Rect(rect.left - rect.width, rect.top, rect.width,
rect.height) # Rect(left, top, width, height)
else: # action if to stay
return rect
'''
defines where the starting x position of the circle
should be while falling.
'''
def circle_falling(crclradius):
newx = 100 - crclRadius
multiplier = random.randint(1, 8) # make more channel by making it a floating point number
newx *= multiplier
return newx
'''
calculate the score based on the relative position of the
circle and the rectangle.
'''
def calculate_score(player, enemy):
if not (player.left <= enemy.left <= player.right): # if the circle'x x position is between the rectangles left and right
return 1
else:
return -1
'''
numpy array can't work with custom objects as indices.
that's why we must create an integer representation of the states
the position of the rectangle and circle combined should give us a unique
identifier. we are storing the value in another dictionary which would hold the unique
indices.
'''
def state_to_number(s):
r = s.player.left
c = s.enemy.left
n = int(str(r) + str(c) + str(s.enemy.top))
if n in QIDic:
return QIDic[n]
else:
if len(QIDic):
maximum = max(QIDic, key=QIDic.get) # Just use 'min' instead of 'max' for minimum.
QIDic[n] = QIDic[maximum] + 1
else:
QIDic[n] = 1
return QIDic[n]
def get_best_action(s):
return np.argmax(Q[state_to_number(s), :])