I've been working with SikuliX to get some try some ATDD. The code works well when only I am the one working with it. However transferring the below code to anyone else is simply counter-productive irrespective of how well I comment the code.
int numOfTries;
while (!isFinishStage && numOfTries != 3) {
numOfTries++;
try {
temp = new Pattern("imgs/img1.png").similar(0.9f);
s.wait(temp, 1);
s.find(temp);
s.hover(temp);
isFinishStage = true;
break;
}catch (FindFailed ff1) {
try {
temp = new Pattern("imgs/img2").similar(0.5f);
s.wait(temp, 1);
s.find(temp);
s.hover(temp);
isFinishStage = true;
break;
} catch (FindFailed ff2) {
try{
temp = new Pattern("imgs/img3");
s.wait(temp, 1);
s.find(temp);
s.click(temp);
} catch (FindFailed ff3) {
continue;
}
}
}
}
A FindFailed exception is thrown once a pattern/image cannot be matched against anything on the screen (similarity simply adjusts the tolerance level). For the current GUI that it is automating, there are three possible scenarios (where this piece of code comes to play)
Screen A pops up
Screen B pops up
Neither 1 or 2, instead 'Next' pops up
Thus we check for Screen A, if not we check for Screen B, if not we check for Next, if not, repeat the cycle until we exceed the number of tries — meaning that the test has failed.
With the way Sikuli works or atleast how I've been interpreting it, you would have to perform various loops through multiple try-catch statements which seems a little off putting.
PS: The idea behind the above code is to just get it to work. If there is any ambiguity let me know so that I can clarify.
The following code is (I think) equivalent to your code:
int numOfTries;
while (!isFinishStage && numOfTries < 3) {
numOfTries++;
if (tryPattern(s, "imgs/img1.png", 0.9f) ||
tryPattern(s, "imgs/img2", 0.5f)) {
isFinishStage = true;
} else {
// Note that the third "attempt" is inconsistent with
// the others because you don't set isFinishedStage.
tryPattern(s, "imgs/img3", 1.0f)
}
}
private boolean tryPattern(SomeClass s, String path, float similarity) {
try {
Pattern temp = new Pattern(path);
if (similarity != 1.0f) {
temp = temp.similar(similarity);
}
s.wait(temp, 1);
s.find(temp);
s.hover(temp);
return true;
} catch (FindFailed ff) {
return false;
}
}
I would like you to read software principles and make your code clean after lecture:
10 Object Oriented Design Principles
After this you should know basics like DRY and KISS principles that should emplace pretty well in your posted code.
Here's how:
String [] patterns = {
"imgs/img1",
"imgs/img2",
"imgs/img3"
};
float [] similarities = {
0.9f,
0.5f,
0.1f
};
for(int i=0; i<patterns.length; i++) {
String str = patterns[i];
try {
float sim = 0.1; // default
try {
sim = similarities[i];
} catch (IndexOutofBoundsException e) {;}
temp = new Pattern(str).similar(sim);
s.wait(temp, 1);
s.find(temp);
s.hover(temp);
if(i != patterns.length - 1){ // Different last case
isFinishStage = true;
break;
}
} catch (FindFailed ff) {
continue;
}
}
Related
I'm thinking how to do when I click the button first time it will show the result. After that i click the second time then the button will clear the result.
Example: First time Click, It will Calculate
R.id.Equal: calculate(true);
Calculate's Method
private void calculate(boolean IsEqualClick) {
String input = getinput();
try {
if (!isEmpty()) {
if (input.contains("x")) {
input.replaceAll("x", "*");
}
}
Expression expression = new ExpressionBuilder(input).build();
double result = expression.evaluate();
if (IsEqualClick) {
inputtext.setText(String.valueOf(twoDForm.format(result)));
resulttext.setText("");
} else {
resulttext.setText(String.valueOf(twoDForm.format(result)));
}
} catch (Exception e) {
stateError = true;
isNumber = false;
}
}
I can't think of how to write a code If i Click second time, it will delete. should I use the if statement again to progress it?
There is no need to check that isEqualClick if you have properly written the switch statement plus it is hardcoded so there is no meaning behind it.
Now for your solution do something like this:-
Declare a global variable boolean toCalculate = true;, this variable will check if we have to calculate or we have to clear the box;
Function call for calculate();
R.id.Equal: calculate();
The calculate() function:-
private void calculate() {
if (toCalculate) {
String input = getinput();
try {
if (!isEmpty()) {
if (input.contains("x")) {
input.replaceAll("x", "*");
}
}
Expression expression = new ExpressionBuilder(input).build();
double result = expression.evaluate();
/*->Write all your code for printing the answer here<-*/
/*for eg:- result.setText(String.valueOf(twoDForm.format(result)))*/
toCalculate = false;
} catch (Exception e) {
stateError = true;
isNumber = false;
}
} else {
/*->Write all your code for clearing the answer here<-*/
/*for eg:- result.setText("")*/
toCalculate = true;
}
}
Or you can do something like this and you don't have to change the function like we did above:-
R.id.Equal: if(toCalculate)
{
calculate();
toCalculate = false;
}else
{
/*->Write all your code for clearing the answer here<-*/
/*for eg:- result.setText("")*/
toCalculate = true;
}
break;
I have needed to program something like this several times since programming Java:
Do something that might fail. If it fails, try it again but at most 3 (or 2 or 5) times.
This approach should work:
for (int i = 0; i < 3; i++) {
try {
doSomething();
} catch(BadException e) {
continue;
}
break;
}
But I do not think that it is very expressive. Do you have a better solution?
Something like this would be nice:
try (maxTimes = 3) {
doSomething();
} catch(BadException e) {
retry;
}
Or:
try (maxTimes = 3) {
doSomething();
if(somethingFailed()) {
retry;
}
}
But this is not possible with Java. Do you know a language with which it is possible?
Java does not let you invent your own syntax, but you can define your own method to help you express the concept with less code:
public static boolean retry(int maxTries, Runnable r) {
int tries = 0;
while (tries != maxTries) {
try {
r.run();
return true;
} catch (Exception e) {
tries++;
}
}
return false;
}
Now you can call this method like this:
boolean success = retry(5, () -> doSomething());
// Check success to see if the action succeeded
// If you do not care if the action is successful or not,
// ignore the returned value:
retry(5, () -> doSomethingElse());
Demo.
So I have written a code that allows a user to find a word in a TextArea. I have nearly succeeded but for one thing. here, I will show you all the code and tell my problem.
if(ta.getText().length() != 0 && t1.getText().length() != 0)
{
char c1[] = ta.getText().trim().toCharArray();
char c2[] = t1.getText().trim().toCharArray();
for(int i=startFlag;i<c1.length;i++)
{
if(c1[i]==c2[0])
{
start = i;
break;
}
}
k=start;
for(int i=0;i<c2.length;i++)
{
if(c2[i] != c1[start++])
{
}
else
countFlag++;
}
if(countFlag==c2.length)
{
ta.select(k,c2.length);
startFlag++;
}
}
For reference, ta is the TextArea and t1 is the TextField where the user enters a word to find. i have a problem in the second for loop. What should I write in the if () block there so that whenever c2[i] != c1[start++] the control is shifted to the first for loop, that would again determine the value of start?
Create a method to get "start" that you can then call whenever you want.
if(ta.getText().length() != 0 && t1.getText().length() != 0)
{
char c1[] = ta.getText().trim().toCharArray();
char c2[] = t1.getText().trim().toCharArray();
k=getStart(startFlag, c1.length);
for(int i=0;i<c2.length;i++)
{
if(c2[i] != c1[start++])
{
start = getStart(startFlag, c1.length);
}
else
countFlag++;
}
if(countFlag==c2.length)
{
ta.select(k,c2.length);
startFlag++;
}
}
And getStart() is:
public int getStart(int startFlag, int length) {
for(int i=startFlag;i<length;i++)
{
if(c1[i]==c2[0])
{
return i;
}
}
}
You may need different inputs to getStart(), but hopefully this gets across the general idea.
The way your code is set up right now, what you're asking for is impossible. To do what you're asking, you'll need to refactor your current code into different methods. More specifically, you'll need to put the for loops into their own methods and then call these methods.
So what you would need to do is make a separate method for the for loop.
public static int startForLoop(int i) {
for(int i=startFlag;i<c1.length;i++)
{
if(c1[i]==c2[0])
{
start = i;
break;
}
}
}
Then you can just call startForLoop(0) initially and in the 2nd for loops if statment:
if(c2[i] != c1[start++])
{
startForLoop(start+1)
}
This will continue the for loop where it left off. If you need to run the 2nd for loop again then you have to make a separate method for it as well and basically place both of them in a while loop that continues till you find the result you want in the 2nd for loop.
May be this code piece help you what you are looking for.
Basically it moves along with the string to be searched in keeping in mind the index of the string to be searched for.
Sorry but i have implemented it in java, but the notion is same and the result returned is the best what i got.you must give it a try!
private static String searchString(String searchIN,String searchFOR){
if (searchFOR != "") {
int index = searchIN.toUpperCase().indexOf(searchFOR.toUpperCase());
String before = "";
String highlighted = "";
String after = "";
while (index >= 0) {
int len = searchFOR.length();
before = searchIN.substring(0, index);
highlighted = "\"" + searchFOR + "\"";//do what ever you want to do with searched string
after = searchIN.substring(index + len);
searchIN = before + highlighted + after;
index = searchIN.toUpperCase().indexOf(searchFOR.toUpperCase(), index + highlighted.length());
}
}
return searchIN;
}
This is my first time experience of decompiling an apk to java code. The following code is of a local TVApp launcher which is ofcourse android based. To my surprise, I found out that the decompilers do not do a complete conversion to the source code. Hence, it messes up a thing or two. I have tried to work around with what I had, and made functions out of labels. Although I got it to work, but I suppose I missed out on some things..
Can someone guide me how to get this to work correctly? Do I have to do a manual refactoring of the code or is there a tool available for this?
public void run()
{
EN_INPUT_SOURCE_TYPE localEN_INPUT_SOURCE_TYPE;
int i;
ITvServiceServer localITvServiceServer;
for (;;)
{
if (LauncherActivity.this.bExitThread.booleanValue()) {
return;
}
synchronized (LauncherActivity.this.bSync)
{
localEN_INPUT_SOURCE_TYPE = LauncherActivity.this.toChangeInputSource;
LauncherActivity.this.toChangeInputSource = EN_INPUT_SOURCE_TYPE.E_INPUT_SOURCE_NONE;
i = LauncherActivity.this.fullScale;
LauncherActivity.this.fullScale = 0;
if (localEN_INPUT_SOURCE_TYPE != EN_INPUT_SOURCE_TYPE.E_INPUT_SOURCE_NONE)
{
localITvServiceServer = ITvServiceServer.Stub.asInterface(ServiceManager.checkService("tv_services"));
if (localITvServiceServer == null) {
Log.w("LauncherActivity", "Unable to find ITvService interface.");
}
}
else
{
if (i != 2) {
break label345;
}
LauncherActivity.this.setPipscale();
try
{
label104:
Thread.sleep(100L);
}
catch (InterruptedException localInterruptedException)
{
localInterruptedException.printStackTrace();
}
}
}
}
for (;;)
{
for (;;)
{
ITvServiceServerCommon localITvServiceServerCommon;
try
{
localITvServiceServerCommon = localITvServiceServer.getCommonManager();
if (localEN_INPUT_SOURCE_TYPE != EN_INPUT_SOURCE_TYPE.E_INPUT_SOURCE_ATV) {
break label324;
}
if (!localITvServiceServerCommon.GetCurrentInputSource().equals(EN_INPUT_SOURCE_TYPE.E_INPUT_SOURCE_STORAGE)) {
break;
}
if (LauncherActivity.this.minidatabase != null) {
break label275;
}
j = 0;
if ((j < 0) || (j > EN_INPUT_SOURCE_TYPE.E_INPUT_SOURCE_NONE.ordinal())) {
break;
}
localITvServiceServerCommon.SetInputSource(EN_INPUT_SOURCE_TYPE.values()[j]);
if (EN_INPUT_SOURCE_TYPE.values()[j] != EN_INPUT_SOURCE_TYPE.E_INPUT_SOURCE_ATV) {
break label290;
}
k = localITvServiceServer.getChannelManager().getCurrentChannelNumber();
if ((k < 0) || (k > 255)) {
break label361;
}
localITvServiceServer.getChannelManager().programSel(k, EN_MEMBER_SERVICE_TYPE.E_SERVICETYPE_ATV);
}
catch (RemoteException localRemoteException1)
{
localRemoteException1.printStackTrace();
}
break;
label275:
int j = LauncherActivity.this.minidatabase.queryCurInputSrc();
continue;
label290:
if (EN_INPUT_SOURCE_TYPE.values()[j] != EN_INPUT_SOURCE_TYPE.E_INPUT_SOURCE_DTV) {
break;
}
localITvServiceServer.getChannelManager().changeToFirstService(EN_FIRST_SERVICE_INPUT_TYPE.E_FIRST_SERVICE_DTV, EN_FIRST_SERVICE_TYPE.E_DEFAULT);
break;
try
{
label324:
localITvServiceServerCommon.SetInputSource(localEN_INPUT_SOURCE_TYPE);
}
catch (RemoteException localRemoteException2)
{
localRemoteException2.printStackTrace();
}
}
break;
label345:
if (i != 1) {
break label104;
}
LauncherActivity.this.setFullscale();
break label104;
label361:
int k = 0;
}
}
Do I have to do a manual refactoring of the code? YES.
The only thing you can do (in Eclipse) is pressing ALT+R on a selected label and change all its occurrences.
Decompiling is not 100% complete/accurate, due to how the process works, I suggest you read: http://en.wikipedia.org/wiki/Decompiler to understand more on the process.
It is fairly accurate though on some virtual machines like Java, as its bytecode includes extensive metadata. That's why you got a 'nice' result.
You will have to do a lot of manual refactoring anyway.
And bear in mind the legality of what you are doing, check licenses and copyright.
Sorry if this is a very closed question that won't be useful to others, but I'm just stumped by this bug and I haven't been able to solve it for weeks!
I am working on a wave based survival game and am currently working on a spawning mechanism.
The code I wrote works perfectly for one wave, but somehow doesn't restart for further waves.
I have written the code below:
public void run() {
while (ingame) {
if (enemyList.isEmpty()) {
stopSpawn = false;
try {
Thread.sleep(500);
spawnNewEnemy();
} catch (InterruptedException ex) {
System.out.println("Interrupted");
}
} else {
if (!enemyList.isEmpty() && !stopSpawn) {
// getEnemyAmount returns the amount of enemies that should be spawned this wave
for (int enemiesSpawned = 0; enemiesSpawned < getEnemyAmount(); enemiesSpawned++) {
try {
Thread.sleep(500);
} catch (InterruptedException ex) {
}
System.out.println(currentWave);
spawnNewEnemy();
}
stopSpawn = true;
}
}
}
}
Here is the spawnNewEnemy method
public void spawnNewEnemy() {
Random spawn = new Random();
int spawnX = spawn.nextInt(500);
int spawnXTest = b.bX - spawnX;
if (spawnXTest < 20) {
spawnX = spawnX + 20;
} else {
}
int spawnY = spawn.nextInt(500);
int spawnYTest = b.bX - spawnY;
if (spawnYTest < 20) {
spawnY = spawnY + 20;
} else {
}
spawnY = spawnY + 20;
spawnX = spawnX + 20;
enemyList.add(new Enemy(spawnX, spawnY));
}
I can read the following in your code:
If the list of enemies is empty, you set stopSpawn to false and spawn an enemy.
That triggers your else-statement.
There, you spawn enemies based on the enemy count.
stopSpawn is set to true, thus your else-statement doesn't get triggered anymore.
Nothing happens anymore untill your enemylist is empty.
If your enemylist is empty again, you start over.
The logics seems ok, so I'm thinking either the way you spawn enemies through spawnNewEnemy() is faulty, or the way you remove enemies from the enemyList is faulty. I see neither of that code so that is as far as I can go in this answer.
I guess your problem with a loop is in stopSpawn value.
You set it to true after the first wave and likely not setting to `false' before starting the next wave.