I'm working on adding directionality to boggle so that the user can trace their path on the board game. I found some code that would help in laying down diagonal functioning to the program but I'm not exactly sure what the code means. It would help a lot if someone could explain the function posted below.
def valid_direction(x1, y1, x2, y2):
dy = y2 - y1
dx = x2 - x1
if dx == 0:
return dy != 0
elif dy == 0:
return dx != 0
else:
return abs(dx) == abs(dy)
I also want to allow the user to input coordinates pertaining to a letter from a 16 letter square board. looks like this in the shell:
|w||e||b||e|
|r||t||o||l|
|e||t||a||e|
|i||p||a||a|
Enter coordinate:
The inputted coordinates get stored in path = [] which I already wrote a function for. My goal is to actually get the function to work so that the user is prompted multiple times until they've finished entering an actual word. Here's the function
def validate_path(path):
word = word_from_path(path, board)
if valid_word(word):
# is it value = value from while loop and the rest?
value = word_value(word)
print("Value of {} is {}".format(word, value))
score += value
else:
print("Invalid word")
return validate_path(path)
And part of the loop for the game
while game:
curr_input = input("Enter coordinate: ")
if curr_input == "quit":
print("Your total score is:", score)
game = False
elif curr_input == "done":
validate_path(path)
Thanks so much to whoever spends the time reading all of this !
The function valid_direction stores delta-y (change in y-coordinate) in dy and delta-x in dx. Then, the ensuing if statements have the following logic:
If the y-coordinate hasn't changed (dy == 0), then if dx == 0 return 0 because the coordinates are the same and it's an invalid move, otherwise return 1.
If the x-coordinate hasn't changed (dx == 0), do the same as in 1. except with y and x reversed.
If both x and y coordinates have changed (dy != 0 and dx != 0) then check if they've both changed by the same absolute amount. If so, then it's a diagonal move by that absolute amount and it returns 1, otherwise it returns 0.
I'm not sure if this is what you want for Boggle though, since I think you want strictly adjacent moves (or a move to a directly diagonal space), so to check a valid move between two points would be:
def valid_direction(x1, y1, x2, y2):
dy = y2 - y1
dx = x2 - x1
if dx == 0:
return abs(dy) == 1
elif dy == 0:
return abs(dx) == 1
else:
return abs(dx) == abs(dy) == 1
Which checks if subsequent moves' coordinates differ by exactly one. Or, more concisely put:
def valid_direction(x1, y1, x2, y2):
dy = y2 - y1
dx = x2 - x1
if not dy and not dx:
return 0
return abs(dx) <= 1 and abs(dy) <= 1
Related
I'm writing a program that moves my mouse (using pyautogui lib) if it has not been moved in x amount of seconds. I take the X,Y coordinates twice once at the start and then again after the time delay, then compare both X and Y values against the previous one. I've having issues with my if statement which in theory should do the above but after testing it out it doesn't work as expected. Can anyone suggest any edits I can a make to fix this simple issue.
Here's my code:
#!/usr/bin/env python3
import pyautogui
import time
currentMouseX, currentMouseY = pyautogui.position() #Grabs X,Y mouse position
print("position X1 is", currentMouseX)
print("position Y1 is", currentMouseY)
X1 = currentMouseX
Y1 = currentMouseY
time.sleep(3)
currentMouseX2, currentMouseY2 = pyautogui.position() #Grabs second X,Y position after 3 seconds
X2 = currentMouseX
Y2 = currentMouseY
print("position X2 is", currentMouseX2)
print("position Y2 is", currentMouseY2)
**if ((X1 == X2) and (Y1 == Y2)):
print ("!!! MOVE MOUSE !!!")
else:
print("Mouse does not need to be moved")**
FYI: I've left the if statement very simple as I'd like it working before I continue with the program. Any help is very much appreciated.
Note: Saying that your code does not work as expected makes no sense unless you explain what it is supposed to do ALONG WITH WHAT IT IS ACTUALLY DOING.
Having said that, looking at your code I assume your problem is that you always get the result "!!! MOVE MOUSE !!!", even if you did move your mouse.
If you look at your code carfully you will notice that X1 and X2 will always be the same, and Y1 and Y2 also, because you assign them using:
X1 = currentMouseX
Y1 = currentMouseY
and
X2 = currentMouseX
Y2 = currentMouseY
without overwriting currentMouseY. Instead, you load the second coordinates into currentMouseX2 and currentMouseY2.
In short your code uses way to many unnessecary assignments. Instead, do the following:
#!/usr/bin/env python3
import pyautogui
import time
prev = pyautogui.position() #Grabs X,Y mouse position
print("position X1 is", prev[0])
print("position Y1 is", prev[1])
time.sleep(3)
after = pyautogui.position() #Grabs second X,Y position after 3 seconds
print("position X2 is", after[0])
print("position Y2 is", after[1])
if (prev == after):
print ("!!! MOVE MOUSE !!!")
else:
print("Mouse does not need to be moved")
Rather than testing for equality, it might be better to test whether the difference is below some threshold value:
moveThresh = 4 # (or suitable small number)
XMove = X2 - X1
YMove = Y2 - Y1
if abs(XMove) < moveThresh and abs(YMove) < moveThresh:
# treat tiny moves as no move
print("The mouse is effectively stationary & the cat is bored")
else:
print("The mouse is moving & the cat is interested")
etc.
Unless you're hooking up some interesting hardware, I doubt you'll be moving the mouse - only the mouse pointer.
I am trying to create a function for a homework assignment which draws a jagged mountain curve using turtles and recursion. The function is called jaggedMountain(x,y,c,t) where x x,y are end coordinates, c is a complexity constant, and t is the turtle object. I am trying to create an image like this:
def jaggedCurve(x,y,c,t):
t.pendown()
x1 = t.xcor() + x / 2
y1 = t.ycor() + y / 2
y1 = y + (random.uniform(0,c)-0.5) * (t.xcor() - x)
if (x1,y1) == (x,y):
return None
else:
jaggedCurve(x1,y1,c,t)
This crashes quickly as the base case never executes, the function is called 993 times, and the recursion depth is exceeded. I have been scratching my head with this for quite some time, are there any suggestions?
Initially, I see two issues with your code. The first is:
if (x1,y1) == (x,y):
Turtles wander a floating point plane, the odds of these being exactly equal is small. You're likely better off doing something like:
def distance(x1, y1, x2, y2):
return ((x2 - x1) ** 2 + (y2 - y1) ** 2) ** 0.5
...
if distance(x1, y1, x, y) < 1.0:
The second issue is that jaggedCurve() draws nothing nor returns anything that can be used for drawing. Somewhere you need to actually move the turtle to cause something to be drawn.
Finally, though it's hard to be certain without a value for c, my guess is even with the above changes you won't get you what you want. Good luck.
Very interesting problem!
My solution is to make a recursive function that draws a mountain curve given two end points. Randomly pick a x coordinate value that lies in between two end points and compute the range of possible y coordinate given the maximum possible slope and randomly pick a y value in between this range and do this recursively. When to end points are close enough, just draw the line between them. Here is the code:
MAX_SLOPE = 45
MIN_SLOPE = -45
MIN_HEIGHT = 0
def dist_squared(P1,P2):
return (P1[0]-P2[0])**2 + (P1[1]-P2[1])**2
def mountain(P1,P2):
if dist_squared(P1,P2) < 1:
turtle.goto(P2)
return
x1,y1 = P1
x2,y2 = P2
x3 = random.uniform(x1,x2)
y3_max = min((x3-x1)*math.tan(math.radians(MAX_SLOPE)) + y1, (x2-x3)*math.tan(-math.radians(MIN_SLOPE)) + y2)
y3_min = max((x3-x1)*math.tan(math.radians(MIN_SLOPE)) + y1, (x2-x3)*math.tan(-math.radians(MAX_SLOPE)) + y2)
y3_min = max(y3_min, MIN_HEIGHT)
y3 = random.uniform(y3_min,y3_max)
P3 = (x3, y3)
mountain(P1,P3)
mountain(P3,P2)
return
turtle.up()
turtle.goto(-400,0)
turtle.down()
mountain((-400,0),(400,0))
I know this was posted like 3 months ago, but hopefully this is helpful to someone that was also assigned this terrible problem 5 days before finals! Ha!
The struggle I had with this problem was not realizing that you only need to pass in one point. To get the point the turtle is starting at, you just use .xcor() and .ycor() that are included in the turtle library.
import turtle
import random
def mountain (x, y, complexity, turtleName):
if complexity == 0:
turtleName.setposition(x, y)
else:
x1 = (turtleName.xcor() + x)/2
y1 = (turtleName.ycor() + y)/2
y1 = y1 + (random.uniform(0, complexity) - 0.5) * (turtleName.xcor() - x)
complexity = complexity - 1
mountain(x1, y1, complexity, turtleName)
mountain(x, y, complexity, turtleName)
def main ():
#Gets input for first coordinate pair, splits, and assigns to variables
coordinate = str(input("Enter the coordinate pair, separated by a comma: "))
x, y = coordinate.split(',')
x = int(x)
y = int(y)
complexity = int(input("Enter the complexity: "))
while complexity < 0:
complexity = int(input("Input must be positive. Enter the complexity: "))
Bob = turtle.Turtle()
mountain(x, y, complexity, Bob)
main ()
My goal is to make a circle shape out of lines in pygame, using random endpoints around the edge of a circle and a constant starting point (the middle of the circle). So I decided that I would give the pygame.draw.line function: screen, aRandomColor, startingPosition, and endingPosition as arguments. Ending position is a tuple containing a randomly generated x value, and a helper function will calculate the y value based on the radius of the circle. My first function calculates the y value like this:
import math
import random
def findY(pos1, pos2, distance, bothValues=False):
p1 =pos1
p2 = pos2
x1 = float(p1[0])
y1 = float(p1[1])
x2 = float(p2[0])
d = float(distance)
y2 = y1 - math.sqrt(d**2 - (x1-x2)**2)
_y2 = y1 + math.sqrt(d**2 - (x1-x2)**2)
if bothValues==True:
return y2, _y2
else:
return y2
and the line drawer:
width = 500
height = 500
def randLine(surface, color=rand, start=rand, end=rand,length=rand):
if start==rand:
start = randPos()
if end==rand:
end = randPos()
if color==rand:
color = randColor()
if length != rand:
end_x = float(random.randint(0,width))
end_pos = (end_x, "y")
y2=findMissing(start_pos, end_pos,l,bothValues=True)
a = random.randint(0,1)
if a==0:
y2 = float(y2[0])
else:
y2 = float(y2[1])
lst = list(end_pos)
lst[1] = y2
end_pos = tuple(lst)
pygame.draw.line(surface, color, start_pos, end_pos)
Then:
drawRandLine(screen,start=(200,200),lenght=100)
(the other functions that those ones called like randPos aren't the problem). This for some reason generated an error that I diagnosed as the value inside the math.sqrt() was a negative number. But that can't happen, since every value in there is raised to power of 2, and thats what I'm confused about. So I changed the value inside math.sqrt() to its absolute value. This made the function not raise any errors, but the circle drawn looked like this:
I know that pygame's coordinate plane's y values upside down, but should that make a difference?
One way of getting a a uniform distribution of angles would be to generate a random angle theta between 0 and 2 * math.pi, and use trigonometry to find the co-ordinates of the end point of the line:
def drawRandLineTrig(start_pos, length):
theta = random.rand() * 2 * math.pi
end_pos = (start_pos[0] + length*math.cos(theta), start_pos[1] + length*math.sin(theta))
# ...
I could Do:
def randPos(origin=(0,0), xdis=width, ydis=height):
randx = random.randint(float(origin[0])-xdis,float(origin[0])+xdis)
randy = random.randint(float(origin[1])-ydis,float(origin[1])+ydis)
return (randx, randy)
def drawRandLine(surface, color=random, start_pos=random, end_pos=random,l=random):
if start_pos==random:
start_pos = randPos()
if end_pos==random:
end_pos = randPos()
if color==random:
color = randColor()
if l != random:
b = random.randint(0,1)
l=float(l)
origin = start_pos
dis = l
if b==0:
end_x = float(random.randint((origin[0]-dis),(origin[0]+dis)))
end_pos = (end_x, "y")
y2=findMissing(start_pos, end_pos,l,bothValues=True)
a = random.randint(0,1)
if a==0:
y2 = float(y2[0])
else:
y2 = float(y2[1])
lst = list(end_pos)
lst[1] = y2
end_pos = tuple(lst)
else:
end_y = float(random.randint((origin[1]-dis),(origin[1]+dis)))
end_pos = ("x", end_y)
x2=findMissing(start_pos, end_pos,l,bothValues=True)
a = random.randint(0,1)
if a==0:
x2 = float(x2[0])
else:
x2 = float(x2[1])
lst = list(end_pos)
lst[0] = x2
end_pos = tuple(lst)
pygame.draw.line(surface, color, start_pos, end_pos)
Which fixes the sqrt of a negative problem, and places an even distribution of lines by either calculating the x OR the y, and setting their limits to the specified length, to avoid the strange length of some of the lines.
Imagine we have two randomly selected points between 0 and 100 for both x and y.
For example:
(95,7), (35,6)
Now using the simple pygame.draw.line() function we could easily draw a line between these points without any gaps.
My question is, how could we find a list of all the coordinates in a single pixel thick line between the two points without any gaps in the line?
Secondly, is this even possible?
I am using this list of pixel for the crack maze algorithm that needs to "shoot" another pixel while regarding any blocking walls that may interfere with its path.
http://www.astrolog.org/labyrnth/algrithm.htm
By irregular, I refer to points which would not generate simple straight lines.
For example, it would be easy to find all the points between:
(0,5) and (5,5)
This has already been covered in this question:
List coordinates between a set of coordinates
Use Bresenham's line algorithm. You can find a simple python implementation here. Here’s a modified version of that implementation, which, given a starting and ending point, can return a list of intermediate points:
def line(x0, y0, x1, y1):
"Bresenham's line algorithm"
points_in_line = []
dx = abs(x1 - x0)
dy = abs(y1 - y0)
x, y = x0, y0
sx = -1 if x0 > x1 else 1
sy = -1 if y0 > y1 else 1
if dx > dy:
err = dx / 2.0
while x != x1:
points_in_line.append((x, y))
err -= dy
if err < 0:
y += sy
err += dx
x += sx
else:
err = dy / 2.0
while y != y1:
points_in_line.append((x, y))
err -= dx
if err < 0:
x += sx
err += dy
y += sy
points_in_line.append((x, y))
return points_in_line
Perhaps it's an overkill but I'd just find the line equation and use a generator expression. To find the equation you can use this example algorithm which will return something like
lambda x: 2*x +1
With that we can do:
f = find_line_equation(A, B) #A B are tuples
points = [(x, f(x)) for x in range(min(A[0], B[0]), max(A[0], B[0]))]
This is assuming you want only integer points. You can also use this loop:
points = []
x = min(A[0], B[0])
increment = 0.1
while x <= max(A[0], B[0]):
points.append((x, f(x))
x += increment
I'm trying to animate smooth motion between two points on the screen. At the moment, I am using the following python generator function to determine the point at which to draw the image:
#indexes (just for readability)
X=0
Y=1
def followLine(pointA, pointB, speed):
x1, y1 = pointA
x2, y2 = pointB
movement=[0, 0]
pos=list(pointA)
diffY=y2-y1
diffX=x2-x1
if abs(diffY) > abs(diffX):
#Y distance is greater than x distace
movement[Y]=speed
numFrames=abs(diffY)//speed
if numFrames==0:
movement[X]=0
else:
movement[X]=abs(diffX)//numFrames
elif abs(diffY) < abs(diffX):
#Y distance is less than x distace
movement[X]=speed
numFrames=abs(diffX)//speed
if numFrames==0:
movement[Y]=0
else:
movement[Y]=abs(diffY)//numFrames
else: #Equal
movement=[speed]*2
if diffY < 0:
#is negative
movement[Y] *= -1
if diffX < 0:
movement[X] *= -1
yield pointA
while (abs(pos[X]-x2) > speed)or(abs(pos[Y]-y2) > speed):
pos[X] += movement[X]
pos[Y] += movement[Y]
yield pos
yield pointB
However, this has 2 problems:
First, my main concern is that if pointA and pointB are very far apart, or if the speed is too low, the animation will pass right by pointB, and will keep going for infinity;
The other problem is that, at the end of the animation, there is a sort of jolt as the image snaps into place. This jolt is usually fairly imperceptible, but I'd like to try and make the animation smoother.
How can I do this? I've been looking into the use of trig functions and that seems promising, but I'm not much of a math person, so I'm having trouble understanding exactly how I might implement it using trig.
Also, for what it's worth I'm using Python 3.2.
There's missing information, I think. Seems like you need to either substitute a numFrames arg for speed, or add a time arg in addition to speed. Assuming the former, how about this. Note this generates numFrames+1 points so that pointA and pointB are always the first and last point, respectively, but that's trivial to change if that's not the behavior you want:
def followLine(pointA, pointB, numFrames):
x1, y1 = pointA
x2, y2 = pointB
diffY = float(y2 - y1) / numFrames
diffX = float(x2 - x1) / numFrames
yield(pointA)
for f in range(1,numFrames):
point = (x1 + f * diffX, y1 + f * diffY)
yield(point)
yield(pointB)
points = followLine((0,0), (1,1), 10)
# then iterate over the points and do whatever
for p in points:
print str(p)