Generate Random Number Using math.random, But Without Repeats - arrays

For a yearly Christmas event for an organization I'm a part of, we usually hold a raffle where people have the opportunity to win free prizes by just attending and getting a number ticket at the door. We use a program written in Flash (Using ActionScript 2.0) that selects a random number utilizing math.random, with some parameters attached to it, as shown below:
//maxNr = 999999999999999;
initRandom = function(){
var nr = Math.ceil(Math.ceil(Math.random()*(maxNr));
var nrString = "";
for( var j=0; j<(maxNr.toString().length-nr.toString().length); j++){
nrString += "0";
}
nrString += nr.toString();
var holder = this.createEmptyMovieClip("holder",1);
for( i=0; i<maxNr.toString().length; i++ ){
var mc = holder.attachMovie("number","n"+i,i+10);
mc._x = i*350;
mc.anim_mc.gotoAndPlay( Math.floor(Math.random()*9) + 1 );
this["iv"+i] = setInterval( this, "revealNumber", 2000 + (500*i), nrString.substr(i,1), i );
}
// scale (if needed) and center
if( holder._width > Stage.width ){
holder._width = Stage.width;
holder._yscale = holder._xscale;
}
holder._x = Stage.width/2 - holder._width/2;
holder._y = 100;
// buttons
back_btn.onRelease = function(){
for(item in holder){
holder[item].removeMovieClip();
}
gotoAndStop("intro");
}
}
revealNumber = function( digit, i ){
clearInterval( this["iv"+i] );
holder["n"+i].gotoAndStop("done");
holder["n"+i]["number_txt"].text = digit;
}
initRandom();
stop();
It's meant to return a random number between 1 and 1000, as defined by:
go_btn.onRelease = function(){
maxNr = Math.max( 1000 , 1 );
gotoAndStop("random");
}
stop();
It was written by a member of our organization who unfortunately passed away during the year, and I have little to no programming knowledge but I am a quick learner and have actually modified some of the code to get to the point it is currently. However, I'm trying to add in a parameter that would disallow the function from repeating a number, ie, excluding an already generated number from being reselected.
I've spent days scouring any resource possible and have only met dead ends.
With the approach currently taken, is it possible to add in this parameter to this existing code, and how can I go about doing that?
Any help, suggestion or reply would be very greatly appreciated!

package
{
public class RandomGenerator
{
private var _st:Number;
private var _en:Number;
private var _len:Number;
private var _pos:Number;
private var _numPos:Number;
private var _myNums:Array;
private var _randNums:Array;
public function RandomGenerator(en:Number, st:Number = 0)
{
_st = st;
_en = en;
// just in case if params order mixup:
if(en < st){
_st = en;
_en = st;
}
_len = _en - _st + 1;
shuffle();
}
public function getNum():Number
{
// if passed last item:
if(_numPos == _len)shuffle();
var myResult:Number = _randNums[_numPos];
_numPos++;
return myResult;
}
private function shuffle():void
{
_numPos = 0;
_randNums = [];
_myNums = [];
// Creating Numbers Array:
var i:Number;
for(i = 0; i<_len; i++){ _myNums[i] = _st + i; }
// Creating shuffled Numbers Array:
i = 0;
while(_myNums.length > 0){
_pos = Math.round(Math.random()*(_myNums.length-1));
_randNums[i] = _myNums[_pos];
i++;
_myNums.splice(_pos,1);
}
}
public function get len():Number
{
return _len;
}
}
}
make an object from this class for example cardGenerator:RandomGenerator = new RandomGenerator(51, 0) and finally you can get random number without repeat with this codes:
for (var i:int = 0; i < cardGenerator.len; i++) {
trace(cardGenerator.getNum());
}

My AS2 is a bit rusty, but I think the following script explains the general idea. You need some registry to record generated numbers so you can skip them next time you generate one. I used the _global object so that this logic transcends even multiple instances of the following script.
// Create an Array to record generated numbers.
// The _global object is always present and can be accessed from anywhere.
if (_global.uniqueNr == undefined)
{
_global.uniqueNr = [];
}
function initRandom()
{
var nr;
do
{
nr = Math.ceil(Math.ceil(Math.random()*(maxNr));
}
while (_global.uniqueNr[nr] == true);
// Record the newly generated number so it would never drop again.
_global.uniqueNr[nr] = true;
// At this point you can be sure that "nr" contains a unique value.

Related

fixing non-null String must be provided to a Text widget

I'm quite new in flutter.
I am working on a quiz app and try to make every quiz has five questions
I faced some problems :
1- I don't want to repeat the same question in the same quiz.[my quiz also start with question number one every time].
2- Every time it reaches my question number ten [which in array] nine my app crash.
NOTE: I'm using a JSON file to store my questions.
int j = 1;
int i = 1;
var random_array;
genrandomarray() {
var distinctIds = [];
var rand = new Random();
for (int i = 1;;) {
distinctIds.add(rand.nextInt(10));
random_array = distinctIds.toSet().toList();
if (random_array.length < 10) {
continue;
} else {
break;
}
}
print(random_array);
}
setState(() {
if (j < 5) {
i = random_array[j];
j++;
} else {
Navigator.of(context).pushReplacement(MaterialPageRoute(
builder: (context) => resultpage(marks: marks),
));
}
disableAnswer = false;
});
genrandomarray() {
var rand = new Random();
make it choose random between questions
var distinctIds = [i = rand.nextInt(10) + 1];
for (int i = 0;;) {
to not crash when it reach to 10 question
distinctIds.add(rand.nextInt(10) + 1);
random_array = distinctIds.toSet().toList();
if (random_array.length < 10) {
continue;
} else {
break;
}
}
print(random_array);
}

Drag and Drop Arrays AS3

I'm trying to create a drag and drop game in Actionscript 3 using mostly arrays. I'm doing it on a simpler game first before going to the main game because I need to know how the codes work first.
The simpler game is just there are two squares and two circles. The two squares are on a different array while the two circles are in the same one. What should happen is that when either circles hit (hitTestPoint) the right square, their x and y becomes the center of the square. (like it clicks to the center). And when either circles hit the left square, it should return the circles to their last position (doesn't have to be their original position).
Here's the code:
package
{
import flash.display.MovieClip;
import flash.events.MouseEvent;
import flash.display.DisplayObject;
import flash.geom.Point;
import flash.events.Event;
public class MC_MAIN extends MovieClip
{
var mc1:mc_circle;
var mc2:mc_circle;
var mc3:mc_square;
var mc4:mc_square;
var Shapes:Array;
var Target:Array;
var WTarget:Array;
var newPlace:Point;
public function MC_MAIN()
{
// constructor code
init();
}
function init():void
{
Shapes = new Array ;
Target = new Array ;
WTarget = new Array ;
mc3 = new mc_square();
mc3.height = 75;
mc3.width = 75;
mc3.x = 400;
mc3.y = 200;
Target.push(mc3);
addChild(mc3);
mc4 = new mc_square();
mc4.height = 75;
mc4.width = 75;
mc4.x = 150;
mc4.y = 200;
WTarget.push(mc4);
addChild(mc4);
mc1 = new mc_circle();
mc1.height = 25;
mc1.width = 25;
mc1.x = 100;
mc1.y = 100;
Shapes.push(mc1);
addChild(mc1);
mc2 = new mc_circle();
mc2.height = 25;
mc2.width = 25;
mc2.x = 200;
mc2.y = 200;
Shapes.push(mc2);
addChild(mc2);
for (var i:int = 0; i<Shapes.length; i++)
{
Shapes[i].addEventListener(MouseEvent.MOUSE_DOWN, DRG);
Shapes[i].addEventListener(MouseEvent.MOUSE_UP, SDRG);
}
}
function DRG(e:MouseEvent):void
{
e.currentTarget.startDrag();
}
function SDRG(e:MouseEvent):void
{
e.currentTarget.stopDrag();
for (var m:int = 0; m<Shapes.length; m++)
{
newPlace = new Point(Shapes[m].x,Shapes[m].y);
}
trace(newPlace);
for (var a:int = 0; a<Target.length; a++)
{
for (var b:int = 0; b<Shapes.length; b++)
{
if (Target[a].hitTestPoint(Shapes[b].x,Shapes[b].y))
{
Shapes[b].x = Target[a].x;
Shapes[b].y = Target[a].y;
}
}
}
for (var c:int = 0; c<WTarget.length; c++)
{
for (var d:int = 0; d<Shapes.length; d++)
{
if (WTarget[c].hitTestPoint(Shapes[d].x,Shapes[d].y))
{
Shapes[d].x = newPlace.x;
Shapes[d].y = newPlace.y;
}
}
}
}
}
}
What happens is that the code for the left square doesn't work but their are no syntax errors. Nothing happens when either circles hit the left square.
And when I'm trying to trace the position of the circles, It just shows the x & y coordinate of only one of them. (I guess it's tracing the first object of the array which is at index 0. I'm just asking if I guessed right for this part.)
I is a bit difficult to follow the logic and there are some points that doesn't make much sense like:
for (var m:int = 0; m<Shapes.length; m++)
{
newPlace = new Point(Shapes[m].x,Shapes[m].y);
}
newPlace will be the position of the last shape in Shapes, so the loop is fairly useless.
I guess what you need is something like that:
public class MC_MAIN extends MovieClip
{
private leftSquares:Array;
private rightSquares:Array;
//more of the members from above
private startPos:Point;
//init the thing and add left and right squares
//to there respective Array
function DRG(e:MouseEvent):void
{
var t:DisplayObject = e.currentTarget;
//save the starting position
startPos = new Point(t.x,t.y);
t.startDrag();
}
function SDRG(e:MouseEvent):void {
var t:DisplayObject = e.currentTarget;
//find all squares from the left
//the target »hits«
var leftHits:Array = leftSquares.filter(
function (square:DisplayObject) {
return square.hitTestPoint(t.x, t.y);
});
//same for the right
var leftHits:Array = rightSquares.filter(
function (square:DisplayObject) {
return square.hitTestPoint(t.x, t.y);
});
//now you can apply the logic
//based on the hit Test result
//this way you can handle the case
//if it hits both, to throw an error
//or alike
if(leftHits.length > 0) {
//reset position
t.x = startPos.x;
t.y = startPos.y;
}
else if (rightHits.length > 0) {
//set the position tp the desired item in rightHits
}
else {
}
}
}
Please not that my Action Script skills haven't been used for a long time, so the code above might not compile. It is meant to illustrate the idea. Important are the following steps:
1. Save the starting position, to be able to reset it
2. Sort the `squares` in respective lists for left and right
3. Hit test both and apply the logic.

AS3 - Auto refreshing display after updating array

So, basically I'm reinventing the wheel by trying to make a sort of spreadsheet in flash for tracking member growth in a game. In this one section I'm adding member names to an array and then placing the names into dynamically created tiles with text fields attached to display the name.
I have a save button which saves the array, and if I save, close, and reopen, then I can see the members I have added. However, I would like it to refresh the stage as soon as the array is changed to reflect the changes made (update the spreadsheet). I will also be adding and removing other tiles dynamically, but I can extrapolate the solution to this problem to all of those later.
Here's the code I have to add members and create the display:
public var mainArray:Array = new Array;
public var i1:Number = 0;
public var memberBox:MovieClip = new MovieClip();
public var MAX_ROWS = 0;
public var MAX_COLS = 0;
public function Tracker() {
MAX_COLS = mainArray.length - 1;
addBtn.addEventListener(MouseEvent.CLICK, addFun); //atchaed to button on stage
public function addFun($e:MouseEvent):void{
mainArray[i1] = [];
mainArray[i1][0] = addNameTxt.text //attached to textfield on stage
i1++;
loadMembers();
public function loadMembers():void{
var multiDimensionalArray:Array = new Array();
//initalize the arrays
for (var row = 0; row <= MAX_ROWS; row++)
{
var boolArray:Array = new Array();
for (var col = 0; col <= MAX_COLS; col++){
boolArray.push(false);
}
multiDimensionalArray.push(boolArray);
}
//now we can set the values of the array as usual
for (var row = 0; row <= MAX_ROWS; row++)
{
for (var col = 0; col <= MAX_COLS; col++){
multiDimensionalArray.push(1); ;
}
}
//create a column of tiles based on mainArray length with a textfield attached to each
buildLevel(multiDimensionalArray);
}
public function buildLevel(s:Array){
var txtArray:Array = new Array();
memberBox.name = "tileHolder";
for(var i=0; i < MAX_ROWS + 1; i++){
for(var o=0; o < MAX_COLS + 1; o++){
var currentTile:MemberBox = new MemberBox();
currentTile.x = i*150;
currentTile.y = o*25;
currentTile.name = "b"+o;
memberBox.addChild(currentTile);
//currentTile.gotoAndStop(int(s[o][i]));
var memberTxt:TextField=new TextField();
currentTile.addChild(memberTxt);
memberTxt.width = 150;
memberTxt.height = 25;
txtArray[o] = memberTxt;
txtArray[o].text = mainArray[o][0];
}
}
memberBox.x = 60;
memberBox.y = 170;
addChild(memberBox);
}
}
The ideal solution would be to attach event listeners to the Array, however, Arrays don't fire events.
Solution #1: Managed Updates
Rather than allowing any piece of code to modify your array directly, write a function that handles updating your array. This way, you can know when to update the display at the same time.
public var mainArray:Array = new Array;
public var i1:Number = 0;
public var memberBox:MovieClip = new MovieClip();
public var MAX_ROWS = 0;
public var MAX_COLS = 0;
public function Tracker() {
MAX_COLS = mainArray.length - 1;
addBtn.addEventListener(MouseEvent.CLICK, addFun); //attached to button on stage
public function addFun(e:MouseEvent):void {
mainArray[i1] = [];
mainArray[i1][0] = addNameTxt.text //attached to textfield on stage
i1++;
loadMembers();
}
public function loadMembers():void {
var multiDimensionalArray:Array = new Array();
//initalize the arrays
for (var row = 0; row <= MAX_ROWS; row++) {
var boolArray:Array = new Array();
for (var col = 0; col <= MAX_COLS; col++) {
boolArray.push(false);
}
multiDimensionalArray.push(boolArray);
}
//now we can set the values of the array as usual
for (var row = 0; row <= MAX_ROWS; row++) {
for (var col = 0; col <= MAX_COLS; col++) {
multiDimensionalArray.push(1); ;
}
}
//create a column of tiles based on mainArray length with a textfield attached to each
buildLevel(multiDimensionalArray);
}
public function buildLevel(s:Array) {
var txtArray:Array = new Array();
memberBox.name = "tileHolder";
for (var i:int = 0; i < MAX_ROWS + 1; i++) {
for(var o=0; o < MAX_COLS + 1; o++) {
var currentTile:MemberBox = new MemberBox();
currentTile.name = i + "_" + o;
currentTile.x = i*150;
currentTile.y = o*25;
memberBox.addChild(currentTile);
//currentTile.gotoAndStop(int(s[o][i]));
var memberTxt:TextField=new TextField();
currentTile.addChild(memberTxt);
memberTxt.width = 150;
memberTxt.height = 25;
txtArray[o] = memberTxt;
txtArray[o].text = mainArray[o][0];
}
}
memberBox.x = 60;
memberBox.y = 170;
addChild(memberBox);
}
public function modifyArray(row:int, col:int, value:*):void {
// Update our array.
mainArray[row][col] = value;
// Update our tile.
var tile:MemberBox = memberBox.getChildByName(row + "_" + col);
tile.getChildAt(0).text = value;
}
}
When you actually modified your array, you'd do that with your function, rather than a direct mainArray[o][i] approach.
// Instead of this
mainArray[o][i] = "foo";
// You'd do this
modifyArray(o, i, "foo");
Update: I'm not sure how better to explain this, so I've posted working example that you can view. It contains the class, and the document code, the fla, and the swf with working updates to the spreadsheet. Let me know if that resolves the issue: SpreadSheet Test # Dropbox
Solution #2: Poll for Changes
Hold two versions of your array in memory. The first is the one you're actively editing, the second is an untouched duplicate to compare against the first. Every so often (once per second?) you iterate over the entire dataset and look for differences. When one is found, update the duplicate array and the displayed spreadsheet.
Here's an example of how you'd do that:
import flash.utils.*;
var last:Number = flash.utils.getTimer();
this.addEventListener("enterFrame", checkData);
var foo:Array = ["a", "b", "c"];
var fooBackup:Array = [];
function update():void {
var txt:TextField;
for (var i:int = 0; i < foo.length; i++) {
// If we don't have a representation of this index, create one.
if (!this.getChildByName("tile"+i)) {
txt = new TextField();
txt.name = "tile" + i;
txt.text = foo[i];
this[txt.name] = txt;
addChild(txt);
txt.y = i * 20;
}
// Update the data if inconsistent.
txt = this.getChildByName("tile"+i) as TextField;
if (fooBackup.hasOwnProperty(i) == false || foo[i] != fooBackup[i]) {
fooBackup[i] = foo[i]
txt.text = foo[i];
trace("Index " + i + " changed. Updated backup, and display.");
}
}
}
function checkData(e:Event):void {
var now:Number = flash.utils.getTimer();
// If the last time we checked is greater than a second, run the check again.
if (now - last > 1000) {
// Update last checked index;
last += 1000;
// For the sake of argument, let's randomly change an index to a random value.
foo[random(0, foo.length-1)] = random(-1000, 1000);
update();
}
}
function random(low:Number=0, high:Number=1):Number {
/* Returns a random number between the low and high values given. */
return Math.floor(Math.random() * (1+high-low)) + low;
}
Solution #3: Roll your own Array
As outlined by Adobe's Extending the Array class, you can subclass Arrays and from there add your own event dispatches when you add/remove entries. This is the more adventurous solution, and (in my humble opinion) the best as it maintains code consistency, while giving broad and efficient powers.

Use the same array to next frame

Im making a game and i complete the level1 at frame1.
When im trying to make the level2 to frame2 i dont know how to transfer my Arrays
to frame2.All the other buttons and functions are working(i copy the eventListeners to frame2)but my enemies wich are in Arrays does nothing!!
Thanks a lot!!!
import flash.events.Event;
stop();
//variables the helicopters
var enemy1Array:Array = new Array();
for (var e1:int = numChildren - 1; e1 >= 0; e1--)
{
var child:DisplayObject = getChildAt(e1);
if (child.name == "enemy1")
{
enemy1Array.push(child);
}
}
stage.addEventListener(Event.ENTER_FRAME, allloop);
function allloop(event:Event):void
{
//move the helicopters
for each(var enemy1:Sprite in enemy1Array)
{
enemy1.x = enemy1.x -= enemy1speed;
if(enemy1.hitTestObject(defense))
{
addChild(explotionbonus3);
explotionbonus3.gotoAndPlay(2);
explotionbonus3.x = enemy1.x;
explotionbonus3.y = enemy1.y;
enemy1.y = 1000;
score -=5;
scoretxt.text = String (score);
}
}
}

Actionscript 3: Trying to create a randomized array

im trying to create a randomized array that will change the position of my pictures(in the tilelist) each time the application is launched. Hope you understand what im looking for, and i dont really understand how to link code correctly here :/
I think its easier simply copying into flash and view from there
thanks :)
Here's my code:
flash.events.MouseEvent;
btn_back.addEventListener(MouseEvent.CLICK, ftilbake);
function ftilbake(evt:MouseEvent)
{
gotoAndStop(1);
}
var heroArray:Array = new Array();
var randomizeArray:Array = new Array();
createArrays()
function createArrays()
{
heroArray[0] = new Array("Rumble","Garen","Lulu","Corki","Warwick");
heroArray[1] = new Array("Bilder/Champions/Rumble.jpg","Bilder/Champions/Garen.jpg","Bilder/Champions/Lulu.jpg","Bilder/Champions/Corki.jpg","Bilder/Champions/Warwick.jpg");
heroArray[2] = new Array("Bilder/Champions/Rumble1.jpg","Bilder/Champions/Garen1.jpg","Bilder/Champions/Lulu1.jpg","Bilder/Champions/Corki1.jpg","Bilder/Champions/Warwick1.jpg");
heroArray[3] = new Array("the Mechanized Menace","the Might of Demacia","the Fae Sorceress","the Daring Bombardier","the Blood Hunter");
heroArray[4] = new Array(0,0,0,0,0);
heroArray[5] = new Array("Rumble.wav","Garen.wav","Lulu.wav","Corki.wav","Warwick.wav");
randomizeArray[0] = new Array();
randomizeArray[1] = new Array();
randomizeArray[2] = new Array();
randomizeArray[3] = new Array();
randomizeArray[4] = new Array();
//randomizing the positions in the array(?)
var randomPos:int = 0;
for (var i:int = 0; i < heroArray.length; i++)
{
randomPos = int(Math.random() * heroArray[0].length);
while (randomizeArray[randomPos][0] != null)
{
randomPos = int(Math.random() * heroArray.length);
}
}
}
var totalKlikk:int = 0;
for (var teller1:int = 0; teller1 <heroArray[0].length; teller1++)
{
leagueChamps.addItem({label:heroArray[0][teller1], source:heroArray[1][teller1]});
}
leagueChamps.columnWidth = 80;
leagueChamps.rowHeight = 80;
leagueChamps.columnCount = 5;
leagueChamps.rowCount = 1;
leagueChamps.direction = "horizontal";
leagueChamps.addEventListener(MouseEvent.CLICK, bildeKlikk);
function bildeKlikk(evt:MouseEvent)
{
var element:Object = leagueChamps.selectedItem;
var fil:String = element.source;
txtChHero.visible = false;
totalKlikk++;
if (totalKlikk <11)
{
for (teller1 = 0; teller1 <heroArray[0].length; teller1++)
{
if (heroArray[1][teller1] == fil)
{
heroArray[4][teller1]++;
if (heroArray[4][teller1] == 1)
{
txtBox1.visible = true;
txtBox2.visible = true;
leagueShow.source = heroArray[2][teller1];
txtBox1.text = heroArray[0][teller1];
txtBox2.text = heroArray[3][teller1];
}
if (heroArray[4][teller1] == 2)
{
txtBox1.visible = true;
txtBox2.visible = true;
leagueShow.source = heroArray[2][teller1];
txtBox1.text = heroArray[0][teller1];
txtBox2.text = heroArray[3][teller1];
heroArray[5][teller1].play();
}
if (heroArray[4][teller1] == 3)
{
bildeKlikk3();
}
}
}
}
else
{
txtChHero.visible = true;
txtChHero.text = "Du har klikket følgende mange ganger på de forskjellige bildene:";
txtH1.text = heroArray[4][0]
txtH2.text = heroArray[4][1]
txtH3.text = heroArray[4][2]
txtH4.text = heroArray[4][3]
txtH5.text = heroArray[4][4]
txtBox1.visible = false;
txtBox2.visible = false;
leagueShow.visible = false;
}
}
function bildeKlikk3()
{
txtBox1.visible = true;
txtBox2.visible = true;
leagueShow.source = heroArray[2][teller1];
txtBox2.text = "Ikke mer informasjon";
}
txtBox2.visible = false;
txtBox1.visible = false;
Array randomization is something which comes up very frequently in all my projects so I ended up creating a static method in my Array utility class for it.
It uses the Fisher–Yates shuffle which is supposed to be the most unbiased (and efficient?) algorithm for shuffling the content of an array. There could be faster ways of doing it (like using the array.sortOn() method, but I am not sure how unbiased a result they get compared to this one.)
The shuffle method:
/**
* shuffle the given array
* #param array
* #return
*/
public static function shuffle(array:Array):Array
{
var index :int;
var item :*;
var limit :int = array.length as int;
for (var i:int = limit-1; i >= 0 ; --i)
{
index = Math.floor(Math.random() * (i + 1));
item = array[index];
array[index] = array[i];
array[i] = item;
}
return array;
}
Example:
var myArray:Array = new Array("Red","Orange","Yellow","Green","Blue");
myArray = ArrayUtils.shuffle(myArray);
where ArrayUtils is the name of the Array Utility class I use. You can simply use the function directly if you don't want to use a utility class of course.
Try this
while (heroArray.length > 0) {
randomizeArray.push(heroArray.splice(Math.round(Math.random() * (heroArray.length - 1)), 1)[0]);
}
Just instatiate randomizeArray though, and don't fill it with empty Arrays like in ur source!
I recommend creating a single object to hold related data, and using a single Array/Vector of that object type.
To answer your question, randomizing an array is fairly easy to do with array.sort() and a random selection function. This method can also be used to randomize any array. you don't need to splice arrays or iterate either.
function sortOnRandom(a:Object, b:Object):Number{
if(Math.random() > 0.5){
return 1;
}else{
return -1;
}
}
myArray.sort(sortOnRandom);

Resources