How to randomly select divs from inside another div? - javascript

I am struggling to randomly select some divs (9 in this case) to place bombs/mines for those selected tiles.
My code for this is:
function place_mines() {
if (document.getElementById("difficulty").selectedIndex == "2") {
for (var u = 0; u < 8; u++) {
}
}
}
Inspected the element, grid which contains all the tiles.

I would use a different approach. I would make a list of tile objects and generate the html from the list. This lets you flag an object as bomb without revealing it to the user by adding it as class name.
After you generated the list, you can take a random subset and flag it as bombs. You could use this approach for example: Sampling a random subset from an array.

I suggest you to give id to the tiles, to later you generate random id , and map the generated id to the tiles

What worked for me was I added a counter to index the elements.
After that, made an array of 9 random numbers from 0-80 (counter starts at 0), checked if the id of the tile selected is in that array, if it was then that tile has a mine else its a normal tile.
tile.setAttribute("id",counter);counter++;

Related

Iterate through js for loop similarly to nth-child(#n + #)

Fairly straightforward question; I'm a bit new to JS and was surprised to be unable to find something in my searches.
Within these two for loops, I'm looping through item previews in a Woocommerce shop. Wordpress automatically adds "first" and "last" classes here to adjust margins for styling. I've got a bit of a hacky thing going here where I'm using upsells as a manual recommended products section.
As you'll see below, I'm trying to first wipe out all instances of those classes on every li, then add "last" classes to only some lis: those that work within the columns/ placement I have set up. I'm trying to do this within an if/then statement that checks for screen width. I wasn't having any luck utilizing two separate for loops within each statement, for reasons that are currently a bit over my head.
What I'd like to do: I'd like to automate the for loop to automatically go through every two (or every 3 in the else statement) elements in my upsellLi variable. With CSS you could do something like .upsell .li:nth-child(1n + 2);. I've tried upsellLi([1] + 2); here, but didn't have any luck.
Thank you so much for taking a look!
function columnChange(mobile) {
if (mobile.matches) { // If media query matches variable below function
//If screen size matches variable (is smaller than 1000px wide in our case), change upsell products to have 2 columns
upsellCols.classList.remove('columns-3');
upsellCols.classList.add('columns-2');
//After that, reset first and last columns, then add .last class to 2nd and 4th items to adjust spacing. This assumes a maximum of two rows.
for (var i = 0; i < upsellLi.length; i++ ) {
upsellLi[i].classList.remove('first');
upsellLi[i].classList.remove('last');
upsellLi[1].classList.add('last');
upsellLi[3].classList.add('last');
upsellLi[5].classList.add('last');
//repeat with 5, 7, etc within brackets to add support for more rows
}
} else { //If screen size is larger than 1000px, change upsell products to have 3 columns
upsellCols.classList.remove('columns-2');
upsellCols.classList.add('columns-3');
//After that, reset first and last columns, then add .last class to 3rd and 6th items to adjust spacing. This assumes a maximum of two rows. The "i is already defined" error in Elementor is actually chill because we're only using one for loop at a time thanks to the if/then statement :)
for (var i = 0; i < upsellLi.length; i++ ) {
upsellLi[i].classList.remove('first');
upsellLi[i].classList.remove('last');
upsellLi[2].classList.add('last');
upsellLi[5].classList.add('last');
//repeat with 8, 11, etc within brackets to add support for more rows
}
}
}
Answer per #CBroe in the comments! Here's where I ended up to get this working:
function columnChange(mobile) {
if (mobile.matches) { // If media query matches variable below function
//If screen size matches variable (is smaller than 1000px wide in our case), change upsell products to have 2 columns
upsellCols.classList.remove('columns-3');
upsellCols.classList.add('columns-2');
//After that, reset first and last columns, then add .last class to last product in each row
for (var i = 0; i < upsellLi.length; i++ ) {
upsellLi[i].classList.remove('first');
upsellLi[i].classList.remove('last');
//Add "last" class to every two instances of upsellLi - check if each iteration's number within the loop is divisible by 2. The 1 at the end offsets the count to start on the second iteration (since the count starts at 0)
if(i % 2 === 1) {
upsellLi[i].classList.add('last');
}
}
} else { //If screen size is larger than 1000px, change upsell products to have 3 columns
upsellCols.classList.remove('columns-2');
upsellCols.classList.add('columns-3');
//After that, reset first and last columns, then add .last class to last product in each row
for (var i = 0; i < upsellLi.length; i++ ) {
upsellLi[i].classList.remove('first');
upsellLi[i].classList.remove('last');
//Add "last" class to every 3 instances of upsellLi - check if each iteration's number within the loop is divisible by 3. The 2 at the end offsets the count to start on the third iteration (since the count starts at 0)
if(i % 3 === 2) {
upsellLi[i].classList.add('last');
}
}
}
}

Changing an items index in an array

I currently have an image sliced up into rectangles and then placed over another image so that I can reveal the image in the back(figure1). I currently have the shapes animating in from left to right and top to bottom(figure2). I want the images to animate in a random way(figure3). Originally I created a position array that I shuffled the values of which created the effect that I want but that obviously also shuffled the image slices. So now I am creating an index array and shuffling the values. I want to swap the sliced images indexes with the new values in the shuffled index array. Splice is not giving the desired effect.
for(i=0;i<100;i++){
var _s = new createjs.Sprite(this._ss);
_s.gotoAndStop(i);
this._container.addChild(_s);
if((i % 10)===0){
_ypos += 21;
_xpos = 34;
};
_s.x = _xpos;
_s.y = _ypos;
_xpos += 34;
this._indexArray.push(i);
this._shapeArr.push(_s);
}
this.shuffleArray(this._indexArray);
for(j=0;j<100;j++){
this._shapeArr[j]//CHANGE INDEX HERE
}
For anyone else that is trying to do something similar here is the revised code in the second for loop. I found this link which helped me to resolve the issue so check the link out and if you find it helpful then give the guy a +1
Move an array element from one array position to another
for(j=0;j<100;j++){
//CHANGED CHILD INDEX HERE
this._shapeArr.splice(this._indexArray[j],0,this._shapeArr.splice(j,1)[0]);
}

Logic behind CAD apps multi-selection and alignment functionality

I am trying to build a small CAD app using HTML5 Canvas and Paper.js
Now I am stuck at a problem I'd hate asking for help for since I believe I should solve this on my own, but everytime I try to think about a solution my head hurts.
I am trying to build the following functions:
Align-left
Align-right
Align-center.
The user is supposed to select a bunch of elements on the canvas and click one of the above functions to align them together.
The whole concept is that the user selects a Reference Item in a way. The elements are aligned relative-to the Reference Item. This ensures that the alignments happen in a user predictable way.
There are 2 ways for the user to select elements
Selection-via-Intersection
The user clicks and drags a selection rectangle. While dragging I
can track in an array which items intersected with the selection
rectangle. I can track the first intersected item here just fine, so I
have a Reference Item .Works perfectly so far.
Selection-via-Click+Shift
The user holds Shift and clicks on elements to do a multi-selection.
It's a functionality I'm sure everyone has seen in any modern graphics
editor. I have yet to figure out a way how to track a first-selected
item here, since items can be set as first-selected and then
deselected.
The problem:
The above selection methods can be COMBINED together -
The user can select-via-intersection and then start select/de-select items using Shift+Click.
Which one from the selectedItems is the Reference-Item now?
An example:
Item 2 was the first-selection on selection-via-intersection. Item 2
was de-selected using Shift+Click. Which one is the Reference-Item
now?.
Here is a GIF that illustrates what I am talking about (although it's invinsible in the GIF the items get selected as soon as the intersection rectangle touches them.)
I am aware that the whole thing will involve some array logic but I cannot seem to grasp how to implement the whole thing.
Notes:
Apart from the complexity of this thing, I have performance constraints as well. Intersection Detection which is used for the Selection-via-Intersection is already a heavy operation and it get's fired continously while the user drags a selection rectangle.
This is the code for Select-Via-Intersection
The following function getSortedIntersects get's called continuously while the user drags a selection rectangle. I log in the console the first selected item:
var checkedSegments = new Array();
function getSortedIntersects(rect) {
//children are all the items drawn on the canvas
var children = project.activeLayer.children;
//I clone the children array into another array and I exclude all items other than Paths
//Intersection Detection works only on paths.
var pathsOnCanvas = children.filter(function (el) {
return el instanceof Path
});
var newCheckedSegments = new Array();
var firstSelection = "";
//Start looping over all Paths on the canvas
for (var i = 0; i < pathsOnCanvas.length; i++) {
//create an array which lists all the intersections. The array is called ''intersections''
var intersections = pathsOnCanvas[i].getIntersections(rect);
//If there is at least 1 intersection OR the rect contains a path then proceed
if (intersections.length > 0 || rect.contains(pathsOnCanvas[i].bounds)) {
//Checks if the selected item at index i is in the newSegments array. If so, it continues iterating the loop without going further at this iteration.
if (newCheckedSegments.indexOf(pathsOnCanvas[i]) >= 0)
continue;
pathsOnCanvas[i].selected = true;
newCheckedSegments.push(pathsOnCanvas[i]);
}
}
for (var i = 0; i < newCheckedSegments.length; i++) {
if (checkedSegments.indexOf(newCheckedSegments[i]) < 0)
checkedSegments.push(newCheckedSegments[i]);
firstSelection = (checkedSegments[0].id);
console.log("first selection is " + firstSelection);
}
for (var i = checkedSegments.length - 1; i >= 0; i--) {
if (newCheckedSegments.indexOf(checkedSegments[i]) < 0) {
checkedSegments[i].selected = false;
checkedSegments.splice(i, 1);
}
}
}

Sort multidimensional object literal array by external value

I am trying to make a homemade line of sight for a game im building which is a gridbased, 2D top-view board game. The board has divs in a 2-dimensional array which are all black and will be transparent if the player is in a corridor which are also in a 2-dimensional array with objects. There are miscellaneous blocks in the corridors and i need to take them into consideration so the divs will stop getting transparent if they appear in the corridors where the player is.
So i've got an idea to sort the array of objects in a given corridor where the player is located by the x,y values.
corridors[i].sort(
function(a)
{
if(a.y > playerObj.position.y && a.x > playerObj.position.x) return 1;
if(a.y < playerObj.position.y && a.x < playerObj.position.x) return -1;
return 0;
});
But this does not seem to work. The changing of the divs background-color to transparent is still beginning from the array's first index. I want it to start from the players position in the corridor and work itself outwards like so:
O is simply a tile, P is the player, X is the tile that has just been made transparent
OOOOOOOOOOOPOOOOOO
OOOOOOOOOOXPOOOOOO
OOOOOOOOOOXPXOOOOO
OOOOOOOOOXXPXOOOOO
But for this scenario to function i need to find how to sort my array correctly, and i hope you can help me with this. The examples i've seen on the net has parameters a and b, so is it not possible to use an external variable? Should i perhaps create the players position as a new object and push it to the array and then sort the array?
Okay so i think i solved it. I simply made the sorting function be stored in a new array and used that instead.

Javascript board game: looking for optimization

I'm working on a html/javascript game for android. It's a board game which does the following.
It has tiles of different colors and user can place one tile (chosen programatically) on the board. If we get 4 or more tiles of the same color/shape we score some points and these tiles will disappear. The tiles above the removed tiles will replace them and new tiles will be added to the empty places. The image below shows how it works (this is just an example, the real board can have different dimensions):
The Tiles are <img> elements with their ids stored in an array which I use to check for matches and replacement.
It all works pretty well but once the new tiles are added to board I need to examine the whole board to check if new matches are avalable. And I want some advice here, because examining the whole board can be really slow. Is there a way I can do this efficiently?
Here's what I thought about doing:
Given the previous example,I thought about examining only the elements in the red area, i.e. only the elements that have been moved or added. It can be effective if the tiles move vertically, as I'll only have to check the moved/added tiles and it'll give me the new matches. But in case where I remove tiles horizontally it can be problematic, because if these tiles are at the bottom i'll have to examine the whole board and i confront the same problem.
Any advice or suggestion will be appreciated.
Note: I didn't add any code because it simply consists of checking the lines and columns for a given tile and look for matches. But if needed I can provide it.
EDIT: Before anyone can object I want to inform that I just added this question to Game Development section as I didn't receive any answers here :).
EDIT: Adding my code
function initializeBoard(){
//items is an array which contains tiles/images names
for(var i=0; i < totalItems; i++)
board[i+1] = Math.floor(Math.random() * (items.length - 1)) + 1;
for(var i=0; i < totalItems; i++)
{
if( !(i % numberShapesXAxis) )
document.write("<BR>");
document.write("<img src=\"images/"+ items[board[i+1]]+ ".gif\" style = \"border:0; height:"+ itemSize+ "px; width:"+ itemSize+ "px;\" name=\"t", i+1,"\" onclick = \"replaceAndCheck(", i+1, ")\"><\/a>");
}
}
//so basically board contains image ids.
How about checking if there is a new match when you move a stone. So when stone x moves down you check if the new position of X creates a match. That way you can create a recursive kind of method.

Categories

Resources