-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathunitStrategy.py
241 lines (198 loc) · 8.74 KB
/
unitStrategy.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
from math import *;
from utils import *;
import random;
import soldiers;
import towers;
#class ProbGene(FloatGene):
# """
# Gene which represents the probabilities used in our organism
# """
# # genes get randomly generated within this range
# randMin = 0.0
# randMax = 1.0
# # probability of mutation
# mutProb = 0.1
# # degree of mutation
# mutAmt = 0.05
class UnitStrategyClass(object):
def __init__(self, economy, owner, homePos):
self.riskiness = {"SoldierClass": 0.5, "TrapClass": 0.25, "TowerClass": 0.1}; # Base probability to get closer to interact
self.curiosity = 0.10; # TODO: Base probability to explore new territory
self.groupSpirit = 0.50; # Base probability to keep close to others
self.fasting = 0.90; # Base probability to return if hungry
self.greed = 0.90; # Base probability to reach for loot, when not enough has been collected
self.spontaneity = 0.05; # Base probability to act without checking/thinking
self.repetition = 0.20; # Base probability to get back to one's last position
self.owner = owner;
self.economy = economy;
self.homePos = homePos;
self.visited = [];
self.lastDirection = None;
# Returns the offset for the unit movement
def decideMove(self, friends, foes, gamemap):
# Update current space as visited
self.visited += [(self.owner.x,self.owner.y)]
# Init direction scores
directionScores = {(-1,-1): 0.0, (0, -1): 0.0, (1, -1): 0.0,
(-1, 0): 0.0, (0, 0) : 0.0, (1, 0) : 0.0,
(-1, 1): 0.0, (0, 1) : 0.0, (1, 1) : 0.0};
bInBattle = False
lFriends = self.friendsInSight(friends, foes);
if len(lFriends) > 0:
# DEBUG LINES
# print("\nFound %d friends in range.\n"%(len(lFriends) - 1));
for curFriend in friends:
if curFriend == self.owner:
continue; # Ignore self
directionScores[self.directionForPosition(curFriend).tuple()] += self.groupSpirit / (len(lFriends) - 1);
lFoes = self.foesInSight(friends, foes);
if len(lFoes) > 0:
# DEBUG LINES
# print("\nFound %d foes in range.\n"%(len(lFoes)));
for curFoe in foes:
if (isinstance(curFoe, soldiers.SoldierClass)):
sCurClassName = "SoldierClass";
if (isinstance(curFoe, towers.TowerClass)):
sCurClassName = "TowerClass";
foeDirection = self.directionForPosition(curFoe).tuple()
directionScores[foeDirection] += self.riskiness[sCurClassName] / len(lFoes);
if (foeDirection == (0,0)):
bInBattle = True
lTrapsInSight = self.trapsInSight(friends, foes, gamemap);
if len(lTrapsInSight) > 0:
# DEBUG LINES
# print("\nFound %d traps in range.\n"%(len(lTrapsInSight)));
for curTrap in lTrapsInSight:
directionScores[self.directionForPosition(curTrap).tuple()] += (self.riskiness["TrapClass"]) / len(lTrapsInSight);
lTreasureInSight = self.treasureInSight(friends, foes, gamemap);
if len(lTreasureInSight) > 0:
# DEBUG LINES
# print("\nFound %d treasures in range.\n"%(len(lTreasureInSight)));
for curTreasure in lTreasureInSight:
# If not enough treasured gathered
if (self.economy.cost(self.owner) * 1.5 - self.owner.treasure > 0):
directionScores[self.directionForPosition(curTreasure).tuple()] += self.greed / len(lTreasureInSight);
# Do we miss home because of hunger?
if self.owner.fullness <= 0.5 * self.distanceFromHome():
directionScores[self.directionForPosition(self.homePos).tuple()] += self.fasting;
# Are we against going back to our last position?
if (self.lastDirection != None):
if (random.random() >= self.repetition):
reverseOfLastDirection = (-self.lastDirection[0], -self.lastDirection[1]);
# DEBUG LINES
# print("Reducing direction %s from %4.2f to zero."%(str(reverseOfLastDirection),
# directionScores[reverseOfLastDirection] ));
# raw_input();
directionScores[reverseOfLastDirection] = 0.0;
# Are we curious to visit new places?
if (random.random() <= self.curiosity):
for xInc in range(-1,2):
for yInc in range(-1,2):
if (self.owner.x + xInc, self.owner.y + yInc) not in self.visited:
directionScores[xInc, yInc] += 1.0
# DEBUG LINES
# sScores = '\n'.join([str(key)+":" + str(val) for key, val in directionScores.iteritems()]);
# print("\n" + sScores + "\n");
# from time import sleep;
# sleep(1);
# raw_input();
##########
# Remove negative values
for key, val in directionScores.iteritems():
if val < 0.0:
directionScores[key] = 0.0;
if bInBattle:
directionScores[0,0] += 5.0; # Increased importance if in bInBattle
# Follow probability
curDirection = None;
# RANDOMLY select
# curScore = random.uniform(0.0, sum(directionScores.values()));
# # DEBUG LINES
# print("Rolled:" + str(curScore) + " from " + str(sum(directionScores.values())));
# sleep(1);
# for curDirection in directionScores.keys():
# curScore -= directionScores[curDirection];
# if curScore < 0:
# break;
# MAX select
curMax = -1.0;
for curCandidate in directionScores.keys():
if directionScores[curCandidate] > curMax:
curDirection = curCandidate;
curMax = directionScores[curCandidate];
# DEBUG LINES
# print("Max is:" + str(curMax) + " by " + str(curDirection));
# raw_input();
# If we are about to stay put or we are spontaneous, choose randomly
if random.random() < self.spontaneity:
# print("Spontaneous reaction!");
# raw_input();
curDirection = random.choice(directionScores.keys());
# If bored (same place)
#if curDirection == (0, 0):
# print("Bored! Aiming for the end of the map...");
# raw_input();
# aim for the end of the map
# curDirection = self.directionForPosition((gamemap.xSize, gamemap.ySize)).tuple();
# Check if in map limits
if self.owner.x == gamemap.xSize - 1:
if curDirection[0] > 0: curDirection= (0, curDirection[1]);
if self.owner.y == gamemap.ySize - 1:
if curDirection[1] > 0: curDirection= (curDirection[0], 0);
if self.owner.x == 0:
if curDirection[0] < 0: curDirection= (0, curDirection[1]);
if self.owner.y == 0:
if curDirection[1] < 0: curDirection= (curDirection[0], 0);
# Save selected direction
self.lastDirection = curDirection;
return curDirection;
# The list of treasures in sight
def treasureInSight(self, friends, foes, gamemap):
return [ curTreasure for curTreasure in gamemap.treasures if (curTreasure.x - self.owner.x < 3 and curTreasure.y - self.owner.y < 3)];
# The list of treasures in sight
def trapsInSight(self, friends, foes, gamemap):
return [ curTrap for curTrap in gamemap.traps if (abs(curTrap.x - self.owner.x) < 3 and abs(curTrap.y - self.owner.y) < 3)];
# The list of foes in sight
def foesInSight(self, friends, foes):
return [ curFoe for curFoe in foes if (abs(curFoe.x - self.owner.x) < 3 and abs(curFoe.y - self.owner.y) < 3)];
# The list of friends in sight
def friendsInSight(self, friends, foes):
return [ curFriend for curFriend in friends if (abs(curFriend.x - self.owner.x) < 3 and abs(curFriend.y - self.owner.y) < 3)];
# The distance from home (as Manhattan distance)
def distanceFromHome(self):
homePos = Point();
homePos.x = self.homePos[0];
homePos.y = self.homePos[1];
return abs(self.owner.x - homePos.x) + abs(self.owner.y - homePos.y); # Manhattan distance
# The movement offset that brings as closer to a position on the map
def directionForPosition(self, pos):
# DEBUG LINES
# try:
# print "Target %s at %s"%(str(pos), str((pos.x, pos.y)));
# except:
# print "Target %s at %s"%(str(pos), str((pos[0], pos[1])));
# print "Self at %s"%(str((self.owner.x, self.owner.y)));
try:
x = pos[0];
y = pos[1];
except:
x = pos.x;
y = pos.y;
iX = Utils.sign(x - self.owner.x );
iY = Utils.sign(y - self.owner.y );
res=Point();
res.x = iX;
res.y = iY;
# DEBUG LINES
# print "Proposed %s"%(str(res));
# raw_input();
return res;
# Returns a score (~probability) to move towards a foe
def moveTowardsFoe(self, foe):
hpRatio = log(self.owner.hp / foe.hp);
attackRatio = log(self.owner.attack / foe.attack);
defenceRatio = log(self.owner.defence / foe.defence);
# The tendency as a ratio of exponential functions
# An value of 3 in the sum of (log) ratios is almost certainty
# that we should move closer.
return exp(hpRatio + attackRatio + defenceRatio) / exp(3);