Python: if condition changing value - python

I have the following code that generates a x_d and x_y. I then want to add or subtract these values from the last calculated x and y (returned from config.get_last_point()), and store it in the latest point.
def generate_asv_configuration(
asv_count, generate_left_concavity, corner_angle=None):
# Create a configuration
config = Configuration(generate_left_concavity)
for i in range(2, asv_count):
# Calculate the angle to be used in the calculations
turning_angle = turning_angle - delta_angle
# Calculate the delta-x, and -y.
x_d = MAX_BOOM_LENGTH * math.cos(turning_angle)
y_d = MAX_BOOM_LENGTH * math.sin(turning_angle)
# print generate_left_concavity
if (i % 2) == 0:
print '1: Left, i: {0}'.format(i)
x = config.get_last_point()[0] - x_d
y = config.get_last_point()[1] - y_d
else:
print '2: Right, i: {0}'.format(i)
x = config.get_last_point()[0] + x_d
y = config.get_last_point()[1] + y_d
config.add_point((x, y))
The problem I'm having is that code generates an image similar to . That looks good, the different points have varying angles (you can see that some are almost closed, others are very open). However, when I change the first if condition to (i % 2) == 0 and generate_left_concavity, and I call it with generate_left_concavity to True, I guess something similar to . The problem is, there is really open polygons.
Unfortunately, I've tried a few different if conditions, and whenever I have generate_left_concavity in the condition, it always generates differently. I have even tried nested if conditions.
I believe I've even tried having the above two conditions, then in a later condition, I check if generate_left_concavity, if so, I add 2 * x_d to compensate. It still generates the images similar to .
I don't see how much of my code could directly affect the generation of x and y calculations based on an if condition, but I could be wrong. I can guarantee, however, that they are always entering the same condition branch, but generate differently.

Not really an answer but: If I think something weird is going on in a conditional, I try to make the conditional suites as simple as possible to eliminate or separate possible problem code. Yours could be refactored:
if (i % 2) == 0:
print '1: Left, i: {0}'.format(i)
x_d, y_d = -x_d, -y_d
else:
print '2: Right, i: {0}'.format(i)
x = config.get_last_point()[0] + x_d
y = config.get_last_point()[1] + y_d

I've looked into a bit more, and it turns out that when I'm trying to generate a left-concavity open polygon, the range of angles that are possible are different to the possible angles for a right-concavity open polygon. Once I found out that if I find the min/max allowed angles for the concavity that I am generating, it was correctly selecting an angle within the bounds, therefore, generating the way I want :) Thanks everyone for you help and guidance!

Related

Python dictionary keys seem to vanish before I delete them

I'm a newbie programmer working on an idea for a small game. I wanted my play space to be a grid for various reasons. Without a lot of good reason, I decided to create a class of GridSquare objects, each object having properties like size, an index to describe what (x,y) coordinates they represented, and some flags to determine if the grid squares were on land or empty space, for example. My grid is a dictionary of these objects, where each GridSquare is a key. The values in the dictionary are going to be various objects in the place space, so that I can easily look up which objects are on each grid square.
Just describing this I feel like a complete lunatic. Please bear in mind that I've only been at this a week.
My problem appears when I try to change the GridSquare objects. For example, I want to use a list to generate the land on each level. So I iterate over the list, and for each value I look through my grid squares using a for loop until I find one with the right index, and flip the GridSquare.land property. But I found that this caused a runtime error, since I was changing keys in a dictionary I was looping through. OK.
Now what I'm trying to do is to create a list of the keys I want to change. For each item in my level-generating list, I go through all the GridSquares in my grid dictionary until I find the one with the index I'm looking for, then I append that GridSquare to a list of old GridSquares that need updating. I then make another copy of the GridSquare, with some properties changed, in a list of altered GridSquares. Finally, I delete any keys from my grid dictionary which match my list of "old" GridSquares, and then add all of the altered ones into my grid dictionary.
The problem is that when I delete keys from my grid dictionary which match my list of "old" keys, I run into keyerrors. I can't understand what is happening to my keys before I can delete them. Using try/except, I can see that it's only a small number of the keys, which seems to vary kind of arbitrarily when I change parts of my code.
I would appreciate any insight into this behaviour.
Here is code for anyone still reading:
aspect_ratio = (4, 3)
screen_size = (1280, 720)
#defining a class of objects called GridSquares
class GridSquare:
def __init__(self, x, y):
self.index = (x, y)
self.land = 0
#creates a dictionary of grid squares which I hope will function as a grid......
grid = {}
for x_index in range(1, (aspect_ratio[0] + 1)):
for y_index in range (1, (aspect_ratio[1] + 1)):
new_square = GridSquare(x_index, y_index)
grid[new_square] = None
#these are lists to hold changes I need to make to the dictionary of grid squares
grid_changes = []
old_gridsquares = []
#this unweildly list is meant to be used to generate a level. Numbers represent land, spaces are empty space.
for number_no, number in enumerate(["1", "1", "1", "1",
" ", " ", " ", " ",
"1", "1", "1", "1"]):
#makes grid squares land if they are designated as such in the list
for gridsquare in grid.keys():
#this if statement is meant to convert each letter's position in the list into an index like the grid squares have.
if gridsquare.index == ((number_no + 1) % (aspect_ratio[0]), ((number_no + 1) // (aspect_ratio[0] + 1)) + 1):
#create a list of squares that need to be updated, and a list of squares to be deleted
old_gridsquares.append(gridsquare)
flagged_gridsquare = GridSquare((number_no + 1) % (aspect_ratio[0]), ((number_no + 1) // (aspect_ratio[0] + 1)) + 1)
flagged_gridsquare.land = 1
#this part is meant to set the flag for the gridsquare that indicates if it is on the far side or the near side,
#if it is land
if number == "1":
flagged_gridsquare.near = 1
grid_changes.append(flagged_gridsquare)
#deletes from grid any items with a key that matches the old squares, and adds updated versions.
for old_gridsquare in old_gridsquares:
try:
del grid[old_gridsquare]
except:
print(old_gridsquare.index)
print(old_gridsquare.land)
for grid_change in grid_changes:
grid[grid_change] = None

How to set up this programm idea? : Elliott Wave Counter on Stock Charts by finding Minima and Maxima and how they relate to each other

My Idea is as follows and i want to really get to learn more about programming and how to structure a program:
I want to let count waves on a stock chart.
Within the Elliott Wave Rules are some specifications, like (most basic):
Wave 2 never retraces more than 100% of wave 1.
Wave 3 cannot be the shortest of the three impulse waves, namely waves 1, 3 and 5.
Wave 4 does not overlap with the price territory of wave 1, except in the
rare case of a diagonal triangle formation.
(from Wikipedia https://en.wikipedia.org/wiki/Elliott_wave_principle#Wave_rules_and_guidelines)
There are more sophisticated rules of course, but in my imagination, they could be addressed by the same iterative logic like in which I want to apply my rules.
Please guys, and girls, give me feedback on my thoughts if they make any sense in structure and layout to set up a program or not, because i lack experience here:
I want to find the minima and maxima, and give them a wavecount depending on the minima and maxima before.
Therefore i would check every candle (every closing price, day, hour, etc) if the value is below or above the previous value and also values. For example:
If there are two candles going up, then one down, then three up, then two down, then two up, this could be a complete Impulsewave, according to the above-listed rules. In total, i would have 10 candles and the following rules must apply:
The third candle (or the first that goes down, after the two going up) must not close below the starting price of the initial candle. AND also it must be met, that the following candles (how much that would become) must all go up in a row, unless they overcome the price of the previous maxima (the second candle).
When the price starts to drop again, it could be counted as wave 4 then (second minima in a sequence) and when it goes up again, this would indicate wave 5.
Then it also must be met, that, if the price starts to go down again, it does not close below the first maxima (in this case the second candle).
And so on and so on.
My question now is: Is this kind of looping through certain data points is even a appropriate way to approach that kind of project? Or am I totally wrong here?
I just thought: because of the fractal character of Elliott waves, I would only need very basic rules, that would depend on, what the same iterative process spits out the previous times it is scanning data points.
What do you think?
Is there a better, a smarter way to realise what i am planing to do?
And also, how I could do this in a good way?
Maybe there is also a way to just feed some patterns into a predefined execution structure and then let this run over data points just as price charts.
What would your approach look like?
Thanks a lot and best wishes, Benjamin
Here is my idea/code for finding highs and lows. It's doenst work standalone. If you have any idea, how it can help to find waves, let me know.
import pandas as pd
import config.Text
class AnalyzerHighLow(object):
def __init__(self, df):
self.high_low = None
self.df = df.close.values
self.highs = pd.DataFrame(columns=[config.Text.date, config.Text.extrema, config.Text.type])
self.lows = pd.DataFrame(columns=[config.Text.date, config.Text.extrema, config.Text.type])
def highlow(self):
idx_start = 0
self.find_high(self.df, idx_start)
self.find_low(self.df, idx_start)
self.high_low = pd.concat([self.highs, self.lows], ignore_index=True, sort=True, axis=0)
self.high_low = self.high_low.sort_values(by=[config.Text.date])
self.high_low = self.high_low.reset_index(drop=True)
return self.high_low
def find_high(self, high_low, idx_start):
pvt_high = high_low[idx_start]
reached = False
for i in range(idx_start + 1, len(high_low)):
act_high = high_low[i]
if act_high > pvt_high:
reached = True
pvt_high = act_high
elif act_high < pvt_high and reached is True:
self.highs.loc[i - 1] = [i - 1, pvt_high, config.Text.maxima]
return self.find_high(high_low, i)
elif act_high < pvt_high:
pvt_high = high_low[i]
if (reached is True) and (i == (len(high_low))):
self.highs.loc[i - 1] = [i - 1, pvt_high, config.Text.maxima]
def find_low(self, high_low, idx_start):
pvt_low = high_low[idx_start]
reached = False
for i in range(idx_start + 1, len(high_low)):
act_low = high_low[i]
if act_low < pvt_low:
reached = True
pvt_low = act_low
elif act_low > pvt_low and reached is True:
self.lows.loc[i - 1] = [i - 1, pvt_low, config.Text.minima]
return self.find_low(high_low, i)
elif act_low > pvt_low:
pvt_low = high_low[i]
if (reached is True) and (i == (len(high_low) - 1)):
self.lows.loc[i - 1] = [i - 1, pvt_low, config.Text.minima]

Find the possible slide downs in a pyramid

I'm losing my mind with this codewars/project euler problem: https://www.codewars.com/kata/551f23362ff852e2ab000037/train/python
I need to find the max sum in all of the possible pyramid slide downs, and as of right know I'm trying to calculate the possible slide downs that exist in the pyramid. It works fine but for integers bigger than 25 the function begins to be really slow.
My code is this:
def find_seq(x):
'''
input: x, positive integer greater than 1
Returns an array with the slides from the top to the bottom of
an x floors high pyramid
'''
list_slides = []
if x == 2:
return [[0,0],[0,1]]
else:
prev_slides = find_seq(x-1)
for el in prev_slides:
list_slides.append([0]+el)
for el in prev_slides:
list_slides.append([0]+list(i+1 for i in el))
return list_slides
I can see that for each new floor the calculating time grows exponentially but I can't think of any other way to adress the problem.
tl;dr: Go from the bottom up for linear complexity.
Well, you are right it grows exponentially.
The problem is not your code, but your direction.
Let's look at the pyramid from bottom up - you can see right away that if you are at the second to last layer and you want to slide down, you will choose the path that is directly under you and has the larger value, i.e you can slide only left or right and the bigger will be better.
Now, going up to the third to last, you only need to find the route down to the floor below which is the best (summing up the value of the bottom floor of course).
keep going like that to the top of the pyramid and by the end, you get the value of the best route, or longest slide.
code:
def longest_slide_down(pyramid):
if len(pyramid) == 1:
return pyramid[0][0]
last_layer = pyramid[-1]
add_layer = []
for i in range(1, len(last_layer)):
add_layer.append(max(last_layer[i], last_layer[i-1]))
pyramid[-2] = [a+b for a, b in zip(pyramid[-2], add_layer)]
return longest_slide_down(pyramid[:-1])
And for the efficiency seekers out there, a numpyed version of the same code:
import numpy as np
def longest_slide_down(pyramid):
if len(pyramid) == 1:
return pyramid[0][0]
pyramid = np.array(pyramid)
pyramid[-2] += np.maximum(pyramid[-1][:-1], pyramid[-1][1:])
return longest_slide_down(pyramid[:-1])

python - generating a non repeating random pairs of numbers

I'm trying to generate random pairs of numbers to place objects at random locations in a grid. I've tried looking for answers but I haven't found one that works for what I need. I don't want the pair to repeat but the objects can still be placed in the same row or column. Also the size of the grid and the number of objects is inputted by the user
def create_bombs(self):
bombs_flaged = 0
#creates the bombs
for i in range(self.bomb_num):
bomb_row = randint(0,self.board_size - 1)
bomb_col = randint(1,self.board_size)
self.bomb_list.append(Bomb(bomb_row, bomb_col, self, bombs_flaged))
One way to think about this is: there are X*Y possible positions (specifically board_size * board_size, in your case), and you want to pick N (self.bomb_num) random samples from those positions, without repetition.
The sample function in the random module does this perfectly:
possible_coordinates = [(x, y) for x in range(X) for y in range(1, Y+1)]
bomb_coordinates = random.sample(possible_coordinates, N)
Creating that list is a little wasteful—but given that board_size is probably something small, like 30, a temporary list of 900 elements is not worth worrying about.
Python's sets are meant to do just what you need: membership testing is very fast, with them (constant time):
def create_bombs(self):
bombs_flagged = 0
existing_bomb_coords = set() # All bomb coordinates so far
# Creates the bombs
while len(existing_bomb_coords) < self.bomb_num: # Looping as much as needed
bomb_row = randint(0, self.board_size-1)
bomb_col = randint(1, self.board_size)
bomb_coords = (bomb_row, bomb_col)
if bomb_coords not in existing_bomb_coords: # Very fast test
self.bomb_list.append(Bomb(bomb_row, bomb_col, self, bombs_flagged))
existing_bomb_coords.add(bomb_coords) # New bomb registration
Now, I like #abarnert's answer too: it is a bit wasteful, as he indicates, but it is very legible.

Basic Functions Help - Python

I'm quite new to Python, and I'm busy trying to figure out how these pesky functions work... The program I'm making is supposed to be working out the area of a triangle, but I can't actually get it to return the local variables to other functions. Any help would be greatly appreciated!
# Area of a triangle
base = 0
height = 0
area = 0
def inData():
base = float(raw_input("Base:"))
height = float(raw_input("Height:"))
return base
return height
def triangle(b,h):
area = b / 2 * h
return area
if __name__ == '__main__':
inData()
triangle(base, height)
print "The area of a triangle of base", base, "and height" , height, "will be", area
There are many problems and misconceptions I see in your code; Let me see if I can start from scratch and try to convey the proper way to do these functions for you. In the end, we will have a working version of your code. :)
note: You do not have to declare functions ahead of time in Python-- it does that itself! So no need for base, height, area at the top!
Functions
Functions are in short, sets of commands that get run in a bundle. You know this. What you miss though are the concepts of arguments and parameters and return vs print.
Arguments vs Parameters
When you define a function, you are setting up what you want it to do in the future and at your beck and call. Just like any function f(x) in math, you want one equation that will work with whatever input you give it. For f(x), x is your input.
In programming, this is referred to as a parameter. So when you write in Python:
def Function(x):
y = x*x
return y
You have defined x as your parameter. Now, Arguments are the values that you put into a function, where the parameters go. In Algebra, the applicable idea would be defining a variable. Knowing this, when you actually use that function:
Function(2)
You will get back 4, because you said run Function(x) where x = 2.
This is the concept of Arguments vs Parameters. It is very useful, because you don't always want to ask a user for input inside the function. The more direct your function is, the less it can do. Sometimes you want to use that same function to do math in the background, for example. You can't very well have raw_input() if you expect the process to work on its own in the background, can you?
This is the true value of Arguments vs Parameters.
Return vs Print
In the same vein as not using raw_input() because it is too direct, you want to avoid using print and use return instead. I know you didn't use print here, but you've misunderstood the workings of return and I figure the same lesson applies.
Here is an example: You have two functions.
def Function1(x,y):
z = x*y
print z
def Function2(x,y):
z = x*y
return z
Function 1 prints z, which means that no matter what you want it to do, it will always print z to the console, even if you want it to just do the math.
Meanwhile, Function 2 returns z, meaning it hands back the value of z to the program as it was called. It is also worth noting that as soon as a function hits the line return, it stops running the function further. There is no reason to code beyond this, because the function is no longer being run, unless you had a more advanced code that skipped over return (for example, an if statement).
Why is return so conceptually important?
Because in your original code, you run the function inData(), and after that, not only do you run return twice, but in your if statement, you don't even use what inData returns, you just tell the program to run inData().
When a function returns a value, you have to assign it to something. Take, for instance, simple math in any random programming language. The code:
x = sqrt(4)
print x
will output 2, because at the end of the function sqrt(), it returns its answer. Here, we assigned x to be variable that sqrt(4) gives a return to. While it's true that:
sqrt(4)
will also print 2 to the console, this is because of fool-proofing by language developers, where in fact the language assumes you want the code printed. You're not telling it to do that.
So, when you run the lines of code:
inData()
triangle(base, height)
You are basically saying:
run the function inData()
run the function triangle(base, height)
When, because of their returns, you need to be saying:
set <variable1> equal to the return of inData()
set <variable2> equal to the return of triangle(base,height)
(there is more simplification to be done here, but we'll approach it in a moment).
One last thing on return. In programming, it is useless to write:
x = 1+1
return x
When return 1+1 accomplishes the same thing. Thus, no need to define what the area of a triangle will be and then return the area. Just tell the function to return what it calculates the area to be in the same line of code!
Have I lost you? Still with me? Good!
Simplification of your code
Your code has a few structural problems that, while it may work, would baffle any more seasoned programmer that looked at it. While we're here, why don't we see if I can have you understand what a better practice for this would be.
In your code, you have written (in a summarized form)
variables defined that you don't need
def FunctionThatGathersData()
def FunctionThatDoesTheMath(x,y)
if (condition)
FunctionThatGathersData()
FunctionThatDoesTheMath(x,y)
print out the results
The structure of this would confuse a programmer who has more experience. He might ask the following questions:
What?
Why are you returning things this way?
Why are the variables defined?
Why don't you combine FunctionThatGathersData and FunctionThatDoesTheMath?
Some of these reasons are already exposited upon above, but let's get to the last two questions.
Why are the variables defined?: On one hand, Python handles variables during execution. So you never have to define them ahead of time, but you can, and the advantage of this is as follows:
x = 0
def Function()
x = 5
y = 10
Looking at this code, you might wonder why x is defined. The simple answer is that Python will see that you already have an x, and thus, when you run Function(), you want to overwrite it with the work inside the function. y on the other hand, has no previous definition, and thus a new variable will be created.
However, in your function we don't need any of that because your answer, in its best form, won't need to depend on x outside the function.
Why can't we just combine the two functions together, using what we learned about parameters, arguments, and returns? (hint: we can!)
Here is a new snippet of code that you should now be able to read and understand. Clear your head of what you've read for a moment and see if it makes sense. In it, you will:
Define your function DoTheMathAndThenGiveMeTheValueBack
Decide if __name__ == '__main__'
Provide your values (put them in variables)
Pass those variables as arguments into the function
tell the program to print the base and height and then area based on the function's return.
The Code
def CalculateTriangleArea(b,h):
return b / 2 * h
if __name__ == '__main__':
base = float(raw_input("Base:"))
height = float(raw_input("Height:"))
area = CalculateTriangleArea(base,height)
print "The area of a triangle of base", base, "and height", height, "will be", area
If you do not grok this, please, comment and ask me more because I remember struggling with this and know what misunderstandings you are having.
Oh! And I forgot to mention to you what to do about multiple returns.
In the event that you need to return more than one value in a function, you can do so through an array or a tuple. This is just a list of values you have stored. You can access any item in an array or tuple by including the index at the end in the form of [i], where the first item is at [0]. For example:
def Function():
string1 = "nobody"
string2 = "expects"
string3 = "the"
string4 = "spanish"
string5 = "inquisition"
return string1, string2, string3, string4, string5
print Function()[0]
print Function()[1]
print Function()[2]
print Function()[3]
print Function()[4]
print Function() #prints the whole tuple!
Will get you:
nobody
expects
the
spanish
inquisition
('nobody', 'expects', 'the', 'spanish', 'inquisition')
Understand? :)
For more hands-on work in python, try this amazing Python tutorial.
When you do return, the function immediately ends, returning the value. Therefore, your inData function will only return the base, not the height. In addition, you seem to be asking the user to input the base and the height twice -- that's unnecessary, since your inData function already does that
Rather, you want to return two values at the same time by doing something like this. (Note -- I renamed some of your functions for clarity)
# Area of a triangle
def get_user_input():
base = float(raw_input("Base:"))
height = float(raw_input("Height:"))
return base, height
def triangle_area(b, h):
area = b / 2 * h
return area
if __name__ == '__main__':
base, height = get_user_input()
area = triangle_area(base, height)
print "The area of a triangle of base", base, "and height" , height, "will be", area
The problems with your code:
# Area of a triangle
base = 0 # You don't need to initialize these values. Even if you want
height = 0 # to make these global you can simple assign inside the if
area = 0 # __name__ == '__main__' condition
def inData():
base = float(raw_input("Base:"))
height = float(raw_input("Height:"))
return base # return immediately stops the execution of the function
return height # and returns the value
def triangle(b,h):
area = b / 2 * h
return area
if __name__ == '__main__':
inData() # You are not assigning the returned value to any variable
triangle(base, height)
print "The area of a triangle of base", base, "and height" , height, "will be", area
Correct version of your program:
# Area of a triangle
def inData():
base = float(raw_input("Base:"))
height = float(raw_input("Height:"))
return base, height
def triangle(b,h):
area = b / 2 * h
return area
if __name__ == '__main__':
base, height = inData()
area = triangle(base, height)
print "The area of a triangle of base", base, "and height" , height, "will be", area

Categories

Resources