Not sure if I'm asking the right question, but is it possible to make python move my mouse with things like pyautogui/selenium actions/or preferably all mouse movements following this algorithm? I want to make my mouse movements as real as possible for a bot I'd like to make. How would I go about doing this if possible? I found the algorithm here: https://web.archive.org/web/20210621155859/https://ben.land/post/2021/04/25/windmouse-human-mouse-movement/
import numpy as np
sqrt3 = np.sqrt(3)
sqrt5 = np.sqrt(5)
def wind_mouse(start_x, start_y, dest_x, dest_y, G_0=9, W_0=3, M_0=15, D_0=12, move_mouse=lambda x,y: None):
'''
WindMouse algorithm. Calls the move_mouse kwarg with each new step.
Released under the terms of the GPLv3 license.
G_0 - magnitude of the gravitational fornce
W_0 - magnitude of the wind force fluctuations
M_0 - maximum step size (velocity clip threshold)
D_0 - distance where wind behavior changes from random to damped
'''
current_x,current_y = start_x,start_y
v_x = v_y = W_x = W_y = 0
while (dist:=np.hypot(dest_x-start_x,dest_y-start_y)) >= 1:
W_mag = min(W_0, dist)
if dist >= D_0:
W_x = W_x/sqrt3 + (2*np.random.random()-1)*W_mag/sqrt5
W_y = W_y/sqrt3 + (2*np.random.random()-1)*W_mag/sqrt5
else:
W_x /= sqrt3
W_y /= sqrt3
if M_0 < 3:
M_0 = np.random.random()*3 + 3
else:
M_0 /= sqrt5
v_x += W_x + G_0*(dest_x-start_x)/dist
v_y += W_y + G_0*(dest_y-start_y)/dist
v_mag = np.hypot(v_x, v_y)
if v_mag > M_0:
v_clip = M_0/2 + np.random.random()*M_0/2
v_x = (v_x/v_mag) * v_clip
v_y = (v_y/v_mag) * v_clip
start_x += v_x
start_y += v_y
move_x = int(np.round(start_x))
move_y = int(np.round(start_y))
if current_x != move_x or current_y != move_y:
#This should wait for the mouse polling interval
move_mouse(current_x:=move_x,current_y:=move_y)
return current_x,current_y
The algorithm you found is going to make human like mouse movement, instead of moving the mouse physically on your screen it will just help you plot the movements on the screen.
To help you see the plot, you can see in the same blog the writer/programmer has used Python matplotlib.
import matplotlib.pyplot as plt
fig = plt.figure(figsize=[13,13])
plt.axis('off')
for y in np.linspace(-200,200,25):
points = []
wind_mouse(0,y,500,y,move_mouse=lambda x,y: points.append([x,y]))
points = np.asarray(points)
plt.plot(*points.T)
plt.xlim(-50,550)
plt.ylim(-250,250)
This block of code is just missing a plt.show() that will show the plot on your screen. Simply add,
plt.show()
at the end and you are good to go.
Now for the second part how can get physical Human like mouse movement. For that you can use a Python package pyHM. To install simply run this command in your shell
pip install pyHM
Then write this script, to move your mouse physically on the screen.
from pyHM import mouse
destination_x = 1000
destination_y = 500
mouse.move(destination_x, destination_y)
You might get an error for scipy.random.randit, let me know if you get this error I will help you out with that as well.
Related
I have been working on a game similar to Angry Birds in which a projectile is launched at a target with the aim of toppling it. However I am struggling to find a way to show the canvas before the initial launch parameters are entered and the animation begins. The first thing that happens when the code is run is that it asks for the inputs but I want to show the visualisation before this happens. Wondering if there was an easy way to do this, the code is below.
scene = canvas(width=640, height=480, center=vector(8,5,0),range=8, background=color.blue)
ground = box(pos=vector(8,-5,0), length=16, height=10, width=0.5, color=color.green)
dist = 5 + random()*10
target = box(pos=vector(dist,1,0), length=0.5, height=2, width=0.5, color=color.red)
height = random() #determines random height of platform between 0 and 1 meters
platform = box(pos=vector(-2,height-0.25,0), length=4, height=0.5, width=0.5, color=color.white)
bird = sphere(pos=vector(0,height+0.3,0), radius=0.3, color=color.yellow)
hit = 0
while hit == 0: #loops until player hits target
#Take initial parameters from player
v0 = float(input('Input your launch velocity:'))
dtheta = float(input('Input your launch angle in degrees:'))
theta = np.radians(dtheta) #convert launch angle to radians
#Draw arrow for initial momentum
px = 0.1*v0*np.cos(theta) #calculate initial x momentum
py = 0.1*v0*np.sin(theta) #calculate initial y momentum
momentum = arrow(pos=bird.pos, axis=vector(px,py,0), shaftwidth=0.1, color=color.orange) #draw arrow representing projectiles initial momentum
# Calculate position of the projectile at a specified interval of time
# Code adapted from my submission to PHAS0007: Computing Session 8
#Define intial parameters
g = 9.81
x = x0 = 0
y = y0 = height
dt = 0.0001 #timestep
t = 0
#conditions that alllow looping when projectile is not in contact with target
while (y > 0 and (x < dist-0.25 or x > dist+0.25)) or (y > 2 and x >= dist-0.25 and x<= dist+0.25):
rate(5000) #set rate of animation
x = x0 + v0*t*np.cos(theta) # calculate new x position
y = y0 + v0*t*np.sin(theta)-0.5*g*t**2 # calculate new y position
bird.pos = vector(x,y,0) # redraw projectile at new position
px = 0.1*v0*np.cos(theta) #calculate x momentum
py = 0.1*v0*np.sin(theta)-0.1*g*t #calculate y momentum
momentum.pos = bird.pos #redraw momentum arrow in new position
momentum.axis = vector(px,py,0) #redraw momentum arrow direction
t += dt # increase timestep increment by dt
momentum.visible = False #removes momentum arrow after projectile motion is finished
#use inverse condition of the loop to determine and print whether the target was hit or not
if y >= 0 and y <= 2 and x >= dist-0.25 and x <= dist+0.25:
#calculate whether the target topples or not
trest = 0.5*100*g*0.5 #calculate the restoring torque
contact_t = 0.01 #define the time projectile is in contact with target
fapp = vector(px, py, 0) / contact_t #calculate applied force of projectile on target
tapp = cross(fapp, vector((dist+0.25)-x, -y, 0)) #calculate applied torque vector of projectile on target
tappm = mag(tapp) #calculate magnitude of applied torque vector
if tappm > trest: #target toppled
#redraw target to be toppled
target.pos = vector(dist+1.25,0.25,0)
target.length = 2
target.height =0.5
print('Target toppled, success!')
hit = 1
else: #target hit but not toppled
print('Target hit but not toppled, try again.')
#animate bird dropping to ground
t=0 #reset time counter
y0=y #set y0 equal to current y position
while y > 0.3:
rate(5000)
y = y0 - 0.5*g*t**2
bird.pos = vector(x,y,0)
t += dt
else:
print('Target Missed, try again.')
My problem: My goal is to create a variable that is a line of code that later on I can just call the variable other than just using that line of code (making the code neater).
Comment: ball_x_pos and ball_y_pos change in the code
My current code:
CASE_1 = ball_y_pos + RADIUS >= WINDOW_HEIGHT # Hitting bottom floor(need to increase Y)
CASE_2 = ball_y_pos - RADIUS <= 0 # Hitting top floor(need to decrease Y)
CASE_3 = ball_x_pos + RADIUS >= WINDOW_WIDTH # Hitting right side(need to decrease X)
CASE_4 = ball_x_pos - RADIUS <= 0 # Hitting left side(need to decrease X)
if CASE_1: # Ball it hitting the bottom floor
Y_CHANGER = 1
if CASE_2: # Ball is hitting the top floor
Y_CHANGER = -1
if CASE_3: # Ball is hitting the right side
X_CHANGER = -1
if CASE_4:
X_CHANGER = 1
What I think is happening: I'm pretty sure that right now the code is defining the values of the cases as False on assignment. I was wondering if there is any way I can still do this.
Thanks in advance!
I'm not sure if I misunderstood the question or not, but it seems you're looking to create a function, whose output changes based on inputs. Maybe something like this would help?
Based on your comment below, you're looking to inline your functions to emulate macro-esque behavior. You can't do this, but some compilers like PyPy will automatically optimize your code, so I wouldn't worry too much about it. Below are examples of functions that oculd do the trick for you:
def CASE_1():
return ball_y_pos + RADIUS >= WINDOW_HEIGHT # Hitting bottom floor(need to increase Y)
def CASE_2():
return ball_y_pos - RADIUS <= 0 # Hitting top floor(need to decrease Y)
def CASE_3():
return ball_x_pos + RADIUS >= WINDOW_WIDTH # Hitting right side(need to decrease X)
def CASE_4():
return ball_x_pos - RADIUS <= 0 # Hitting left side(need to decrease X)
if CASE_1(): # Ball it hitting the bottom floor
Y_CHANGER = 1
if CASE_2(): # Ball is hitting the top floor
Y_CHANGER = -1
if CASE_3(): # Ball is hitting the right side
X_CHANGER = -1
if CASE_4():
X_CHANGER = 1
This defines four functions, each of which , when called, evaluates its statement and returns True or False based on its result. Note that this implies global variables (which are poor practice) - since you also mentioned ball_x_pos and ball_y_pos change in the code, you likely want to pass the variables in. Something like this would be better practice:
def CASE_1(y_pos):
return y_pos + RADIUS >= WINDOW_HEIGHT # Hitting bottom floor(need to increase Y)
def CASE_2(y_pos):
return y_pos - RADIUS <= 0 # Hitting top floor(need to decrease Y)
def CASE_3(x_pos):
return x_pos + RADIUS >= WINDOW_WIDTH # Hitting right side(need to decrease X)
def CASE_4(x_pos):
return x_pos - RADIUS <= 0 # Hitting left side(need to decrease X)
if CASE_1(ball_y_pos): # Ball it hitting the bottom floor
Y_CHANGER = 1
if CASE_2(ball_y_pos): # Ball is hitting the top floor
Y_CHANGER = -1
if CASE_3(ball_x_pos): # Ball is hitting the right side
X_CHANGER = -1
if CASE_4(ball_x_pos):
X_CHANGER = 1
. . . a variable that is a line of code that later on I can just call the variable other than just using that line of code . . .
This is essentially describing a function.
To write one, you could have, for example:
def is_hitting_bottom():
return ball_y_pos + RADIUS >= WINDOW_HEIGHT
if is_hitting_bottom():
Y_CHANGER = 1
The benefits of using functions here are minimal though. Really, this is just giving the code a nicer name.
You probably want code like the following, because if you have a ball with an x and a y position, you are likely to have more of them later on:
def get_changes(px, py):
dx, dy = 0, 0
if py + RADIUS >= WINDOW_HEIGHT:
dy = 1
if py - RADIUS <= 0:
dy = -1
if px + RADIUS >= WINDOW_WIDTH:
dx = 1
if px - RADIUS <= 0:
dx = -1
return dx, dy
def update_position(px, py):
dx, dy = get_changes(px, py)
return px+dx, py+dy
ball_x_pos, ball_y_pos = update_position(ball_x_pos, ball_y_pos)
(btw I think you have the changes the wrong way round, eg if the Y pos is so large that it is in danger of going over the window height, which is actually the floor, then I think that Y should be reduced.)
I am trying to plot a curved path for a robot to follow using the following as a guide: http://rossum.sourceforge.net/papers/CalculationsForRobotics/CirclePath.htm
The code i have does not create a path that ends at the destination. I am expecting the path to curve left or right depending on the quadrant the destination is in (+x+y,+x-y,-x+y,-x-y)
import math
start = [400,500]
dest = [200,300]
speed = 10
startangle = 0
rc =0
rotv =0
rads =0
def getPos(t):
ang = (rotv*t)+rads
x = start[0] - rc * math.sin(rads) + rc * math.sin(rotv*(t)+rads)
y = start[1] + rc * math.cos(rads) - rc * math.cos(rotv*(t)+rads)
return (int(x),int(y), ang)
dx = dest[0] - start[0]
dy = dest[1] - start[1]
rads = math.atan2(-dy,dx)
rads %= 2*math.pi
distance = (dx**2 + dy**2)**.5 #rg
bangle = 2*rads
rc = distance /(2 * math.sin(rads))
if rads > (math.pi/2):
bangle = 2*(rads-math.pi)
rc= -rc
if rads < -(math.pi/2):
bangle = 2*(rads+math.pi)
rc= -rc
pathlength = rc * bangle
xc = start[0] - rc * math.sin(rads)
yc = start[1] + rc * math.cos(rads)
rotcenter = [xc,yc]
traveltime = pathlength/speed
rotv = bangle/traveltime
for p in range(int(traveltime)):
pos = getPos(p)
Start: Blue, End: Red, Rotation Point: Purple
UPDATE:
I have added code to allow positive and negative x/y values. I have updated the image.
To answer your question I first read through the article you linked. I think it is very interesting and explains the ideas behind the formulas pretty well, althought it lacks the formulas for when the starting position is not at the origin and when the starting angle is not 0.
It took a little while to come up with these formulas, but now it works for every case I could think of. To be able to use the formulas given in the linked article, I used the names of the variables given there. Notice that I also used the notation with t_0 as the starting time, which you just ignored. You can easily remove any instance of t_0 or set t_0 = 0.
The last part of the following code is used for testing and creates a little red turtle that traces the path of the computed arc in the specified direction. The black turtle indicates the goal position. Both turtles are close to each other at the end of the animation, but they are not directly above each other, because I am only iterating over integers and it is possible that t_1 is not an integer.
from math import pi, hypot, sin, cos, atan2, degrees
def norm_angle(a):
# Normalize the angle to be between -pi and pi
return (a+pi)%(2*pi) - pi
# Given values
# named just like in http://rossum.sourceforge.net/papers/CalculationsForRobotics/CirclePath.htm
x_0, y_0 = [400,500] # initial position of robot
theta_0 = -pi/2 # initial orientation of robot
s = 10 # speed of robot
x_1, y_1 = [200,300] # goal position of robot
t_0 = 0 # starting time
# To be computed:
r_G = hypot(x_1 - x_0, y_1 - y_0) # relative polar coordinates of the goal
phi_G = atan2(y_1 - y_0, x_1 - x_0)
phi = 2*norm_angle(phi_G - theta_0) # angle and
r_C = r_G/(2*sin(phi_G - theta_0)) # radius (sometimes negative) of the arc
L = r_C*phi # length of the arc
if phi > pi:
phi -= 2*pi
L = -r_C*phi
elif phi < -pi:
phi += 2*pi
L = -r_C*phi
t_1 = L/s + t_0 # time at which the robot finishes the arc
omega = phi/(t_1 - t_0) # angular velocity
x_C = x_0 - r_C*sin(theta_0) # center of rotation
y_C = y_0 + r_C*cos(theta_0)
def position(t):
x = x_C + r_C*sin(omega*(t - t_0) + theta_0)
y = y_C - r_C*cos(omega*(t - t_0) + theta_0)
return x, y
def orientation(t):
return omega*(t - t_0) + theta_0
#--------------------------------------------
# Just used for debugging
#--------------------------------------------
import turtle
screen = turtle.Screen()
screen.setup(600, 600)
screen.setworldcoordinates(0, 0, 600, 600)
turtle.hideturtle()
turtle.shape("turtle")
turtle.penup()
turtle.goto(x_1, y_1)
turtle.setheading(degrees(orientation(t_1)))
turtle.stamp()
turtle.goto(x_0, y_0)
turtle.color("red")
turtle.showturtle()
turtle.pendown()
for t in range(t_0, int(t_1)+1):
turtle.goto(*position(t))
turtle.setheading(degrees(orientation(t)))
I am not sure at which point your code failed, but I hope this works for you. If you intend to use this snippet multiple times in you code consider encapsulating it in a function that takes in the given values as parameters and returns the position function (and if you like rotation function as well).
I am new to Python, and currently having a rough time with turtle graphics. This is what I am trying to solve
On Turtellini (the planet where Python turtles live) the
transportation system propels turtles with a giant slingshot. A
particular turtle's original location (x0, y0) is (-180, -100). He is
then shot upward at an initial vertical velocity (vy) of 88 units per
second and a horizontal velocity (vx) of 20 units per second to the
right. He travels for 16 seconds. The acceleration due to gravity (g)
is 11 units per second squared. The the location of the turtle at a
given second (t) is calculated as follows: x = x0 + vx * t and y = y0
+ vy * t - g/2 * t2 . This program is to show how a turtle travels over this period of time.
The output should be like this:
Here is what I should do;
set up the constants (vertical velocity, horizontal velocity,
gravity) and variables (x and y coordinates) set up the turtle by
giving him a proper shape, putting his tail up, moving him to the
initial position, putting his tail down make a loop that repeats for
seconds 1 through 16 inclusive. in each iteration of the loop display
the the values of the x and y variables (in the shell window), move
the turtle to those coordinates, have the turtle stamp his shape,
calculate the new values for the x and y variables after the loop
terminates, move the turtle to the last calculated coordinates,
change his color, and stamp his shape, then wait for a mouse click
My code so far:
import turtle
def main():
wn = turtle.Screen()
turtellini = turtle.Turtle()
t = int(input("Blab blab blab: "))
x0 = -180
y0 = -100
vx = 20
vy = 88
g = 11
x = (float(x0 + vx * t))
y = (float(y0 + vy * t - g / 2 * t**2))
turtellini.color("black")
turtellini.shape("turtle")
turtellini.up()
turtellini.goto(-180,-100)
turtellini.down()
for i in range(1,16,1):
turtellini.stamp()
turtellini.forward(i)
turtellini.right(i)
print(x)
print(y)
if __name__ == "__main__":
main()
I know I am doing bad; but can anyone help me to solve this problem?
You seem to have most of the parts and pieces. The biggest issue I see is you didn't put your x,y calculation in the loop. The loop iteration variable i is really t in your motion equations. Each time you calculate a new x,y you simply move the turtle to that position:
import turtle
from math import pi, atan
x0, y0 = -180, -100 # initial location
vx, vy = 20.0, 88.0 # initial velocity in units per second
travel_time = 16 # seconds
g = 11.0 # acceleration due to gravity in units per second squared
turtellini = turtle.Turtle(shape='turtle', visible=False)
turtellini.penup()
turtellini.radians() # to make turtle compatible with math.atan()
turtellini.setheading(pi / 2) # straight up
turtellini.goto(x0, y0)
turtellini.pendown()
turtellini.showturtle()
turtellini.stamp()
for t in range(1, travel_time + 1):
x = x0 + vx * t
y = y0 + vy * t - g / 2 * t**2
turtellini.goto(x, y)
print(x, y)
angle = atan((vy * t - g * t**2) / (vx * t)) # a guess!
turtellini.setheading(angle)
turtellini.stamp()
turtle.exitonclick()
Unlike the gold standard image, I assumed the turtle was aerodynamic like a bullet and travelled head first through the flight. I don't know, and couldn't quickly find, the formula for the flight angle of a projectile so I guessed from the existing formulas:
I am reading Python Programming by John Zelle and I am stuck on one the exercises shown in the picture below.
You can view my code below. I know the code is very ugly. (Any tips are appreciated)
Here's my code so far:
from graphics import *
def regression():
# creating the window for the regression line
win = GraphWin("Regression Line - Start Clicking!", 500, 500)
win.setCoords(0.0, 0.0, 10.0, 10.0)
rect = Rectangle(Point(0.5, 0.1), Point(2.5, 2.1))
rect.setFill("red")
rect.draw(win)
Text(rect.getCenter(), "Done").draw(win)
message = Text(Point(5, 0.5), "Click in this screen")
message.draw(win)
points = [] # list of points
n = 0 # count variable
sumX = 0
sumY = 0
while True:
p = win.getMouse()
p.draw(win)
# if user clicks in a red square it exits the loop and calculates the regression line
if (p.getX() >= 0.5 and p.getX() <= 2.5) and (p.getY() >= 0.1 and p.getY() <= 2.1):
break
n += 1 # count of the points
# get the sum of the X and Y points
sumX = sumX + p.getX()
sumY = sumY + p.getY()
# tuple of the X and Y points
dot = (p.getX(), p.getY())
points.append(dot)
avgX = sumX / n
avgY = sumY / n
top = 0
bottom = 0
# my ugly attempt at the regression equation shown in the book
for i in points:
gp = 0
numer = points[gp][0] * points[gp][1]
top = top + numer
denom = points[gp][0] ** 2
bottom = bottom + denom
gp += 1
m = (top - sumX * sumY) / (bottom - sumX ** 2)
y1 = avgY + m * (0.0 - avgX)
y2 = avgY + m * (10.0 - avgX)
regressionline = Line(Point(0, y1), Point(10.0, y2))
regressionline.draw(win)
raw_input("Press <Enter> to quit.")
win.close()
regression()
When I run the program the regression line never appears to be the real line of best fit. I believe I am interpreting the regression equation incorrectly in my code. What needs to be changed to get the correct regression line?
Issues:
from my_library import * should be avoided; better to specify exactly what you want from it. This helps keep your namespace uncluttered.
you've got one massive block of code; better to split it into separate functions. This makes it much easier to think about and debug, and may help you reuse code later. Sure, it's a toy problem, you're not going to reuse it - but the whole point of doing exercises is to develop good habits, and factoring your code this way is definitely a good habit! A general rule of thumb - if a function contains more than about a dozen lines of code, you should consider splitting it further.
the exercise asks you to keep track of x, y, xx, and xy running sums while getting input points. I think this is kind of a bad idea - or at least more C-ish than Python-ish - as it forces you to do two different tasks at once (get points and do math on them). My advice would be: if you are getting points, get points; if you are doing math, do math; don't try doing both at once.
similarly, I don't like the way you've got the regression calculation worrying about where the sides of the window are. Why should it know or care about windows? I hope you like my solution to this ;-)
Here's my refactored version of your code:
from graphics import GraphWin, Point, Line, Rectangle, Text
def draw_window()
# create canvas
win = GraphWin("Regression Line - Start Clicking!", 500, 500)
win.setCoords(0., 0., 10., 10.)
# exit button
rect = Rectangle(Point(0.5, 0.1), Point(2.5, 2.1))
rect.setFill("red")
rect.draw(win)
Text(rect.getCenter(), "Done").draw(win)
# instructions
Text(Point(5., 0.5), "Click in this screen").draw(win)
return win
def get_points(win):
points = []
while True:
p = win.getMouse()
p.draw(win)
# clicked the exit button?
px, py = p.getX(), p.getY()
if 0.5 <= px <= 2.5 and 0.1 <= py <= 2.1:
break
else:
points.append((px,py))
return points
def do_regression(points):
num = len(points)
x_sum, y_sum, xx_sum, xy_sum = 0., 0., 0., 0.
for x,y in points:
x_sum += x
y_sum += y
xx_sum += x*x
xy_sum += x*y
x_mean, y_mean = x_sum/num, y_sum/num
m = (xy_sum - num*x_mean*y_mean) / (xx_sum - num*x_mean*x_mean)
def lineFn(xval):
return y_mean + m*(xval - x_mean)
return lineFn
def main():
# set up
win = draw_window()
points = get_points(win)
# show regression line
lineFn = do_regression(points)
Line(
Point(0., lineFn(0. )),
Point(10., lineFn(10.))
).draw(win)
# wait to close
Text(Point(5., 5.), "Click to exit").draw(win)
win.getMouse()
win.close()
if __name__=="__main__":
main()
the for loop is all messed up! you have an i that changes in the loop, but then use gp which is always 0.
you want something more like:
for (X, Y) in points:
numer += X * Y
denom += X * X
...or move gp = 0 to before the for loop.
...or drop that part completely and add a sumXY and a sumXX to the sumX and sumY.
either way, once you fix that it should be ok (well, or maybe some other bug....).