setting the chances of occurrence of elements in an array - actionscript-3

For example I have 3 elements in an array:
public function randomTile():Number
{
var tiles:Array = new Array(fire,ice,water);
var index:Number=Math.floor(Math.random()*tiles.length);
return tiles[index];
}
How to set the chances of occurrence of fire(70%), ice(10%), and water(20%)?

This should work for any number of elements and you can specify any chance value.
var tiles:Array = [
{"item":"fire", "chance":70 },
{"item":"ice", "chance":10 },
{"item":"water","chance":20}
];
var picked:Object = pickRandomByChance(tiles);
trace(picked.item);
public function pickRandomByChance(options:Array):Object
{
var copy:Array = [];
var range:Number = 0;
for (var i:int = 0; i < options.length; i++)
{
copy.push( { "item":options[i].item, "chance":options[i].chance } );
range += copy[i].chance;
if (i > 0)
copy[i].chance += copy[i - 1].chance;
}
var pick:Number = Math.floor(Math.random() * range);
for (i = 0; i < copy.length; i++)
{
if (pick <= copy[i].chance)
return copy[i];
}
return null;
}

There quite a few ways you could do this, and it largely depends of the scope of your project. If you just have the three elements, using a switch statement would be easy:
var rand:Number = Math.random();
switch(true){
case rand >= .3:
//use fire
break;
case rand >= .1
//use water
break;
default:
//use ice
}
Someone else may have a better way though

Related

Odd numbers of object extraction from an array

I'm trying to get 2 objects at a time form the array for now. but soon I will be using odd number of length and splicing items.
This works out perfectly so far with Even numbers in the Array, but I am not sure how to make it work with odd numbers. The way I think it may work is ask it to check the objects coming up next and if it is less than 2 than change the counters to 1. but I am not even sure how to put that in code specifically. I posted my code so far be
import flash.events.MouseEvent;
import flash.net.Socket;
var socket_Array_current_position = 0;
var socket_counter = 2;
var socket_Array: Array = new Array ();
socket_Array.push(socket_one, socket_two,socket_three, socket_four, socket_five, socket_six);
go_next_left.addEventListener(MouseEvent.CLICK, go_left);
go_next_right.addEventListener(MouseEvent.CLICK, go_right);
function go_left(going_left:MouseEvent)
{
if (socket_Array_current_position > 0)
{
socket_remove();
socket_Array_current_position -= socket_counter;
socket_x_position = 125;
socket_display();
}
}
function go_right(going_right:MouseEvent)
{
if (socket_Array_current_position < socket_Array.length-socket_counter)
{
socket_remove();
socket_Array_current_position += socket_counter;
socket_x_position = 125;
socket_display();
}
}
socket_display();
function socket_display()
{
var s = 0;
for (s; s < socket_counter; s++)
{
addChild(socket_Array[socket_Array_current_position + s]);
socket_Array[socket_Array_current_position + s].x = socket_x_position;
socket_Array[socket_Array_current_position + s].y = socket_y_position;
//socket_Array[s].addEventListener(MouseEvent.CLICK, picked);
socket_x_position = socket_x_position + 275;
}
}
function socket_remove()
{
var s = 0;
for (s; s < socket_counter; s++)
{
removeChild(socket_Array[socket_Array_current_position+s]);
}
}
I suppose that you want display X objects (in this case two) at a time from an array. Whatever length. I'm using Math lib. Consider that I didn't try the code below with sdk or Flash.
const X_START_POS:int = 125;
const COLUMN_WIDTH:int = 275;
const QTY_SCREEN:int = 2;
var socket_Array:Array = new Array();
var socket_Array_pos:int = 0;
var socket_Array_target:int = 0; // target is always right
var socket_Array_on_screen:Array = new Array();
// socket_Array.length must be >= QTY_SCREEN, always.
socket_Array.push(socket_one, socket_two, socket_three, socket_four, socket_five, socket_six);
go_next_left.addEventListener(MouseEvent.CLICK, go_left);
go_next_right.addEventListener(MouseEvent.CLICK, go_right);
socket_display();
function go_left(going_left:MouseEvent) {
socket_Array_target = Math.max(socket_Array_pos - QTY_SCREEN, 0);
socket_display();
}
function go_right(going_right:MouseEvent) {
socket_Array_target = Math.min(socket_Array_pos + QTY_SCREEN, socket_Array.length - QTY_SCREEN);
socket_display();
}
function socket_display() {
socket_remove();
socket_x_position = X_START_POS;
var limit:int = socket_Array_target + QTY_SCREEN;
for (var i = socket_Array_target; i < limit; i++) {
show_socket(socket_Array[i]);
socket_x_position += COLUMN_WIDTH;
}
socket_Array_pos = socket_Array_target;
}
function show_socket(asocket:DisplayObject) {
addChild(asocket);
asocket.x = socket_x_position;
asocket.y = socket_y_position;
socket_Array_on_screen.push(asocket); // remember me
}
function socket_remove() {
var qty:int = socket_Array_on_screen.length;
for (var s = 0; s < qty; s++) {
removeChild(socket_Array_on_screen.pop());
}
}

Issue with for loop in an Array

Initially the array holds the default values as 100. Once if the enemy looses its health then i want to set the default values from 100 to 0. When all the array elements gets a value of 0 then the message will trace as game win.
var enemyHealth:Array = new Array(100,100,100,100,0);
for (var i = 0; i< enemyHealth.length; i++)
{
if (enemyHealth[i] == 0)
{
trace ("game win");
}
}
Actually the issue is if any one of the array element holds a value of 0 then it trace a massage as game win.
So can any one help me in this regard.
You need to check all elements, not just one:
var allZero:Boolean = true;
var enemyHealth:Array = new Array(100,100,100,100,0);
for (var i = 0; i< enemyHealth.length; i++)
{
if (enemyHealth[i] != 0)
{
allZero = false;
break; // We know it's not a win, so we can stop the loop early
}
}
if (allZero) {
trace ("game win");
}
I would do something like this
var enemyHealth:Array = new Array(100,100,100,100,0);
var isDead:Boolean = true;
for (var i = 0; i< enemyHealth.length; i++)
{
if (enemyHealth[i] != 0)
{
isDead = false;
break;
}
}
if(isDead)
{
trace ("Game Win");
}
You can do what the other answerers have said or something like this which might help you more to get the exact amount of enemies dead.
var enemyHealth:Array = new Array(100,100,100,100,0);
var enemiesDead:int=0;
for (var i = 0; i< enemyHealth.length; i++)
{
if (enemyHealth[i] == 0)
{
enemiesDead++;
}
}
if(enemiesDead==enemyHealth.length)
{
trace("Game Over");
}
You can use the every method to check that every element of your array (or vector) meet a criterion.
const enemyHealth:Vector.<uint> = new <uint>[100,100,100,100,0];
const zeroHealth:Function = function(item:uint, index:int, vector:Vector.<uint>):Boolean {
return item === 0;
}
if (enemyHealth.every(zeroHealth)) {
trace("Game win")
}
I have changed the array to a Vector because they are more efficient, and you can specify the type of the elements, but it also works fine with array.

Assigning the name of the skins in the array into buttons

I have a code to randomize Skins
private var tiles:Array = [
{"item":"Skin1", "chance":70 },
{"item":"Skin2", "chance":5 },
{"item":"Skin3", "chance":10 },
{"item":"Skin4", "chance":10 },
{"item":"Skin5", "chance":5 }
];
public function pickRandomByChance(options:Array):Object{
var copy:Array=[];
for (var i:int = 0; i < options.length; i++) {
copy.push( { "item":options[i].item, "chance":options[i].chance } );
}
var range:Number = 0;
for (i = 0; i < copy.length; i++){
range += copy[i].chance;
if (i > 0)
copy[i].chance += copy[i - 1].chance;
}
var pick:Number = Math.floor(Math.random() * range);
for (i = 0; i < copy.length; i++){
if (pick <= copy[i].chance)
return copy[i];
}
return null;
}
My question is how can i assign these skins to one of my buttons using setStyle?
button1.setStyle("skinClass", pickRandomByChance(tiles).item);
i tried to use the above code but i got an error #1009: Cannot access a property or method of a null object reference.
I think that your function is returning null (when setting they style its essentially calling null.item). I didn't test this code by I'm pretty sure it will work. Maybe give it a try. In my opinion, it's a little simpler.
public function pickRandomByChance(options:Array):Object{
var weightedArray:Array = [];
var range:Number = 0;
for each(var tile:Object in options){
for(var x = 0; x < tile.chance; x++){
weightedArray.push(tile);
}
range += tile.chance;
}
return(weightedArray[Math.floor(Math.random() * range)].item);
}
EDIT: Now that I look at your skin array I think I found the error. Try the skin names without quotes:
var tiles:Array = [ {"item":Skin1, "chance":70 },
{"item":Skin2, "chance":5 },
{"item":Skin3, "chance":10 },
{"item":Skin4, "chance":10 },
{"item":Skin5, "chance":5 }
];
EDIT: See the revised return above and also apply the skin as shown below:
button1.setStyle("skinClass", pickRandomByChance(tiles));

XMLListCollection find index value

I want to find specific value on a XMLListCollection.
I try to use something like this but it doesn't work!
var xmllisteRDV:XMLList= XML(event.result).RDVClinik;
xmlCollSuivi = new XMLListCollection(xmllisteRDV);
var index:Number = -1;
for(var i:Number = 0; i < xmllisteRDV.length(); i++)
{
if(XML(xmllisteRDV[i]).#grDateDeb == todayDate)
{
index = i;
break;
}
}
First going to try pointing out errors in the original code:
var xmllisteRDV:XMLList= XML(event.result).RDVClinik; //Unnecessary cast, event.result is Object compiler will not check or know the run-time type, doesn't care because Object is declared dynamic meaning properties can be added to it dynamically, if RDVClinik didn't exist on the particular Object type it would simply be null casting as XML gives it no information about this "property"
xmlCollSuivi = new XMLListCollection(xmllisteRDV);
var index:Number = -1;
for(var i:Number = 0; i < xmllisteRDV.length(); i++) //length is a property not a method on XMLListCollection this should throw a compile time error
{
if(XML(xmllisteRDV[i]).#grDateDeb == todayDate)// I see no type when debugging for the result of xmllisteRDV[i] not positive here but this cast is at the least unnecessary
{
index = i;
break;
}
}
Here's a version I think will work possibly with changes to how todayDate is built
var date:Date = new Date();
var todayDate:String = date.dateUTC+"/"+date.dayUTC+"/"+date.fullYear;
var index:int=-1;
for(var i:int = 0; i < flex3Projects.length; i++)
{
trace(xmllisteRDV[i].#grDateDeb)
if(xmllisteRDV[i].#grDateDeb.toString() == todayDate)
{
index = i;
break;
}
}
With you help, I found the solution
private function setSelectedItem():void
{
var gData:Object = dgSuiviClini.dataProvider;
var todayDate:String= new DateUtility().DateAsToString(new Date());
for(var i:Number=0; i < gData.length; i++)
{
var thisObj:Object = gData.getItemAt(i);
if(thisObj.grDateDeb == todayDate)
{
dgSuiviClini.selectedIndex = i;
//sometimes scrollToIndex doesnt work if validateNow() not done
dgSuiviClini.validateNow();
//dgSuiviClini.scrollToIndex(i);
}
else{
dgSuiviClini.validateNow();
// dgSuiviClini.scrollToIndex(gData.length);
}
}
dgSuiviClini.validateNow();
dgSuiviClini.editedItemPosition = { rowIndex: gData.length-1, columnIndex: nColSaisie };
}
Thanks

Making comparisson to items in an Object

I have the following object:
var users:Object= new Object();
users[0]["user_id"] = "1124";
users[0]["name"] = "ikke";
users[0]["age"] = "24";
users[0]["gender"] = "male";
users[1]["user_id"] = "1318";
users[1]["name"] = "test";
users[1]["age"] = "20";
users[1]["gender"] = "male";
var selectors:Object = new Object();
selectors["user_id"] = 1318;
selectors["gender"] = "male";
what i want is to use the selectors object in an if statement. In humans lanuguage it should be something like:
for (var index:String in users) {
If users[index]["gender"] == selectors[gender] && users[index]["user_id"] == "male" -> then trace "success".
}
The tricky part is that the selectors object is dynamic. Sometimes it can contain only 1 item , sometimes 3 items. Or it can also be null. In that case it should allways trace success. Anyone that can help me?
for(var i:int = 0; i < users.length; i++) {
var success:Boolean = true;
for(var key:String in selectors) {
if(users[i][key] != selectors[key]) {
success = false;
break;
}
}
if(success) {
trace('success for user ' + i);
}
}