In KRL can I have a persistent variable count down instead of up? - krl

I want to have an app variable count down instead of up. I put the following in the postlude of one rule:
fired {
app:pies -= 1 from 10;
}
The variable app:pies would count from 10 down to 1 but it never reached zero. I need to stop giving out pies when I run out. Why doesn't the variable ever reach zero? Is there a better way to do this?

It seems that decrementing an app variable won't ever cause it to go below 1. I have no idea why that is. You can make an app variables be less than 1. This code, for example, starts the variable at -2 and increments it from there, which works fine:
app:test += 1 from -2;
Decrementing just doesn't seem to work like that...
I would suggest just adjusting the count by 1, such that you pretend that 1 means 0. Your app might look like this in that case:
rule morePies {
select when web pageview ".*"
if (app:pies > 1) then {
notify("You get a pie", "Yay!");
}
fired {
app:pies -= 1 from 11;
}
}
rules piesAreGone {
select when web pageview ".*"
if (app:pies <= 1) then {
notify("No pies left", "Sorry.");
}
}

Related

Unity - Everything freezes on " yield return new WaitForSeconds(); "?

Ok! all of my code in this scene is in one script and one manager object.
all of it is about 700 lines. so I can't put it here.
I tested different things:
1) switch platform from android to
pc/mac
2) test on a previous version
of unity( previous 2017, and current
on is 2018.1 )
none of them solve the problem.
then I change some part of the code that I suspected to cause the problem. ( none of them solve the solution ).
then I started to put Debug.Log()s everywhere. so I found where it freezes.
Here Is the code:
IEnumerator ShowSigns(int Button1State, int EqualState, int Button2State)
{
Debug.Log("ShowSigns");
if (Button1State == 1)
{
OperationOneCorrectSign.GetComponent<CanvasGroup>().alpha = 1;
}
else if (Button1State == 2)
{
OperationOneIncorrectSign.GetComponent<CanvasGroup>().alpha = 1;
}
if (EqualState == 1)
{
EqualCorrectSign.GetComponent<CanvasGroup>().alpha = 1;
}
else if (EqualState == 2)
{
EqualIncorrectSign.GetComponent<CanvasGroup>().alpha = 1;
}
if (Button2State == 1)
{
OperationTwoCorrectSign.GetComponent<CanvasGroup>().alpha = 1;
}
else if (Button2State == 2)
{
OperationTwoIncorrectSign.GetComponent<CanvasGroup>().alpha = 1;
}
Debug.Log("BeforeWaiting");
yield return new WaitForSeconds(0.3f);
Debug.Log("AfterWaiting");
OperationOneCorrectSign.GetComponent<CanvasGroup>().alpha = 0;
OperationOneIncorrectSign.GetComponent<CanvasGroup>().alpha = 0;
EqualCorrectSign.GetComponent<CanvasGroup>().alpha = 0;
EqualIncorrectSign.GetComponent<CanvasGroup>().alpha = 0;
OperationTwoCorrectSign.GetComponent<CanvasGroup>().alpha = 0;
OperationTwoIncorrectSign.GetComponent<CanvasGroup>().alpha = 0;
state = GameState.CreateNewProblem;
Debug.Log("EndSigns");
}
I found that it freezes on this:
yield return new WaitForSeconds(0.3f);
Very strange!!!
This is a picture of the game.
The game is a simple game that shows 2 math phrase and player should choose the bigger or equal.
The logic is this way:
1) make new phrases and change the game state to "ChooseAnswer"
2) player press one of 3 buttons and the answer checked and score and other things changes and the ShowSigns coroutine will start and ends after 0.3 seconds. and as you see at the end of the coroutine state changes to "CreateNewProblem".
3) in the Update when CreateNewProblem detects, the code call for the NewProblem() function to make new phrases and at the end of that game state changes to "ChooseAnswer".
this logic repeats over and over until time reaches zero.
a "step" variable increase and decrease by 1 by any correct and incorrect answer. and a variable level = steps/10 determines the difficulty of phrases.
the game works correctly on %98 click On buttons. but usually, it freezes somewhere after step 20. In 21, 23, 27, 34 ... very randomly. but always after 20 and some time no freeze until time ends. and always right before yield return. exactly at the same line.
I read many questions and answers but none of them was helpful. I have no while loop, no while(true), as long as I know and check my code no infinite loop, on StopAllCoroutines ... nothing. and I stuck for 2 days.
thanks all of you for helping.
OH,and Here Is the code file
The cause of the freezing is using Random.Range to control a while loop which is in the code linked in your question. One way to get random number without using the while loop is to generate them into List then remove each one you use. This should prevent Random.Range from freezing Unity.

Script is taking 11 - 20 seconds to lookup up an item in an 18,000 row data set

I have two Google sheets workbooks.
One is the "master" source of lookup data with a key based on manufacturer item #, which could be anything from 1234 to A-01/234-Name_1. This sheet, referenced via SpreadsheetApp.openByUrl, has 18,000 rows and 13 columns. The key column has been converted to plain text and the sheet is sorted by this column.
The second is the "template" where people enter item #s that they need to look up against the master, typically 20 - 1500 items at a time.
The script is in the template. It is very slow and routinely times out after 30 minutes. It was written by someone else and I am new to App Script, but I think I've managed to understand what the script is doing and where the bottleneck is occurring.
It does a bunch of stuff, but this is the meat of the lookup:
var numrows = master.getDataRange().getNumRows();
var masterdata = master.getDataRange().getValues();
var itemnumberlist = template.getDataRange().getValues();
var retreiveddata = [];
// iterate through the manf item number list to find all matches in the
// master and return those matches to another sheet
for (i = 1; i < template.getDataRange().getValues().length; i++) {
for (j = 0; j < numrows; j++) {
if (masterdata[j][1].toString() === itemnumberlist[i][1].toString()) {
retreiveddata.push(data[j]);
anothersheet.appendRow(data[j]);
}
}
}
I used Logger.log() to determine that each time through the i loop is taking 11 - 19 seconds, which just seems insane.
I've been doing some google searching and I've tried a couple of different things...
First I tried moving the writing of found data out of the for loop so the script would be doing all of its reading first and then writing in one big chunk, but I couldn't get it exactly right. My two attempts are below.
var mycounter = 0;
for (i = 0; i < template.getDataRange().getValues().length; i++) {
for (j = 0; j < numrows; j++) {
if (masterdata[j][0].toString() === itemnumberlist[i][0].toString()) {
retreiveddata.push(masterdata[j]);
mycounter = mycounter + 1;
}
}
}
// Attempt 1
// var myrange = retreiveddata.length;
// for(k = 0; k < myrange; k++) {
// anothersheet.appendRow(retreiveddata.pop([k]);
// }
//Attempt 2
var myotherrange = anothersheet.getRange(2,1,myothercounter, 13)
myotherrange.setValues(retreiveddata);
I can't remember for sure, because this was on Friday, but I think both attempts resulted in the script trying to write the entire master file into "anothersheet".
So I temporarily set this aside and decided to try something else. I was trying to recreate the issue in a couple of sample spreadsheets, but I was unable to do so. The same script is getting through my 15,000 row sample "master" file in less than 1 second per lookup. The only thing I can think of is that I used a random number as my key instead of a weird text string.
That led me to think that maybe I could use a hash algorithm on both the master data and the values to be looked up, but this is presenting a whole other set of issues.
I borrowed these functions from another forum post:
function GetMD5Hash(value) {
var rawHash = Utilities.computeDigest(Utilities.DigestAlgorithm.MD5,
value);
var txtHash = '';
for (j = 0; j <rawHash.length; j++) {
var hashVal = rawHash[j];
if (hashVal < 0)
hashVal += 256;
if (hashVal.toString(16).length == 1)
txtHash += "0";
txtHash += hashVal.toString(16);
Utilities.sleep(100);
}
return txtHash;
}
function RangeGetMD5Hash(input) {
if (input.map) { // Test whether input is an array.
return input.map(GetMD5Hash); // Recurse over array if so.
Utilities.sleep(100);
} else {
return GetMD5Hash(input)
}
}
It literally took me all day to get the hash value for all 18,000 item #s in my master spreadsheet. Neither GetMD5Hash nor RangeGetMD5Hash will return a value consistently. I can only do a few rows at a time. Sometimes I get "Loading..." indefinitely. Sometimes I get "#Name" with a message about GetMD5Hash being undefined (despite the fact that it worked on the previous row). And sometimes I get "#Error" with a message about an internal error.
This method actually reduces the lookup time of each item to 2 - 3 seconds (much better, but not great). However, I can't get the hash function to consistently work on the input data.
At this point I'm so frustrated and behind on my other work that I thought I'd reach out to the smart people on these forums and hope for some sort of miracle response.
To summarize, I'm looking for suggestions on these three items:
What am I doing wrong in my attempt to move the write out of the for loop?
Is there a way to get my hash value faster or utilize a different method to accomplish the same goal?
What else can I try to help speed up the script?
Any suggestions you can offer would be greatly appreciated!
-Mandy
It sounds like you hit on the right approach with attempting to move the appendRow() call out of the loop. Anytime you are reading or writing to a spreadsheet you can expect the individual call to take 1 to 2 seconds, so this will eat up a lot of time when you get matches. Storing the matches in an array and writing them all at once is the way to go.
Another thing I notice is that your script calls getValues() in the actual for loop condition statement. The condition statement is executed each time on each iteration of the loop, so this is potentially wasting a lot of time even when you don't have matches.
A final tweak that may be helpful depending on your desired behaviour. You can stop the inner for loop after it finds the first match, which, if you only care about the first match or know there will only be one match, will save you a lot of iterations. To do this, put "break" immediately after the retreiveddata.push(masterdata[j]); line.
To fix the getValues issue, Change:
for (i = 1; i < template.getDataRange().getValues().length; i++) {
To:
for (i = 1; i < itemnumberlist.length; i++) {
And that fix along with the appendRow issue, and including the break call:
for (i = 1; i < itemnumberlist.length; i++) {
for (j = 0; j < numrows; j++) {
if (masterdata[j][0].toString() === itemnumberlist[i][0].toString()) {
retreiveddata.push(masterdata[j]);
break; //stop searching after first match, move on to next item
}
}
}
//make sure you have data to write before trying to write it.
if(retreiveddata.length > 0){
var myotherrange = anothersheet.getRange(2,1,retreiveddata.length, retreiveddata[0].length);
myotherrange.setValues(retreiveddata);
}
If you are re-using the same sheet for "anothersheet" on each execution, you may also want to call anothersheet.clear() to erase any existing data before you write your fresh results.
I would pass on the hashing approach altogether, comparing strings is comparing strings, so whether they are hashes or actual part numbers I wouldn't expect a significant difference.

How to make a counter for Ignition Designer using Python

I'm trying to do a counter that would count the amout of times when a tag (measuring conditions) is either 0 or 32767. The counter should count +1 in either case.
I'm trying something like this (but I know it's a mess):
def count(self):
while x == 0 or X == 32676
print count += 1
or somethin like this:
def isEqual(num):
x == 0 or x == 32676
print counter += 1
elif: print counter
You could make a memory tag to store your counter. Then make a gateway tag change script to check for your two values each time the tag changes. Increment your counter each time the tag is equal to either of those two values. Like this:
if (newValue.value in [0, 32676]) and (not initialChange):
system.tag.write('counter', system.tag.read('counter').getValue() + 1)
set label bound to the tag you are tracking,
create memory tag for counter
add value change script that will run every time the value of the tag you are tracking changes
Script should look like:
counter = system.tag.readBlocking(["[default]My/Tag/counter"])
counter = counter + 1
system.tag.writeBlocking(["[default]My/Tag/counter"],["counter"])

Calling a function inside itself

I have a function, and in some cases I want it to be used two times in a row, is there a way to call the function inside itself
something like, my function is a lot longer and being abel to do something like this would save a lot of time
func theFunc() {
count++
if count < 4 {
thFunc()
}
}
That's called recursion, and it's perfectly legal:
var count = 0
func theFunc() {
print(count)
count += 1
if count < 4 {
theFunc()
}
}
theFunc() // 0 1 2 3
The only trick is not to recurse too deeply, as you risk running out of resources, and don't forget to put some sort of "stopper" (such as your if count < 4), lest you recurse forever, resulting in (oh the irony) a stack overflow.
[Extra for experts: there are some languages, such as LISP, that are optimized for recursion, and where recursion is actually preferred to looping! But Swift is not really one of those.]

Count dead enemies in Unity3D

I'm programming a racing game.
You can wreck your opponents and I want to count the enemies you've wrecked.
I do this in this way:
if(Wrecked){
Smoke.Emit();
EngineTorque = 0;
PlayerCar_Script.EnemyWrecked += 1;
}
I think you can see my issue. It will not count just 1 up it will count endless ....
How can I fix this ? I also tried SendMessage, but it ends up in the same issue :/
It will not count just 1 up it will count endless
that sounds like you're running the above code repeatedly, but not setting PlayerCar_Script.EnemyWrecked back to 0 between each run. I'm guessing you have this in the car's monobehavior.update() function. Instead, only increment EnemyWrecked when you change from not wrecked to wrecked.
Use a variable for each wreckable car to determine if it was wrecked the last time you checked.
bool wasWreckedLastFrame = false;
and then change your above code segment to this:
if(Wrecked && wasWreckedLastFrame==false){
wasWreckedLastFrame = true;
Smoke.Emit();
EngineTorque = 0;
PlayerCar_Script.EnemyWrecked += 1;
}