Mutating elements in an array in Javascript - javascript

Ok so I want to subtract 9 to numbers(elements in an array) over 9:
finalCredDigits = [10, 8, 18, 9, 16, 6, 16, 5, 14, 3, 14, 6, 10, 5, 8]
Thats what I tried
finalCredDigits.forEach(arr =>{
if(arr > 9){
finalCredDigits.push(arr - 9);
}
});
Output = [10, 8, 18, 9, 16, 6, 16, 5, 14, 3, 14, 6, 10, 5, 8, 1, 9, 7, 7, 5, 5, 1]
I know its cuz the result is being pushed in the array but i want to mutate it and replace the answer with numbers over 9

If you want a similar but new array, you should use Array.map():
const finalCredDigits = [10, 8, 18, 9, 16, 6, 16, 5, 14, 3, 14, 6, 10, 5, 8];
const newFinalCredDigits = finalCredDigits.map(v => {
if (v > 9) {
return v - 9;
} else {
return v;
}
});
console.log(newFinalCredDigits.join());
console.log("Is new array?", newFinalCredDigits !== finalCredDigits);
If you want to mutate the array itself with Array.forEach(), you should use the callback's additional parameters:
const finalCredDigits = [10, 8, 18, 9, 16, 6, 16, 5, 14, 3, 14, 6, 10, 5, 8];
finalCredDigits.forEach((v, i, array) => {
if (v > 9) {
array[i] = v - 9;
}
});
console.log(finalCredDigits.join());
But functional programming usually implies preferring immutable over mutable states, so if your array is shared and we'd mutate it with Array.forEach(), it would be considered a code smell. Therefore I'd use a regular for-loop instead:
const finalCredDigits = [10, 8, 18, 9, 16, 6, 16, 5, 14, 3, 14, 6, 10, 5, 8];
{
const l = finalCredDigits.length;
for (let i = 0; i < l; ++i) {
if (finalCredDigits[i] > 9) finalCredDigits[i] -= 9;
}
}
console.log(finalCredDigits.join());

You need to assign to the array index to replace the element, not push a new element.
forEach() passes a second argument to the callback function, containing the current index. You can use this for the assignment.
const finalCredDigits = [10, 8, 18, 9, 16, 6, 16, 5, 14, 3, 14, 6, 10, 5, 8];
finalCredDigits.forEach((el, i) =>{
if(el > 9){
finalCredDigits[i] = el - 9;
}
});
console.log(finalCredDigits);

Try this
let finalCredDigits = [10, 8, 18, 9, 16, 6, 16, 5, 14, 3, 14, 6, 10, 5, 8]
finalCredDigits = finalCredDigits.map(number => {
if (number > 9) {
return number - 9
}
return number
})
console.log(finalCredDigits)

Related

array doesn't push expected element

I'm learning JavaScript and having this problem. Basically I have to check for invalid credit cards number
// All valid credit card numbers
const valid1 = [4, 5, 3, 9, 6, 7, 7, 9, 0, 8, 0, 1, 6, 8, 0, 8]
const valid2 = [5, 5, 3, 5, 7, 6, 6, 7, 6, 8, 7, 5, 1, 4, 3, 9]
const valid3 = [3, 7, 1, 6, 1, 2, 0, 1, 9, 9, 8, 5, 2, 3, 6]
const valid4 = [6, 0, 1, 1, 1, 4, 4, 3, 4, 0, 6, 8, 2, 9, 0, 5]
const valid5 = [4, 5, 3, 9, 4, 0, 4, 9, 6, 7, 8, 6, 9, 6, 6, 6]
// All invalid credit card numbers
const invalid1 = [4, 5, 3, 2, 7, 7, 8, 7, 7, 1, 0, 9, 1, 7, 9, 5]
const invalid2 = [5, 7, 9, 5, 5, 9, 3, 3, 9, 2, 1, 3, 4, 6, 4, 3]
const invalid3 = [3, 7, 5, 7, 9, 6, 0, 8, 4, 4, 5, 9, 9, 1, 4]
const invalid4 = [6, 0, 1, 1, 1, 2, 7, 9, 6, 1, 7, 7, 7, 9, 3, 5]
const invalid5 = [5, 3, 8, 2, 0, 1, 9, 7, 7, 2, 8, 8, 3, 8, 5, 4]
// Can be either valid or invalid
const mystery1 = [3, 4, 4, 8, 0, 1, 9, 6, 8, 3, 0, 5, 4, 1, 4]
const mystery2 = [5, 4, 6, 6, 1, 0, 0, 8, 6, 1, 6, 2, 0, 2, 3, 9]
const mystery3 = [6, 0, 1, 1, 3, 7, 7, 0, 2, 0, 9, 6, 2, 6, 5, 6, 2, 0, 3]
const mystery4 = [4, 9, 2, 9, 8, 7, 7, 1, 6, 9, 2, 1, 7, 0, 9, 3]
const mystery5 = [4, 9, 1, 3, 5, 4, 0, 4, 6, 3, 0, 7, 2, 5, 2, 3]
// An array of all the arrays above
const batch = [valid1, valid2, valid3, valid4, valid5, invalid1, invalid2, invalid3, invalid4, invalid5, mystery1, mystery2, mystery3, mystery4, mystery5]
The validity of a credit card is accessed by this algorithm (Luhn algorithm):
function validateCred(card_number){
let sum = card_number[card_number.length-1];
let flag = 1;
for (i = card_number.length-2; i >= 0; i--){
if (flag % 2 !== 0){
card_number[i] *= 2;
if (card_number[i] > 9){
card_number[i] -= 9;
}
}
sum += card_number[i];
flag++;
}
if (sum % 10 === 0){
return true;
} else {
return false;
}
}
And I have to create an array with all the invalid cards:
function findInvalidCards(numbers){
let invalid_array = [];
for (i = 0; i < numbers.length; i++){
if (!validateCred(numbers[i])){
invalid_array.push(numbers[i]);
}
}
return invalid_array;
}
When I call the findInValidCards function, it raises the heap out of memory error, I tried to follow the solution from this link and raise the usage memory to 8gb but the problem persists. After debugging, I found out that this line invalid_array.push(numbers[i]) actually appends a undefined variable to the array, not the element that I wanted. What could possibly cause this problem?
As Nina had said in the comments, you should be defining i with let each time you're writing the for loop or else you're going to have unpredictable behavior
However, you also had an issue in your validateCred function where you were mutating the original Array while checking it - you can simply clone the input Array with let clone = card_number.slice(0);, and then reference clone for your checks
Also, you can simplify findInvalidCards by using .filter(), like:
function findInvalidCards(numbers) {
return numbers.filter(x => !validateCred(x));
}
// All valid credit card numbers
const valid1 = [4, 5, 3, 9, 6, 7, 7, 9, 0, 8, 0, 1, 6, 8, 0, 8];
const valid2 = [5, 5, 3, 5, 7, 6, 6, 7, 6, 8, 7, 5, 1, 4, 3, 9];
const valid3 = [3, 7, 1, 6, 1, 2, 0, 1, 9, 9, 8, 5, 2, 3, 6];
const valid4 = [6, 0, 1, 1, 1, 4, 4, 3, 4, 0, 6, 8, 2, 9, 0, 5];
const valid5 = [4, 5, 3, 9, 4, 0, 4, 9, 6, 7, 8, 6, 9, 6, 6, 6];
// All invalid credit card numbers
const invalid1 = [4, 5, 3, 2, 7, 7, 8, 7, 7, 1, 0, 9, 1, 7, 9, 5];
const invalid2 = [5, 7, 9, 5, 5, 9, 3, 3, 9, 2, 1, 3, 4, 6, 4, 3];
const invalid3 = [3, 7, 5, 7, 9, 6, 0, 8, 4, 4, 5, 9, 9, 1, 4];
const invalid4 = [6, 0, 1, 1, 1, 2, 7, 9, 6, 1, 7, 7, 7, 9, 3, 5];
const invalid5 = [5, 3, 8, 2, 0, 1, 9, 7, 7, 2, 8, 8, 3, 8, 5, 4];
// Can be either valid or invalid
const mystery1 = [3, 4, 4, 8, 0, 1, 9, 6, 8, 3, 0, 5, 4, 1, 4];
const mystery2 = [5, 4, 6, 6, 1, 0, 0, 8, 6, 1, 6, 2, 0, 2, 3, 9];
const mystery3 = [6, 0, 1, 1, 3, 7, 7, 0, 2, 0, 9, 6, 2, 6, 5, 6, 2, 0, 3];
const mystery4 = [4, 9, 2, 9, 8, 7, 7, 1, 6, 9, 2, 1, 7, 0, 9, 3];
const mystery5 = [4, 9, 1, 3, 5, 4, 0, 4, 6, 3, 0, 7, 2, 5, 2, 3];
// An array of all the arrays above
const batch = [valid1, valid2, valid3, valid4, valid5, invalid1, invalid2, invalid3, invalid4, invalid5, mystery1, mystery2, mystery3, mystery4, mystery5];
function validateCred(card_number) {
let clone = card_number.slice(0);
let sum = clone[clone.length - 1];
let flag = 1;
for (i = clone.length - 2; i >= 0; i--) {
if (flag % 2 !== 0) {
clone[i] *= 2;
if (clone[i] > 9) {
clone[i] -= 9;
}
}
sum += clone[i];
flag++;
}
if (sum % 10 === 0) {
return true;
} else {
return false;
}
};
// And I have to create an array with all the invalid cards:
function findInvalidCards(numbers) {
let invalid_array = [];
for (let i = 0; i < numbers.length; i++) {
if (!validateCred(numbers[i])) {
invalid_array.push(numbers[i]);
}
}
return invalid_array;
}
let invalidCardArray = findInvalidCards(batch);
// Prettier console.log()
invalidCardArray.forEach(x => console.log(validateCred(x) + ':', ...x));
The i variable is defined as global if you don't define it with var or let. So when it starts from findInvalidCards function the i value is zero but when it access the validateCred function, the i value changes.So when it will finish from validateCred function, i value will be -1 and it will try to increment it in findInvalidCards for loop and i value will be zero.That will happen over and over again,it will go in infinite loop causing the memory exception and everything crashes.
I have debug your code, so i know how it goes. :)
function findInvalidCards(numbers){
let invalid_array = [];
//make i local variable by defining it let or var, otherwise it will be global
for (var i = 0; i < numbers.length; i++){
if (!validateCred(numbers[i])){
invalid_array.push(numbers[i]);
}
}
return invalid_array;
}
function validateCred(card_number){
let sum = card_number[card_number.length-1];
let flag = 1;
//make i local variable by defining it let or var, otherwise it will be global
for (var i = card_number.length-2; i >= 0; i--){
if (flag % 2 !== 0){
card_number[i] *= 2;
if (card_number[i] > 9){
card_number[i] -= 9;
}
}
sum += card_number[i];
flag++;
}
if (sum % 10 === 0){
return true;
} else {
return false;
}
}

How to loop 2D array in a anti-clock wise fashion?

Given a 2D array of m x n dimension, how can I loop through them in anti-clockwise fashion?
For example:
matrix = [
[ 1, 2, 3, 4 ],
[ 5, 6, 7, 8 ],
[ 9, 10, 11, 12 ],
[ 13, 14, 15, 16 ]
]
1st loop: 1, 5, 9, 13, 14, 15, 16, 12, 8, 4, 3, 2
2nd loop: 6, 10, 11, 7, 6
I really don't mind if the implementation is given in ruby or js
My current solution is like this:
(1..rotate).each do
bottom_left_corner = i
top_right_corner = j
start_nth_layer = 1; end_nth_layer = matrix.length - 2
matrix.reverse_each do
matrix[bottom_left_corner].unshift(matrix[bottom_left_corner - 1].shift) if bottom_left_corner > 0
matrix[top_right_corner] << matrix[top_right_corner + 1].pop if top_right_corner < matrix.length - 1
bottom_left_corner -= 1; top_right_corner += 1
end
nth_layer(matrix, start_nth_layer, end_nth_layer)
end
Update
The output doesn't format doesn't matter, as long as it outputs the correct order.
Purpose of the problem
The purpose of this problem is traverse these arrays anti-clockwise, layer by layer, until no more layers. For each traversal, we shift the values in anti-clockwise. For example:
Iteration 1: Iteration 2: Iteration 3:
============== ============= ==============
1 2 3 4 2 3 4 8 3 4 8 12
5 6 7 8 1 7 11 12 2 11 10 16
9 10 11 12 => 5 6 10 16 => 1 7 6 15
13 14 15 16 9 13 14 15 5 9 13 14
This is Matrix Layer Rotation problem. Here is my full solution:
function matrixRotation(matrix, rotate) {
var r = matrix.length, c = matrix[0].length;
var depth = Math.min(r,c)/2;
for(var i=0;i<depth;i++) {
var x = i, y = i, n = (r-i*2 - 2)*2 + (c-i*2-2)*2+4, dir = 'down', index=0;
var buf = [];
while(index < n) {
buf.push(matrix[x][y]);
if(dir == 'down') {
if(x+1 >= r-i) {
dir = 'right';
y++;
} else {
x++;
}
} else if(dir == 'right') {
if(y+1 >= c-i) {
dir = 'up';
x--;
} else {
y++;
}
} else if(dir == 'up') {
if(x-1 <= i-1) {
dir = 'left';
y--;
} else {
x--;
}
} else if(dir == 'left') {
y--;
}
index++;
}
var move = rotate%n;
buf = [...buf.slice(buf.length-move), ...buf.slice(0, buf.length-move)]
x = i, y = i, dir = 'down', index = 0;
while(index < n) {
matrix[x][y] = buf[index];
if(dir == 'down') {
if(x+1 >= r-i) {
dir = 'right';
y++;
} else {
x++;
}
} else if(dir == 'right') {
if(y+1 >= c-i) {
dir = 'up';
x--;
} else {
y++;
}
} else if(dir == 'up') {
if(x-1 <= i-1) {
dir = 'left';
y--;
} else {
x--;
}
} else if(dir == 'left') {
y--;
}
index++;
}
}
matrix.map(row => console.log(row.join(' ')));
}
const matrix = [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12], [13, 14, 15, 16]]
// rotate count
const r = 3
matrixRotation(matrix, r);
This approach should support any sizes of matrix and matrix[n]. Give it a try with various test cases if this works for you.
Note that I ignore any performance defects here.
var arr = [
[ 1, 2, 3, 4 ],
[ 5, 6, 7, 8 ],
[ 9, 10, 11, 12 ],
[ 13, 14, 15, 16 ]
],
result = [];
while ( arr.flat().length ) {
var res = [];
// 1. Left side
arr.forEach(x => res = res.concat( x.splice(0, 1) ));
// 2. Bottom side
if (arr.length) {
res = res.concat( ...arr.splice(arr.length - 1, 1) );
}
// 3. Right side
var tmp = [];
if (arr.flat().length) {
arr.forEach(x => tmp.push( x.splice(arr.length - 1, 1) ));
res = res.concat( ...tmp.reverse() );
}
// 4. Top side
if (arr.length) {
tmp = [].concat( ...arr.splice(0, 1) );
res = res.concat( tmp.reverse() );
}
result.push(res);
}
console.log(result);
I would write this in a layered fashion, writing matrix transposition logic (that is, flipping a matrix over the northwest-southeast diagonal), using that and a simple reverse to build a counter-clockwise rotation of the matrix, using that rotation to build a clockwise spiral, and finally using transpose again alongside the clockwise spiral to build a counter-clockwise spiral.
I chose this order because a clockwise spiral is more commonly requested, but it would be easy enough to build the counterclockwise spiral directly. Hint: rotateClockwise = m => transpose(reverse(m)).
const reverse = a => [...a].reverse();
const transpose = m => m[0].map((c, i) => m.map(r => r[i]))
const rotateCounter = m => reverse(transpose(m))
const spiralClockwise = m => m.length < 2
? m[0]
: m[0].concat(spiralClockwise(rotateCounter(m.slice(1))))
const spiralCounter = m => spiralClockwise(transpose(m))
console.log(spiralCounter([
[1, 2, 3, 4],
[5, 6, 7, 8],
[9, 10, 11, 12]
]))
Note that the intermediate functions here are quite possibly useful in their own right. So this strikes me as a good way to break down the problem.
This is how I went about it in ruby:
def counter_clockwise!(arr)
return arr if arr.size <= 1
rotation = [
arr.map(&:shift)
.concat(arr.pop,
arr.map(&:pop).reverse,
arr.shift.reverse).compact
]
rotation.push(*send(__method__,arr)) unless arr.all?(&:empty?)
rotation
end
def counter_clockwise(arr)
counter_clockwise!(arr.map(&:dup))
end
Example:
arr = [
[ 1, 2, 3, 4 ],
[ 5, 6, 7, 8 ],
[ 9, 10, 11, 12 ],
[ 13, 14, 15, 16 ],
[ 17, 18, 19, 20 ],
[ 21, 22, 23, 24 ]
]
counter_clockwise(arr)
#=> [[1, 5, 9, 13, 17, 21, 22, 23, 24, 20, 16, 12, 8, 4, 2, 3],
# [6, 10, 14, 18, 19, 15, 11, 7]]
This method recursively processes the outside edges into groups ("Loops" in your original post). Obviously if you just wanted the counter clockwise spiral without the groups you could flatten the return value.
This will also process non M x N Matrices such as:
arr = [
[ 1, 2, 3, 4 , 72 ],
[ 5, 6, 7, 8 , 73 ],
[ 9, 10, 11 , 12 ],
[ 13, 14, 16 , 75 ],
[ 17, 18, 19, 20 , 76 ],
[ 21, 22, 23, 24 , 77 ]
]
counter_clockwise(arr)
#=> [[1, 5, 9, 13, 17, 21, 22, 23, 24, 77, 76, 75, 12, 73, 72, 4, 3, 2],
# [6, 10, 14, 18, 19, 20, 16, 11, 8, 7]]
If you want each edge and can guarantee M x N then this will work too
def counter_clockwise_edges(arr)
return arr if arr.size == 1
arr = arr.transpose
[arr.shift].push(*send(__method__,arr.map(&:reverse)))
end
counter_clockwise_edges(arr)
#=> [[1, 5, 9, 13, 17, 21],
[22, 23, 24],
[20, 16, 12, 8, 4],
[3, 2],
[6, 10, 14, 18],
[19, 15, 11, 7]]
The following is a modification of my answer to this SO question, which differs from this one only in that the array is traversed in the opposite direction.
arr = matrix.map(&:dup).transpose
out = []
loop do
out = out + arr.shift
break out if arr.empty?
arr = arr.transpose.reverse
end
#=> [1, 5, 9, 13, 14, 15, 16, 12, 8, 4, 3, 2, 6, 10, 11, 7]
The steps are as follows.
arr = matrix.map(&:dup).transpose
#=> [[1, 5, 9, 13], [2, 6, 10, 14], [3, 7, 11, 15], [4, 8, 12, 16]]
I've duped the elements of matrix so that the latter will not be mutated.
out = []
out = out + arr.shift
#=> [1, 5, 9, 13]
arr
#=> [[2, 6, 10, 14], [3, 7, 11, 15], [4, 8, 12, 16]]
arr = arr.transpose.reverse
#=> [[14, 15, 16], [10, 11, 12], [6, 7, 8], [2, 3, 4]]
out = out + arr.shift
#=> [1, 5, 9, 13, 14, 15, 16]
arr
#=> [[10, 11, 12], [6, 7, 8], [2, 3, 4]]
arr = arr.transpose.reverse
#=> [[12, 8, 4], [11, 7, 3], [10, 6, 2]]
out = out + arr.shift
#=> [1, 5, 9, 13, 14, 15, 16, 12, 8, 4]
arr
#=> [[11, 7, 3], [10, 6, 2]]
arr = arr.transpose.reverse
#=> [[3, 2], [7, 6], [11, 10]]
out = out + arr.shift
#=> [1, 5, 9, 13, 14, 15, 16, 12, 8, 4, 3, 2]
arr
#=> [[7, 6], [11, 10]]
arr = arr.transpose.reverse
#=> [[6, 10], [7, 11]]
out = out + arr.shift
#=> [1, 5, 9, 13, 14, 15, 16, 12, 8, 4, 3, 2, 6, 10]
arr
#=> [[7, 11]]
arr = arr.transpose.reverse
#=> [[11], [7]]
out = out + arr.shift
#=> [1, 5, 9, 13, 14, 15, 16, 12, 8, 4, 3, 2, 6, 10, 11]
arr
#=> [[7]]
arr = arr.transpose.reverse
#=> [[7]]
out = out + arr.shift
#=> [1, 5, 9, 13, 14, 15, 16, 12, 8, 4, 3, 2, 6, 10, 11, 7]
arr
#=> []
As arr is now empty we break and return out.
arr
arr = arr.transpose.reverse
out = out + arr.shift
arr
arr = arr.transpose.reverse
out = out + arr.shift
arr
arr = arr.transpose.reverse
out = out + arr.shift
arr
arr = arr.transpose.reverse
out = out + arr.shift
arr
arr = arr.transpose.reverse
out = out + arr.shift
arr
arr = arr.transpose.reverse
Given the array:
array =
[
[ '00', '01', '02', '03', '04', '05'],
[ '10', '11', '12', '13', '14', '15'],
[ '20', '21', '22', '23', '24', '25'],
[ '30', '31', '32', '33', '34', '35']
]
This returns the external loop:
external_ccw_round = [array.map(&:shift), array.pop, array.map(&:pop).reverse, array.shift.reverse].flatten
#=> ["00", "10", "20", "30", "31", "32", "33", "34", "35", "25", "15", "05", "04", "03", "02", "01"]
Leaving just the core
array #=> [["11", "12", "13", "14"], ["21", "22", "23", "24"]]
For matrix with more than one row.
This is a method with a recursive implementation
Works on any matrix 2D.
def ccw_scan(array, result=[])
return array if array.size <= 1
result << [array.map(&:shift), array.pop, array.map(&:pop).reverse, array.shift.reverse]
if array.size >= 2
then ccw_scan(array, result)
else result << array
end
result.flatten.compact
end
Call the method on the array:
ccw_scan(array)
#=> ["00", "10", "20", "30", "31", "32", "33", "34", "35", "25", "15", "05", "04", "03", "02", "01", "11", "21", "22", "23", "24", "14", "13", "12"]

Restructure one dimensional array into variable length two dimension array

I am trying to convert a one dimensional array into a two dimensional array where the length of the rows are different depending on the maximum number of columns which is supplied as an argument. I basically want to include every nth index till the end of array is reached or max number of columns are done whatever happens earlier. So for the following input:
arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
19, 20]
columns = 7
I want the following output:
[1, 4, 7, 10, 13, 16, 19]
[2, 5, 8, 11, 14, 17, 20]
[3, 6, 9, 12, 15, 18]
I have tried the following code but it only works for few values:
var array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20];
function getOutput(arr, columns) {
var rows = Math.ceil(arr.length / columns);
var res = [];
for (var i = 0; i < rows; i++) {
tmp = [];
for (var j = 0, index = i; j < columns; j++) {
if (index < arr.length)
tmp.push(arr[index]);
index += rows;
}
res.push(tmp);
}
return res;
}
console.log(getOutput(array, 7))
JSFiddle available here: https://jsfiddle.net/varunsharma38/fwfz4veo/4/
I do not understand what I am missing. Although, I would not mind using some libraries, I would prefer a vanilla JS based solution.
Thanks in advance!!
Here is another solution using array#reduce.
var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20],
columns = 7,
result = arr.reduce((r,v,i,a) => {
var index = i% (Math.ceil(a.length/columns));
r[index] = r[index] || [];
r[index].push(v);
return r;
},[]);
console.log(result);

Adding new unique number to the array [duplicate]

This question already has answers here:
How to randomize (shuffle) a JavaScript array?
(69 answers)
Closed 8 years ago.
I have array of few random numbers ( I do not know which ones it's going to be and how many of them, but it's mainly in range from 1 to 15, should not be more )
How to add new random number to this which should be as close as possible to this range and which will be unique ( can not be the same as one of the existing numbers )?
It's in javascript, example array:
var myarray = [4,5,1,9,6];
A function like this should work:
function addRandom(array, max)
{
if(array.length === max) {
return array;
}
var number = Math.round(Math.random() * (max - 1)) + 1;
if(array.indexOf(number) === -1) {
array.push(number);
return array;
}
return addRandom(array, max);
}
This takes your starting array and a maximum random integer. If the length of the array is already equal to the max integer, then the array is full and you won't ever find a new one. Otherwise, we make a new random number between 1 and the maximum.
To do this, we use Math.random() (which returns a float from 0-1), multiply it by one less the maximum, round the result with Math.round(), and add 1. If you say our max is 15, then this takes a float from 0 to 1 and multiplies it by 14 so you get 0 to 14. This is then rounded to an integer and we add 1 so we have a range of 1 to 15.
Finally, we use Array.indexOf() (IE 9+) to see if the number already exists. If it doesn't, then we use Array.push() to append the number and then return the new array. Otherwise, we will run the function again and generate a new number.
Use my JSFiddle to test this. I start with an array with length 5, and loop through it 15 times. You will see in the console that a random number is appended each time until every number is generated. An example out put is:
[4, 5, 1, 9, 6, 8]
[4, 5, 1, 9, 6, 8, 15]
[4, 5, 1, 9, 6, 8, 15, 2]
[4, 5, 1, 9, 6, 8, 15, 2, 3]
[4, 5, 1, 9, 6, 8, 15, 2, 3, 12]
[4, 5, 1, 9, 6, 8, 15, 2, 3, 12, 14]
[4, 5, 1, 9, 6, 8, 15, 2, 3, 12, 14, 7]
[4, 5, 1, 9, 6, 8, 15, 2, 3, 12, 14, 7, 11]
[4, 5, 1, 9, 6, 8, 15, 2, 3, 12, 14, 7, 11, 10]
[4, 5, 1, 9, 6, 8, 15, 2, 3, 12, 14, 7, 11, 10, 13]
[4, 5, 1, 9, 6, 8, 15, 2, 3, 12, 14, 7, 11, 10, 13]
[...]

JavaScript/jQuery - Array list does not go across whole board

So, I'm working with A* Pathfinding. I got it working however it doesn't work all the way. It works all the way until the last 4 columns to the right. Weird.
It works all the way until X is 10 or less. Which is weird because Y's max is 10. Maybe it's together? I don't know. But my map is 15 columns by 10 rows. Here is an online example: http://mystikrpg.com/html5/
An interesting error I get is Uncaught TypeError: Cannot read property '8' of undefined.
The 8 is the Y of where you clicked. If you click a the very first gray block on the right-side (since row 0 is walled off). Then that 8 would say 1.
Here's the part where it lays out the nodes.
// Creates a Graph class used in the astar search algorithm.
function Graph(grid) {
var nodes = [];
var row, rowLength, len = grid.length;
for (x = 0; x <= 10; x++) {
row = grid[x];
nodes[x] = new Array(15);
for (y = 0; y <= 15; y++) {
nodes[x][y] = new GraphNode(x, y, row[y]);
}
}
this.input = grid;
this.nodes = nodes;
}
However, you can download it offline and put it on localhost, if you'd like here http://mystikrpg.com/html5/Ethios.rar
Anyway... something else I found:
My loadMap() function returns an array of 11 elements.
And when x_block is 13 (clicking on X axis of map) for example, graph.nodes[x_block][y_block] returns undefined.
Here is my loadMap() function:
function loadMap(map) {
if (map == 1) {
return [[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
[1, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 1],
[1, 13, 1, 13, 13, 13, 13, 13, 1, 1, 1, 1, 1, 13, 13, 1],
[1, 13, 1, 1, 13, 1, 1, 13, 1, 13, 13, 1, 13, 13, 13, 1],
[1, 13, 13, 1, 1, 1, 13, 13, 1, 13, 13, 1, 1, 1, 13, 1],
[1, 13, 13, 1, 13, 1, 13, 13, 13, 13, 13, 1, 13, 13, 13, 1],
[1, 13, 13, 13, 13, 1, 13, 13, 13, 13, 13, 1, 13, 13, 13, 1],
[1, 13, 1, 13, 13, 13, 13, 13, 1, 1, 1, 1, 13, 13, 13, 1],
[1, 13, 1, 1, 1, 1, 13, 13, 13, 13, 1, 13, 13, 13, 13, 1],
[1, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 1],
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]];
}
}
As you can see, it's 15 columns across and 10 rows down.
What am I doing wrong?
UPDATE NEW
for (y = 0; y <= 10; y++) {
row = grid[y];
nodes[y] = new Array(15);
for (x = 0; x <= 15; x++) {
console.log("X: " + x + " Y: " + y);
//console.log("Row: " + row[x]);
nodes[x][y] = new GraphNode(x, y, row[x]);
}
}
You have your x and y nomenclature the wrong way around.
The x axis should be the second dimension in your table, e.g. nodes[y][x]:
for (y = 0; y <= 10; x++) {
row = grid[y];
nodes[y] = [];
for (x = 0; x <= 15; x++) {
nodes[y][x] = new GraphNode(x, y, row[y]);
}
}

Categories