python: increase a variable as another decreases - python

I'm making a game where I have a force field. I need the force towards the source to increase as I get closer. I have a code that gets the distance between the player and the source and I want to set the strength of the force as the distance between the objects. However, as I get closer to the source, the distance decreases and so does the strength of the force. Is it possible to have another variable that somehow goes opposite of the distance so that as distance decreases, it increases?

Try the following structure:
import math
force_constant = 100 #linearly increases the force applied to the player
max_pull_constant = 1 #fractionally decreases the maximum force applied to the player
point_source = [0,0,0]
point_player = [0,10,0]
def radius (point_player, point_source):
return_value_vector = [(p-s)**2 for p, s in zip(point_player, point_source)]
return_value_scalar = math.sqrt(sum(return_value_vector))
return return_value_scalar
def pulling_force(point_player, point_source):
return_value_scalar = force_constant/(max_pull_constant + radius(point_player, point_source))
def pulling_force_vector(point_player, point_source):
return_radius = radius(point_player, point_source)
return_vector = [(p-s)/return_radius for p, s in zip(point_player, point_source)]
return_force = pulling_force(point_player, point_source)
return_value_force_vector = [return_force*v for v in return_vector]
return return_value_force_vector
#Main program here
#Call pulling_force(player_location, source_location) to get the force from the force field
This structure should be what you are looking for, I wrote it assuming three dimensions, edit as needed. Enjoy!

Related

Calculating right triangle using random points in Python

I am trying to create right triangles using random coordinates in turtle. Sometimes my code works, while other times the hypotenuse of my triangle goes in the wrong direction. I have spent hours trying to figure out what it causing the inconsistency.
There are several shapes within the code. However, only the RightTriangle class is giving me issues so I have removed the others.
If anyone is able to figure out how I can resolve the issues I am having I would be extremely grateful.
from turtle import Turtle
import random
from math import sqrt, degrees, asin, acos, atan
class Shape():
turtle = Turtle()
class RightTriangle(Shape):
def __init__(self, A, B):
self.A = A
self.B = B
def draw(self):
a = (self.B[0] - (self.A[0]))
b = (self.B[1] - (self.A[1]))
c = (sqrt((self.B[0] - self.A[0])**2 + (self.B[1] - self.A[1])**2))
angleA = degrees(atan(a/b))
angleB = degrees(atan(b/a))
Shape.turtle.penup()
Shape.turtle.setposition(self.A)
Shape.turtle.pendown()
Shape.turtle.forward(a)
Shape.turtle.right(90)
Shape.turtle.forward(b)
Shape.turtle.right(180-angleA)
Shape.turtle.forward(c)
Shape.turtle.penup()
def random_shapes(count):
def random_point():
return (random.randint(-200,200), random.randint(-200,200))
shapes = []
for i in range(1, count+1):
shapes += [RightTriangle(random_point(), random_point())]
return shapes
def main():
shapes = random_shapes(15)
for s in shapes:
s.draw()
input ('Hit <enter> key to end.')
input ('Have a nice day!')
main()
With your existing code the lengths of the edges can be negative which changes the meaning of your "forward" movements and "right" turns. Use absolute values when calculating lengths:
a = abs(self.B[0] - (self.A[0]))
b = abs(self.B[1] - (self.A[1]))
Note that c is always positive.
As a side note, you don't need the angleB variable in your code.
You are using a and b to represent dx and dy, and always starting at A. Think about whether it can be right to always do right(90) (hint, it cannot). If B is vertically above A you will go down instead of up (if you adopt the abs mentioned by Selcuk).
One really simply way to do this is to just point back towards point A in the turtle code. You can do this with
Shape.turtle.setheading(Shape.turtle.towards(self.A))
in the place of
Shape.turtle.right(180-angleA)
This is definitely the least truly mathematical way to solve this but it does work quite nicely.

OR-TOOLS google how to tell the solver to stop when reaching a certain result

I have a simple 3d assignment problem.
I'm randomly generating integer numbers between 0 and 100 for a cost matrix.
I've noticed that when the size of the problem is large enough say 40 assigments.(40X40X40 cost matrix).The total cost reaches 0. which makes sense.
as the matrix grows bigger I assume there are more ways to reach the desired results and I Don't expect the solve time to rise exponentially.
But id does.
I assume this is because the algorithm isn't satisficed with a zero result until it is absolutely sure its optimal.
My question is is there a way to tell the solver to stop when it reaches a certain total cost?
I haven't found that option in the docs
when I try to limit the time
solver.SetTimeLimit(TIME)
the solver simply cant find a solution.
I tried adding the constraint suggested in one of the answers (total cost>=0) but it had no effect.
when adding the following line for a 20X20X20 problem
solver.Add(solver.Objective().Value() >= 1)
the solver cant find a solution
but when adding
solver.Add(solver.Objective().Value() >= 0)
it find a solution with total cost of 4 why can't it find the same solution with the first constraint?
and how do I tell it to stop when reaching 0?
solver.Add(solver.Objective().Value() >= 0)
does not do what you expect. solver.Objective() is a class of type MPObjective. Calling Value() on it checks is a solution has been found, and returns 0 if this is not the case.
So in practice, you are executing:
solver.Add(0 >= 0)
which is a no op.
In order to limit the objective, you should create one integer variable new_var from 0 to sum(cost_coefficients), then add new_var = sum(cost_coefficients * bool_vars), and finally minimize new_var.
there is a link to solution - https://github.com/google/or-tools/issues/1439
You need to set RoutingMonitor Class and connect with AddAtSolutionCallback.
def make_routing_monitor(routing_model: pywrapcp.RoutingModel, stop_objective: int, failure_limit: int) -> callable:
class RoutingMonitor:
def __init__(self, model: pywrapcp.RoutingModel):
self.model = model
self._counter = 0
self._best_objective = float('inf')
self._counter_limit = failure_limit
self._stop_objective = stop_objective
def __call__(self):
if self._stop_objective==self.model.CostVar().Min():
self.model.solver().FinishCurrentSearch()
return RoutingMonitor(routing_model)
And connect to the solver:
routing_monitor = make_routing_monitor(routing, data['total_distance'] ,0)
routing.AddAtSolutionCallback(routing_monitor)
solution = routing.SolveWithParameters(search_parameters)

Creating a monte carlo simulation from a loop python

I am attempting to calculate the probablility of a for loop returning a value lower than 10% of the initial value input using a monte-carlo simulation.
for i in range(0, period):
if i < 1:
r=(rtn_daily[i]+sig_daily[i]*D[i])
stock = stock_initial * (1+r)
elif i >=1:
r=(rtn_daily[i]+sig_daily[i]*D[i])
stock = stock * (1+r)
print(stock)
This is the for-loop that I wish to run a large number of times (200000 as a rough number) and calculate the probability that:
stock < stock_initial * .9
I've found examples that define their initial loop as a function and then will use that function in the loop, so I have tried to define a function from my loop:
def stock_value(period):
for i in range(0, period):
if i < 1:
r=(rtn_daily[i]+sig_daily[i]*D[i])
stock = stock_initial * (1+r)
elif i >=1:
r=(rtn_daily[i]+sig_daily[i]*D[i])
stock = stock * (1+r)
return(stock)
This produces values for 'stock' that don't seem to fit the same range as before being defined as a function.
using this code I tried to run a monte-carlo simulation:
# code to implement monte-carlo simulation
number_of_loops = 200 # lower number to run quicker
for stock_calc in range(1,period+1):
moneyneeded = 0
for i in range(number_of_loops):
stock=stock_value(stock_calc)
if stock < stock_initial * 0.90:
moneyneeded += 1
#print(stock) this is to check the value of stock being produced.
stock_percentage = float(moneyneeded) / number_of_loops
print(stock_percentage)
but this returns no results outside the 10% range even when looped 200000 times, it seems the range/spread of results gets hugely reduced in my defined function somehow.
Can anyone see a problem in my defined function 'stock_value' or can see a way of implementing a monte-carlo simulation in a way I've not come across?
My full code for reference:
#import all modules required
import numpy as np # using different notation for easier writting
import scipy as sp
import matplotlib.pyplot as plt
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#collect variables provided by the user
stock_initial = float(12000) # can be input for variable price of stock initially.
period = int(63) # can be edited to an input() command for variable periods.
mrgn_dec = .10 # decimal value of 10%, can be manipulated to produce a 10% increase/decrease
addmoremoney = stock_initial*(1-mrgn_dec)
rtn_annual = np.repeat(np.arange(0.00,0.15,0.05), 31)
sig_annual = np.repeat(np.arange(0.01,0.31,0.01), 3) #use .31 as python doesn't include the upper range value.
#functions for variables of daily return and risk.
rtn_daily = float((1/252))*rtn_annual
sig_daily = float((1/(np.sqrt(252))))*sig_annual
D=np.random.normal(size=period) # unsure of range to use for standard distribution
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# returns the final value of stock after 63rd day(possibly?)
def stock_value(period):
for i in range(0, period):
if i < 1:
r=(rtn_daily[i]+sig_daily[i]*D[i])
stock = stock_initial * (1+r)
elif i >=1:
r=(rtn_daily[i]+sig_daily[i]*D[i])
stock = stock * (1+r)
return(stock)
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# code to implement monte-carlo simulation
number_of_loops = 20000
for stock_calc in range(1,period+1):
moneyneeded = 0
for i in range(number_of_loops):
stock=stock_value(stock_calc)
if stock < stock_initial * 0.90:
moneyneeded += 1
print(stock)
stock_percentage = float(moneyneeded) / number_of_loops
print(stock_percentage)
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Posting an answer as I don't have the points to comment. Some queries about your code - going through these might help you find an answer:
Why have you defined rtn_annual as an array, np.repeat(np.arange(0.00,0.15,0.05), 31)? Since it just repeats the values [0.0, 0.05, 0.1], why not define it as a function?:
def rtn_annual(i):
vals = [0.0, 0.05, 0.1]
return vals[i % 3]
Likewise for sig_annual, rtn_daily, and sig_daily - the contents of these are all straightforward functions of the index, so I'm not sure what the advantage could be of making them arrays.
What does D actually represent? As you've defined it, it's a random variable with mean of 0.0, and standard deviation 1.0. So around 95% of the values in D will be in the range (-2.0, +2.0) - is that what you expect?
Have you tested your stock_value() function even on small periods (e.g. from 0 to a few days) to ensure it's doing what you think it should? It's not clear from your question whether you've verified that it's ever doing the right thing, for any input, and your comment "...(possibly?)" doesn't sound very confident.
Spoiler alert - it almost certainly doesn't. In the function stock_value, your return statement is within the for loop. It will get executed the first time round, when i = 0, and the loop will never get any further than that. This would be the chief reason why the function is giving different results to the loop.
Also, where you say "returning a value lower than 10% of...", I assume you mean "returning a value at least 10% lower than...", since that's what your probability stock < stock_initial * .9 is calculating.
I hope this helps. You may want to step through your code with a debugger in your preferred IDE (idle, or thonny, or eclipse, whatever it may be) to see what your code is actually doing.

How to initialize data for a function that is repeatedly called

This is surely a beginner's question, I'm just having trouble searching for it.
What I want to do is calculate points on a circle for thousands of circles which I will later render. Because I will be rendering many thousands of circles a second, I thought I'd try to avoid unncessary overhead. To do this, I've created a function that calculates a number of points (which I want to be variable, a larger circle will need more points calculated) on a unit circle, and another function which can take these points, translate them and then scale by the radius.
My original code ended up something like this:
class Circle():
...
def CalcCircle(segments):
does some stuff to calculate generic coordinates
def CreateCircle(x, y, r, segments):
does some stuff to create a circle using CalcCircle(segments)
Obviously the problem was that even though I might only want to create circles with 20 segments, I was calling the CalcCircle function (and repeating the same calculations) every time I called CreateCircle.
The only way I could figure out how to fix this was:
class Circle():
...
def CalcCircle(segments):
does some stuff to calculate generic coordinates
CreateCircle_has_not_been_run = True
def CreateCircle(x, y, r, segments):
if Circle.TransCircle_has_not_been_run:
generic_circle = Circle.CalcCircle(segments)
Circle.CreateCircle_has_not_been_run = False
does some stuff to create a circle using generic_circle
I've never formally learnt programming so I'm not sure if this is considered good design. Surely it would become messy if every time I wanted to "initialize" data or call a function only on the first run through I had to make a random class variable. The reason I ask is I'm constantly running into this problem, so I assume there must be a standard way of doing it.
Edit: An example of how the call will be made.
#window.event
def on_draw():
window.clear()
width = window.get_size()[0]
height = window.get_size()[1]
radius = int(width/50)
segments = int(radius*1.5)
for i in range(N):
pyglet.gl.glColor3f(0.05,0.2,0.9)
DrawCircle(positions[i][0],positions[i][1],width,segments)
DrawCage(width,height)
DrawLabel(width,height)
etc.
I'm aware that there's problems here but I'm just trying to illustrate the example (positions comes from the update function if anyone is wondering). As I've said earlier, this is a problem I run into all the time.
I could call Circle.CalcCircle() from the on_resize() function as per Achim's suggestion. I have a hard time believing however that standard practice is to stick two random functions into a class (as it stands neither of them necessarily need to even be in the Circle class), one of which is implicitly dependent on the other and both of which are called in different parts of the code.
I would do something like this:
class Circle:
def __init__(self):
self.unit_circle_points = None
def CalcCircle(self, segments):
# Do some stuff to calculate segments,
# assign calculated values to class attribute
self.unit_circle_points = calculated_points
def CreateCircle(self, X, y, r, segments):
# If circle points have not yet been calculated then calculate
# and store, else just load stored points
if self.unit_circle_points is None:
self.CalcCircle(segments)
unit_circle_points = self.unit_circle_points
# Now use unit_circle_points to do some calculations
Every time you instantiate a circle object it will come with an attribute named unit_circle_points that is initialized to None. When you call the CreateCircle method on that object for the first time it will see that the unit_circle_points attribute is None and perform the necessary computations by calling CalcCircle, storing the results. On subsequent calls to the CreateCircle method of this Circle object the unit_circle_points attribute will no longer be None, and the method will simply use the values stored in the attribute.
Edit:
If this requires to much "implicit" behavior for your taste, you can shift things around so that CalcCircle must be called explicitly by the user to generate the pre-calculated data.
class Circle:
def __init__(self):
self.unit_circle_points = None
def CalcCircle(self, segments):
# Do some stuff to calculate segments,
# assign calculated values to class attribute
self.unit_circle_points = calculated_points
return self
def CreateCircle(self, X, y, r):
# If circle points have not yet been calculated then raise an error,
# else load previously calculated points
if self.unit_circle_points is None:
raise Exception("You'd better explicitly call CalcCircle first.")
unit_circle_points = self.unit_circle_points
# Now use unit_circle_points to do some calculations

What is the most effective way to incremente a large number of values in Python?

Okay, sorry if my problem seems a bit rough. I'll try to explain it in a figurative way, I hope this is satisfactory.
10 children. 5 boxes. Each child chooses three boxes. Each box is opened:
- If it contains something, all children selected this box gets 1 point
- Otherwise, nobody gets a point.
My question is about what I put in bold. Because in my code, there are lots of kids and lots of boxes.
Currently, I proceed as follows:
children = {"child_1" : 0, ... , "child_10": 0}
gp1 = ["child_3", "child_7", "child_10"] #children who selected the box 1
...
gp5 = ["child_2", "child_5", "child_8", "child_10"]
boxes = [(0,gp1), (0,gp2), (1,gp3), (1,gp4), (0,gp5)]
for box in boxes:
if box[0] == 1: #something inside
for child in box[1]:
children[child] += 1
I worry mainly about the for loop that assigns each child an extra point. Because in my final code, I have many many children, I fear that doing so would slow the program too.
Is there a more efficient way for all children of the same group may have their point faster?
Represent children as indices into arrays, not as strings:
childrenScores = [0] * 10
gp1 = [2,6,9] # children who selected box 1
...
gp5 = [1,4,7,9]
boxes = [(0,gp1), (0,gp2), (1,gp3), (1,gp4), (0,gp5)]
Then, you can store childrenScores as a NumPy array and use advanced indexing:
childrenScores = np.zeros(10, dtype=int)
...
for box in boxes:
if box[0]:
childrenScores[box[1]] += 1 # NumPy advanced indexing
This still involves a loop somewhere, but the loop is deep inside NumPy instead, which should provide a meaningful speedup.
The only speed up that I can think of is to use numpy arrays and stream the sum operation.
children[child] += np.ones(len(children[child]))
You should benchmark the operation and see if that is too slow for your business case.
What I would do
In the gpX lists don't save the "name of the child" (e.g. "child_10") but save a reference to the child's number of points.
How to do that
Using the fact that lists are objects in python, you can:
Change the children dict to look like: children = {"child_0": [0], "child_1": [0], ...} and so on.
When you assign to group, don't assign the key but assign the value (e.g. gp1.append(children["child_0"])).
The loop should then look like: for child in box[1]: child[0]+=1. This WILL update the children dict.
EDIT:
Why this is faster:
Because you leave out the part where you search for children[child], which might be costly.
This technique works because by storing the totals in a mutable type, and appending those values to the group lists, both the dict value and each box's list value will point to the same list entries, and changing one will change the other.
Two general points:
(1) Based on what you've told us, there's no reason to focus your energy on minor performance optimizations. Your time would be better spent thinking about ways to make your data structures less awkward and more communicative. A bunch of interrelated dicts, lists, and tuples quickly becomes difficult to maintain. For an alternative, see the example below.
(2) As the game designer, you understand that events follow a certain sequence: first the kids select their boxes, and later they discover whether they get points for them. But you don't have to implement it that way. A kid can choose a box and get points (or not) immediately. If there's a need to preserve the child's ignorance about such outcomes, the parts of your algorithm that depend on such ignorance can enforce that veil of secrecy as needed. The upshot: there is no need for a box to loop through its children, awarding points to each one; instead, award the points immediately to kids as boxes are selected.
import random
class Box(object):
def __init__(self, name):
self.name = name
self.prize = random.randint(0,1)
class Child(object):
def __init__(self, name):
self.name = name
self.boxes = []
self.score = 0
self._score = 0
def choose(self, n, boxes):
bs = random.sample(boxes, n)
for b in bs:
self.boxes.append(b)
self._score += b.prize
def reveal_score(self):
self.score = self._score
boxes = [Box(i) for i in range(5)]
kids = [Child(i) for i in range(10)]
for k in kids:
k.choose(3, boxes)
# Later in the game ...
for k in kids:
k.reveal_score()
print (k.name, k.score), '=>', [(b.name, b.prize) for b in k.boxes]
One way or another, you're going to be looping over the children, and your answer appears to avoid looping over children who don't get any points.
It might be slightly faster to use filter or itertools.ifilter to pick the boxes that have something in them:
import itertools
...
for box in itertools.ifilter(lambda x: x[0], boxes):
for child in box[1]
children[child] += 1
If you don't need to immediately print the number of points for every child, you could calculate it on demand, thus saving time. This could help if you only need to query a child every now and then for how many points it has. You can cache each result as you obtain is so you don't go about calculating it again the next time you need it.
Firstly, you'll need to know which groups a child belongs to. We'll store this information as map we'll call childToGroupsMap, which will map each child to an array holding the boxes it belongs to, like so:
childToGroupsMap = {}
for child in children:
childToGroupsMap[child[0]] = []
for box in boxes:
for child in box[1]:
if (box[1] not in childToGroupsMap[child]):
childToGroupsMap[child].append(box[1])
This constructs the reverse map from children to boxes.
It'll also help to have a map from each box to a boolean representing whether it's been opened:
boxToOpenedMap = {}
for box in boxes:
boxToOpenedMap[box[1]] = box[0]
Now, when someone queries how many points a child has, you can go through each of the boxes it belongs to (using childToGroupsMap, of course), and simply count how many of those boxes have been mapped to 1 in the map boxes:
def countBoxesForChild(child):
points = 0
for box in childToGroupsMap[child]
if boxToOpenedMap[box] == 1:
points += 1
return points
To make this better, you can cache the resulting number of points. Make a map like so:
childToPointsCalculated = {}
for child in children:
childToPointsCalculated[child[0]] = -1
Where the -1 denotes that we don't yet know how many points this child has.
Finally, you can modify your countBoxesForChild function to exploit the cache:
def countBoxesForChild(child):
if childToPointsCalculated[child] != -1
return childToPointsCalculated[child]
points = 0
for box in childToGroupsMap[child]
if boxToOpenedMap[box] == 1:
points += 1
childToPointsCalculated[child] = points
return points

Categories