Create a function that accepts a string and groups repeated values - javascript

Create a function that accepts a string and groups repeated values. The groups should have the following structure: [[value, first_index, last_index, times_repeated], ..., [value, first_index, last_index, times_repeated]].
value: Character being assessed.
first_index: Index of characters first appearance.
last_index: Index of characters last appearance.
times_repeated: Number of consecutive times character repeats.
Examples
findRepeating("a") ➞ [["a", 0, 0, 1]]
findRepeating("aabbb") ➞ [["a", 0, 1, 2], ["b", 2, 4, 3]]
findRepeating("1337") ➞ [["1", 0, 0, 1], ["3", 1, 2, 2], ["7", 3, 3, 1]]
findRepeating("aabbbaabbb") ➞ [["a", 0, 1, 2], ["b", 2, 4, 3], ["a", 5, 6, 2], ["b", 7, 9, 3]]
I am able to do it for unique characters.
But unable to do it for
Number of consecutive times character repeats
MY CODE
function findRepeating(str) {
let unique = [...new Set([...str])]
return unique.map(x=>[x,str.indexOf(x),str.lastIndexOf(x),[...str].filter(a=>a==x).length])
}
EXPECTED RESULT
Test.assertSimilar(findRepeating(''), [])
Test.assertSimilar(findRepeating('a'), [['a', 0, 0, 1]])
Test.assertSimilar(findRepeating('1337'), [['1', 0, 0, 1], ['3', 1, 2, 2], ['7', 3, 3, 1]])
Test.assertSimilar(findRepeating('aabbb'), [['a', 0, 1, 2], ['b', 2, 4, 3]])
Test.assertSimilar(findRepeating('addressee'), [['a', 0, 0, 1], ['d', 1, 2, 2], ['r', 3, 3, 1], ['e', 4, 4, 1], ['s', 5, 6, 2], ['e', 7, 8, 2]])
Test.assertSimilar(findRepeating('aabbbaabbb'), [['a', 0, 1, 2], ['b', 2, 4, 3], ['a', 5, 6, 2], ['b', 7, 9, 3]])
Test.assertSimilar(findRepeating('1111222233334444'), [['1', 0, 3, 4], ['2', 4, 7, 4], ['3', 8, 11, 4], ['4', 12, 15, 4]])
Test.assertSimilar(findRepeating('1000000000000066600000000000001'), [['1', 0, 0, 1], ['0', 1, 13, 13], ['6', 14, 16, 3], ['0', 17, 29, 13], ['1', 30, 30, 1]])
ACTUAL RESULT
Test Passed: Value == '[]'
Test Passed: Value == "[['a', 0, 0, 1]]"
Test Passed: Value == "[['1', 0, 0, 1], ['3', 1, 2, 2], ['7', 3, 3, 1]]"
Test Passed: Value == "[['a', 0, 1, 2], ['b', 2, 4, 3]]"
FAILED: Expected: "[['a', 0, 0, 1], ['d', 1, 2, 2], ['r', 3, 3, 1], ['e', 4, 4, 1], ['s', 5, 6, 2], ['e', 7, 8, 2]]", instead got: "[['a', 0, 0, 1], ['d', 1, 2, 2], ['r', 3, 3, 1], ['e', 4, 8, 3], ['s', 5, 6, 2]]"
FAILED: Expected: "[['a', 0, 1, 2], ['b', 2, 4, 3], ['a', 5, 6, 2], ['b', 7, 9, 3]]", instead got: "[['a', 0, 6, 4], ['b', 2, 9, 6]]"
Test Passed: Value == "[['1', 0, 3, 4], ['2', 4, 7, 4], ['3', 8, 11, 4], ['4', 12, 15, 4]]"
FAILED: Expected: "[['1', 0, 0, 1], ['0', 1, 13, 13], ['6', 14, 16, 3], ['0', 17, 29, 13], ['1', 30, 30, 1]]", instead got: "[['1', 0, 30, 2], ['0', 1, 29, 26], ['6', 14, 16, 3]]"
function findRepeating(str) {
let unique = [...new Set([...str])]
return unique.map(x=>[x,str.indexOf(x),str.lastIndexOf(x),[...str].filter(a=>a==x).length])
}
console.log("Fails ",JSON.stringify(findRepeating('addressee')),"\nexpected", `[['a',0,0,1],['d',1,2,2],['r',3,3,1],['e',4,4,1],['s',5,6,2],['e',7,8,2]]`)
console.log("Fails ",JSON.stringify(findRepeating('aabbbaabbb')),"\nexpected", `[['a',0,1,2],['b',2,4,3],['a',5,6,2],['b',7,9,3]]`)
console.log("Passes ",JSON.stringify(findRepeating('1111222233334444')),"\nexpected", `[['1',0,3,4],['2',4,7,4],['3',8,11,4],['4',12,15,4]]`)
console.log("Fails ",JSON.stringify(findRepeating('1000000000000066600000000000001')),"\nexpected", `[['1',0,0,1],['0',1,13,13],['6', 14,16,3],['0',17,29,13],['1',30,30,1]]`)

You could take an array of same characters with a regular expression which looks for a character and same following onces as a group and map the wanted information.
function findRepeating(string) {
var i = -1;
return (string.match(/(.)\1*/g) || []).map(s => [s[0], ++i, i += s.length - 1, s.length]);
}
console.log(findRepeating("")); // []
console.log(findRepeating("a")); // [["a", 0, 0, 1]]
console.log(findRepeating("aabbb")); // [["a", 0, 1, 2], ["b", 2, 4, 3]]
console.log(findRepeating("1337")); // [["1", 0, 0, 1], ["3", 1, 2, 2], ["7", 3, 3, 1]]
console.log(findRepeating("aabbbaabbb")); // [["a", 0, 1, 2], ["b", 2, 4, 3], ["a", 5, 6, 2], ["b", 7, 9, 3]]

Your code assumes that each group is about a different character. As soon as you have two groups with the same character, things like lastIndex will give the wrong result.
Just use a plain for-loop.
function findRepeating(str) {
let result = [];
let start = 0;
for (let i = 0; i < str.length; i++) {
if (str[i] !== str[i+1]) {
result.push([str[i], start, i, i-start+1]);
start = i+1;
}
}
return result;
}
console.log(findRepeating(''), [])
console.log(findRepeating('a'), [['a', 0, 0, 1]])
console.log(findRepeating('1337'), [['1', 0, 0, 1], ['3', 1, 2, 2], ['7', 3, 3, 1]])
console.log(findRepeating('aabbb'), [['a', 0, 1, 2], ['b', 2, 4, 3]])
console.log(findRepeating('addressee'), [['a', 0, 0, 1], ['d', 1, 2, 2], ['r', 3, 3, 1], ['e', 4, 4, 1], ['s', 5, 6, 2], ['e', 7, 8, 2]])

Related

Why is random order slow in my Sudoku backtracking solving algorithm compared to "in order"

When running my sudoku backtracking algorithm using random ordering for finding new available locations, it takes way longer than when finding the available locations, left to right, top to bottom. Why? How should I change the code to have quick random ordering?
//Taking forever
let posOrder = [[4, 4], [4, 0], [7, 0], [4, 8], [2, 3], [0, 8], [6, 0], [0, 6], [0, 5], [5, 4], [8, 2], [7, 7], [5, 1], [6, 3], [3, 2], [3, 3], [1, 2], [6, 2], [0, 7], [4, 2], [1, 4], [0, 1], [1, 1], [7, 1], [5, 2], [0, 2], [3, 7], [1, 6], [0, 4], [8, 1], [5, 6], [2, 1], [8, 3], [6, 4], [8, 6], [2, 7], [6, 6], [8, 7], [1, 8], [7, 4], [4, 7], [4, 5], [8, 4], [6, 1], [2, 2], [1, 5], [7, 6], [3, 6], [5, 0], [4, 1], [2, 8], [6, 8], [3, 1], [5, 3], [3, 4], [7, 2], [2, 5], [8, 5], [5, 5], [7, 8], [8, 8], [6, 5], [6, 7], [4, 6], [2, 6], [3, 5], [2, 0], [5, 7], [1, 0], [0, 3], [2, 4], [7, 5], [8, 0], [7, 3], [0, 0], [3, 8], [5, 8], [3, 0], [1, 7], [1, 3], [4, 3]]
//Goes quickly
//let posOrder = [[0, 0], [0, 1], [0, 2], [0, 3], [0, 4], [0, 5], [0, 6], [0, 7], [0, 8], [1, 0], [1, 1], [1, 2], [1, 3], [1, 4], [1, 5], [1, 6], [1, 7], [1, 8], [2, 0], [2, 1], [2, 2], [2, 3], [2, 4], [2, 5], [2, 6], [2, 7], [2, 8], [3, 0], [3, 1], [3, 2], [3, 3], [3, 4], [3, 5], [3, 6], [3, 7], [3, 8], [4, 0], [4, 1], [4, 2], [4, 3], [4, 4], [4, 5], [4, 6], [4, 7], [4, 8], [5, 0], [5, 1], [5, 2], [5, 3], [5, 4], [5, 5], [5, 6], [5, 7], [5, 8], [6, 0], [6, 1], [6, 2], [6, 3], [6, 4], [6, 5], [6, 6], [6, 7], [6, 8], [7, 0], [7, 1], [7, 2], [7, 3], [7, 4], [7, 5], [7, 6], [7, 7], [7, 8], [8, 0], [8, 1], [8, 2], [8, 3], [8, 4], [8, 5], [8, 6], [8, 7], [8, 8]]
const backtrack = (board) => {
const pos = posOrder.find(p => board[p[0]][p[1]] === 0)
if(!pos)
return true
const [row, col] = pos
return (shuffleArray([1, 2, 3, 4, 5, 6, 7, 8, 9]).some(number => {
if (!numberExists(board, number, row, col)) {
board[row][col] = number
if (backtrack(board))
return true
else {
board[row][col] = 0
return false
}
}
}))
}
const shuffleArray = (array) => {
for (let i = array.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1)); // This ; is necessary... apparently
[array[i], array[j]] = [array[j], array[i]]
}
return array
}
const numberInRow = (board, number, row) => board[row].some(col => col === number)
const numberInCol = (board, number, col) => board.some(row => row[col] === number)
const numberInRegion = (board, number, row, col) => {
const r = 3*Math.floor(row/3)
const c = 3*Math.floor(col/3)
return [board[r], board[r+1], board[r+2]].some(arr=> [arr[c], arr[c+1], arr[c+2]].some(nbr => nbr === number))
}
const numberExists = (board, number, row, col) => (
numberInRow(board, number, row) ||
numberInCol(board, number, col) ||
numberInRegion(board, number, row, col)
)
const sudokuBoard = [
[0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0]
]
backtrack(sudokuBoard)
Note that I'd prefer to randomize the order every time, just kept one randomized order to rerun the example.
In the non-random order, after 9 placements all combinations for the first row that would have duplicates, have already been eliminated. After 27 placements, there are already 3 lines and three 3x3 boxes completed. That means already some alternatives had to be considered at an early stage to make it work. For instance, there was only one possible digit to place at move 9.
The random order will in a first phase allow the placement of digits with much more liberty, as a lot of initial coordinates are not directly related, and so fewer choices have to be redone at an early stage. This means more wrong moves are left on the board for a longer time and will therefore take much more time before they are eventually undone and replaced by a different choice.
To get the better performance it is of utmost importance that early choices are good and don't have to be redone. So that means that the sudoku constraints have to be eagerly sought.
I would therefore say that the best order is to fill lines, columns and boxes as soon as possible. For instance, this seems to be a promising order:
The first line
The top-left box (so completing it with 6 more positions)
The second line (completing the 6 remaining positions)
The top-center box (completing 3 remaining positions)
The third line & top-right box (completing 3 remaining positions)
The first column (completing 6 remaining positions)
The second column (completing 6 remaining positions)
... etc

Filter each inner property arrays with Ramda

I have an object like this:
const arrays = {
one: [[1, 33, 41], [2, 0, 27], [3, 7, 9], [4, 1, 3]],
two: [[1, 77, 2], [2, 6, 3], [3, 0, 0], [4, 55, 3]],
three: [[1, 4, 6], [2, 0, 0], [3, 5, 6], [4, 0, 0]],
};
As you can see each first number is equal:
1 for each first inner array
2 for each second inner array
3 for each third inner array
etc...
I want to filter based on the first number of each array
and some comparator number e.g. [3]
If we have a filter number [3] (smaller or equal to 3),
the wanted result would be:
const arrays = {
one: [[1,33,41], [2,0,27], [3,7,9]],
two: [[1,77,2], [2,6,3], [3,0,0]],
three: [[1,4,6], [2,0,0], [3,5,6]],
};
Since all first numbers of inner arrays are smaller than or equal to 3.
The arrays starting with 4,5... are ignored.
What would be the ramda's way to have this functionality?
I like Ramda's map function because it can iterate over the properties of an object (and so avoid Object.fromEntries & Object.entries) and apply a function to each one of them. That function is filter which will take as argument the inner arrays. The function given to filter is itself a composition of gte and head; takes the first element of an array and compare it with 3:
const arrays =
{ one: [[1, 33, 41], [2, 0, 27], [3, 7, 9], [4, 1, 3]]
, two: [[1, 77, 2], [2, 6, 3], [3, 0, 0], [4, 55, 3]]
, three: [[1, 4, 6], [2, 0, 0], [3, 5, 6], [4, 0, 0]] };
map(filter(compose(gte(3), head)), arrays);
// ^ ^ ^ ^ ^
// A B C D E
//=> { one: [[ 1, 33, 41], [2, 0, 27], [3, 7, 9]]
//=> , two: [[ 1, 77, 2], [2, 6, 3], [3, 0, 0]]
//=> , three: [[ 1, 4, 6], [2, 0, 0], [3, 5, 6]] }
map over each property (A); each array is passed to filter (B)
Each inner array is passed to compose (C)
Take the head of each inner array (E) and compare with 3 (D)
Scott Christopher rightly pointed out in the comments that gte can be confusing when partially applied. In fact the whole composition can be replaced with this simple lambda: ([x]) => x <= 3.
Alternative solution which I like too:
map(filter(([x]) => x <= 3), arrays);
I'd totally subscribe for #customcommander's approach,
just wanted to add that you can also pass numerical indexes to R.propSatisfies.
const headIs3OrBelow = R.propSatisfies(R.gte(3), 0);
const fn = R.map(R.filter(headIs3OrBelow));
// ===
const data = {
one: [[1, 33, 41], [2, 0, 27], [3, 7, 9], [4, 1, 3]],
two: [[1, 77, 2], [2, 6, 3], [3, 0, 0], [4, 55, 3]],
three: [[1, 4, 6], [2, 0, 0], [3, 5, 6], [4, 0, 0]],
};
console.log(
fn(data),
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.27.1/ramda.js" integrity="sha512-3sdB9mAxNh2MIo6YkY05uY1qjkywAlDfCf5u1cSotv6k9CZUSyHVf4BJSpTYgla+YHLaHG8LUpqV7MHctlYzlw==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
Also agree that gte and other similar methods are very difficult to read, because they kind of read backwards as is 3 gte than x... in Haskell you could do something like:
3 `gte` x
Vanilla approach:
const headIs3OrBelow = ([head]) => head <= 3;
const fn = (data) => Object.entries(data).reduce(
(res, [k, lists]) => ({ ...res, [k]: lists.filter(headIs3OrBelow) }),
{},
);
// ===
const data = {
one: [[1, 33, 41], [2, 0, 27], [3, 7, 9], [4, 1, 3]],
two: [[1, 77, 2], [2, 6, 3], [3, 0, 0], [4, 55, 3]],
three: [[1, 4, 6], [2, 0, 0], [3, 5, 6], [4, 0, 0]],
};
console.log(
fn(data),
);
I understand you would like to use Ramda, this is not a solution using the library but accomplishes the same. You could create an object from entries that are filtered by comparing the first array value a[0] to the maxVal passed to the function.
const arrays = {
one: [[1, 33, 41], [2, 0, 27], [3, 7, 9], [4, 1, 3]],
two: [[1, 77, 2], [2, 6, 3], [3, 0, 0], [4, 55, 3]],
three: [[1, 4, 6], [2, 0, 0], [3, 5, 6], [4, 0, 0]],
};
const filterArrays = (arsObj, maxVal) => {
return Object.fromEntries(Object.entries(arsObj).map(([k, v]) => {
return [k, v.filter((a) => a[0] <= maxVal)];
}));
}
const result = filterArrays(arrays, 3);
console.log(result);

Find if few array items exists in any one of many arrays?

Have these 2 Javascript arrays
// The player which has a "winning" combination (1, 5, 9)
player1Cells = [ 5, 9, 1, 6]
// Player which doesnt have a "winning" combination
player2Cells = [ 2, 1, 4, 8]
A player has a "winning" combination if 3 of their numbers match one of the arrays in this array:
winningCombinations = [
[1, 2, 3], [4, 5, 6], [7, 8, 9],
[1, 4, 7], [2, 5, 8], [3, 6, 9],
[1, 5, 9], [3, 5, 7]
];
In the example, player1Cells has a winning combination - 1, 5, 9. The other player doesn't
I figured there is a way to loop through the winningCombinations in some way, and compare it against the player compare but I don't know best approach to comparing these in an efficient way.
You can use some method on the winning array and then filter method to check if player has more than 3 matches as current array in some loop.
const w = [[1, 2, 3], [4, 5, 6], [7, 8, 9],[1, 4, 7], [2, 5, 8], [3, 6, 9],[1, 5, 9], [3, 5, 7]];
const player1Cells = [ 5, 9, 1, 6];
const player2Cells = [ 2, 1, 4, 8];
function check(arr, p) {
return arr.some(a => {
const match = p.filter(e => a.includes(e));
return match.length >= 3;
})
}
console.log(check(w, player1Cells));
console.log(check(w, player2Cells));
You may use:
Array.prototype.some()
Array.prototype.every()
Array.prototype.includes()
Working Example:
let player1Cells = [5, 9, 1, 6];
let player2Cells = [2, 1, 4, 8];
let winningCombinations = [
[1, 2, 3], [4, 5, 6], [7, 8, 9],
[1, 4, 7], [2, 5, 8], [3, 6, 9],
[1, 5, 9], [3, 5, 7]
];
let checker = function(w, p) {
return w.some(a => a.every(v => p.includes(v)));
}
console.log(checker(winningCombinations, player1Cells));
console.log(checker(winningCombinations, player2Cells));

Elements in table not being read because of uncaught error

I'm so frustrated with a project I working on in which if there are duplicate elements in a table I want to hide them. I find the duplicates without a problem. The issues starts when I try to hide the duplicates. I'm using vanilla JavaScript without any frame works or libraries. I get this error that is really hard to decipher.
Uncaught Type Error: Cannot read property 'e' of undefined
e is first duplicate element in the table
I don't have any hard coded data in my HTML - it's all JavaScript. I have never done a display none this way before so I thought I would reach out for some help. My code is below.
Appreciating Your Help In Advance.
var data = [
['e', 0, 1, 2, 3, 4],
['a', 54312, 235, 5, 15, 4],
['a', 6, 7, 8, 9, 232],
['a', 54, 11235, 345, 5, 6],
['b', 0, 1, 2, 3, 4],
['b', 54312, 235, 5, 15, 4],
['c', 62, 15, 754, 93, 323],
['d', 27, 11235, 425, 18, 78],
['d', 0, 1, 2, 3, 4],
['d', 54312, 235, 5, 15, 4],
['e', 6, 7, 8, 9, 232],
['e', 54, 11235, 345, 5, 6],
['e', 0, 1, 2, 3, 4],
['e', 54312, 235, 5, 15, 4],
['e', 62, 15, 754, 93, 323],
['e', 27, 11235, 425, 18, 78]
];
//Create a HTML Table element.
var table = document.createElement("TABLE");
var elems = document.getElementsByClassName("tableRow");
//Get the count of columns.
var columnCount = data[0].length;
//Add the data rows.
for (var i = 0; i < data.length; i++) {
var row = table.insertRow(-1);
for (var j = 0; j < columnCount; j++) {
//Searching for duplicates
var num = data[i][0];
for (var otherRow = i + 1; otherRow < data.length; otherRow++) {
var dup = data[otherRow][0];
console.log("What is the dup" + dup);
if (num === dup) {
console.log("duplicate");
elems.data[dup].style.display = "none";
}
}
var cell = row.insertCell(-1);
cell.innerHTML = data[i][j];
cell.innerHtml = myZero;
}
}
var dvTable = document.getElementById("dvTable");
dvTable.innerHTML = "";
dvTable.appendChild(table);
You can separate the de-duplication and actually creating the elements from your data. Using Array.filter you can remove all duplicates so you don't have to worry about that when you do the inserting.
var data = [
['e', 0, 1, 2, 3, 4],
['a', 54312, 235, 5, 15, 4],
['a', 6, 7, 8, 9, 232],
['a', 54, 11235, 345, 5, 6],
['b', 0, 1, 2, 3, 4],
['b', 54312, 235, 5, 15, 4],
['c', 62, 15, 754, 93, 323],
['d', 27, 11235, 425, 18, 78],
['d', 0, 1, 2, 3, 4],
['d', 54312, 235, 5, 15, 4],
['e', 6, 7, 8, 9, 232],
['e', 54, 11235, 345, 5, 6],
['e', 0, 1, 2, 3, 4],
['e', 54312, 235, 5, 15, 4],
['e', 62, 15, 754, 93, 323],
['e', 27, 11235, 425, 18, 78]
];
var alreadyFound = [];
data = data.filter(function(item, pos, arr) {
var key = item[0];
// If we have already found this character, then skip.
if (alreadyFound.indexOf(key) > -1) return false;
// Otherwise, add this char to alreadyFound and include the item.
alreadyFound.push(key);
return true;
});
//Create a HTML Table element.
var table = document.createElement("TABLE");
var elems = document.getElementsByClassName("tableRow");
//Get the count of columns.
var columnCount = data[0].length;
//Add the data rows.
for (var i = 0; i < data.length; i++) {
var row = table.insertRow(-1);
for (var j = 0; j < columnCount; j++) {
var cell = row.insertCell(-1);
cell.innerHTML = data[i][j];
}
}
var dvTable = document.getElementById("dvTable");
dvTable.innerHTML = "";
dvTable.appendChild(table);
<div id="dvTable"></div>
I agree with Red Mercury. you first need to remove duplicates in your array.
Red Mercury answer is perfectly valid but here is a dirty quick multi-dimensional array deduplication function I am using for such stuff.
var data = [
['e', 0, 1, 2, 3, 4],
['a', 54312, 235, 5, 15, 4],
['a', 6, 7, 8, 9, 232],
['a', 54, 11235, 345, 5, 6],
['b', 0, 1, 2, 3, 4],
['b', 54312, 235, 5, 15, 4],
['c', 62, 15, 754, 93, 323],
['d', 27, 11235, 425, 18, 78],
['d', 0, 1, 2, 3, 4],
['d', 54312, 235, 5, 15, 4],
['e', 6, 7, 8, 9, 232],
['e', 54, 11235, 345, 5, 6],
['e', 0, 1, 2, 3, 4],
['e', 54312, 235, 5, 15, 4],
['e', 62, 15, 754, 93, 323],
['e', 27, 11235, 425, 18, 78]
];
function multiDimlUniq(arr) {
var uniques = [];
var founds = {};
for (var i = 0, l = arr.length; i < l; i++) {
var s = JSON.stringify(arr[i]);
if (founds[s]) {
continue;
}
uniques.push(arr[i]);
founds[s] = true;
}
return uniques;
}
var reduced = multiDimlUniq(data)

Multidimensional array values jquery

need some help with a script completely on array that I'm doing
skill = [
//[ID, "NAME", TMLEVEL, Learn, Mastery, Prerequisite, PrerequisiteLvl],
//Schoolgirl, Fighter
[0, "Steel Punch", 0, 0, null, null],
[1, "Shockwave", 1, 1, 2, null],
[2, "Bull's Eye", 10, 2, 2, null],
[3, "Burning Rave", 20, 2, 2, null],
[4, "Shockvibe", 20, 1, 2, null],
[5, "Sense Breaker", 20, 1, 2, null],
[6, "Luck Breaker", 20, 1, 2, null],
[7, "Pumping Heart", 25, 3, 3, skill[3], 1],
[8, "Armor Breaker", 30, 2, 2, skill[1], 10],
[9, "Upper Smash", 40, 2, 2, skill[2], 10],
[10, "Hyper Beat", 45, 4, 3, [skill[2],skill[3]], [10,10]],
[11, "Tornado Bomb", 50, 3, 3, skill[8], 1]
];
I need that inside the array, in certain points, to call th array again to put the array value in there, like i have here.
In theory this works fine, without any error, but when i call the array inside it,it says that it's "undefined".
Any one knows how can i do this without rewrite everything on it? (because i use this in +- 300 code lines).
After a long process, I have come up with a solution that will replace all prerequisites, even if they are several levels deep (e.g. skill_3 requires skill_2 which requires skill_1...).
This will require your skill variable to be correctly declared (in your question, not all of the skills had 7 variables).
Here is an example of what the variable will look like:
var skill = [
//[ID, "NAME", TMLEVEL, Learn, Mastery, Prerequisite, PrerequisiteLvl],
[0, "Steel Punch", 0, 0, 0, null, null],
[1, "Shockwave", 1, 1, 2, null, null],
[2, "Bull's Eye", 10, 2, 2, 7, null],
[3, "Burning Rave", 20, 2, 2, null, null],
[4, "Shockvibe", 20, 1, 2, null, null],
[5, "Sense Breaker",20, 1, 2, null, null],
[6, "Luck Breaker", 20, 1, 2, null, null],
[7, "Pumping Heart",25, 3, 3, 3, 1],
[8, "Armor Breaker",30, 2, 2, 7, 10],
[9, "Upper Smash", 40, 2, 2, 2, 10],
[10,"Hyper Beat", 45, 4, 3, [2,3], [10,10]],
[11,"Tornado Bomb", 50, 3, 3, 8, 1]
];
Now, I thought of a function setPrerequisites() that will, for 1 skill, recursively set it's prerequisites:
Array.prototype.setPrerequisites = function(){
if (typeof this[5] === "number")
{
this[5]=skill[getPosOfSkill(this[5])];
this[5].setPrerequisites();
}
else if (this[5] instanceof Array)
{
if (this[5].isSkill()) this[5].setPrerequisites();
else
{
for(var i = 0; i < this[5].length; i++)
{
this[5][i] = skill[getPosOfSkill(this[5][i])];
this[5][i].setPrerequisites();
}
}
}
}
This function uses isSkill() to determine whether an array is a skill, or an array of skill IDs:
Array.prototype.isSkill = function(){
return this.length==7 && typeof this[1]==="string";
}
It also uses getPosOfSkill(id) to look for the right skill in case your skills were listed in no particular order, or if ID's are missing:
function getPosOfSkill(id){
for(var i=0; i<skill.length; i++) if (skill[i][0]==id) return i;
return false;
}
All you have to do is declare your skill variable, and then fill it:
for (var i = 0; i < skill.length; i++) skill[i].setPrerequisites();
// if you want to see the results
console.log(skill);
Here is a jsFiddle Demo
You'll have to either rethink your whole approach here (recommended), or set those items to null at first, then rerun the declaration:
skill = [
//[ID, "NAME", TMLEVEL, Learn, Mastery, Prerequisite, PrerequisiteLvl],
//Schoolgirl, Fighter
[0, "Steel Punch", 0, 0, null, null],
[1, "Shockwave", 1, 1, 2, null],
[2, "Bull's Eye", 10, 2, 2, null],
[3, "Burning Rave", 20, 2, 2, null],
[4, "Shockvibe", 20, 1, 2, null],
[5, "Sense Breaker", 20, 1, 2, null],
[6, "Luck Breaker", 20, 1, 2, null],
[7, "Pumping Heart", 25, 3, 3, null, 1],
[8, "Armor Breaker", 30, 2, 2, null, 10],
[9, "Upper Smash", 40, 2, 2, null, 10],
[10, "Hyper Beat", 45, 4, 3, null, null],
[11, "Tornado Bomb", 50, 3, 3, null, 1]
];
skill = [
//[ID, "NAME", TMLEVEL, Learn, Mastery, Prerequisite, PrerequisiteLvl],
//Schoolgirl, Fighter
[0, "Steel Punch", 0, 0, null, null],
[1, "Shockwave", 1, 1, 2, null],
[2, "Bull's Eye", 10, 2, 2, null],
[3, "Burning Rave", 20, 2, 2, null],
[4, "Shockvibe", 20, 1, 2, null],
[5, "Sense Breaker", 20, 1, 2, null],
[6, "Luck Breaker", 20, 1, 2, null],
[7, "Pumping Heart", 25, 3, 3, skill[3], 1],
[8, "Armor Breaker", 30, 2, 2, skill[1], 10],
[9, "Upper Smash", 40, 2, 2, skill[2], 10],
[10, "Hyper Beat", 45, 4, 3, [skill[2],skill[3]], [10,10]],
[11, "Tornado Bomb", 50, 3, 3, skill[8], 1]
];
That way, the array elements you are trying to access already exist, now you are just overwriting them.
I think i found a easy way, but still has the problem if it's defined after, but since i only call the values defined before there is no problem for now.
But if anyone knows some way better let me know please.
Here is what i do still using only arrays:
var skill = [];
skill[0] = [0, "Steel Punch", 0, 0, null, null];
skill[1] = [1, "Shockwave", 1, 1, 2, null];
skill[2] = [2, "Bull's Eye", 10, 2, 2, null];
skill[3] = [3, "Burning Rave", 20, 2, 2, null];
skill[4] = [4, "Shockvibe", 20, 1, 2, null];
skill[5] = [5, "Sense Breaker", 20, 1, 2, null];
skill[6] = [6, "Luck Breaker", 20, 1, 2, null];
skill[7] = [7, "Pumping Heart", 25, 3, 3, skill[3], 1];
skill[8] = [8, "Armor Breaker", 30, 2, 2, skill[1], 10];
skill[9] = [9, "Upper Smash", 40, 2, 2, skill[2], 10];
skill[10] = [10, "Hyper Beat", 45, 4, 3, [skill[2],skill[3]], [10,10]];
skill[11] = [11, "Tornado Bomb", 50, 3, 3, skill[8], 1];
This way i define them and i'm still using the arrays has i wanted (1 night of sleep makes me think much better :P)

Categories

Resources