How to set condition to True? - python

I've created a program that uses pyautogui to locate an image stored in the directory and click on it when it finds it. So when it sees 'Microsoft Edge' it instantly clicks on it. I have this running on a loop and want to stop the loop when it finds the image. This is really important for me—but I want the loop to stop even before it clicks it, so while 'double' is False, as you will see below.
Here it is:
import pyautogui as p
import time
import random
import os
import pygame
from hashlib import sha256
def search(query):
p.hotkey("ctrl","e")
time.sleep(.1)
p.write(query)
p.press("enter")
time.sleep(.67)
def imageFind(image,g,double):
a = 0
b = 0
while(a==0 and b==0):
try:
a,b = p.locateCenterOnScreen(image,grayscale=g)
except TypeError:
pass
if double == True:
p.doubleClick(a,b)
else:
p.click(a,b)
return a,b
#p.hotkey("win","d")
counter = 1
while counter == 1:
image_find = imageFind("Edge.png",False,False)
if image_find == True:
imageFind("Edge.png",False,True)
counter = 0
I've done if image_find == True but it doesn't work as the loop continues.
So how do I code this so that when it finds the image, it stops. How do confirm that what it finds is a True statement?

imageFind does not return a single bool values but instead returns a tuple. your True condition is when both a and b are non zero so change your if image_find == True: to if all(image_find):
all() returns True only if all values are True or non zero

Or try to check if the minimum is nonzero:
if min(image_find):

Related

When I use While Loop my Code no Longer works

import pyautogui
import pydirectinput
import time
x = 1
while x <190:
for number in range(190):
time.sleep(0.1)
pyautogui.click(480, 595)
x = x+1
if x == 190:
pydirectinput.keyDown('shiftleft')
time.sleep(2.5)
pydirectinput.keyUp('shiftleft')
x = 1
When I run this all it does is repeat the first code and does not activate the second code I am a newb at coding so I don't know why this is happening. It just activates the 2nd "x = 1" instead of doing the code above it first then resetting the loop.
I want the code to run indefinitely but run both codes instead of only the click code
What should I put in after "if x == 190:"
A while loop executes the code inside its body as long as its condition evaluates to true. Your condition is whether x is equal to 1 or not.
You initialize x to 1, but you never change its value in your while loop's body. So, the condition is always true, and you have an infinite loop.
You need to modify the value of x inside your while loop to break out of the loop.
import pydirectinput
import time
x = 1
while x == 1:
for number in range(190):
time.sleep(0.1)
pyautogui.click(480, 595)
pydirectinput.keyDown('shiftleft')
time.sleep(2.5)
pydirectinput.keyUp('shiftleft') ```

Unable to end loop by changing varaible

I am trying to build something simple from a book that I have. I want it to only accept one of two inputs, either Clockwise or Counterclockwise. However, the program enters the while loop even while they type Clockwise or Counterclockwise. Is there a way I can fix this?
import turtle
Spin = input("Clockwise or Counterclockwise?")
while Spin != "Clockwise" or Spin != "Counterclockwise":
print("Please Try Again")
Spin = {input("Clockwise or Counterclockwise?")}
x = input(str("Put in desired Length:"))
SideLength = int(x)
def drawSideAndTurn(SideLength):
turtle.forward(SideLength)
if Spin == "Clockwise":
turtle.right(90)
if Spin == "Counterclockwise":
turtle.left(90)
y = (input("Number of Sides:"))
n = int(y)
x = 1
while x <= n:
drawSideAndTurn(SideLength)
drawSideAndTurn(SideLength)
x += 1
SideLength += 10
I'm not really sure how to define it so that Spin could be equal to the string input of a user.
The issue isn't in the value in String; the issue is in the Boolean condition you're expressing.
Your while loop is framed as follows:
while Spin != "Clockwise" or Spin != "Counterclockwise":
print("Please try again!")
Let's walk through the evaluation for arbitrary inputs.
Suppose your user enters Clockwise.
Spin != "Clockwise" will evaluate to False
Spin != "Counterclockwise" is equivalent to "Clockwise" != "Counterclockwise", which is True
while False or True is while True, so the body of the while loop will evaluate.
Suppose instead your user enters Counterclockwise.
Spin != "Clockwise" will evaluate to True.
while True or [...] is while True, so the body of the while loop will evaluate (Python evaluates Boolean conditions lazily, so it won't even bother testing the part of the expression to the right of the or; see here).
If you want to validate the input to ensure it's in one of two values (Clockwise or Counterclockwise) you need to check something like:
while not (Spin == "Clockwise" or Spin == "Counterclockwise"):
...
or:
while Spin != "Clockwise" and Spin != "Counterclockwise"):
...
You can express this condition more concisely as:
while Spin not in ("Clockwise", "Counterclockwise"):
...
Better yet, if the set of inputs is known and reasonably fixed, you can write something like this:
from enum import Enum
class Spin(Enum):
CLOCKWISE = "clockwise"
COUNTERCLOCKWISE = "counterclockwise"
def __str__(self):
return self.value
input_spin = input("Enter direction of spin:")
# Loosely normalize input_spin so that "ClockwiSe "
# is treated like a valid input for "clockwise".
while not input_spin.strip().lower() in map(str, Spin):
...
Just change “or” to “and”. The input can’t be both be “clockwise” and “counter clockwise” at the same time, that’s why it never exits the while loop.

Python's range() function not looping

I tried to make a 'random' text program with 2 possible outputs, randomization works but range() isn't working. I always make some stupid mistakes so don't go hard one me over some stupid small thing pls
import time
import pyautogui
import random
time.sleep(2)
for i in range(50):
if int(random.randint(1,2)) == 1:
pyautogui.typewrite('bruh1')
pyautogui.press('enter')
random.randint(1,2)
elif int(random.randint(1,2)) == 2:
pyautogui.typewrite('bruh2')
pyautogui.press('enter')
random.randint(1,2)
x is the random number returned by random.randint(). Not sure calling x() is the right thing. Can you please have a closer look at that part?
import time
import pyautogui
import random
def typewrite(text):
pyautogui.typewrite(text)
pyautogui.press('enter')
for _ in range(50): # I use _ for variable if don't use it
x = random.randint(0,1) # return 0 or 1 of type int
if x: # if x is 1
typewrite('bruh1')
else: # if x is 0
typewrite('bruh2')

How do I make rolling text for a loading screen?

I want to make a loading screen that does this, but replaces the current line:
LOADING
OADINGL
ADINGLO
DINGLOA
INGLOAD
...
I want to be able to control the number of letters it prints at once. What I tried:
from itertools import cycle
from time import sleep
itr = cycle('LOADING')
for i in range(10):
sleep(0.3)
print('\r', ''.join(next(itr)))
But the output is:
L
O
A
D
I
N
G
L
O
A
You will need to use the end keyword in print to avoid printing each message to a new line. I recommend the approach where you build the string to be displayed on each iteration and then display it. I don't like the cycle approach because you're unable to index into the cycle object very easily. Instead, we can use regular string indexing along with the modulus operator to ensure we don't go out of bounds and can still "loop" over the string over and over.
import time
def scrolling_text(msg, n_chars):
"""
Displays scrolling text of whatever 'msg' and ensures that only n_chars
are shown at a time. If n_chars is greater than the length of msg, then
the string displayed may "loop" around.
Inputs:
msg: str - The message to display
n_chars: int - The number of characters to display at a time
Outputs: Returns None, displays the scrolling text indefinitely.
"""
len_msg = len(msg)
counter = 0
while True:
displayed = ""
for char in range(n_chars):
displayed += msg[(counter+char)%len_msg]
print(f"\r{displayed}", end="")
time.sleep(0.05)
counter = (counter + 1) % len_msg
return
scrolling_text("LOADING", 25)
Each iteration of the while True loop will build the string to be displayed (inside the nested for loop) and then display it. At the end of the while loop, it would be enough to have counter += 1 however for a long-running script, you might end up with counter being unnecessarily large. By letting counter = (counter + 1) % len_msg, we can ensure counter never gets higher than the length of the message.
Straightforwardly with Python slicing:
from time import sleep
from sys import stdout
s = 'LOADING'
for i in range(10):
sleep(0.3)
if i > len(s): i = i - len(s)
stdout.write('\r' + ''.join(s[i:] + s[:i]))

Stop iteration from inside a function

I am using an iterator to flexiblily go through a collection. In my function there are several cases in which the function gets a new item and processes them. So there are several cases in which something like this happens:
it = iter(range(10))
while condition:
try:
item = next(it)
item.do_many_different_things()
except StopIteration:
break
And that makes everything extremly messy, so I wanted to move it into a seperate methode. But than I can't use break, because python doesn't know what loop it should break. So far I'm returning a None type, and break the loop if a None was returned. But is there a more elegant solution?
You can return value from the do_many_different_things() function and change the condition variable accordingly, so it breaks out of the while loop as needed.
def func(it):
item = next(it)
res = item.do_many_different_things()
yield res
it = iter(range(1, 10))
condition = True
while condition:
for item in func(it):
condition = item
This will run all elements from 1..9, because they are all truthy. If you start this with the regular range(10) it would stop on the first element since it's 0.
Once the method return False, the while loop breaks.
I don't know what your code, nested loops and items are, so I will just show you how to break out from nested loops spread across different functions. I will also show you, how you can differentiate three cases:
1. Your item.do_many_different_things() method wants to break
2. You ran out of items
3. Your condition evaluates to False
This is purely educational to show you some Python features which you might find useful, not necessarily in this exact combination.
from __future__ import print_function
# I'm on Python 3 - you will need the above line on Python 2
# I don't know what your code is supposed to do so I'll just generate random integers
from random import Random
r = Random()
r.seed()
class BreakOutNested(Exception): pass
class Item(object):
def do_many_different_things(self):
x = r.randint(0, 50)
if x == 50:
raise BreakOutNested()
self.x = x
def iterator_0(item):
for i in range(5):
item.do_many_different_things()
yield i
def iterator_1(items):
for item in items:
for i in iterator_0(item):
item.i = i
yield item
items = iterator_1(Item() for i in range(5))
x = 50
try:
while x != 0:
item = next(items)
print(item.i, item.x)
x = item.x
except BreakOutNested:
print('Broke out from many loops with exception trick')
except StopIteration:
print('Simply ran out of items')
else:
print('Got x == 0')
Run this a couple of times as the exit scenario is random.

Categories

Resources