-
Notifications
You must be signed in to change notification settings - Fork 128
/
helpers.js
249 lines (195 loc) · 9.05 KB
/
helpers.js
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
var helpers = {};
// Returns false if the given coordinates are out of range
helpers.validCoordinates = function (board, distanceFromTop, distanceFromLeft) {
return (!(distanceFromTop < 0 || distanceFromLeft < 0 ||
distanceFromTop > board.lengthOfSide - 1 || distanceFromLeft > board.lengthOfSide - 1));
};
// Returns the tile [direction] (North, South, East, or West) of the given X/Y coordinate
helpers.getTileNearby = function (board, distanceFromTop, distanceFromLeft, direction) {
// These are the X/Y coordinates
var fromTopNew = distanceFromTop;
var fromLeftNew = distanceFromLeft;
// This associates the cardinal directions with an X or Y coordinate
if (direction === 'North') {
fromTopNew -= 1;
} else if (direction === 'East') {
fromLeftNew += 1;
} else if (direction === 'South') {
fromTopNew += 1;
} else if (direction === 'West') {
fromLeftNew -= 1;
} else {
return false;
}
// If the coordinates of the tile nearby are valid, return the tile object at those coordinates
if (helpers.validCoordinates(board, fromTopNew, fromLeftNew)) {
return board.tiles[fromTopNew][fromLeftNew];
} else {
return false;
}
};
// Returns an object with certain properties of the nearest object we are looking for
helpers.findNearestObjectDirectionAndDistance = function (board, fromTile, tileCallback) {
// Storage queue to keep track of places the fromTile has been
var queue = [];
// Keeps track of places the fromTile has been for constant time lookup later
var visited = {};
// Variable assignments for fromTile's coordinates
var dft = fromTile.distanceFromTop;
var dfl = fromTile.distanceFromLeft;
// Stores the coordinates, the direction fromTile is coming from, and it's location
var visitInfo = [dft, dfl, 'None', 'START'];
// Just a unique way of storing each location we've visited
visited[dft + '|' + dfl] = true;
// Push the starting tile on to the queue
queue.push(visitInfo);
// While the queue has a length
while (queue.length > 0) {
// Shift off first item in queue
var coords = queue.shift();
// Reset the coordinates to the shifted object's coordinates
dft = coords[0];
dfl = coords[1];
// Loop through cardinal directions
var directions = ['North', 'East', 'South', 'West'];
for (var i = 0; i < directions.length; i++) {
// For each of the cardinal directions get the next tile...
var direction = directions[i];
// ...Use the getTileNearby helper method to do this
var nextTile = helpers.getTileNearby(board, dft, dfl, direction);
// If nextTile is a valid location to move...
if (nextTile) {
// Assign a key variable the nextTile's coordinates to put into our visited object later
var key = nextTile.distanceFromTop + '|' + nextTile.distanceFromLeft;
var isGoalTile = false;
try {
isGoalTile = tileCallback(nextTile);
} catch (err) {
isGoalTile = false;
}
// If we have visited this tile before
if (visited.hasOwnProperty(key)) {
// Do nothing--this tile has already been visited
// Is this tile the one we want?
} else if (isGoalTile) {
// This variable will eventually hold the first direction we went on this path
var correctDirection = direction;
// This is the distance away from the final destination that will be incremented in a bit
var distance = 1;
// These are the coordinates of our target tileType
var finalCoords = [nextTile.distanceFromTop, nextTile.distanceFromLeft];
// Loop back through path until we get to the start
while (coords[3] !== 'START') {
// Haven't found the start yet, so go to previous location
correctDirection = coords[2];
// We also need to increment the distance
distance++;
// And update the coords of our current path
coords = coords[3];
}
// Return object with the following pertinent info
var goalTile = nextTile;
goalTile.direction = correctDirection;
goalTile.distance = distance;
goalTile.coords = finalCoords;
return goalTile;
// If the tile is unoccupied, then we need to push it into our queue
} else if (nextTile.type === 'Unoccupied') {
queue.push([nextTile.distanceFromTop, nextTile.distanceFromLeft, direction, coords]);
// Give the visited object another key with the value we stored earlier
visited[key] = true;
}
}
}
}
// If we are blocked and there is no way to get where we want to go, return false
return false;
};
// Returns the direction of the nearest non-team diamond mine or false, if there are no diamond mines
helpers.findNearestNonTeamDiamondMine = function (gameData) {
var hero = gameData.activeHero;
var board = gameData.board;
// Get the path info object
var pathInfoObject = helpers.findNearestObjectDirectionAndDistance(board, hero, function (mineTile) {
if (mineTile.type === 'DiamondMine') {
if (mineTile.owner) {
return mineTile.owner.team !== hero.team;
} else {
return true;
}
} else {
return false;
}
}, board);
// Return the direction that needs to be taken to achieve the goal
return pathInfoObject.direction;
};
// Returns the nearest unowned diamond mine or false, if there are no diamond mines
helpers.findNearestUnownedDiamondMine = function (gameData) {
var hero = gameData.activeHero;
var board = gameData.board;
// Get the path info object
var pathInfoObject = helpers.findNearestObjectDirectionAndDistance(board, hero, function (mineTile) {
if (mineTile.type === 'DiamondMine') {
if (mineTile.owner) {
return mineTile.owner.id !== hero.id;
} else {
return true;
}
} else {
return false;
}
});
// Return the direction that needs to be taken to achieve the goal
return pathInfoObject.direction;
};
// Returns the nearest health well or false, if there are no health wells
helpers.findNearestHealthWell = function (gameData) {
var hero = gameData.activeHero;
var board = gameData.board;
// Get the path info object
var pathInfoObject = helpers.findNearestObjectDirectionAndDistance(board, hero, function (healthWellTile) {
return healthWellTile.type === 'HealthWell';
});
// Return the direction that needs to be taken to achieve the goal
return pathInfoObject.direction;
};
// Returns the direction of the nearest enemy with lower health
// (or returns false if there are no accessible enemies that fit this description)
helpers.findNearestWeakerEnemy = function (gameData) {
var hero = gameData.activeHero;
var board = gameData.board;
// Get the path info object
var pathInfoObject = helpers.findNearestObjectDirectionAndDistance(board, hero, function (enemyTile) {
return enemyTile.type === 'Hero' && enemyTile.team !== hero.team && enemyTile.health < hero.health;
});
// Return the direction that needs to be taken to achieve the goal
// If no weaker enemy exists, will simply return undefined, which will
// be interpreted as "Stay" by the game object
return pathInfoObject.direction;
};
// Returns the direction of the nearest enemy
// (or returns false if there are no accessible enemies)
helpers.findNearestEnemy = function (gameData) {
var hero = gameData.activeHero;
var board = gameData.board;
// Get the path info object
var pathInfoObject = helpers.findNearestObjectDirectionAndDistance(board, hero, function (enemyTile) {
return enemyTile.type === 'Hero' && enemyTile.team !== hero.team;
});
// Return the direction that needs to be taken to achieve the goal
return pathInfoObject.direction;
};
// Returns the direction of the nearest friendly champion
// (or returns false if there are no accessible friendly champions)
helpers.findNearestTeamMember = function (gameData) {
var hero = gameData.activeHero;
var board = gameData.board;
// Get the path info object
var pathInfoObject = helpers.findNearestObjectDirectionAndDistance(board, hero, function (heroTile) {
return heroTile.type === 'Hero' && heroTile.team === hero.team;
});
// Return the direction that needs to be taken to achieve the goal
return pathInfoObject.direction;
};
module.exports = helpers;