13 Replies Latest reply: Sep 13, 2012 9:37 AM by sinious RSS

    Random Array without Sequential Repeats

    saratogacoach Community Member

      Hi,

       

      Continuing to build the eLearning exercise (much help from kglad). Ran into a problem with sequential repeats in the random array, needing a solution. The AS3 script (much help here from kglad) to generate and then shuffle the array, often (since there are only 9 potential elements for an array length of 70) produces sequential repeats. For example, using 1,2,3,4,5,6,7,8,9 as elements, the shuffled final array can produce 2,2,2,1,4,5,9,3,3.......

       

      Problem is that when these repeats are used in  textbox.text, there is no transition between same (repeated) "words." If a word changes (for example from 5 to 3), the user sees a visiable change. However, with these repeats (for example, 3 to 3), there is no transition: the repeat appears to just stay the same for a longer time. Then the user isn't sure if they've already chosen this word.

       

      In any  event, it would be better, since I can't seem to add a visible transition for repeats, to simply avoid sequential repeats, if possible. But cannot figure out a way to add this to the script.

       

      Any help appreciated.

       

      The current random array and shuffle scripts:

       

       

      var index:int = 0;
      var numToDisplay:int = 10;
      var groupA:Array = ["1","2","3"]
      var groupB:Array = ["4","5","6"]
      var groupC:Array = ["7","8","9"]
      var word_array:Array = [];
      var i:int;
      for(i=0;i<3;i++){
      word_array.push(groupA[Math.floor(groupA.length*Math.random())]);
      }
      for(i=0;i<3;i++){
      word_array.push(groupB[Math.floor(groupB.length*Math.random())]);
      }
      for(i=0;i<3;i++){
      word_array.push(groupC[Math.floor(groupC.length*Math.random())]);
      }
      
      shuffle(word_array);
      
      function shuffle(a:Array) {
              var i:int;
              var j:int;
              var e:*;
              var len:int = a.length;
              for (i = len-1; i>=0; i--) {
                  j=Math.floor((i+1)*Math.random());
                  e = a[i];
                  a[i] = a[j];
                  a[j] = e;
              }
      }
      
        • 1. Re: Random Array without Sequential Repeats
          sinious CommunityMVP

          Are you literally doing the arrays as small as above or is that pseudo? If so you should just shuffle groupA/B/C and add them iteratively (word_array.push(groupA[i])). That will shuffle the 3 numbers and guarantee no duplicates because you're not randomly picking a number, you're using them all, in their shuffled order.

           

          I'm not familiar with exactly what you're trying to do besides what I see there which is apparently generate an array with 1-9 shuffled. I don't understand why you're breaking them up into 3 groups unless this is pseudo and not actually the real code. I presume you want to add a lot more, potentially duplicate numbers to each group to go this route because it's overkill to just generate a random list of numbers 1-9.

          • 2. Re: Random Array without Sequential Repeats
            saratogacoach Community Member

            Hi,

             

            Sorry for not providing more detail. The final mixed array of 70 is made up of a ratio of items from the 3 groups (A,B,C) that is 20:20:30. The numbers used in this illustration are stand-in's for the words. But, Group A, Group B and Group C each only have 3 members. So repeats are difficult to avoid.

             

            The rest of the script has timer, setTimeout's in order to quickly present the words to the user who then in split second (600ms with an additional 400ms ,plus 100ms for an O or X to show correct/incorrect, until the next word is displayed). The word transitions are difficult to manage in this short a time. When there is a sequential repeat (3,3 or 7,7, etc.) then there isn't any noticeable visual change between the 2 same words. Since choosing (by pressing or not pressing a button) is required in the exercise, the user can become confused whether they are seeing the same word they have already reacted to (press or no-press). So, one way to prevent this would be to avoid sequential repeats. Another way, which I can't figure out how to implement is to get a very brief duration blink between words when they transition to indicate to the user that a change has occured. I'm a  social worker with modest self-taught scripting skills. So, very challenging. But I'm always game to learn.

             

            Thank you for your interest and help.

            • 3. Re: Random Array without Sequential Repeats
              sinious CommunityMVP

              Can you explain the relevance of breaking it into 3 groups?

              • 4. Re: Random Array without Sequential Repeats
                saratogacoach Community Member

                Sure,

                 

                The exercise replicates a published study which uses 3 separate categories of words as stimuli presented to an exercise-taker. For the scoring of results to work, and allow comparison to published score results, it require precise replication of the published exercise design: out of 70 final presented items, 20 must be from Group A, 20 from Group B and 30 from Group C. (If the word stimuli or time exposure were different, results and data comparisons would not be valid.)

                 

                The only other option, if I can't fix this, is to start over and build it a different way: use 70 frames, each with a hard-coded word. Then I would need a script to randomly present these (gotoAndPlay) without repeating the same frame, and assure that all 70 are presented. Whew!

                 

                I also tried modyifying the shuffle function (see above) by splicing out and pushing duplicates to the end. Unfortunately my scripting was not successful: I seem to have translated array elements into array positions instead, which won't work.

                 

                 

                function shuffle(a:Array) {
                
                        var i:int;
                
                        var j:int;
                
                        var e:*;
                
                        var len:int = a.length;
                        
                        
                        
                        for (i = len-1; i>=0; i--) {
                
                            j=Math.floor((i+1)*Math.random());
                
                            e = a[i];
                
                            a[i] = a[j];
                
                            a[j] = e;
                
                        }
                for (i = 0; i < a.length - 1; i++){  //newly added script that results in array positions instead of words in replaced parts of the array.
                        for (j = i + 1; j < a.length; j++){
                            if (a[i] === a[j]){
                                a.splice(j, 1);
                                a.push(j);
                            }
                        }
                    }
                    }
                

                Any help appreciated.

                • 5. Re: Random Array without Sequential Repeats
                  sinious CommunityMVP

                  Ah, ok.. I'd approach it a little different with array splice and cloning. Something that would allow you to add in more values to any group would be like so:

                   

                  // content

                  var groupA:Array = ["1","2","3"];

                  var groupB:Array = ["4","5","6"];

                  var groupC:Array = ["7","8","9"];

                   

                  // master list

                  var wordOrder:Array = new Array();     // words list

                  var helperArr:Array = new Array();    // helper array

                   

                  // generate all 70 elements

                  while (wordOrder.length < 70)

                  {

                      var cloneArr:Array = new Array();

                   

                      // select proper group to get content from based on amount in wordOrder

                      if (wordOrder.length < 21)

                      {

                          cloneArr = groupA.concat();

                      }

                      else if (wordOrder.length < 41)

                      {

                          cloneArr = groupB.concat();

                      }

                      else

                      {

                          cloneArr = groupC.concat();

                      }

                   

                      // return a shuffled array of values guaranteeing the first item does

                      // not duplicate the last word added

                      helperArr = shuffle(cloneArr);

                   

                      // push returned shuffled values in, stopping if length is met

                      while ((helperArr.length > 0) && (wordOrder.length < 70))

                      {

                          wordOrder.push(helperArr.splice(0,1));

                      }

                  }

                   

                  trace(wordOrder);

                   

                  function shuffle(sourceArr:Array):Array

                  {

                      // new shuffled array to return after filling

                      var destArr:Array = new Array();

                   

                      // splice the sourceArr into the destArr randomly

                      while (sourceArr.length > 0)

                      {

                          destArr.push(sourceArr.splice(int(Math.random() * sourceArr.length), 1)[0]);

                      }   

                   

                      // assure first value does not match last value added, otherwise shift

                      if (destArr[0] == wordOrder[wordOrder.length - 1])

                      {

                          // remove last value off array, replace with first

                          destArr.unshift(destArr.pop());

                      }

                   

                      return destArr;

                  }

                   

                  Any size array can be used in any group and it'll shuffle them. Lastly before completing and returning a shuffled array it will check the last value added to wordOrder and make sure it doesn't match the first item being returned or that would be a duplicate. If that's the case it just pops the last value off the array and adds it to the beginning to assure it's not a duplicate.

                   

                  If for whatever reason you do add in the same value multiple times in a single group the pop/shift won't work because you chance the last value being identical to the first and I'm not testing for that in the code above. You can paste this in a new AS3 document and it will trace out the list it generates at the end.

                   

                  Just out of best practices I originally added a second argument to shuffle so you could pass in the last added value and it would compare against the value you sent. I simplified it by directly reading from wordOrder inside the function. That's hard coding or coupling the function directly rather than keeping it generic and it's not best practice, but for your purposes I don't think it will harm you.

                  • 6. Re: Random Array without Sequential Repeats
                    saratogacoach Community Member

                    Thank you very much for this. I did try it in a new AS3 doc and got an output of 68 instead of 70. Not sure why? Since need 70.

                     

                    Probably chopped off first and last? I can see how this could happen.

                     

                    Not sure how to fix this.

                     

                    Could work if this fixed. (But, the words from the study that must be used in the exercise are specific. So, no way to change them.)

                    • 7. Re: Random Array without Sequential Repeats
                      sinious CommunityMVP

                      I get 70 every time. Try to copy and paste it again. Examples:

                       

                      3,1,2,1,3,2,1,2,3,1,2,3,1,3,2,3,1,2,3,1,2,5,4,6,4,5,6,4,6,5,4,5,6,4,5,6,4,6,5,6,4,5,9,8,7, 9,7,8,9,7,8,9,8,7,8,9,7,8,9,7,8,9,7,8,9,7,9,7,8,9 [70]

                      3,1,2,3,2,1,2,3,1,2,1,3,1,3,2,1,2,3,1,2,3,5,4,6,4,6,5,4,5,6,5,6,4,6,4,5,6,4,5,4,6,5,9,7,8, 7,8,9,8,9,7,8,7,9,8,7,9,8,7,9,7,9,8,9,8,7,8,9,7,9 [70]

                      1,2,3,1,3,2,3,1,2,3,1,2,1,3,2,3,1,2,1,3,2,4,6,5,6,5,4,5,6,4,5,4,6,4,6,5,4,5,6,5,4,6,8,9,7, 9,7,8,9,8,7,9,7,8,7,9,8,9,8,7,8,7,9,7,9,8,9,8,7,8 [70]

                      • 8. Re: Random Array without Sequential Repeats
                        saratogacoach Community Member

                        Yes, sorry about that. Must have mis-counted.

                         

                        I'll try integrating it into the script that I already have, see if I can get it to work in the exercise.

                         

                        Much thanks!

                        • 9. Re: Random Array without Sequential Repeats
                          sinious CommunityMVP

                          You're welcome and if you're all set please mark the thread as answered so we can filter unanswered questions. Good luck!

                          • 10. Re: Random Array without Sequential Repeats
                            saratogacoach Community Member

                            Unfortunately, can't get it to work as needed in the exercise:

                             

                            The one problem I am encountering when testing: the 3 groups are not mixing together but instead all clustered in either the first, second or third groups of positions in the array.

                             

                            In this exercise, the final mixed array needs to interleave Groups A, B and C.

                             

                            Nvere-the-less, I am marking it "correct" since the script is very capable, and no further help needed on this here.

                             

                            (I'm going to try another way to create the exercise, using multiple frames (70-one for each word). This will also make navigation and scoring easier.)

                             

                            Again, thanks very much for your help.

                            • 11. Re: Random Array without Sequential Repeats
                              sinious CommunityMVP

                              Remember you have an array shuffle function already that scales to any size array. In the example above you only need to add one line of code to shuffle the final array:

                               

                              wordOrder = shuffle(wordOrder);

                               

                              It will perform the "check for duplicate" function unneededly at that point but it shouldn't matter.

                               

                              edit:

                               

                              Oops I won't erase it but you can't do that. It suffers from what I mentioned above where no group can contain duplicates and the array produced definitely has duplicates in it.

                               

                              If they need to be mixed together I suggest you not break them into 3 different groups. There's no purpose at that point. You should make a single array full of the 9 different words and add them randomly. You had previously mentioned you needed 20 from the first group, 20 from the second and 30 from the 3rd. I just followed that recipe. What you want requires a bit more code but I think you have enough code now to understand how you can achieve what you want. Post back if you have any questions on your attempt.

                               

                              I'll give you a lead but I'm not going to complete the logic so you can try to see if you can finish it yourself. Always helps to learn. The shuffle's splice() randomization in the while(){} loop can be rewritten to check for a duplicate like this:

                               

                              while (sourceArr.length > 0)

                              {

                                  var randPos:int = int(Math.random() * sourceArr.length);

                               

                                   // check if current word is the same as the last word added, if so ignore and continue

                                  if (sourceArr[randPos] == destArr[destArr.length - 1]) { continue; }

                               

                                  destArr.push(sourceArr.splice(randPos, 1)[0]);

                              }   

                               

                              Note: please do not add that and leave it at that. It will most likely create an infinite loop and hang you.

                               

                              Here's the challenge. You can randomly pick from the source array to add to the destination array and eventually get down to the last few numbers. Picture it in your mind. You may end up with the destArr's last word as "1" and all you have left in sourceArr is 5 "1"'s. Therefore the test will fail every time because all you have is a bunch of duplicate "1"s and the "continue;" will put you in an infinite loop.

                               

                              Your challenge is to sense when all you have left is a handful of the same word and then sprinkle them into the destArr in a random place. You can do that by looping over the values of sourceArr to see if they're all the same. If they are, and they match the last value added to destArr, then you need to handle sprinkling these into destArr.

                              • 12. Re: Random Array without Sequential Repeats
                                saratogacoach Community Member

                                Hi sinious,

                                 

                                Thank you for your continued support and help. I've spent the morning unsuccessfully trying to build the alternative version, about ready to give up with that as well. (Hit a wall with scoring: if the user chooses the correct word, an "O" displays. Easy enough. But, if they decide not to (correctly) click on the button, an "X" needs to appear to provide feedback that this was incorrect, before the timer moves to the next frame and next word. Detecting, during split seconds, if the user has clicked or not, setting a Bool, for example, that the checking function would check before displaying the "X", has been unsuccessful. If they click correctly at the last split second, setting the Bool, it's too late and the "X" displays anyway, giving false feedback.)

                                 

                                Been at this for over 1 week, hours and hours, no joy, no likely solution, given my scripting skills.

                                 

                                I can sort of understand what you are suggesting, but not enough to actually implement it. (Plus even if I could get this part working, I would still face the same scoring and feedback problem (see above).

                                 

                                So, am considering just putting it aside. More than my skill level can achive at this time.

                                 

                                Your script, and expert understanding are impressive! Much thanks for your help.

                                 

                                Best Wishes,

                                • 13. Re: Random Array without Sequential Repeats
                                  sinious CommunityMVP

                                  If you pick it back up and have more questions feel free to open a new thread. You're welcome and good luck!