Javascript: Search for an array in an array of arrays - javascript

I am looking at the best way to search for an instance of an array containing the elements of a given array, in an array of arrays.
Now, I understand that that's a confusing line. So here's an example to illustrate the scenario.
I have a search set which is an array with 9 items, representing a game board of 9 cells. The values can be 1, 0 or null:
var board = [1, 0, 1, 1, 0, 1, 0, 0, null];
I also have a result set, which is an array of arrays:
var winningCombos = [[0,1,2],[3,4,5],[6,7,8],[0,3,6],[1,4,7],[2,5,8],[0,4,8],[2,4,6]]
Each array in winningCombo represents indices in the board array, that are winning combinations.
There are 8 winning combinations.
Each winning combination is a group of 3 indices, that would win, if their values are all 1.
i.e. to win, the board could be:
board = [1,1,1,0,0,0,null,null,0]; // Index 0,1, and 2 are 1, matching winningCombos[0]
or
board = [null,null,1,0,1,0,1,null,0]; // Index 2,4, and 6 are 1, matching winningCombos[7]
My question is:
What is the way in Javascript to perform this operation (maybe with ES6)?
What I have come up with so far is this:
const win = [[0,1,2],[3,4,5],[6,7,8],[0,3,6],[1,4,7],[2,5,8],[0,4,8],[2,4,6]];
let board = [null,null,1,0,1,0,1,null,0];
let score = [];
board.forEach(function(cell, index)
{
if(cell === 1)
score.push(index);
});
console.log(score);
console.log(win.indexOf(score) > -1)
But I'm having a tough time finding the array in the array of arrays. Although the score is [2,4,6] and this exact array exists in win, it doesn't show up in the result, because of the way object equality works in Javascript I assume.
In a nutshell, I'm trying to see if score exists in win
I found this solution, but it seems quite hacky. Is there a better way to handle this?

You can use Array.prototype.some(), Array.prototype.every() to check each element of win, score
const win = [
[0, 1, 2],
[3, 4, 5],
[6, 7, 8],
[0, 3, 6],
[1, 4, 7],
[2, 5, 8],
[0, 4, 8],
[2, 4, 6]
];
let board = [null, null, 1, 0, 1, 0, 1, null, 0];
let score = [];
board.forEach(function(cell, index) {
if (cell === 1)
score.push(index);
});
console.log(score);
let bool = win.some(function(arr) {
return arr.every(function(prop, index) {
return score[index] === prop
})
});
console.log(bool);

Using ES6 you can map the win array to the actual values at each one of those locations:
const win = [[0,1,2],[3,4,5],[6,7,8],[0,3,6],[1,4,7],[2,5,8],[0,4,8],[2,4,6]];
let board = [null,null,1,0,1,0,1,null,0];
let winning_spots = win.map((spots) => spots.map((i) => board[i]));
>>> winning_spots
[[null, null, 1], [0, 1, 0], [1, null, 0], [null, 0, 1], [null, 1, null], [1, 0, 0], [null, 1, 0], [1, 1, 1]]
Then we can filter by which ones have all of either 1's or 0's:
let one_winners = winning_spots.filter((spots) => spots.every((e) => e == 1));
let zero_winners = winning_spots.filter((spots) => spots.every((e) => e == 0));
>>> one_winners
[[1, 1, 1]]
>>> zero_winners
[]
Finally, if we want to find whether there is a winner, just check the lengths:
let is_winner = (one_winners.length + zero_winners.length) > 0

Related

Is there a way to match an array values to another array values?

I'm trying to make a winCondition in which an activePlayer which is either player1 or player2. Matches with any of the arrays that hold specific values.
I set my board up where each button has their own data-number going from 0 to 8.
When the activePlayer clicks on one of those buttons, they will push that data-number to their own array
const player1 = Players("Player 1", 0, "X", []);
const player2 = Players("Player 2", 0, "O", []);
I then want to check if either of those players array values matches with any of the winning combinations(markersToHit). The markersToHit is an array that holds multiple arrays inside, all those arrays are all the possible ways to win in a tic tac toe. From top to bottom, left-to-right or right-to-left, and diagonal.
const checkWinAndTie = () => {
const winCheck = () => {
const markersToHit = [
[0, 1, 2],
[3, 4, 5],
[6, 7, 8],
[0, 3, 6],
[1, 4, 7],
[2, 5, 8],
[0, 4, 8],
[2, 4, 6],
]
//I want to check if the activePlayer PlayerHits(which holds an array), matches
//with any of the values inside markersToHit
//if they match, I want to display the activePlayer has won the round and add a score to them
for (let i = 0; i < markersToHit.length; i++) {
console.log(markersToHit[i]);
if (markersToHit[i] === getActivePlayer().playerHits) {
console.log(`${getActivePlayer().name} wins!`);
}
}
console.log(`${getActivePlayer().name} :${getActivePlayer().playerHits}`);
}
winCheck();
}
I tried to make an if statement that will match the values from the winningCombination to the activePlayer values in it's array. I'm expecting it to output on which player has won the round but I'm just stuck on the moment. Honestly, been five days.
Any ideas on how I can accomplish this?
Here is the codepen, if you're not clear on it. The console shows the playerHits I'm talking about:
https://codepen.io/jimmyjimenez2400/pen/ZEjvrPq
All comments in the code:
// Copied from your code, the winning combinations
const markersToHit = [
[0, 1, 2],
[3, 4, 5],
[6, 7, 8],
[0, 3, 6],
[1, 4, 7],
[2, 5, 8],
[0, 4, 8],
[2, 4, 6],
];
// Call this function with an array holding the player's current choices
function isItAWinner(choices) {
let winner = false;
// Loop through all winning combinations
markersToHit.forEach(winningCombination => {
// If a winning combination has already been found, skip
if(winner) return;
// matchers contains the intersection of the player's choices and the current winning combination
let matches = winningCombination.filter(singleMarker => {
return choices.includes(singleMarker)
});
// If all three necessary choices of this winning combination are matched, this player wins
if (matches.length === 3) {
console.log("Winning combination: " + matches);
winner = true;
}
});
return winner;
}
// An example: player's choices (spoiler: they win)
const playersChoices = [0, 3, 8, 6];
console.log(isItAWinner(playersChoices));
const checkWinAndTie = () => {
const winCheck = () => {
const markersToHit = [
[0, 1, 2],
[3, 4, 5],
[6, 7, 8],
[0, 3, 6],
[1, 4, 7],
[2, 5, 8],
[0, 4, 8],
[2, 4, 6],
]
//I want to check if the activePlayer PlayerHits(which holds an array), matches
//with any of the values inside markersToHit
//if they match, I want to display the activePlayer has won the round and add a score to them
for (let i = 0; i < markersToHit.length; i++) {
console.log(markersToHit[i]);
- if (markersToHit[i] === getActivePlayer().playerHits) {
+ if (getActivePlayer().playerHits.every((val, j) => val === markersToHit[i][j]))
console.log(`${getActivePlayer().name} wins!`);
}
}
console.log(`${getActivePlayer().name} :${getActivePlayer().playerHits}`);
}
winCheck();
}
You are checking if the two arrays are the same object, but you want to check if the elements of the array are contained in the players values.
for (let i = 0; i < markersToHit.length; i++) {
const hasRow = markersToHit[i].every(f => getActivePlayer().playerHits.includes(""+f));
if (hasRow) {
console.log(`${getActivePlayer().name} wins!`);
}
}
Note that the values in the player array and the markers array are of different types (string vs int), so you either have to adapt one of them or compare with == instead of ===.

More efficient JavaScript code for finding variables in nested arrays from another random array

I am relatively new to JavaScript and I am writing some test code to check win lines in a TicTacToe (Noughts and Crosses) game.
After several iterations this is what I have come up with, but I still feel that it is unwieldy and relies too much on global variables.
Is there a better way to write this code?
const wins = [[0,1,2],[3,4,5],[6,7,8],
[0,3,6],[1,4,7],[2,5,8],
[0,4,8],[2,4,6]];
const moves = [0,5,2,4,3]; // example list of moves
var winLine = [];
const won = [true, true, true];
wins.forEach(function (win) {
win.forEach((square) => winLine.push(moves.some((move) => square == move)));
if(JSON.stringify(winLine) == JSON.stringify(won)){
logWin();
} else {
winLine =[];
}
});
function logWin() {
console.log("win");
}
You could filter the winning positions and get an array of lines.
If this array is empty, no win.
This code utilizes some array methods:
Array#filter
Array#every
Array#includes
const
wins = [[0, 1, 2], [3, 4, 5], [6, 7, 8], [0, 3, 6], [1, 4, 7], [2, 5, 8], [0, 4, 8], [2, 4, 6]],
moves = [0, 5, 2, 4, 3],
winLines = wins.filter(p => p.every(v => moves.includes(v)));
console.log(winLines);
You could go for a completely different approach where you first apply the moves on a bit board (of 9 bits), and then verify via bit operations whether there is a win:
// Patterns of winning lines
const wins = [0x7, 0x38, 0x1C0, 0x49, 0x92, 0x124, 0x111, 0x54];
const moves = [0,5,2,4,3]; // example list of moves
// Convert moves to bit board
const pattern = moves.reduce((acc, i) => acc | (1 << i), 0);
// Overlay each winning line pattern to see if there is a match
const hasWon = wins.some(win => (win & pattern) === win);
console.log(hasWon);

how to solve targetArrayInGivenOrder in JavaScript

Write a function that takes two arrays of integers (nums and index) and
returns a target array under the following rules:
Initially target array is empty.
From left to right read nums[i] and index[i], insert at index index[i] the
value nums[i] in target array.
Repeat the previous step until there are no elements to read in nums and index.
Example 1
Input: nums = [0, 1, 2, 3, 4], index = [0, 4, 1, 2, 3]
Output: [0, 4, 1, 2, 3]
Example 2
Input: nums = [1, 2, 3, 4, 0], index = [0, 1, 2, 3, 0]
Output: [1, 2, 3, 4, 1]
Your example does not match your description. According to your example, you want to insert the nums[index[i]] in your target array's i'th position.
You can do this using Javascript's array.map function like this -
const targetArray = index.map(i => nums[i]);
You may need to add necessary sanity checks as well depending on the contexts.
You can simply achieve this by using Array.forEach() along with Array.splice() method.
Live Demo :
const numsArr = [1, 2, 3, 4, 0];
const indexArr = [0, 1, 2, 3, 0];
let outputArr = [];
numsArr.forEach((elem, index) => {
outputArr.splice(index, 0, numsArr[indexArr[index]]);
});
console.log(outputArr);

javascript Delete from array between 2 indices

With an array of: [1, 2, 3, 4, 5, 6]
I would like to delete between 2 indices such as 2 and 4 to produce [1, 2, null, null, 5, 6]. What's the easiest way to do this?
Hopefully better than this:
const array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
let i = 2;
const rangeEnd = 9;
while (i < rangeEnd) {
delete array[i];
i++;
}
console.log(array)
If you want to use some native API you can actually do this with splice(). Otherwise, you should iterate a for loop through your array and change the value in each iteration.
Here is an example of how it would be done:
const array = [1, 2, 3, 4, 5, 6]
array.splice(3, 2, null, null) // the First element is beginning index and the second is count one will indicate how many indexes you need to traverse from the first one, then you should provide replace element for each of them.
console.log(array)
Note: For more info about it you can read more here.
There is a possible workaround for large scale replacement, so I will give it a touch here:
var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
var anotherArr = Array(2).fill(null); // or you can simply define [null, null, ...]
Array.prototype.splice.apply(arr, [3, anotherArr.length].concat(anotherArr));
console.log(arr);
As you mean the range (2, 4] so you can follow this:
The range is: lower limit exclusive and the upper limit inclusive.
const arr = [1, 2, 3, 4, 5, 6];
const deleteRange = (arr, f, t) => {
return arr.map((item, i) => {
if (i + 1 > f && i + 1 <= t) {
return null;
}
return item;
})
}
console.log(deleteRange(arr, 2, 4));

How to modify value of n dimensional array element where indices are specified by an array in Javascript

I have an n-dimensional array and I want to access/modify an element in it using another array to specify the indices.
I figured out how to access a value, however I do not know how to modify the original value.
// Arbitrary values and shape
arr = [[[8, 5, 8],
[9, 9, 9],
[0, 0, 1]],
[[7, 8, 2],
[9, 8, 3],
[9, 5, 6]]];
// Arbitrary values and length
index = [1, 2, 0];
// The following finds the value of arr[1][2][0]
// Where [1][2][0] is specified by the array "index"
tmp=arr.concat();
for(i = 0; i < index.length - 1; i++){
tmp = tmp[index[i]];
}
// The correct result of 9 is returned
result = tmp[index[index.length - 1]];
How can I modify a value in the array?
Is there a better/more efficient way to access a value?
This is a classic recursive algorithm, as each step includes the same algorithm:
Pop the first index from indices.
Keep going with the array that the newly-popped index points to.
Until you get to the last element in indices - then replace the relevant element in the lowest-level array.
function getUpdatedArray(inputArray, indices, valueToReplace) {
const ans = [...inputArray];
const nextIndices = [...indices];
const currIndex = nextIndices.shift();
let newValue = valueToReplace;
if (nextIndices.length > 0) {
newValue = getUpdatedArray(
inputArray[currIndex],
nextIndices,
valueToReplace,
);
} else if (Array.isArray(inputArray[currIndex])) {
throw new Error('Indices array points an array');
}
ans.splice(currIndex, 1, newValue);
return ans;
}
const arr = [
[
[8, 5, 8],
[9, 9, 9],
[0, 0, 1]
],
[
[7, 8, 2],
[9, 8, 3],
[9, 5, 6]
]
];
const indices = [1, 2, 0];
const newArr = getUpdatedArray(arr, indices, 100)
console.log(newArr);
You can change the values in array like this,
arr[x][y][z] = value;
Does this help?
I think what you're looking for is this:
arr[index[0]][index[1]][index[2]] = value;
I'm having trouble understanding what you're attempting to do in the second part of your example.

Categories

Resources