Recursive function causing my script to exit - autohotkey

When I call this function it runs for a few minutes and then the script exits. I have found if I set the sleep period higher it takes longer for it to exit. Are there any ways I can write this so that it never exits? I think it has to do with the memory being used. The delay between loops has to be 500ms or lower.
Waitbeforefight()
{
Random, Wbf, 500, 500
sleep %Wbf%
ImageSearch, FoundX2, FoundY2, 855, 915, 1024, 1071, *30 E:\Desktop\Capture23.png
if ErrorLevel = 2
{
MsgBox Could not conduct the search.
ExitApp
}
else if ErrorLevel = 1
{
return
}
else
{
sleep %Wbf%
Waitbeforefight()
}
}
Even when I make a simple script like this it exits.
func1()
{
sleep 50
func1()
}
F1::
{
func1()
}

As Jongware commented,
It exits because the stack overflows: both of functions call themselves, and never return. Change the recursive call into a continuous loop to solve it.
After attempting an image search, there are three paths your function can take:
If the search couldn't be conducted, the script exits.
If the image wasn't found, the function returns.
Otherwise, the image was found and the function repeats.
Since the first two cases are exiting the function, it is very simple to change your function to use a loop: just remove the recursive call and wrap the content of the function in a Loop {}.
Waitbeforefight()
{
Loop
{
Random, Wbf, 500, 500
sleep %Wbf%
ImageSearch, FoundX2, FoundY2, 855, 915, 1024, 1071, *30 E:\Desktop\Capture23.png
if ErrorLevel = 2
{
MsgBox Could not conduct the search.
ExitApp
}
else if ErrorLevel = 1
{
return
}
else
{
sleep %Wbf%
; Instead of calling self, just allow the loop to continue.
}
}
}

Related

AutoHotKey - Functions cannot contain functions error

I'm new to AutoHotKey and I wanted to create a script macro for a flash game but when I run it, it creates an error.
#NoEnv ; Recommended for performance and compatibility with future AutoHotkey releases.
; #Warn ; Enable warnings to assist with detecting common errors.
SendMode Input ; Recommended for new scripts due to its superior speed and reliability.
SetWorkingDir %A_ScriptDir% ; Ensures a consistent starting directory.
condChecker := false
state := true
Mine()
{
Sleep, rand(10,80)
Send, {Space}
while(state = true)
{
PixelGetColor, gemColor, 982, 433
if(gemColor = B93557)
{
state := true
{
else(gemColor = 96885A)
{
state := false
}
Sleep, rand(90,120)
}
}
^-::
loop 10000
{
getState()
if(state = true)
{Mine()}
else
{Sleep, rand(70,150)}
}
When I press Run Script on the ahk file, a menu pops up saying
Error at line 20.
Line Text else(gemColor = 96885A)
Error: Functions cannot contain functions.
The program will now exit.
I don't know where to start with this error and I read up on other forums saying that my formatting was incorrect.
A couple of various things:
The curly brace after state := true should be the other way (}, not {)
There is no default rand function in AHK, you are probably either looking for Random, or you have a custom function called rand that you is not shown in your question. In any case, I'll write a function rand(a,b) that will return an integer value between a and b
rand(a, b)
{
Random, rand, a, b
return rand
}
Additionally, there is another function getState() that is being invoked inside the loop 10000. I'm not sure what it is supposed to do (or if you meant something like GetKeyState instead), but I'll assume that you have that covered on your end.
As #Pranav Hosangadi mentioned, you likely wanted an else if statement instead of just an else statement on this line: else(gemColor = 96885A)
Are you sure you want SendMode Input? Although it does have superior speed than standard Send, its use is normally limited to typing text in a text box. It seems that you are trying to send a keystroke to a flash game, so you might want to check whether that functioning as you intend it to.
When writing a end curly brace (}) to conclude an if() or else() clause, you need to put it on its own line. (i.e. change
if(state = true)
{Mine()}
else
{Sleep, rand(70,150)}
to something like
if(state = true)
{
Mine()
}
else
{
Sleep, rand(70,150)
}
or even (since the if and else statements here only trigger one line of code each)
if(state = true)
Mine()
else
Sleep, rand(70,150)
So, that was a bit long, but here is the final code:
#NoEnv ; Recommended for performance and compatibility with future AutoHotkey releases.
; #Warn ; Enable warnings to assist with detecting common errors.
; ---> Double check this! ---> SendMode Input
SetWorkingDir %A_ScriptDir% ; Ensures a consistent starting directory.
condChecker := false
state := true
Mine()
{
Sleep, rand(10,80)
Send, {Space}
while(state = true)
{
PixelGetColor, gemColor, 982, 433
if(gemColor = B93557)
{
state := true
}
else if(gemColor = 96885A)
{
state := false
}
Sleep, rand(90,120)
}
}
rand(a, b)
{
Random, rand, a, b
return rand
}
^-::
loop 10000
{
;getState()
if(state = true)
Mine()
else
Sleep, rand(70,150)
}
lmk if something doesn't work properly, and I'll try to update this response

Difference between sleep(1) and while(sleep(1))

I have the following piece of code while looking for sigchild code. In the code below 50 children are created and the parent process waits in sigchild handler until all 50 children are destroyed.
I get the expected result if I use while(sleep(1)) at the end of main, however if I replace it by sleep(1), the parent gets destoyed before all child processes terminate.
int l=0;
/* SIGCHLD handler. */
static void sigchld_hdl (int sig)
{
/* Wait for all dead processes.
* We use a non-blocking call to be sure this signal handler will not
* block if a child was cleaned up in another part of the program. */
while (waitpid(-1, NULL, WNOHANG) > 0) {
printf(" %d",l++);
}
printf("\nExiting from child :: %d\n",l);
}
int main (int argc, char *argv[])
{
struct sigaction act;
int i;
memset (&act, 0, sizeof(act));
act.sa_handler = sigchld_hdl;
if (sigaction(SIGCHLD, &act, 0)) {
perror ("sigaction");
return 1;
}
/* Make some children. */
for (i = 0; i < 50; i++) {
switch (fork()) {
case -1:
perror ("fork");
return 1;
case 0:
return 0;
}
}
/* Wait until we get a sleep() call that is not interrupted by a signal. */
while (sleep(1)) {
}
// sleep(1);
printf("\nterminating\n");
return 0;
}
I have the following piece of code while looking for sigchild code. In
the code below 50 children are created and the parent process waits in
sigchild handler until all 50 children are destroyed.
No, it does not. waitpid WNOHANG will fail if there is nobody exited. And there is no guarantee all the children exited (or will exit) during execution of the handler.
Even with mere sleep(1) there is no guarantee any child will manage to exit, but in practice most of them will.
sleeping is a fundamentally wrong approach here. Since you know how many children you created, you should wait for all of them to finish and that's it. For instance you can decrement a counter of existing children each time you reap something and wait for it to go to 0.
Depending on how the real program looks like, it may be you don't want the handler in the first place: just have the loop at the end, but without WNOHANG.
I also have to comment about this:
/* Wait for all dead processes.
* We use a non-blocking call to be sure this signal handler will not
* block if a child was cleaned up in another part of the program. */
You can't mix a signal handler and waiting on your own. You risk snatching the process from the other code waiting for it, what happens then?
It's a design error. fork/exit behaviour has to either be unified OR decentralized.
From the manual page
Return Value
Zero if the requested time has elapsed, or the number of seconds
left to sleep, if the call was interrupted by a signal handler.
So I guess without the while bit, the sleep is being interrupted, hence that process ending quickly

AutoHotKey infinite while loop

Is there a way to create something like this in AutoHotKey?
bool isReady = false;
while (!isReady) {
// Do something here
isReady = true;
}
I tried to experiment with While loop, but it ended with just 1 loop regardless of the condition I give the program. I am currently using Version 1.0.47.06.
I read the documentation here: http://www.autohotkey.com/docs/commands/While.htm I tried to give the while loop a value of true. But it only executed once. (I was expecting it to loop forever, until I terminate the script).
condition := true
while (condition)
{
MsgBox, condition
}
while (true)
{
MsgBox, true
}
Your code is correct, but the While command requires version 1.0.48+.
You should update to the latest version of AHK here - http://ahkscript.org/download/
To create a infinite loop , you can use this syntax:
Loop
{
; Your other code goes here
}

Perl do...while and last command

I've just encountered some very weird behavior that I really can't explain:
do {
my $qry = $self->getHTMLQuery(undef, $mech->content());
next if (!defined($qry));
push(
#prods,
map { 'http://www.XXXXYYYX.com'.$_->attr('href') }
$qry->query('div.prodInfo div.prodInfoBox a.prodLink.GridItemLink')
);
$qry->delete();
$TEST++;
last if ($TEST >= 10);
} while(eval { $mech->follow_link(class => 'jump next') });
print "WHILE ENDED\n";
The code above never prints "WHILE ENDED" even though it does seem to go out of the while loop when $TEST >= 10.
But the following code does print "WHILE ENDED":
do {
my $qry = $self->getHTMLQuery(undef, $mech->content());
next if (!defined($qry));
push(
#prods,
map { 'http://www.XXXXYYYX.com'.$_->attr('href') }
$qry->query('div.prodInfo div.prodInfoBox a.prodLink.GridItemLink')
);
$qry->delete();
$TEST++;
} while(eval { $mech->follow_link(class => 'jump next') } && $TEST <= 10);
print "WHILE ENDED\n";
In both tests, the initial value of $TEST is 0.
Is the behavior of last in do...while different than in for and while {...}?
A do block with a looping modifier doesn't count as a real loop as far as next, last, and redo are concerned. This is mentioned in perlsyn, where you'll find the tip Schwern mentioned about surrounding it with a bare block to make last work. But that won't work with next, because a bare block is only executed once, so next acts like last. To make next work, you can put the bare block inside the do, but then last will act like next.
If you need both next and last to work with a do ... while, the easiest way is to use an infinite loop with the real condition in a continue block. These 2 loops are equivalent, except that the second is a real loop, so it works with next & last:
do { ... } while condition;
while (1) { ... } continue { last unless condition };
From perldoc -f last:
"last" cannot be used to exit a block that returns a value such as
"eval {}", "sub {}" or "do {}"
TLP is right. The standard work around for this (I just hit it myself) is to wrap the do/while in a bare block which, counter-intuitively, does respect loop controls.
{ do {
last;
} while 1; }
The block outside will catch last. If you want to handle next you have to put the bloc inside.
do {{
next;
}} while 1;
The block inside will catch next.
Unfortunately you can't do both.

What does for (;;) mean in Perl?

I was looking though a fellow developers code when I saw this ..
for (;;){
....
....
....
}
I have never seen ";;" used in a loop. What does this do exactly?
It loops forever. ';;' equates to no start value, no stop condition and no increment condition.
It is equivalent to
while (true)
{
...
}
There would usually be a conditional break; statement somewhere in the body of the loop unless it is something like a system idle loop or message pump.
All 3 parts are optional. An empty loop initialization and update is a noop. An empty terminating condition is an implicit true. It's essentially the same as
while (true) {
//...
}
Note that you it doesn't have to be all-or-nothing; you can have some part and not others.
for (init; cond; ) {
//...
}
for (; cond; update) {
//...
}
for (init; ; update) {
//...
}
Just like in C, the for loop has three sections:
a pre-loop section, which executes before the loop starts.
a continuing condition section which, while true, will keep the loop going.
a post-iteration section which is executed after each iteration of the loop body.
For example:
for (i = 1, acc = 0; i <= 10; i++)
acc += i;
will add up the numbers from 1 to 10 inclusive (in C and, assuming you use Perl syntax like $i and braces, in Perl as well).
However, nothing requires that the sections actually contain anything and, if the condition is missing, it's assumed to be true.
So the for(;;) loop basically just means: don't do any loop setup, loop forever (breaks notwithstanding) and don't do any iteration-specific processing. In other words, it's an infinite loop.
Infinite loop. A lot of the time it will be used in a thread to do some work.
boolean exit = false;
for(;;) {
if(exit) {
break;
}
// do some work
}
Infinite Loop (until you break out of it).
It's often used in place of:
while(true) { // Do something }
It's the same as
while(true) {
...
}
It loops forever.
You don't need to specify all of the parts of a for loop. For example the following loop (which contains no body, or update token) will perform a linear search of myArray
for($index = -1; $myArray[++$index] != $target;);