0

I am attempting to have the image pieces randomize yet not overlap when the "Randomize" button is clicked. Instead, they start to overlap. Any ideas on how to randomize the images, or shuffle them?

Full code here: https://jsfiddle.net/Klammertime/guus9df7/

JavaScript code attempting to randomize images:

$('button').click(function() {
    for (var i = 0; i < 100; i++) {
        var randomN = Math.floor(Math.random() * 15) + 1;
        console.log(randomN);
        var imageBox = $('#board').children("div:nth-child(" + randomN + ")");
        console.log(imageBox);
        Move(imageBox, 175);
    }
});

Full JavaScript code here:

 $(document).ready(function() {
     var zi = 1;
     var EmptySquare = 16;

     $.fn.extend({
         fifteen:

             function(square_size) {
             var gameObjectElement = '#' + $(this).attr('id');

             var sqSize = square_size + 'px';
             var boardSize = (square_size * 4) + 'px';

             $(gameObjectElement).html('<div id="board"></div>');

             $('#board').css({
                 position: 'absolute',
                 width: boardSize,
                 height: boardSize,
                 border: '1px solid gray'
             });

             for (var i = 0; i < 16; i++) {
                 $('#board').append("<div class='" + i + "' style='left:" + ((i % 4) * square_size) + "px; top: " + Math.floor(i / 4) * square_size + "px; width: " + square_size + "px; height: " + square_size + "px; background-position: " + (-(i % 4) * square_size) + "px " + -Math.floor(i / 4) * square_size + "px; '></div>");

                 // Select the children of #board ID that are divs, and the 16th one, then make backgroundImage nothing, and background color of white. 
                 // This emptys the 16th square.
                 $('#board').children("div:nth-child(" + EmptySquare + ")").css({
                     backgroundImage: "",
                     background: "#ffffff"
                 });

                 // Attach a click event to each of the squares, or divs.
                 $('#board').children('div').click(function() {
                     Move(this, square_size);
                 });

                 $('button').click(function() {
                     for (var i = 0; i < 100; i++) {
                         var randomN = Math.floor(Math.random() * 15) + 1;
                         console.log(randomN);
                         var imageBox = $('#board').children("div:nth-child(" + randomN + ")");
                         console.log(imageBox);
                         Move(imageBox, 175);
                     }

                 });
             }
         }
     });

     function Move(clicked_square, square_size) {
         var movable = false;

         // oldx is really just empty square x and empty square y
         // swap the old with the new, just make it so new has x and y for top and bottom of the empty spot

         var empty_x = $('#board').children("div:nth-child(" + EmptySquare + ")").css('left');
         var empty_y = $('#board').children("div:nth-child(" + EmptySquare + ")").css('top');

         var image_x = $(clicked_square).css('left');
         var image_y = $(clicked_square).css('top');

         // parseInt is used because the oldy has 'px' in it, you just want the number
         // check to see if clicked square or image_x and image_y is north of empty square
         if (empty_x == image_x && image_y == (parseInt(empty_y) - square_size) + 'px') movable = true;

         // check to see if clicked square is south of empty square, so its y would be more, so +
         if (empty_x == image_x && image_y == (parseInt(empty_y) + square_size) + 'px') movable = true;

         // check to see if clicked square is left of empty square, which makes left less, or x less
         if ((parseInt(empty_x) - square_size) + 'px' == image_x && image_y == empty_y) movable = true;

         // check to see if clicked square is right of empty square, so left is more
         if ((parseInt(empty_x) + square_size) + 'px' == image_x && image_y == empty_y) movable = true;

         if (movable) {
             // increment z-index up from 1 so that new tile is on top of others
             $(clicked_square).css('z-index', zi++);

             // move image square into the empty square position using animate
             // Durations are given in milliseconds; higher values indicate slower animations, not faster ones. 200 is ms
             $(clicked_square).animate({
                 left: empty_x,
                 top: empty_y
             }, 100, function() {
                 // move empty square where image square you just moved was
                 $('#board').children("div:nth-child(" + EmptySquare + ")").css('left', image_x);
                 $('#board').children("div:nth-child(" + EmptySquare + ")").css('top', image_y);
             });
         }
     }

     // initialize game with 175 by 175 squares inside the #game_object div
     $('#game_object').fifteen(175);
 });
Sushil
  • 2,837
  • 4
  • 21
  • 29
Klammertime
  • 78
  • 1
  • 8

2 Answers2

2

Your random function (Math.floor(Math.random() * 15) + 1;) doesn't guarantee there are no random numbers repeating, so there are strong chances of two or more images occupying the same space after you randomize them.

Perhaps you could make an array with index numbers of images and just shuffle that. There are tons of array shuffle examples online, such as this one: https://stackoverflow.com/a/6274381/965907

Here's a simple one I wrote quickly - it pops a random element from the original array and pushes it into a new array until all the slots have been filled. I think it will work nicely with your code:

function shuffle() {
  var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9];
  var newArr = [];
  var len = arr.length;
  while (newArr.length != len) {
    newArr.push(arr.splice(Math.floor(Math.random() * arr.length), 1));
  }
  alert(newArr);
}
<button onclick="shuffle()">Shuffle</button>
Community
  • 1
  • 1
Shomz
  • 37,421
  • 4
  • 57
  • 85
  • 1
    Thank you, @dippas! (haha, I upvoted that one who knows when) Also, I added a simple one I just wrote to my answer. – Shomz Jun 23 '15 at 23:40
  • Thank you very much all of you for help. I created a shuffling function based on this comment: https://jsfiddle.net/Klammertime/6s35coda/ – Klammertime Jun 24 '15 at 16:31
  • You're welcome, @Klammertime! Looks nice, btw. rapid clicking the buttom will still cause some overlapping, so you might want to fix that as well. – Shomz Jun 24 '15 at 17:50
0

Like Shomz already answered, you want to shuffle your images. (stolen from How to randomize (shuffle) a JavaScript array?)

function shuffle(array) {
    var currentIndex = array.length,
        temporaryValue, randomIndex;

    // While there remain elements to shuffle...
    while (0 !== currentIndex) {

        // Pick a remaining element...
        randomIndex = Math.floor(Math.random() * currentIndex);
        currentIndex -= 1;

        // And swap it with the current element.
        temporaryValue = array[currentIndex];
        array[currentIndex] = array[randomIndex];
        array[randomIndex] = temporaryValue;
    }

    return array;
}

$('button').click(function() {
    var positions = [];
    $('#board div').each(function(idx, div) {
        positions.push($(div).offset());
    });

    shuffle(positions);

    $('#board div').each(function(idx, div) {
        $(div).offset(positions[idx]);
    });
});

fiddle

Community
  • 1
  • 1
Fabricator
  • 12,722
  • 2
  • 27
  • 40