String and Int Array Sorting - javascript

I've got a problem sorting arrays. I'm currently trying to optimize a thing in a strategy game I play, and for that I need to calculate distance between all members of my alliance, the first towards the others and so on. No problem doing that actually. But now, what I want to do is sort the array of distance "ascending" and problem is, I need to write the corresponding nickname to match the distance. I've been searching for 2 days and I can't figure out a working solution.
I tried to copy the array before sorting it, but I need the unsorted array and with that sort function, it sorts the copy too !
Actually the code provided is good, speaking of distance accuracy but not sorted ascending. If I sort the distances, the nicknames are no longer corresponding. I don't know why they appear in the order of the pseudo_list because It's supposed to be sorted through nSort2()
This is what I've ended up with so far :
//Sorting Distance[i] Array List
function nSort(arr)
{
return arr.sort((a, b) => a - b);
}
//Calculating Distance
function calcDist(xA, yA, xB, yB)
{
return Math.sqrt(Math.pow((xB-xA), 2)+Math.pow((yB-yA), 2));
}
//Here i'm trying to retrieved unsorted position of distance by index to sort the nicknames by their respective distances
function nSort2(arr_str, arr_nbr)
{
var arr_nbr2 = arr_nbr.splice(0);
var arr_sort = nSort(arr_nbr2);
var str_sort = [];
arr_str.forEach(function(element, i)
{
j = arr_sort.indexOf(arr_nbr2[i], i);
str_sort[i] = arr_str[j];
});
console.log(str_sort);
return str_sort;
}
var pseudo_list = ["teddy95", "gabrielc", "ngozi"]; //The list (I just put the first 3 to not to write to much unnecessary code)
var x_ = [29, 26, 4]; // The X Coordinate list
var y_ = [519, 461, 143]; // The Y Coordinate list
var distance = [[]]; // The 2D Array for distance (distance[0][0] being the member's distance tower himself (which is obviously 0).
//Calculating Distances And Storing them in the 2D Array
y_.forEach(function(element, i)
{
distance[i] = [];
x_.forEach(function(element, j)
{
distance[i][j] = Math.ceil(calcDist(x_[i], y_[i], x_[j], y_[j]));
});
});
//Displaying Sorted Array ascending (Trying)
y_.forEach(function(element, i)
{
x_.forEach(function(element, j)
{
document.write(pseudo_list[i] + ' -> ' + nSort2(pseudo_list, distance[i])[j] + ': ' + distance[i][j] + '<br>');
});
});

I think your problem come from over complicating the data structures (I'm not insulting you just sharing an opinion).
In the code below all the input (pseudo, x, y) is stored in an object so player data is easier to manipulate.
Then I'm not using a matrix because you end up creating new issues namely I'd expect distance[1][2] = distance[2][1] so sorting will create duplicate results (and the diagonal doesn't help since it represents the distance from yourself). Instead I have a 1D array constructed with no duplicates, i.e. it contains the distance from the first element to all the others (i.e. second, third, ...), then the second element from the "ones on the right" (i.e. third, fourth, ...), ...
Once you have all the distance information, sorting is a trivial task so is displaying the result.
//Calculating Distance
function calcDist(xA, yA, xB, yB) {
return Math.sqrt(Math.pow((xB - xA), 2) + Math.pow((yB - yA), 2));
}
let players = [{
pseudo: "teddy95",
x: 29,
y: 519
},
{
pseudo: "gabrielc",
x: 26,
y: 461
},
{
pseudo: "ngozi",
x: 4,
y: 143
}]
let distances = []
players.forEach(function (element, i) {
for (let j = i + 1; j < players.length; ++j) {
distances.push({
player1: element,
player2: players[j],
distance: Math.ceil(calcDist(element.x, element.y, players[j].x, players[j].y))
})
}
})
distances.sort(function (a, b) { return a.distance - b.distance })
distances.forEach(function (element, i) {
document.write(element.player1.pseudo + ' - ' + element.player2.pseudo + ' dist ' + element.distance + '<br>')
})

Related

Which algorithm should be used to find the point?

You need to find some unknown, predetermined point in three-dimensional space, in the smallest number of attempts, using only a function that can return the distance from
any point you pass to it to the desired unknown point.
To solve the problem, first implement a function f that, by taking the coordinates of any point s(x, y, z), return the distance between that point and a conditionally unknown, randomly generated point
point you arbitrarily generate r(x, y, z), where x, y, z can be integers between
0 и 100.
For example, for an arbitrarily generated point r(0, 0, 10) and a point passed to the function
s(0, 0, 0), the result of the function would be as follows:
f(s) = 10 // the distance between s(0, 0, 0) and r(0, 0, 10) is 10
Next, implement the algorithm itself for the assignment. The algorithm should find the coordinates of
of an arbitrarily generated point with the least number of calls to the function f.
I have a randomizer instead of an algorithm, that's all I got. Help.
const pointToFound = {
x: 12,
y: 9,
z: 76,
};
let attemts = 0;
let isXFound = false;
let isYFound = false;
let isZFound = false;
const pointHistory = [];
const getRandomPoint = () => {
return {
x: isXFound ? isXFound : Math.floor(Math.random() * 101),
y: isYFound ? isYFound : Math.floor(Math.random() * 101),
z: isZFound ? isZFound : Math.floor(Math.random() * 101),
};
};
const getDifference = (point, pointToCompare) => {
return {
x:
Math.max(point.x, pointToCompare.x) - Math.min(point.x, pointToCompare.x),
y:
Math.max(point.y, pointToCompare.y) - Math.min(point.y, pointToCompare.y),
z:
Math.max(point.z, pointToCompare.z) - Math.min(point.z, pointToCompare.z),
};
};
const condition = !isXFound && !isYFound && !isZFound;
while (condition) {
const point = getRandomPoint();
const difference = getDifference(point, pointToFound);
pointHistory.push(point);
attemts += 1;
if (isXFound && isYFound && isZFound) {
console.log("Total attempts: ", attemts);
console.log(point);
break;
}
if (difference.x === 0 && !isXFound) {
isXFound = point.x;
}
if (difference.y === 0 && !isYFound) {
isYFound = point.y;
}
if (difference.z === 0 && !isZFound) {
isZFound = point.z;
}
}
console.log(pointHistory);
I have a randomizer instead of an algorithm, that's all I got. Help.
This can be done with at most 3 guesses and often with 2 guesses:
Let the first guess be [0, 0, 0], and ask for the distance
Find in the 100x100x100 cube all points that have that distance to [0, 0, 0]. There might be around 100-200 points that have that distance: consider all of these candidates.
Take the first candidate as the second guess and ask for the distance
Find among the other candidates the ones that have exactly that distance to the first candidate. Often there will be only one point that satisfies this condition. In that case we can return that candidate and only 2 guesses were necessary.
Otherwise (when there is more than one candidate remaining) repeat the previous step which will now certainly lead to a single point.
Here is an implementation that provides a blackbox function which chooses the secret point in a local variable, and which returns two functions: f for the caller to submit a guess, and report for the caller to verify the result of the algorithm and report on the number of guesses. This is not part of the algorithm itself, which is provided in the findPoint function.
const rnd = () => Math.floor(Math.random() * 101);
const distance = (a, b) =>
a.reduce((acc, x, i) => acc + (x - b[i]) ** 2, 0) ** 0.5;
function findPoint(f) {
// First guess is always the zero-point
let guess = [0, 0, 0];
let dist = f(guess);
if (dist === 0) return guess; // Extremely lucky!
// Find the points in the cube that have this distance to [0,0,0]
let candidates = [];
const limit = Math.min(100, Math.round(dist));
for (let x = 0; x <= limit; x++) {
const p = [x, limit, 0];
// Follow circle in X=x plane
while (p[1] >= 0 && p[2] <= limit) {
const d = distance(p, guess);
const diff = d - dist;
if (Math.abs(diff) < 1e-7) candidates.push([...p]);
if (diff >= 0) p[1]--;
else p[2]++;
}
}
// As long there are multiple candidates, continue with a guess
while (candidates.length > 1) {
const candidates2 = [];
// These guesses are taking the first candidate as guess
guess = candidates[0];
dist = f(guess);
if (dist === 0) return guess; // lucky!
for (const p of candidates) {
let d = distance(p, guess);
let diff = d - dist;
if (Math.abs(diff) < 1e-7) candidates2.push(p);
}
candidates = candidates2;
}
return candidates[0]; // Don't call f as we are sure!
}
function blackbox() {
const secret = [rnd(), rnd(), rnd()];
console.log("Secret", JSON.stringify(secret));
let guessCount = 0;
const f = guess => {
guessCount++;
const dist = distance(secret, guess);
console.log("Submitted guess " + JSON.stringify(guess) + " is at distance " + dist);
return dist;
};
const report = (result) => {
console.log("Number of guesses: " + guessCount);
console.log("The provided result is " + (distance(secret, result) ? "not" : "") + "correct");
}
return {f, report};
}
// Example run
const {f, report} = blackbox();
const result = findPoint(f);
console.log("Algorithm says the secret point is: " + JSON.stringify(result));
report(result);
Each run will generate a new secret point. When running this thousands of times it turns out that there is 1/9 probability that the algorithm needs a third guess. In the other 8/9 cases, the algorithm needs two guesses.
One idea is as follows:
You pick an initial random point, and for each dimension, find the exact value. How? For the sake of symmetry, suppose that you desire to find x of the target point. Increase by one the x, and compute the distance of the new point from the target point. If it goes further, it means that you should move in the opposite direction. Hence, you can run a binary search and get the distance to find the exact x of the target point. Otherwise, it means that you are going in the right direction along X-axis. So, do a binary search between all points with the same y and z such that their x values can change from x+1 to 100. A more formal solution comes in the following (just a pseudo-code).
You should also ask about the complexity of this solution. As the dimension of the point is constant (3) and checking these conditions take a constant time, the complexity of number of calling getDifference function is O(log(n)). What is n here? the length of valid range for coordinates (here is 100).
1. p: (x,y,z) <- Pick a random coordinate
2. dist: (dist_x, dist_y, dist_z) <- getDifference(p, TargetPoint)
3. For each dimension, do the following (i can be 0 (x), 1 (y), 2 (3)):
4. if(dist == 0):
5. isFound[i] <- p[i]
6. continue
7. new_i <- p[i] + 1
8. new_point <- p
9. new_point[i] <- new_i
10. new_dist <- getDifference(new_point, pointToFound)
11. if(new_dist == 0):
12. isFound[i] <- new_point[i];
13. continue
14. if(new_dist[i] > dist[i]):
15. isFound[i] <- binary_search for range [0, p[i]-1] to find the exact value of the pointToFound in dimension i
15. continue
16. else:
17. isFound[i] <- binary_search for range [p[i] + 1, 100] to find the exact value of the pointToFound in dimension i
18. continue
Following method will work for coordinates with positive or negative real values as well.
Let's say you are searching for the coordinates of point P. As the first query point, use origin O. Let the distance to the origin O be |PO|. At this point, you know that P is on the surface of sphere
(P.x)^2 + (P.y)^2 + (P.z)^2 = |PO|^2 (1)
As the second query point, use Q = (|PO|, 0, 0). Not likely but if you find the distance |PQ| zero, Q is the point you are looking for. Otherwise, you get another sphere equation, and you know that P is on the surface of this sphere as well:
(P.x - |PO|)^2 + (P.y)^2 + (P.z)^2 = |PQ|^2 (2)
Now, if you subtract (1) from (2), you get
(P.x - |PO|)^2 - (P.x)^2 = |PQ|^2 - |PO|^2 (3)
Since the only unknown in this equation is P.x you can get its value:
P.x = (((-|PQ|^2 + |PO|^2) / |PO|) + |PO|)/2)
Following similar steps, you can get P.y with R = (0, |PO|, 0) and P.z with S = (0, 0, |PO|). So, by using four query points O, Q, R, and S you can get the coordinates of P.

Javascript double nested for loop traversing

I am fairly new to JavaScript and I am trying to find a way to write this without using a double for loop by either using higher order function or data structures.
I have these two defined type here
List = {
'start' ? : Position
'end' ? : Position
}
Position = {
row?: number;
column?: number;
}
This is the for loop that I believe can be optimized or avoid using for loop for.
for (let row = list.start.row; row <= list.end.row; row++) {
for (let col = list.start.column; col <= list.end.column; col++) {
console.log(`row: ${row}, col: ${col}`);
}
}
So if the I have the list defined as
list.start.row = 2, list.start.column = 4
list.end.row = 3, list.start.column = 6
I should have (2,4) (2,5) (2,6) (3,4) (3,5) (3,6) output as the console messages and order does not matter. What would be the most optimal way of doing this? Thank you in advance!
You can absolutely do this with a single loop. In fact its a very common way to navigate multi dimensional arrays in memory. For example, you have a chunk of raw image data, and you want to get the pixel information at point(80,120). You'd have to be able to convert the (x,y) coordinates to some offset. This is trivial if you know the width of a row. To get the pixel information, assuming each pixel is 8 bits simply calculate i = y * width + x. You can use this same technique to create a multi dimensional array using one loop. You'd have to apply the above formula in reverse to find the (x,y) points from (i, width). Computing the width is easy, its the end.column - start.column and calculating the number of elements would be the height * width. The height is obviously the difference in rows. You would then loop through your entire linear domain and project the i back to (x,y) in your array.
It might be easier to just look at the sample code.
const list = {
start: { row: 2, column: 4 },
end: { row: 3, column: 6 }
};
const x0 = list.start.column;
const y0 = list.start.row;
const x1 = list.end.column;
const y1 = list.end.row;
const width = x1 - x0 + 1; // range is inclusive so [2,2] has a width of 1.
const height = y1 - y0 + 1; // same here.
const results = Array.from({ length: width * height }, (_, n) => {
const row = (n - n % width) / width + y0;
const column = n % width + x0;
return [row, column];
});
console.log(results);
Should you do it instead of a nested loop? Probably not in javascript. Complexity is still O(mn) and so its no faster algorithmically then a nested loop. The compiler/vm will likely optimize a [x,y] nested loop into something like this for you anyway.
It always will be a nested loop if you want to print all values of x for all values of y. You can use different syntax, such as forEach, but it'll always be the same concept - and the solution you have is actually the most optimal and efficient (as there'll always be xy combinations for x and y values; so if your time complexity is O(mn), it's fine).

JavaScript: function return closest value

I am trying to return the value of the closest object to my position in a function.
I tried to put the entities in a array and than I tried return closest object to my position with a for loop, but it did not work. How can I do this?
function getMyEntity() {
return Game.currentGame.world.localPlayer.entity.getFromTick();
}
function getOtherEntity() {
var MyPlayerEntity = getMyEntity();
var entities = Game.currentGame.world.entities;
for (var uid in entities) {
// how i get closest entity to my player entity here?
var gameObject = entities[uid].fromTick;
console.log(entities[uid].fromTick.position, MyPlayerEntity.position)
if (gameObject.entityClass == "Prop" && gameObject.uid !== MyPlayerEntity.uid) {
return gameObject;
}
}
}
function aimAssist() {
var MyPlayerEntity = getMyEntity();
var OtherEntity = getOtherEntity();
if (OtherEntity == undefined) return
var aimPosition = {
x: OtherEntity.position.x - MyPlayerEntity.position.x,
y: OtherEntity.position.y - MyPlayerEntity.position.y
}
return aimPosition;
}
I'll give you a bad advice, for now it'll work, as your game grows it will be bad because of O(n^2) complexity. Read a bit about quadtrees and see if you can do that. Meanwhile you can compare the euclidean distance, do not need to take the square root:
Object.keys(entities)
.map(function(d,i){
var dx = entities[d].fromTick.position.x - MyPlayerEntity.position.x,
dy = entities[d].fromTick.position.y - MyPlayerEntity.position.y,
result = {D:(dx * dx) + (dy + dy), obj:entities[d] , valueOf: function(){return this.D};
return result;
}).sort(function(a,b){
return a-b;
})[0].obj; //this returns the closest one
So your original function becomes this:
function getOtherEntity() {
var MyPlayerEntity = getMyEntity();
var entities = Game.currentGame.world.entities;
return Object.keys(entities)
.map(function(d,i){
var dx = entities[d].fromTick.position.x - MyPlayerEntity.position.x,
dy = entities[d].fromTick.position.y - MyPlayerEntity.position.y,
result = {D:(dx * dx) + (dy + dy), obj:entities[d] , valueOf: function(){return this.D};
return result;
}).sort(function(a,b){
return a-b;
})[0].obj; //this returns the closest one
}
I'd create an array of objects which contain the Object-ID and distance, and sort it by distance.
The first array-item is the closest to the player.
The array may look like
[{uid: 1234, distance: 12}, {uid: 1235, distance: 16}, ...]
You can sort arrays with arrayName.sort(sortingFunction)
assuming you can get x and y coordinates from gameObject.position and MyPlayerEntity.position you could use a bit of Pitagoras: c^2 = a^2 +b^2, with c being the distance
let a = gameObject.position.x - MyPlayerEntity.position.x;
let b = gameObject.position.y - MyPlayerEntity.position.y;
let distanceSquared = a*a + b*b;
Since you don't seem to need the exact distance and sqrt() is expensive, you can use the value in distanceSquared and other variables declared outside of the loop to keep track
let closestDistance;
let closest;
to make the proper comparisons
if(distanceSquared < closestDistance){
closestDistance = distanceSquared;
closest = gameObject;
}
After you loop through the array, the closest entity reference should be:
return closest;

JavaScript - Create a new method that finds the largest sum of consecutive entries in an Array

I need to create a method that finds the largest sum of consecutive entries in an array given a group size. It should take an array and the interval size as inputs and should return both the largest sum and the index of the first entry in the group.
For example, in the following Array [1,1,1,1,1,1,1,2] given a group size of 2 the result would be a maximum sum of 3 and a position of 6.
How would one Complete this?
Thanks!
Since you didn't post any code my answer will be general.
The easiest way will be to loop through the array and finding sum of current digit with n consecutive digits, up until the currentDigitIndex<=array.length-n, in this loop you should compare currentDigitSum with the currentMaxSum and store which ever is larger in the currentMaxSum (also store the maxSumPositionIndex).
While solving this problem you should account for a things like: what if array length is equal to 1 or 0, what if an array has negative integers, what if group size will be larger than array length, what if your array has 2 or 3 equally large sums...
Here is an answer I came up with. It works in MOST scenerios, not all, therefore the answer can be improved on.
Array.prototype.maxGroupOf = function (size) {
max = -Infinity;
indexSpot = 0;
len = this.length - size + 1;
add = function (x, y) {
return x + y;
};
this.forEach(function (x, y) {
if (y > len) return;
b = this.slice(y, y + size).reduce(add, 0);
if (b > max) {
max = b;
indexSpot = y;
}
}, this);
return {
sum: max,
position: indexSpot
};
};
console.log([1, 1, 1, 1, 1, 1, 1, 2].maxGroupOf(2));
---Output---
Object {sum: 3, position: 6}

Knapsack - determining set from total value

After seeing this lecture I created the following knapsack code. In the lecture, the professor says it will be easy to determine the set from the optimal value (minute 19:00), however I can not find how to do it. I provide an example in the code which sums the values to 21, how can I determine the set (in this case 12, 7, 2) from this value?
/*
v = value
w = weight
c = capacity
*/
function knapsack(v, w, c) {
var n = v.length,
table = [];
// create two-dimensional array to hold values in memory
while (table.length <= c) {
table.push([]);
}
return ks(c, 0);
function ks(c, i) {
if (i >= n) {
table[c][i] = 0;
return table[c][i];
}
if (c < w[i]) {
if (table[c][i+1] === undefined) {
table[c][i + 1] = ks(c, i + 1);
}
return table[c][i + 1];
}
else {
if (table[c][i + 1] === undefined) {
table[c][i + 1] = ks(c, i + 1);
}
if (table[c - w[i]][i + 1] === undefined) {
table[c - w[i]][i + 1] = ks(c - w[i], i + 1);
}
return Math.max(table[c][i + 1], v[i] + table[c - w[i]][i + 1]);
}
}
}
//This is a test case
var v = [7, 2, 1, 6, 12];
var w = [3, 1, 2, 4, 6];
var c = 10;
var result = knapsack(v, w, c);
document.getElementById("solution").innerHTML = result;
<pre>Optimal solution value is: <span id="solution"></span></pre>
That's not easy at all. Determining whether a subset of some set of numbers has a certain sum is known as the subset sum problem, and it is NP-complete, just like knapsack itself. It would be a lot easier to just keep pointers to the solution of the subproblem from which you constructed the optimal solution to a larger subproblem. That way you can just walk back along the pointers from the globally optimal solution to find the actual set that gave you the optimal value.
(EDIT: as noted in the comments by j_random_hacker, once we have the DP table, we can actually determine the set that gave the optimal value in O(n2) time, by starting from the optimal solution and working backwards through the table, consider each possible item that could have been the last item added and checking if that solution matches the expected value.)
On a different note, I'd recommend watching some different lectures. The guy makes some strange claims, like that O(nc) -- n number of items, c capacity -- is much less than O(2n), which is simply not true when c is large. (In fact, this is called a pseudo-polynomial time solution, and it is still exponential in the length of the input, measured in bits.)

Categories

Resources