In my loop I have a number that is constantly changing - I need to figure out how to tell if the number is increasing or decreasing:
Some pseudo code that doesnt work :)
var now:Number;
var then:Number;
function loop():void
{
now = changingNumber;
then = changingNumber;
if (now > then) {
// increasing
}else {
// decreasing
}
}
var now:int = 0;
var thn:int = 0;
function loop():void
{
// Change the number.
now = changingNumber;
if(now > thn)
{
trace("Got larger.");
}
else if(now < thn)
{
trace("Got smaller.");
}
else
{
trace("Maintained value.");
}
// Store the changed value for comparison on new loop() call.
// Notice how we do this AFTER 'now' has changed and we've compared it.
thn = now;
}
Alternatively, you can prepare a getter and setter for your value and manage an increase or decrease there.
// Properties.
var _now:int = 0;
var _thn:int = 0;
// Return the value of now.
function get now():int
{
return _now;
}
// Set a new value for now and determine if it's higher or lower.
function set now(value:int):void
{
_now = value;
// Comparison statements here as per above.
// ...
_thn = _now;
}
This method will be more efficient and not require a loop.
Related
I want to open all nodes of Flex mx Tree in such a way that UI is responsive at all times. Normally when there are limited no of nodes then this code works just fine.
public function expandAllNodes():void {
for (var i:int = 0; i < this.dataProvider.length; i++) {
expandChildrenOf(this.dataProvider.getItemAt(i), true);
}
}
maybe i need to callLater instead of directly calling the function
public function expandAllNodes():void {
for (var i:int = 0; i < this.dataProvider.length; i++) {
calllater(expandChildrenOf,[this.dataProvider.getItemAt(i), true]);
}
}
but this is not working either.
Using callLater won't help in this case. From the documentation,
The callLater method queues an operation to be performed for the next screen refresh, rather than in the current update.
Using callLater in your loop will simply push all the expandChildrenOf() calls to the next screen refresh -- which will still put way too much work into a single update cycle.
Instead, you could spread your loop over several frames and limit work done per frame:
private var processingLimit:int = 10; //experiment to get a reasonable value for this
private var totalNodes:int = 0;
private var nodesProcessed:int = 0;
public function expandAllNodes():void {
this.totalNodes = this.dataProvider.length;
this.addEventListener(Event.ENTER_FRAME, expandNextNode);
}
private function expandNextNode(e:Event):void {
var numToProcess = Math.min(processingLimit + nodesProcessed, totalNodes);
for (var i:int = nodesProcessed; i < numToProcess; i++) {
nodesProcessed++;
expandChildrenOf(this.dataProvider.getItemAt(i), true);
}
if (numToProcess == totalNodes) {
this.removeEventListener(Event.ENTER_FRAME, expandNextNode);
}
}
n.b. Make sure that expandChildrenOf doesn't recursively open children of children -- if it does, then you could still end up expanding the entire tree based on a single call to expandChildrenOf(1);!
This is how i solved the issue
private const PROCESSING_LIMIT:int = 25;
public var _expandNodesStack:Vector.<Object>;
private function expandNextNode(e:Event):void {
for (var i:int = 0; i < PROCESSING_LIMIT; i++) {
var item:* = _expandNodesStack.pop();
if (item)
expandItem(item, true);
else
break;
}
if (_expandNodesStack.length == 0) {
this.removeEventListener(Event.ENTER_FRAME, expandNextNode);
}
}
public function expandAllNodes():void {
if(this.dataProvider == null || this.dataProvider.length <= 0) return;
if (_expandNodesStack != null && _expandNodesStack.length > 0) {
//already expanding so abort this operation
return;
}
if (_expandNodesStack == null) _expandNodesStack = new <Object>[];
iterateAndPushToStack(this.dataProvider.getItemAt(0));
_expandNodesStack.reverse();
this.addEventListener(Event.ENTER_FRAME, expandNextNode);
}
private function iterateAndPushToStack(item:Object):void {
if (iterator == null)
return;
// if it is not a branch item there's nothing to do
if (item != null && item.children is ArrayCollection && item.children.length > 0) {
_expandNodesStack.push(item);
var childItems:ArrayCollection;
childItems = item.children;
if (childItems) {
for each (var object:Object in childItems) {
iterateAndPushToStack(object);
}
}
}
}
Hello Im trying to setup EVERY-n-week events for gmail-snooze thus it would be reocurring events not just one time.
I would like to save everyXweek labeled-threads into "newpage" from the already created Xweek labeled-threads in "page" array. I used page = oldLabel.getThreads(0, 100); to grab the Xweek data.
I tried newpage = everyXweekLabel.page; and newpage = page[everyXweekLabel]; but newpage never gets turned into an array with threads.... so it doesnt work...
How i would like this to work:
threads will have multiple labels.
XweekSnooze is our iteration count down timing label
everyXweekSnooze is our static label to reset the thread once placed in inbox
An example would be thread#1 has 1weekSnooze left (which will be removed on the very next iteration) and it also has an every8weekSnooze label (which will need to apply an 8weekSnooze label once the email is put into inbox)
After the 8weekSnooze label is applied it then iterates (7weekSnooze, 6...) down until it is put into the inbox again where the every8weekSnooze label places another 8weekSnooze label back on to iterate through.
I can make this work for n-weeks but I cannot get the EVERY-n-week part to work since I cannot figure out how to pull everyXweek labels from previously pulled page-thread that contains Xweek labels and other labels as well.
Any help you can extend would be greatly appreciated for sure !
Thanks.
JP
function getLabelNameXWeekSnooze(i) {
return "Snooze/" + i + "weekSnooze";
}
function getLabelNameEveryXWeekSnooze(i) {
return "Snooze/" + "every" + i + "weekSnooze";
}
function moveWeekSnoozes() {
var oldLabel, newLabel, page;
for (var i = 1; i <= WEEKS_TRACKED; ++i) {
newLabel = oldLabel;
oldLabel = GmailApp.getUserLabelByName(getLabelNameXWeekSnooze(i));
page = null;
newpage = null;
// Get threads in "pages" of 100 at a time
while(!page || page.length == 100) {
page = oldLabel.getThreads(0, 100);
if (page.length > 0) {
if (newLabel) {
// Move the threads into "today’s" label
newLabel.addToThreads(page);
} else {
// Time to Unsnooze
GmailApp.moveThreadsToInbox(page);
if (MARK_UNREAD) {
GmailApp.markThreadsUnread(page);
}
// after returning mail to inbox please create an
// XweekSnooze label for every thread in page that has associated everyXweekSnooze label
// for example every3weekSnooze thread will need 3weekSnooze label to iterate/delay from
for (var j = 1; j <= WEEKS_TRACKED; ++j) {
// format the label data
everyXweekLabel = GmailApp.getUserLabelByName(getLabelNameEveryXWeekSnooze(j));
XweekLabel = GmailApp.getUserLabelByName(getLabelNameXWeekSnooze(j));
//trying to grab all thread from page that have everyXweek label and save to new page
newpage = everyXweekLabel.page;
if (newpage.length > 0) {
XweekLabel.addToThreads(newpage);
}
}
// Move the threads out of "yesterday’s" label
oldLabel.removeFromThreads(page);
}
}
}
}
For reference, the original Gmail Snooze algorithm can be found here: Gmail Snooze with Apps Script. The algorithm is based on the idea of percolating a set of Gmail labels on threads, using an Apps Script trigger to handle the timing.
Basically, the problem in your question boils down to the need to find a set of GmailThreads that all have two specified labels (that is, the union of the set of threads that have label A and the set that has label B).
Apps Script doesn't provide a direct way of doing this, so you have to do a bit of work. The approach is straightforward: get the set of threads that have label A, iterate through them to check each for label B, and then record the threads that have both.
In this case, we will use an object to record the threads that have been moved to the inbox but now need to be reset. After adjusting all the other labels, we will have a separate reset step. It's important to do this separately, since if you reset a thread while percolating you will accidentally adjust it one too many times.
function moveSnoozes() {
var oldLabel, newLabel, page;
// Set up an empty record of threads that will need
// to be reset
var resets = {};
for (var i = 1; i <= WEEKS_TRACKED; ++i) {
resets[getLabelNameXWeekSnooze(i)] = [];
}
for (var i = 1; i <= WEEKS_TRACKED; ++i) {
newLabel = oldLabel;
oldLabel = GmailApp.getUserLabelByName(getLabelNameXWeekSnooze(i));
page = null;
// Get threads in "pages" of 100 at a time
while(!page || page.length == 100) {
page = oldLabel.getThreads(0, 100);
if (page.length > 0) {
if (newLabel) {
// Move the threads into "today’s" label
newLabel.addToThreads(page);
} else {
// Unless it’s time to unsnooze it
GmailApp.moveThreadsToInbox(page);
if (MARK_UNREAD) {
GmailApp.markThreadsUnread(page);
}
// Now check for everyXweekSnooze label and
// record individual threads that need to be reset
for(var t=0; t<page.length; t++) {
var thread = page[t];
var resetLabel = findResetLabel(thread);
if(resetLabel) {
resets[resetLabel.getName()].push(thread);
}
}
if (ADD_UNSNOOZED_LABEL) {
GmailApp.getUserLabelByName("Unsnoozed")
.addToThreads(page);
}
}
// Move the threads out of "yesterday’s" label
oldLabel.removeFromThreads(page);
}
}
}
// Reset recorded threads
for (var i = 1; i <= WEEKS_TRACKED; ++i) {
var resetLabelName = getLabelNameXWeekSnooze(i);
var resetLabel = GmailApp.getUserLabelByName(resetLabelName);
resetLabel.addToThreads(resets[resetLabelName]);
}
}
// Given a GmailThread, check to see if it has
// any of the everyXweekSnooze labels and return
// the first one found
// #param {Object} thread - GmailThread to examine
// #return {Object} GmailLabel - the first everyXweekSnooze
// label found, or null if none are found
function findResetLabel(thread) {
for (var i = WEEKS_TRACKED; i >= 1; i--) {
var label = getLabelNameEveryXWeekSnooze(i);
var labels = thread.getLabels();
for (var j = 0; j < labels.length; j++) {
if(labels[j].getName() == label) {
return GmailApp.getUserLabelByName(getLabelNameXWeekSnooze(i));
}
}
}
return null;
}
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;
}
I'm assuming it's a logical error because it doesn't return any compiler or run-time errors.
my functions:
function closetest() {
tooclose=false;
for (i=0; i<10; i++) {
if (Math.abs(entry[0]-entry[i])<100) {
tooclose=true;
}
}
}
function xassignment() {
for (i=0; i<10; i++) {
entry[i+1]=entry[i];
}
do {
entry[0] = int(Math.random()*(stage.stageWidth - 30));
closetest();
} while (tooclose == false);
}
Here is where the function is called
mcMain.addEventListener(Event.ENTER_FRAME, moveChar);
function moveChar(event:Event):void {
if (gameOver == false) {
if (enemyTime < enemyLimit) {
enemyTime++;
} else {
var newEnemy = new Enemy();
xassignment();
newEnemy.y=-1*newEnemy.height;
newEnemy.x=entry[0];
addChild(newEnemy);
enemyTime=0;
}
}
}
I'm making a game that involves objects being dropped from a randomly generated x coordinate, I made these functions to make sure that objects aren't being dropped too close to each other but it doesn't appear to have any effect.
You haven't described what effect you are observing, but I noticed this:
for (i=0; i<10; i++) {
if (Math.abs(entry[0]-entry[i])<100) {
tooclose=true;
}
}
This will result in tooclose always being true, because your loop begins at 0, therefore you compare entry[0] with itself. Try starting the loop at 1 instead.
You haven't declared or changed tooclose within xassignment. You should instead return a Boolean from closetest() which will be queried. Another logical error is, you are advancing previous values by 1 in your array, while incrementing the index. So you have i=0, entry[1]=entry[0]. Then i is incremented, entry[2]=entry[1] - bam, entry[2] too starts being requal to entry[0]! And so on, so the entire array of entries now equals to what was rolled on the previous attempt, instead of storing 10 previous values. Fixed that too.
function closetest():Boolean {
for (var i:int=1; i<10; i++) {
if (Math.abs(entry[0]-entry[i])<100)
return true;
}
return false;
}
function xassignment() {
for (i=10; i>0; i--) entry[i]=entry[i-1];
do {
entry[0] = int(Math.random()*(stage.stageWidth - 30));
} while(closetest());
}
Note though, if your closetest implementation will receive a [X,100,300,500,700] array the loop will be endless, as there's no X position that will satisfy your range of 100 for absolute difference. So, fix it with the following:
function xassignment() {
for (i=10; i>0; i--) entry[i]=entry[i-1];
var loops:int=10;
do {
entry[0] = int(Math.random()*(stage.stageWidth - 30));
loops--;
} while((loops>0)&&closetest());
}
This will force an exit from that loop if we tried 10 randoms and none satisfied - the last attempt is returned.
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.