JavaScript slider puzzle - javascript

Ultimately I'm making a slider puzzle with a table, but at the moment I am generating a new puzzle and shuffling the tiles, but it appears that something in my code is making this work incorrectly. (not all the table cells are populated, etc.) Any idea what could be causing this?
In the program I am writing, I am using body onload to build the puzzle but for some reason that won't work in the Fiddle:
</head>
<body onload="newPuzzle(_r, _c)">
</body>
Fiddle Example

Try changing
//declare and populate array
var _array = new Array();
for (var i = 0; i <= r*c; i++)
{
_array[i] = i;
}
to
//declare and populate array
var _array = new Array();
for (var i = 1; i < r*c; i++)
{
_array[i] = i;
}
_array[0] = "";
AND changing this:
var rand = Math.floor(Math.random() * _array.length) + i;
to this:
var rand = Math.floor(Math.random() * _array.length);
Just a note, as you're shuffling with a new array, there is not point in the first configuration (0 to 8), that way you can remove two FORs and just set a fixed value when generating it (before shuffle).
Like so:
gridTable[0].rows[i].cells[j].innerHTML = "0";

Related

PaperJs Add 2 raster as 2 symbols in the same project

I have this project in paperjs:
var url = "http://www.clker.com/cliparts/q/I/s/P/E/3/yellow-umbrella-md.png";
raster = new Raster(url);
raster.rotate(10);
raster.scale(0.4);
var url2 = "https://images.vexels.com/media/users/3/145373/isolated/preview/98721f602aa3fadb040e0a161ab3f966-waterdrop-vislumbrante-vis-o-ilustra--o-by-vexels.png";
secondRaster = new Raster(url);
secondRaster.scale(0.9);
var count = 150;
var symbol = new Symbol(raster);
var secondSymbol = new Symbol(secondRaster);
for (var i = 0; i < count; i++) {
// The center position is a random point in the view:
var center = Point.random() * view.size;
var placedSymbol = symbol.place(center);
placedSymbol.scale(i / count);
}
function onFrame(event) {
// Run through the active layer's children list and change
// the position of the placed symbols:
for (var i = 0; i < count; i++) {
var item = project.activeLayer.children[i];
// Move the item 1/20th of its width to the right. This way
// larger circles move faster than smaller circles:
item.position.y += item.bounds.width / 80;
// If the item has left the view on the right, move it back
// to the left:
if (item.bounds.bottom > view.size.width) {
item.position.y = -item.bounds.width;
}
}
}
The first raster has a symbol works good, but the second can't make it work... I read about to add more than one symbol to project.activeLayer.children but don't work. Even if I do a group of an array with both symbols also don't show up.
I read in a post that symbols can't be added as a group. Being that be true, it should be ok to be added even though isolated...
Anybody had done something similar?
Thank you
There are some mistakes in your code:
The most important one, that make you think that the second raster doesn't work, is that you are creating the second raster with the variable url instead of url2. So both rasters use the same image as source...
You need to place the second symbol like you do with the first one otherwise it will never get rendered.
When iterating through active layer children, make sure to iterate over all children by using project.activeLayer.children.length (as you are placing count * 2 symbols).
When checking for bottom reaching items, use height instead of width.
Here is a sketch demonstrating the solution.
var COUNT = 10;
var raster = new Raster('http://www.clker.com/cliparts/q/I/s/P/E/3/yellow-umbrella-md.png');
raster.rotate(10);
raster.scale(0.4);
var secondRaster = new Raster('https://images.vexels.com/media/users/3/145373/isolated/preview/98721f602aa3fadb040e0a161ab3f966-waterdrop-vislumbrante-vis-o-ilustra--o-by-vexels.png');
secondRaster.scale(0.15);
var symbol = new Symbol(raster);
var secondSymbol = new Symbol(secondRaster);
for (var i = 1; i <= COUNT; i++) {
// first symbol
symbol.place(Point.random() * view.size).scale(i / COUNT);
// second symbol
secondSymbol.place(Point.random() * view.size).scale(i / COUNT);
}
function onFrame(event) {
for (var i = 0; i < project.activeLayer.children.length; i++) {
var item = project.activeLayer.children[i];
item.position.y += item.bounds.height / 80;
if (item.bounds.bottom > view.size.height) {
item.position.y = -item.bounds.height;
}
}
}

Randomize gallery array

I'm trying to randomize a gallery of images. The HTML contains only the images, the idea is to then get the array, shuffle it and add them to divs acting as thumbnails. I took the shuffling code from here (the Durstenfeld version): How to randomize (shuffle) a JavaScript array?
My code:
var pics = document.getElementsByTagName("img");
//the Durstenfeld shuffle
for (m = pics.length - 1; m > 0; m--) {
var k = Math.floor(Math.random() * (m + 1));
var temp = pics[m];
pics[m] = pics[k];
pics[k] = temp;
}
//giving ID to each image and adding them to a thumbnail div
for (e = 0; e < pics.length; e++) {
pics[e].id = e;
var photo = document.getElementById(e);
var parent_section = photo.parentNode;
var new_div = document.createElement("div");
new_div.classList.add("thumbnail");
new_div.appendChild(photo);
parent_section.appendChild(new_div);
}
The thing is, this works perfectly fine in IE, but in all of the other browsers I tried, the images are simply placed in the default order (the order in which they are written in the HTML). The shuffling itself should be correct so I'm sure there's something wrong with my implementation of it, but I can't figure it out.
Your Array isnt an Array. Do this:
var pics = Array.from(document.getElementsByTagName("img"));

New to JavaScript and think I need a loop for this.....?

I've got a 180 character string of numbers which needed to be broken down into 6 groups, separated into 2 character figures and then sorted into ascending order.
I've done this, but it looks dirty and I'm pretty sure with my gradual improvement of understanding of JavaScript, that a neat little loop would save me a huge amount of repetition.
<script type="text/javascript">
var ticketString = "011722475204365360702637497481233455758302154058881928446789061241507324334876840738576186051132437816395663800818206590104559628214294664710935667287132130687703253151692742547985".match(/.{1,2}/g);
var groupa = ticketString.slice (0,15);
groupa.sort();
var groupb = ticketString.slice (15,30);
groupb.sort();
var groupc = ticketString.slice (30,45);
groupc.sort();
var groupd = ticketString.slice(45,60);
groupd.sort();
var groupe = ticketString.slice(60,75);
groupe.sort();
var groupf = ticketString.slice(75,90);
groupf.sort();
function displayArray () {
document.getElementById('ticketOne').innerHTML = groupa;
document.getElementById('ticketTwo').innerHTML = groupb;
document.getElementById('ticketThree').innerHTML = groupc;
document.getElementById('ticketFour').innerHTML = groupd;
document.getElementById('ticketFive').innerHTML = groupe;
document.getElementById('ticketSix').innerHTML = groupf;
}
The outputs are placed into paragraphs for now, but I know this could be done easier than the way I have it. The function displayArray loads off the body tag.
If you could rename your elements from ticketOne, ticketTwo etc to ticket1, ticket2 etc:
<script type="text/javascript">
var ticketString = "011722475204365360702637497481233455758302154058881928446789061241507324334876840738576186051132437816395663800818206590104559628214294664710935667287132130687703253151692742547985".match(/.{1,2}/g);
for (var i=0; i<ticketString.length/15; i++) {
var group = ticketString.slice(i*15, i*15+15);
group.sort();
document.getElementById('ticket'+(i+1)).innerHTML = group;
}
</script>
So here is what I think is the best solution:
var ticketString = "011722475204365360702637497481233455758302154058881928446789061241507324334876840738576186051132437816395663800818206590104559628214294664710935667287132130687703253151692742547985".match(/.{1,2}/g);
var group = [];
for (var i = 0; i < 180 / 15 / 2; i++) {
group[i] = ticketString.slice(i * 15, (i + 1) * 15);
group[i].sort();
document.getElementById('ticket[' + i + ']').innerHTML = group[i];
}
What I'm doing here is that I created a local array called group, which is in turn easier to handle within a loop than using a name like "group1" or "ticketFirst".
After that I practically did the same you did, but since I used the for loop I was able to short it down significantly.
The reason why I used i < 180 / 15 / 2 is because you're pairing them in character packs of 2. for (var i = 0; i < 180 / 15 / 2; i++) You ofcourse have to have an HTML like this:
<body>
<p id="ticket[0]"></p>
<p id="ticket[1]"></p>
<p id="ticket[2]"></p>
<p id="ticket[3]"></p>
<p id="ticket[4]"></p>
<p id="ticket[5]"></p>
</body>
You can reduce it to:
var groupArray = [];
for(var i=0;i<100;i+=15){
groupArray.push(ticketString.slice (i,15+i));
groupArray[groupArray.length-1].sort();
}
You could do something like this, if you changed your 'ticket' id's to a generic 'ticket' class;
var ticketString = "011722475204365360702637497481233455758302154058881928446789061241507324334876840738576186051132437816395663800818206590104559628214294664710935667287132130687703253151692742547985".match(/.{1,2}/g);
var tickElem = document.querySelectorAll('.ticket');
var strPoint = 0;
for(var i in tickElem)
{
var grp = ticketString.slice(strPoint, (strPoint += 15));
grp.sort();
tickElem[i].innerText = grp.join('');
}
How about this compact version:
var start = 0;
['ticketOne', 'ticketTwo', 'ticketThree', 'ticketFour', 'ticketFive', 'ticketSix']
.forEach(function (id) {
document.getElementById(id).innerHTML = ticketString.slice(start, start += 15).sort();
});
<script>
var ticketString ="011722475204365360702637497481233455758302154058881928446789061241507324334876840738576186051132437816395663800818206590104559628214294664710935667287132130687703253151692742547985".match(/.{1,2}/g);
function loadTickets () {
var ticket = [];
for (var i = 0; i < ticketString.length / 15; i++) {
ticket[i] = ticketString.slice(i * 15, (i + 1) * 15).sort();
var tableCre = document.createElement("TABLE");
tableCre.setAttribute("id","ticketTable" + i)
document.body.appendChild(tableCre);
document.getElementById('ticketTable' + i).innerHTML = ticket[i];
}
console.log(ticketString);
console.log(ticket);
};
</script>
Got it fixed, #Quikers - given you the thumbs up; as this was the thinking I had - brought the .sort() function into the ticket[i] variable to trim it a little and based on the number of arrays, I have dynamically created 6 tables that hold the strings inside them. I have to develop the tables and set them up, but I am pretty much there now. Thanks for all your help.

Loop through array of images in javascript

I'm trying to loop through an array of images but can't seem to get past image 2.
The array should also loop back to 1 when the last image has passed...
var WorkArray = new Array('work/01.png', 'work/02.png', 'work/03.png', 'work/04.png');
var nelements = WorkArray.length;
preload_image_object = new Image();
var i = 0;
for(i=0; i<=nelements; i++) {
preload_image_object.src = WorkArray[i];
}
function cC() {
var nelements = WorkArray.length;
var i = 0;
for(i=0; i<=nelements; i++) {
nelements = WorkArray[i];
}
document.getElementById("work").style.backgroundImage="url('"+WorkArray[i]+"')";
}
You can save the current file and use modulo to run in cyclic manner.
It will look something like that:
var WorkArray = new Array('work/01.png', 'work/02.png', 'work/03.png', 'work/04.png');
var currentImage = 0
function nextImage(){
currentImage = (currentImage + 1) % WorkArray.length;
document.getElementById("work").style.backgroundImage="url('"+WorkArray[currentImage]+"')";
}
You are overwriting nelements with the current element of the loop:
nelements = WorkArray[i];
The following should fix your loops:
var WorkArray = new Array('work/01.png', 'work/02.png', 'work/03.png', 'work/04.png');
var preload_image_object = new Image();
/* Lets get rid of `nelements`, as its just confusing. Get the length here.
* If, for performace reasons you want to use elements, the best way is to reverse
* aka for(var i = WorkArray.length-1; i >= 0 ; i--)
* Also, its simpler to declare the var in your for-loop itself instead of outside of it.
*/
for(var i = 0; i <= WorkArray.length; i++){
preload_image_object.src = WorkArray[i];
}
Also, again for simplifications sake, your application of the background-image could be done inside your for loop as well, and can be made to look cleaner with some spaces and omitting the ' inside your url():
document.getElementById("work").style.backgroundImage = "url(" + WorkArray[i] + ")";

Javascript Random problem?

var swf=["1.swf","2.swf","3.swf"];
var i = Math.floor(Math.random()*swf.length);
alert(swf[i]); // swf[1] >> 2.swf
This case ,Random output One number.
How to Random output two different numbers ?
var swf = ['1.swf', '2.swf', '3.swf'],
// shuffle
swf = swf.sort(function () { return Math.floor(Math.random() * 3) - 1; });
// use swf[0]
// use swf[1]
Even though the above should work fine, for academical correctness and highest performance and compatibility, you may want to shuffle like this instead:
var n = swf.length;
for(var i = n - 1; i > 0; i--) {
var j = Math.floor(Math.random() * (i + 1));
var tmp = swf[i];
swf[i] = swf[j];
swf[j] = tmp;
}
Credits to tvanfosson and Fisher/Yates. :)
You can use splice to remove the chosen element, then simply select another randomly. The following leaves the original array intact, but if that's not necessary you can use the original and omit the copy. Shown using a loop to demonstrate how to select an arbitrary number of times upto the size of the original array.
var swf=["1.swf","2.swf","3.swf"];
var elementsToChoose = 2;
var copy = swf.slice(0);
var chosen = [];
for (var j = 0; j < elementsToChoose && copy.length; ++j) {
var i = Math.floor(Math.random()*copy.length);
chosen.push( copy.splice(i,1) );
}
for (var j = 0, len = chosen.length; j < len; ++j) {
alert(chosen[j]);
}
I would prefer this way as the bounds are known (you are not getting a random number and comparing it what you already have. It could loop 1 or 1000 times).
var swf = ['1.swf', '2.swf', '3.swf'],
length = swf.length,
i = Math.floor(Math.random() * length);
firstRandom = swf[i];
// I originally used `delete` operator here. It doesn't remove the member, just
// set its value to `undefined`. Using `splice` is the correct way to do it.
swf.splice(i, 1);
length--;
var j = Math.floor(Math.random() * length),
secondRandom = swf[j];
alert(firstRandom + ' - ' + secondRandom);
Patrick DW informed me of delete operator just leaving the value as undefined. I did some Googling and came up with this alternate solution.
Be sure to check Tvanfosson's answer or Deceze's answer for cleaner/alternate solutions.
This is what I would do to require two numbers to be different (could be better answer out there)
var swf=["1.swf","2.swf","3.swf"];
var i = Math.floor(Math.random()*swf.length);
var j;
do {
j = Math.floor(Math.random()*swf.length);
} while (j === i);
alert(swf[i]);
alert(swf[j]);
Edit: should be j===i

Categories

Resources