Tkinter Canvas "Go-To" Function - python

I'm relatively new to Python, and I'm working with the tkinter canvas. I currently use
pos = canvas.coords(object)
speed = 5 #could be any number though
destpos = canvas.coords(destination)
xdist = destpos[2]-pos[2]
ydist = destpos[3]-pos[3]
#finds hypotenuse of an imaginary right triangle
fraction = speed/math.sqrt(xdist**2+ydist**2)
#puts the values into ratio so the object knows how far x and y they need to go
x = xdist * fraction
y = ydist * fraction
#canvas.move() function so the object moves
canvas.move(self.id, x, y)
However, I'd like a simple already added method of moving an object to another destination at a given speed.
I need to use this code dozens of times in an application I'm working on, and I'd prefer using a simpler method compared to a function.
In summary, what I want is a simple method of completing the same task that is a bit easier to understand. (The method is a bit buggy and I can't ever figure out why)

Related

Slow chess bot, need to go faster

I have created a chess bot using minimax and alpha beta pruning, along it I have also created a GUI. But my bot can't go very deep before becoming extremely slow. Already in depth 4 it can take up to 40-50 seconds to find a move.
The algorithm looks like this:
def minimax(depth,board, alpha, beta, is_max):
if depth == 0:
return evaluation(board)
leg_moves = board.legal_moves
if is_max:
value = -9999
for i_move in leg_moves:
move = chess.Move.from_uci(str(i_move))
board.push(move)
value = max(value, minimax(depth - 1, board, alpha, beta, False))
board.pop()
alpha = max(alpha, value)
if beta <= alpha:
return value
return value
else:
value = 9999
for i_move in leg_moves:
move = chess.Move.from_uci(str(i_move))
board.push(move)
value = min(value, minimax(depth - 1, board, alpha, beta, True))
board.pop()
beta = min(beta, value)
if(beta <= alpha):
return value
return value
To summarize, how do I make it faster?
Implementing a Negamax function instead of Minimax will make future efficiency implementations much easier as a start, it will also make the code look cleaner:
def negamax(depth, board, alpha, beta, color):
if depth == 0:
return evaluation(board)
leg_moves = board.legal_moves
for i_move in leg_moves:
move = chess.Move.from_uci(str(i_move))
board.push(move)
value = -negamax(depth - 1, board, -beta, -alpha, -color)
board.pop()
alpha = max(alpha, value)
if beta <= alpha:
return value
return value
Then you might want to look into concepts such as sorting the moves before going into the recursive function, since you will get a beta cutoff much faster that way and not having to look through as many moves. Then you can also implement for example a transposition table (with iterative deepening), null moves and late move reduction.
You probably also want to look at your move generation and see if you can make it any faster. For example, what board representation do you use?
I have made a chess engine in Python which is not at all top notch. It goes to depth 6 in about 15 seconds and you can find the code here for inspiration: Affinity Chess. It uses a 1D board representation, but a bitboard representation would be even faster.
I would also highly recommend looking at www.chessprogramming.org, there is lots of really nice information there.
There are many factors for make the algorithm fast adding more standard features of chess programs. But only 4 moves and so much time is not normal with your source code. How do you generate the moves? You should not ask about them via the UCI protocol, instead try to generate them really fast. In particular do not search about figures on the board, instead organize there positions in a list and add/remove them if they are taken from the board.
Maybe your evaluation function is slow. If you only take care of the values of the pieces, then have a variable to hold the difference of the colours and only update it if a piece is taken or restore. So the evaluation needs nearly no time anymore.
In a java program i reach a depth of 7 in 4s with implementing this details without using methods like hashtables.

Mass spring system with method of Verlet (1d)

For my home work I have to make a mass spring system (eventually 2d) but I'm trying 1d first). But I can't get it to work, please help me. We have to use the method of Verlet and we have to implement the following function in python. Is my code wrong? And how can I do it best?
Formula: https://drive.google.com/open?id=1Oi4MVOyTPvMLqZ35zFtQTgPlxNNrCHZy
def verlet():
result = 2 * py[0] # 2y(ti)
result -= py_prev[0] # - y(ti - dt)
result += (GRAVITATION + (-Ks * (py[0] - py_prev[0]))) / MASS
py_prev[0] = py[0]
py[0] = result/20
How have you defined the variables? Could you include your entire program?
If all variables are defined the code runs.
Looking at your code, I don't see how you have calculated the last term in the formula.
result += (GRAVITATION + (-Ks * (py[0] - py_prev[0]))) / MASS
You need to define the time difference between two points. (This is not py[0] - py_prev[0], this is the height difference).
I think the last term in the formula can be calculated like this:
result -= delta_t**2 * py[0]
Later on, you are going to need to use a for loop (or even better arrays, but a for loop is easier) to save the position of the oscillator at each time point.

How to draw fibonacci sequence using turtle module

This is my first question ever, and I am a complete and utter beginner, so please don't eat me :) What I am trying to to is to draw a fibonacci sequence using the Python turtle module. My code is as follows:
import turtle
zuf = turtle.Turtle()
while True:
zuf.forward(10)
zuf.left(3.1415)
This, however, drives around in circles only. I have tried to create a variable, say X, and assign a fibonacci rule to it xn = xn-1 + xn-2 then I'd put it in here zuf.forward(x) but it doesn't work. I tried multiple variations of that, but none seems to work. Please don't give a whole solution, only some hint, thanks a lot.
I think I can get you from where you are to where you want to be. First, your invocation of:
zuf.left(3.1415)
seems to indicate you're thinking in radians, which is fine. But you need to tell your turtle that:
zuf = turtle.Turtle()
zuf.radians()
this will still make your code go in circles, but very different circles. Next, we want to replace 10 with our fibonacci value. Before the while loop, initialize your fibonacci counters:
previous, current = 0, 1
as the last statement in the while loop, bump them up:
previous, current = current, current + previous
and in your forward() call, replace 10 with current. Next, we need to turn the line that it's drawing into a square. To do this, we need to do two things. First, loop the drawing code four times:
for i in range(4):
zuf.forward(current)
zuf.left(3.1415)
And second, replace your angle with pi/2 instead:
zuf.left(3.1415 / 2)
If you assemble this all correctly, you should end up with a figure like:
showing the increasing size of the fibonacci values. Not the greatest looking image, you'll still have to do some work on it to clean it up to look nice.
Finally, I was impressed with the fibonacci drawing code that #IvanS95 linked to in his comment, that I wrote a high speed version of it that uses stamping instead of drawing:
from turtle import Screen, Turtle
SCALE = 5
CURSOR_SIZE = 20
square = Turtle('square', visible=False)
square.fillcolor('white')
square.speed('fastest')
square.right(90)
square.penup()
previous_scaled, previous, current = 0, 0, 1
for _ in range(10):
current_scaled = current * SCALE
square.forward(current_scaled/2 + previous_scaled/2)
square.shapesize(current_scaled / CURSOR_SIZE)
square.left(90)
square.forward(current_scaled/2 - previous_scaled/2)
square.stamp()
previous_scaled, previous, current = current_scaled, current, current + previous
screen = Screen()
screen.exitonclick()
This is not a whole solution for you, only a hint of what can be done as you're drawing your squares and this is a stamp-based solution which plays by different rules.

Computing the circumference, area, and ratio of circumference to area of a circle

Studying for a CS test and basically I have to follow instructions that are similar to this.
Write a program, that is a file containing a main function followed by
a call to the main, and name the program ratio.py. The basic structure
of the program should look like this:
def main():
...
return
main() where the ellipsis indicates where you should place the code that performs following computations:
-you should prompt the user for an integer value corresponding to the
radius of a circle. Do this with code similar to:
radius = int(input("circle radius? "))
compute the circumference of the circle using the formula c = 2 πr where r is the radius and c is the circumference. Use the value of
3.14159 for π
compute the area of the circle using the formula c = πr2
print the ratio of the circumference to the area (the ratio of a to b is a divided by b)
Here is what I have written so far. I got the circumference and the area but how do I get it to make a ratio between the two and print the ratio.
def main():
radius = int(input("circle radius? "))
pi = 3.14159
r = radius
c = 2*pi*r
print(2*pi*r)
a = pi*r*r
print(pi*r*r)
ratio = c / a
return(ratio)
print("the ratio of the circumference to the area is",ratio)
main()
The ultimate goal is to get something like this:
$ python3 ratio.py
circle radius? 2
the ratio of the circumference to the area is ????
where ???? is replaced by the actual ratio.
You are extremely close to solving this. Here are a couple ideas to help you finish it:
import statements should generally go at the top of the file, not inside a function. They will work in the function, but it is poor form. This was probably not taught in class, but you get used to seeing particular patterns as you read other people's code.
As a matter of style, Python generally uses capital letters for names of constants, so PI=3.14159 is more common than pi=3.14159. This is minor and works either way. It is a good style to adhere to, since it will help make your code match others' code.
You need to calculate the area using the equation given to you: a = PI*r*r (NOTE - the original question incorrectly uses 'c' for the area. 'c' is the circumference.)
You need to return c/a, which is the ratio that was requested.
You probably need to print out the return value for testing. You can do that by storing the value returned by main() in a variable and then printing it.
Here is how to return a value from your main() function:
def main():
...
return c/a
ratio = main()
print(ratio)
# or...
print("The ratio is:", ratio)
it's odd that you do c = (2*math.pi*r) when you have pi declared as a variable above two lines. Doing math.pi goes to python's math library and digs up a more accurate version of pi. For all intents and purposes, you are just completely not using that pi variable.
see http://docs.python.org/2/library/math.html for more information.
Furthermore, you do the same computation twice.
c = 2*math.pi*r
return(2*math.pi*r)
c just ends up being garbage collected (which is to say, the computer does the computation then INTO THE TRASH IT GOES) and never being used. It would be better to simply return c
For scoping issues, which I'm sure you wouldn't really know about as a beginner, put import math above your main function, unindented.
just for future reference though, SO tends to be for isolated problems that you have spotted in code; not for a full code review. A more acceptable question would be along the lines of "my function is returning an unexpected value", not "my function is not working"

What is wrong with my snap to grid code?

First of all, I'm fairly sure snapping to grid is fairly easy, however I've run into some odd trouble in this situation and my maths are too weak to work out specifically what is wrong.
Here's the situation
I have an abstract concept of a grid, with Y steps exactly Y_STEP apart (the x steps are working fine so ignore them for now)
The grid is in an abstract coordinate space, and to get things to line up I've got a magic offset in there, let's call it Y_OFFSET
to snap to the grid I've got the following code (python)
def snapToGrid(originalPos, offset, step):
index = int((originalPos - offset) / step) #truncates the remainder away
return index * gap + offset
so I pass the cursor position, Y_OFFSET and Y_STEP into that function and it returns me the nearest floored y position on the grid
That appears to work fine in the original scenario, however when I take into account the fact that the view is scrollable things get a little weird.
Scrolling is made as basic as I can get it, I've got a viewPort that keeps count of the distance scrolled along the Y Axis and just offsets everything that goes through it.
Here's a snippet of the cursor's mouseMotion code:
def mouseMotion(self, event):
pixelPos = event.pos[Y]
odePos = Scroll.pixelPosToOdePos(pixelPos)
self.tool.positionChanged(odePos)
So there's two things to look at there, first the Scroll module's translation from pixel position to the abstract coordinate space, then the tool's positionChanged function which takes the abstract coordinate space value and snaps to the nearest Y step.
Here's the relevant Scroll code
def pixelPosToOdePos(pixelPos):
offsetPixelPos = pixelPos - self.viewPortOffset
return pixelsToOde(offsetPixelPos)
def pixelsToOde(pixels):
return float(pixels) / float(pixels_in_an_ode_unit)
And the tools update code
def positionChanged(self, newPos):
self.snappedPos = snapToGrid(originalPos, Y_OFFSET, Y_STEP)
The last relevant chunk is when the tool goes to render itself. It goes through the Scroll object, which transforms the tool's snapped coordinate space position into an onscreen pixel position, here's the code:
#in Tool
def render(self, screen):
Scroll.render(screen, self.image, self.snappedPos)
#in Scroll
def render(self, screen, image, odePos):
pixelPos = self.odePosToPixelPos(odePos)
screen.blit(image, pixelPos) # screen is a surface from pygame for the curious
def odePosToPixelPos(self.odePos):
offsetPos = odePos + self.viewPortOffset
return odeToPixels(offsetPos)
def odeToPixels(odeUnits):
return int(odeUnits * pixels_in_an_ode_unit)
Whew, that was a long explanation. Hope you're still with me...
The problem I'm now getting is that when I scroll up the drawn image loses alignment with the cursor.
It starts snapping to the Y step exactly 1 step below the cursor.
Additionally it appears to phase in and out of allignment.
At some scrolls it is out by 1 and other scrolls it is spot on.
It's never out by more than 1 and it's always snapping to a valid grid location.
Best guess I can come up with is that somewhere I'm truncating some data in the wrong spot, but no idea where or how it ends up with this behavior.
Anyone familiar with coordinate spaces, scrolling and snapping?
Ok, I'm answering my own question here, as alexk mentioned, using int to truncate was my mistake.
The behaviour I'm after is best modeled by math.floor().
Apologies, the original question does not contain enough information to really work out what the problem is. I didn't have the extra bit of information at that point.
With regards to the typo note, I think I may be using the context in a confusing manner... From the perspective of the positionChanged() function, the parameter is a new position coming in.
From the perspective of the snapToGrid() function the parameter is an original position which is being changed to a snapped position.
The language is like that because part of it is in my event handling code and the other part is in my general services code. I should have changed it for the example
Do you have a typo in positionChanged() ?
def positionChanged(self, newPos):
self.snappedPos = snapToGrid(newPos, Y_OFFSET, Y_STEP)
I guess you are off by one pixel because of the accuracy problems during float division. Try changing your snapToGrid() to this:
def snapToGrid(originalPos, offset, step):
EPS = 1e-6
index = int((originalPos - offset) / step + EPS) #truncates the remainder away
return index * gap + offset
Thanks for the answer, there may be a typo, but I can't see it...
Unfortunately the change to snapToGrid didn't make a difference, so I don't think that's the issue.
It's not off by one pixel, but rather it's off by Y_STEP. Playing around with it some more I've found that I can't get it to be exact at any point that the screen is scrolled up and also that it happens towards the top of the screen, which I suspect is ODE position zero, so I'm guessing my problem is around small or negative values.

Categories