AS3 sortOn woes - actionscript-3

I have an Array called alarmQueue. I'm pushing a new arrays in to it with the contents [hours:int, minutes:int, seconds:int] and I'd like to use alarmQueue.sortOn() to sort the queue of alarms Ascending but I'm having problems getting my head around the logic.
// the function to push the alarm in to a queue
public function setAlarm(_hours:int = 0, _minutes:int = 0, _seconds:int = 0):void
{
var alarmAsArray:Array = new Array(_hours, _minutes, _seconds);
alarmQueue.push(alarmAsArray);
alarmQueue.sortOn([0, [1, 2]], Array.NUMERIC | Array.DESCENDING);
trace(alarmQueue);
}
I'm setting these alarms:
clock.setAlarm(1, 0, 31); // alarm 1
clock.setAlarm(12, 1, 21); // alarm 2
clock.setAlarm(12, 1, 19); // alarm 3
and getting the following traces:
1,0,31
12,1,21,1,0,31
12,1,21,12,1,19,1,0,31
I seem to be ordering them as: alarm 2, alarm 3, alarm 1
but I want to be ordering them by hour, then minute and seconds.
Can anyone shed any light on my sorting woes?
Cheers!
thanks for the feedback.
I've tested:
alarmQueue.push(
{
hours: _hours,
minutes: _minutes,
seconds: _seconds
});
alarmQueue.sortOn(
['hours', 'minutes', 'seconds'],
[Array.NUMERIC | Array.ASCENDING, Array.NUMERIC | Array.ASCENDING, Array.NUMERIC | Array.ASCENDING]
);
if(alarmQueue.length == 3)
{
for(var i:int = 0; i SMALLERTHAN alarmQueue.length; i++)
{
trace(alarmQueue[i].hours,alarmQueue[i].minutes, alarmQueue[i].seconds);
}
}
I had to change the trace slightly due to the array items being objects now and used SMALLERTHAN as the < symbol seems to break to code tags here, but the app wouldn't compile as Flex Builder was telling me Array.ASCENDING not being a sort method, so I checked livedocs and found no mention of it there too. Any other guesses?

This should work, but I have not tested it.
public function setAlarm(_hours:int = 0, _minutes:int = 0, _seconds:int = 0):void
{
alarmQueue.push(
{
hours: _hours,
minutes: _minutes,
seconds: _seconds
});
alarmQueue.sortOn(['hours', 'minutes', 'seconds'], Array.NUMERIC);
}

Found the answer after some tinkering. The default method of sorting is ascending but there's no option to set Ascending as a secondry sorting method. So by performing two sorts, the first descending on the minutes and seconds, the second is a sortOn the hours with no parameter applied so it sorts ascending!
var alarmAsArray:Array = new Array(_hours, _minutes, _seconds);
alarmQueue.push(alarmAsArray);
alarmQueue.sortOn([1, 2]);
alarmQueue.sortOn([0], Array.DESCENDING);
if(alarmQueue.length == 3)
{
trace(alarmQueue);
}
this gives the correct output of: 12,1,19 12,1,21 1,0,31
Many thanks all!
ant

Related

Angular: Posting Data to a Table with a loop and giving a problem when posting the i of the loop into the table

Good day,
I am trying to get data into a table, with the tour_id and every single media_id (the station_id i am getting from somewhere else), the ordernumber is what is giving me a headache:
I am trying to get every station one number for every media i am posting.
For example:
station 1 has 2 medias
and station 2 has 3
then the odernumbers should be like this: 0, 0, 1, 1, 1
I am using the following Code at this moment:
for(var i = 0; i < this.currentStations.length; i++){
this.http.get("http://localhost:3000/mediasforstation/" + this.currentStations[i].id).subscribe((res) => {
medias = res;
for (var j = 0; j < medias.length; j++){
this.http.post("http://localhost:3000/posttourstations",
{"tour_id": id, "media_id": medias[j].id, "ordernumber": i}).subscribe(function(res) {
console.log(res);
}.bind(this));
}
});
}
Everything but the ordernumber works, however, the ordernumber always takes the number of stations involved, in our example above it would be 2.
How do I fix this?
Thank you very much for your help.
As I understand, you need to keep the index value. The type of variable i is var which is function scoped. Within outer loop, you are calling an API that returns some response, meanwhile the value of i is updated and for next index/counter, the API call has been sent. When you get response from API calls, you get the value of i where the outer loop has been called of.
In other words, you need to understand the difference between var and let. Your problem can be solved by replacing
for(var i=0;...)
with
for(let i=0;...)
Here's providing you the sample code.
//block scoped - retains value of i
for (let i=0;i<10;i++){
this.http.get('https://jsonplaceholder.typicode.com/users').subscribe(res=>{
for(var j=0;j<5;j++){
console.log(`i=>${i}`)
}
})
}
//function scoped - gets updated value of i
for (var i=0;i<10;i++){
http.get('https://jsonplaceholder.typicode.com/users').subscribe(res=>{
for(var j=0;j<5;j++){
console.log(`i=>${i}`)
}
})
}

AS3 Null Object Reference After Null Check

I have been looking for a solution to this for a while now but cannot find anything.
This problem is very odd so I'll give some background. I am making a tower defense game, and while implementing status effects on enemies (slowed, on fire, etc.) I ran into a weird problem. When the tower kills the enemy with a projectile everything is fine, but for some reason when the enemy is killed by a status effect, I get a null object reference error (both are handled with the method "Enemy.damage(damage:int)"). The weird thing about this is that the status effects are stored in an array that is only referenced in 3 spots. In the ENTER_FRAME event (one ENTER_FRAME event is used to process every aspect in the Game), in the constructor (status = new Array();) and in the destroy method.
One weird part is that if the "status" variable was null, other variables from the destroy method would have given me errors a long time ago. The really weird part is that I have a null check right before I get the error.
Here is where I get the error:
//STATUS EFFECTS
if (status == null) {
trace("test");
}
if (status != null && status.length != 0) {
for (var i:int = 0; i < status.length; i++) {//LINE 101
status[i].applyEffect();
}
}
Here is the error:
TypeError: Error #1009: Cannot access a property or method of a null object reference.
at game.enemies::Enemy/update()[C:\flash\game\enemies\Enemy.as:101]
"test" never gets printed, and even with the null check I still get the error
EDIT: Here is the Enemy class: http://pastebin.com/LAyMMB1P
The StatusEffect & FireEffect classes: http://pastebin.com/GTGDmjt8 (I can only post 2 links, each is in its own file)
status variable is referenced in StatusEffect.destroy() and here:
override public function onHit(e:Enemy) {
if (upgradeLevel >= 1) {
var onFire = false;
for (var i:int = 0; i < e.status.length; i++) {
if (e.status[i].name_ == "fire") {
onFire = true;
}
}
if (!onFire) {
e.status.push(new FireEffect(e));
}
}
if (upgradeLevel >= 2) {
if (enemiesHit.indexOf(e) == -1) {
enemiesHit.push(e);
e.damage(1);
}
if (upgradeLevel == 2 && enemiesHit.length == 2) {
destroy();
}
} else {
e.damage(super.damage);
destroy();
return;
}
}
This is happening because you can potentially destroy your enemy in the middle of the for loop on line 101.
Destroying the enemy sets the status array to null, so on the next iteration when it checks if i < status.length, status is null, thus the error.
So to illustrate, stepping through the code, let's assume at line 101 there are two items in the status array:
First loop, item at index 0 gets applyEffect() called on it.
inside applyEffect() the specificApplication() method can be called.
inside specificApplication() the super.enemy.damage(1); method is called.
inside the enemy.damage() method, you can potentially call the enemy.destroy method
inside the enemy.destroy method, you set status = null.
NOW the loop from line 101 loops, but status is now null.
Fix this by breaking out of your loop if the enemy is destroyed.
for (var i:int = 0; i < status.length; i++) {//LINE 101
status[i].applyEffect();
if(!status) break;
}
You also have some issue with splicing:
enemy.status.splice(enemy.status.indexOf(this), 1);
While there is nothing wrong with that line on it's own, let's step through the code:
line 101 of Enemy class:
for (var i:int = 0; i < status.length; i++) {
You loop through the status array. For this example, let's say you have two items in the array.
Item A is at position 0. Item B is at position 1 in the array.
First loop, i has a value of 0.
You call status[i].applyEffect(), since i == 0, that is item A.
Inside applyEffect let's say your condition is met so you call destroy (on the StatusEffect class)
Inside the StatusEffect.destroy() method you splice the status array.
Now status has only one item, item B, and item B now has an index of 0 (instead of 1).
Your loop loops, now i == 1.
However, there is no longer any item at index 1 so the loop exits, skipping item B.
To solve it, iterate backwards instead, then your indices won't get out of whack when you splice:
var i:int = status.length
while(i--){
status[i].applyEffect();
}
As an aside, it would be much cleaner if you used var status:Vector.<StatusEffect> instead of an var status:Array. You'd get compile time checking and type safety that way.

How to create an auto click button

I have a list of cases in the queue that I need to grab. As you can imagine, it's a bit repetitive and time consuming. I'm new at programming and haven't figured a way to create a script that auto-click/grab these cases. Can someone help?
Code to:
1) Search and Click "Grab"
- will take 4 seconds for the page to refresh
2) Click grab again
3) stop after 50 cases are grabbed
This code doesn't work
window.setTimeout("pushSubmit()",3000);
function pushSubmit()
{document.getElementById('Grab').click();
Assuming your page is not refreshed in the process, you could keep a counter of how many "Grabs" you have done:
var counter = 0;
var maxCount = 50;
function pushSubmit() {
if(counter++ < maxCount) {
document.getElementById('Grab').click();
window.setTimeout(pushSubmit,3000);
}
}
//start the process
pushSubmit();
Here is a jsfiddle example
EDIT:
Or what I would probably prefer, set up the function so it can be used with any number of iterations.
function pushSubmit(max, count) {
count = typeof count !== 'undefined' ? count : 1;
if(count <= max) {
document.getElementById('Grab').click();
window.setTimeout(function() { pushSubmit(max, ++count) },3000);
}
}
//start the process with the max number of iterations it should perform
pushSubmit(50);
Example

How do I return a value from the Function used to initialize an array in Mathematica

In this example I'm trying to create an Array of length 5 where each ellement contains the number of times .3 can be summed without exceeding 1. i.e. 3 times. So each element should contain the number 3. Here is my code:
Array[(
workingCount = 0;
workingSum = 0;
done = false;
While[! done,
workingSum = workingSum + .3;
If[workingSum > 1, done = true; workingCount, workingCount++]
])
, 5]
In the 3rd to last line there I have workingCount without a ; after it because it seems like in Mathematica omitting the ; causes the value a statement resolves to to be returned.
Instead I get this:
{Null[1], Null[2], Null[3], Null[4], Null[5]}
Why does this happen? How can I get my program to do what I want it to do? i.e. In the context of the function passed to Array to initialize it's elements, how to I use complicated multi-line functions?
Thanks in advance.
Two things:
First, one way to be able to do that in Mathematica is
Array[
Catch[
workingCount = 0;
workingSum = 0;
done = False;
While[! done,
workingSum = workingSum + .3;
If[workingSum > 1,
done = True; Throw#workingCount,
workingCount++]]] &,
5]
Second, and most important: you never should do that in Mathematica! Really.
Please visit for example the Stack Exchange site for Mathematica, and read the questions an answers there to get some grip on the programming style.
Your problem comes from the fact that you are trying to initialize your array, but are trying to do so without an explicit function call - which is what you need to do.
See here for documentation on Arrays in Mathematica:
http://reference.wolfram.com/mathematica/ref/Array.html
That aside, and minor errors (True and False have to be capitalized), this is what you want to do:
f[x_] :=
(
workingCount = 0;
workingSum = 0;
done = False;
While[done != True, workingSum = workingSum + 0.3;
If[workingSum > 1, done = True, workingCount++]
];
Return[workingCount];
);
Array[f, 5] (* The array here is generating 5 values of the return value of f[x_] *)

What does this mean in AS3?

Hello I've started to learning AS3 from one book and found something I don't understand.
Ellipse(_board[row][column]).fill = getFill(row, column);
_board is two dimensional array of Ellipse type, so I just dont understand why is Ellipse(Ellipse object) used when it apparently works without it, or I haven't seen any changes when I omitted it.
Ellipse(_board[row][column]) is a type cast Type(object)
Because you can push anything into an Array the compiler doesn't know what kind of objects are stored within the Array. So it is good style to cast objects if you retrive them from an Array to their correct type.
This has several benefits:
if such an object is not of the type you expect or null, you will know when you typecast instead of getting an error later somewhere far away
the code executes a bit faster if you are explicit about the types
if you use a good IDE it can provide you with autocompletion when it knows the types
_board is a multidimensional array filled first with Arrays.
In the BoardDisplay.mxml
(Hello! Flex 4 : Chapter 3. Hello Spark: primitives, comp... > FXG and MXML graphics—building a game.. - Pg. 80) ,
<Graphic version="1.0" viewHeight="601" viewWidth="701"
xmlns=" library://ns. adobe. com/flex/spark"
xmlns:fx=" http://ns. adobe. com/mxml/2009"
xmlns:mx=" library://ns. adobe. com/flex/halo"
initialize="createBoard()"
click=" clickHandler(event)">
initialize calls createBoard().
private function createBoard():void {
newGame();
_board = new Array(6);
for (var row:int = 0; row < 6; row++) {
_board[row] = new Array(7);
for (var col:int = 0; col < 7; col++) {
_board[row][col] = addEllipse(row, col); //Magic Happens!
}
}
}
addEllipse returns Ellipse to each entry in _board
private function addEllipse(row:int, col:int):Ellipse {
var ellipse:Ellipse = new Ellipse();
ellipse.x = 4 + col*100;
ellipse.y = 5 + row*100;
ellipse.width = 90;
ellipse.height = 90;
ellipse.fill = getFill(row,col); // Magic Found !
ellipse.stroke = new SolidColorStroke(0x000000, 1, 1.0, false,"normal", null, "miter", 4);
boardGroup.addElement(ellipse);
return ellipse;
}
The author casted it as maxmx said but did not really need to as all the entries were of type Ellipse so
Ellipse(_board[row][column]).fill = getFill(row, column);
can work as
_board[row][column].fill = getFill(row, column);