I want to get unique random numbers each time from nos 1-40 without using an array.Is there any optimised way to get this in action script 3.
No, you have to use permutation, as you have to record those numbers you've already generated. And using these numbers require a set of some kind, aka Array. It's possible to solve this issue by using other data types, but they will essentially narrow down to an array of some sort.
A simple permutation code looks like this:
class Permutation {
private var _a:Array; // or Vector.<int> if you like
private var n:int; // next element
public function Permutation() {
reset(1);
}
public function reset(size:int=100):void {
_a.length=0;
for (n=0;n<size;n++) _a.push(n);
for (n=0;n<size;n++) {
var x:int=Math.floor(size*Math.random());
if (x==n) continue;
var swap:int=_a[x];
_a[x]=_a[n];
_a[n]=swap;
}
n=0;
}
public function getNext():int {
if (n==_a.length) return -1; // or any error value
n++;
return _a[n-1];
}
}
No array.
var generatedNumberCount:int;
var generatedNumberRef:Object = {};
for(var i:int = 0; i < 150; i++)
{
var result:Number = generateRandomInt(50);
trace(result);
}
trace(generatedNumberCount)
function generateRandomInt(limit:int):Number
{
if(generatedNumberCount >= limit)
{
return NaN;
}
var output:int = Math.ceil(Math.random() * limit);
while(generatedNumberRef[output] != undefined)
{
output = Math.ceil(Math.random() * limit);
}
generatedNumberRef[output] = true;
generatedNumberCount++;
return output;
}
Related
I'm trying to put a pause between "Long ago," and what comes after that but I'm having trouble trying to do it. How could I make it work? I've attempted to use a timer but I'm not very good at doing that which made it hard to implement it.
Here is my code:
var snd: textStory = new textStory();
var snd2: soundStory = new soundStory();
var myString: String = "Long ago, two races\nruled over Earth:\nHUMANS and MONSTERS.";
var myArray: Array = myString.split("");
snd2.play();
addEventListener(Event.ENTER_FRAME, frameLooper);
function frameLooper(event: Event): void {
if (myArray.length > 0) {
if (n == 1) {
tf.appendText(myArray.shift());
n = 0;
snd.play();
} else {
n++;
}
} else {
removeEventListener(Event.ENTER_FRAME, frameLooper);
}
}
Something like that, I think. It is a data-driven solution where you prepare a proper data input so that your main loop (ENTER_FRAME handler in your case) won't have to think too much and just process one data entry at once.
var E:Array = [""];
// It is considered a good tone to name classes
// starting with uppercase: TextStory, SoundStory.
var snd: textStory = new textStory();
var snd2: soundStory = new soundStory();
var laString:String = "Long ago";
var myString:String = ", two races\nruled over Earth:\nHUMANS and MONSTERS.";
var myArray:Array = new Array;
// Here we form an Array that starts with "Long ago"
// then 20 empty entries to skip, then the rest.
myArray = myArray.concat(tocharArray(laString));
myArray = myArray.concat(emptySpaces(20));
myArray = myArray.concat(tocharArray(myString));
snd2.play();
addEventListener(Event.ENTER_FRAME, frameLooper);
function frameLooper(event: Event): void
{
if (myArray.length < 1)
{
removeEventListener(Event.ENTER_FRAME, frameLooper);
return;
}
var aChar:String = myArray.shift();
// Just skip a frame if there's an empty character.
if (aChar == "")
{
return;
}
tf.appendText(aChar);
// Make no typing sound on space characters... I guess?
if (aChar != " ")
{
snd.play();
}
}
// Returns an Array ["", "", "", ... , ""] of the given length.
function emptySpaces(length:int):Array
{
// This doubles E as many times as needed
// to allow us to make a slice long enough.
while (E.length < length)
{
E = E.concat(E);
}
// Returns a portion of E of the given length.
return E.slice(0, length);
}
// Converts the given String into an Array
// of characters and empty "" entries.
function tocharArray(value:String):Array
{
var result:Array = new Array;
for (var i:int = 0; i < value.length; i++)
{
// You can put more or less "" here to make the
// typing loop skip more than a single
// frame after typing a character.
result.push(value.charAt(i), "", "");
}
return result;
}
I have a random number variable defined as below
var rannum:Number = Math.floor(Math.random()*50+1);
Then I have a trigger that calls for a new random number everytime a button is clicked
ranbtn.addEventListener(MouseEvent.CLICK, reran);
function reran (event:MouseEvent):void
{
rannum = Math.floor(Math.random()*50+1);
}
I would like to prevent the same random number from being selected until all the numbers have been selected and then possibly start over?
I found a few threads like this one but none of them were specifically what I needed
You need to create an array of the possible values and each time you retrieve a random index from the array to use one of the values, you remove it from the array.Here you have an easy example with javascript.
var uniqueRandoms = [];
var numRandoms = 50;
function makeUniqueRandom() {
// refill the array if needed
if (!uniqueRandoms.length) {
for (var i = 0; i < numRandoms; i++) {
uniqueRandoms.push(i);
}
}
var index = Math.floor(Math.random() * uniqueRandoms.length);
var val = uniqueRandoms[index];
// now remove that value from the array
uniqueRandoms.splice(index, 1);
return val;
}
I've found another option, You can declare an array of Integers:[1,2,3,4...50] and sort them randomly.
var sorted:Array = [];
for(var i:int = 0; i < 50; i++){
sorted.push(i);
}
//I'm making a copy of sorted in unsorted
var unsorted:Array = sorted.slice();
//Randomly sort
while(sorted.join() == unsorted.join()){
unsorted.sort(function (a:int, b:int):int { return Math.random() > .5 ? -1 : 1; });
}
If you get a selected num, you can add one until it is not selected.
Create a list of integers from 1 to 50.
Pick a random integer from the list and remove it.
When there are no more integers left (after 50 picks), repeat step 1.
Code:
function createRangeOfIntegers(from:int, to:int):Vector.<int> {
if (from >= to) throw new ArgumentError("Invalid arguments");
var integers:Vector.<int> = new <int>[];
for (var i:int = from; i <= to; i++) {
integers.push(i);
}
return integers;
}
function getRandomInteger(integers:Vector.<int>):int {
var index:int = Math.random() * integers.length;
var integer:int = integers.splice(index, 1)[0];
return integer;
}
Example:
// create all the possible integers
var integers:Vector.<int> = createRangeOfIntegers(1, 50);
// select a random integer
var random:int = getRandomInteger(integers);
// When you've selected all integers you can start over
if (integers.length == 0)
integers = createRangeOfIntegers(1, 50);
I'm currently learing to program in AS3 in Flash CS6 (I have no previous programming experience), and now I'm trying to pass an argument to a parameter from a text box in the UI.
Here's what I've come up with:
btnKnapp.addEventListener(MouseEvent.CLICK, skrivUt(int(txtInput.text)));
function skrivUt(x:int)
{
for(var i:int=1; i<=5; i++)
{
var output:String = "";
for(var j:int=0; j<x; j++)
{
output += String(i);
}
trace(output);
txtOutput.appendText(output + "\n");
output = "";
}
}
So I want to execute the skrivUt function, and use the integer written in the txtInput text box as the x parameter,when I press the button btnKnapp.
This is a way that I'm using to pass parameters to EventListener.
btnKnapp.addEventListener(MouseEvent.CLICK, nextfuncWithParams(skrivUt, int(txtInput.text)));
function nextfuncWithParams(nextfunc: Function, params: int): Function{
return function(): void{
nextfunc(params);
}
}
function skrivUt(x:int): void
{
// Your logic
}
If you want to pass multiple params, use Object type like below.
var obj: Object = new Object();
obj.param1 = "Some String param";
obj.param2 = 123;
obj.param3 = false;
btnKnapp.addEventListener(MouseEvent.CLICK, nextfuncWithParams(skrivUt, obj));
function nextfuncWithParams(nextfunc: Function, params: Object): Function{
return function(): void{
nextfunc(params);
}
}
function skrivUt(params: Object): void
{
trace(params.param1);
trace(params.param2);
trace(params.param3);
}
the following code will definitely work
btnKnapp.addEventListener(MouseEvent.CLICK, skrivUt);
function skrivUt(e:MouseEvent)
{
var x:int = int(txtInput.text);
for(var i:int=1; i<=5; i++)
{
var output:String = "";
for(var j:int=0; j<x; j++)
{
output += String(i);
}
trace(output);
txtOutput.appendText(output + "\n");
output = "";
}
}
I would like to create an array of numbers and then randomize those numbers.
Here is what I've come up with. It does two things.
It gets an array from 0 to the length specified. What the main question was about.
It then randomizes the items in that array
// returns [1,2,3,4,5,6,7,8,9,10] except shuffled
var array:Array = getSequenceArray(10);
/**
* Get an array of the range of numbers from 1 to the number specified and randomize them.
* */
public function getRandomArray(count:int):Array {
// this part is not looped. yay!
var array:Array = new Array(count).map(function (item, index) { return index + 1; });
return randomizeArray(array);;
}
/**
* Randomize items in an array
* */
public function randomizeArray(original:Array, cloneArray:Boolean = true):Array {
var length:int = original.length;
var shuffledArray:Array = [];
var newArray:Array = original.slice();
var randomNumber:Number;
// this is still using a loop. this loop is less of an issue than the first
while (length) {
randomNumber = Math.floor(Math.random() * length);
shuffledArray.push(newArray.splice(randomNumber, 1)[0]);
length--;
}
if (!cloneArray) {
original.splice(0, shuffledArray.length);
original.push.apply(this, shuffledArray);
return original;
}
return shuffledArray;
}
when comparing simple arrays, i use something like the following function to concatenate and remove duplicates:
//Merge
public function merge(a1:Array, a2:Array):Array
{
var result:Array = a1.concat(a2);
var dictionary:Dictionary = new Dictionary();
for each (var item:Object in result)
dictionary[item] = true;
result = new Array();
for (var key:Object in dictionary)
result.push(key);
dictionary = null;
return result;
}
however, this approach doesn't work on complex arrays.
is there a well known algorithm, or is it even possible to write a function of recursion that can compare a Vector.<Object> with another? one that will always work even if the some objects being compared have additional key/value pairs?
[EDIT]
to be more clear, using a dictionary to determine if items in a simple array only works on primitive data types (int, number, string, etc.) or object references, so the above example works if it's passed 2 arrays resembling something like this:
var arr1:Array = new Array(1, 2, 3, 4, 5);
var arr2:Array = new Array(8, 7, 6, 5, 4);
resulting in a merged array with the following values:
1, 2, 3, 8, 7, 6, 5, 4
in contrast, i'm asking if it's possible to pass a function 2 complex arrays or Vector.<Object> all containing unique objects that may have identical key/value pairs and remove redundencies in the resulting Vector.<Object>. for example:
var vec1:Vector.<Object> = new Vector.<Object>();
vec1.push({city:"Montreal", country:"Canada"});
vec1.push({city:"Halifax", country:"Canada"});
var vec2:Vector.<Object> = new Vector.<Object>();
vec2.push({city:"Halifax", country:"Canada"});
vec2.push({city:"Toronto", country:"Canada"});
merging the above 2 vector objects would result in the following vector by determining and removing objects with identical key/value pairs:
{city:"Montreal", country:"Canada"}
{city:"Halifax", country:"Canada"}
{city:"Toronto", country:"Canada"}
i'm searching for an algorithm which could handle the removal of these similar objects without having to know about their specific key/value names or how many key/value pairs there are within the object.
Sure you can, you can build a similar example with any type of Vector:
public function mergeObjectVectors(v1:Vector.<Object>,
v2:Vector.<Object>):Vector.<Object>
{
var dictionary:Dictionary = new Dictionary();
var concat:Vector.<Object> = v1.concat(v2);
var result:Vector.<Object> = new Vector.<Object>();
for each(var i:Object in concat)
{
if (!dictionary[i])
{
dictionary[i] = true;
result.push(i);
}
}
return result;
}
However if you plan on accepting vectors of any type, it's different:
public function testing():void
{
var v1:Vector.<Object> = new Vector.<Object>();
v1.push({name:"Object 1"});
v1.push({name:"Object 2"});
// Vector w duplicates
var v2:Vector.<Object> = new Vector.<Object>();
var o:Object = {name:"Object 3"};
v2.push(o);
v2.push(o);
v2.push(o);
var resultVector:Vector.<Object> = mergeAnything(v1, v2, Class(Vector.<Object>));
var resultArray:Array = mergeAnything(v1, v2, Array);
var resultObject:Object = mergeAnything(v1, v2, Object);
}
public function mergeAnything(o1:Object, o2:Object, resultClass:Class):*
{
var dictionary:Dictionary = new Dictionary();
var result:Object = new resultClass();
var i:int;
for each(var o:Object in o1)
{
if (!dictionary[o])
{
dictionary[o] = true;
result[i++] = o;
}
}
for each(o in o2)
{
if (!dictionary[o])
{
dictionary[o] = true;
result[i++] = o;
}
}
return result;
}
The first example will be more resource-efficient.
EDIT:
This should do it, try it with your example:
public function mergeObjectVectors(v1:Vector.<Object>, v2:Vector.<Object>):Vector.<Object>
{
var concat:Vector.<Object> = v1.concat(v2);
var result:Vector.<Object> = new Vector.<Object>();
var n:int = concat.length;
loop:for (var i:int = 0; i < n; i++)
{
var objectToAdd:Object = concat[i];
var m:int = result.length;
for (var j:int = 0; j < m; j++)
{
var addedObject:Object = result[j];
if (this.areObjectsIdentical(objectToAdd, addedObject))
{
continue loop;
}
}
result.push(objectToAdd);
}
return result;
}
private function areObjectsIdentical(o1:Object, o2:Object):Boolean
{
var numComparisons:int = 0;
for (var s:String in o1)
{
numComparisons++;
if (o1[s] != o2[s])
{
return false;
}
}
for (s in o2)
{
numComparisons--;
}
return !numComparisons;
}