I'm trying to create a program that runs a basic simulation.
Create a row of ten boxes, let a random number generator pick which direction he moves, and keep track of him.
The problem for the last while now is that the initial position is not being friendly.
I want to start in the middle - five - but no matter where I put that line, I get an error.
Here's the code:
import random
def right_movement():
p = p + 1
m = m + 1
times[p] = p
print times
def left_movement():
p = p - 1
m = m + 1
times[p] =+ 1
def main():
p = 5
times = [0] * 11
times[p] = 1
m = 0
print times
while p >= 0 and p <= 10:
x = random.randint(0, 1)
if x > 0:
right_movement()
else:
left_movement()
if p == 11:
print "Movement to the right into location 11."
print "Number of moves is " + m + "."
else:
print "Movement to the left into location 0."
print "Number of moves is " + m + "."
main()
No matter where I put p = 5, I get an error in reference to that. I'm running Python 2.7.
The problem is related to something called scope.
In a nutshell, what you did is you first created a variable called "p" within your main function. However, that does not mean that the other functions you create will be able to know that p exists.
I think this might be easier to understand if I give an example. In the first line of right_movement, you do p = p + 1. Since you're using p to add 1 to it, Python is going to look to see if you've assigned the variable p within right_movement. Since you didn't, it's going to sort of "move up" a layer, and see if you assigned the variable p within the file in general. Since you didn't assign p in either of those (you assigned inside main), Python will give up.
There are several solutions to this. The quick-and-dirty one would be to use something called "global" variables, and would look like this:
import random
p = 5
m = 0
times = [0] * 11
def right_movement():
global p
global m
global times
p = p + 1
m = m + 1
times[p] = p
print times
def left_movement():
global p
global m
global times
p = p - 1
m = m + 1
times[p] =+ 1
print times
def main():
times[p] = 1
print times
while p >= 0 and p <= 10:
x = random.randint(0, 1)
if x > 0:
right_movement()
else:
left_movement()
if p == 11:
print "Movement to the right into location 11."
print "Number of moves is " + str(m) + "."
else:
print "Movement to the left into location 0."
print "Number of moves is " + str(m) + "."
main()
You move the p, m, and times variables outside of the main function to the file, and make sure to use the global keyword to let Python know that you want to modify the variables inside the function, rather then temporarily creating a new one.
However, this isn't the cleanest solution -- using global variables is considered bad practice for a variety of reasons.
A better solution might be to keep track of the state within main, and rewrite your code to look like this:
import random
def right_movement(times, p):
p += 1
times[p] += 1
return p
def left_movement(times, p):
p -= 1
times[p] =+ 1
return p
def main():
p = 5
moves = 0
times = [0] * 11
times[p] = 1
print times
while 0 <= p <= 10:
moves += 1
x = random.randint(0, 1)
if x > 0:
p = right_movement(times, p)
else:
p = left_movement(times, p)
print times
if p == 11:
print "Movement to the right into location 11."
print "Number of moves is " + str(moves) + "."
else:
print "Movement to the left into location 0."
print "Number of moves is " + str(moves) + "."
main()
You are trying to share the same variables among several functions, without passing the values in to the functions as arguments. In order to do this, you need to use global variables.
Something like this:
import random
p = 5
times = [0] * 11
m = 0
def right_movement():
global p, times, m
p = p + 1
...
So, first you need to declare the variables outside of any function, then you need that global statement in each function that uses the variables.
Related
The outer while loop should exit when current_digit and powers[digit_of_powers] both equal 26 but the while-loop doesn't exit as it should.
As a proof of what I'm claiming, see for yourself, the last line never executes. The program is stuck in the stopped while loop.
I'm new to programming so I may do daft mistakes
#enter a number in base 10 and find how it's written in choosen base... or at least thats what it should do
import math
def find_powers(num, base, start_num): #stackoverflow experts, this function is not important for my problem
power = 1 # power starts as a '1' each iteration
while start_num + power <= num:
power *= base
if start_num != num:
power /= base
powers.append(round(math.log(power, base)))
find_powers(num, base, start_num + power)
num = 7892 #enter choosen number in base 10 here
base = 10 #enter choosen base here. I put ten because its much easier to check the program with a base I'm familiar with
powers = []
find_powers(num, base, 0)
print(powers)
print('')
check = 0 #this script is not necessary, it's just a way for me to check if it can find the input of the def find_powers function from its output.
for i in powers: # It if it does then the function still work
check += base**i
print(check)
print('')
string = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'
digits = []
# Two things to check here
# 1. if powers[i] misses a digit or not.
# If it does, digits.append(0)
# 2. How many times the same power comes (it'll always be in row)
digit_of_powers = 0
while digit_of_powers != len(powers):
digit_of_powers += 1
print('digits_of_powers = ' + str(digit_of_powers))
current_digit = powers[digit_of_powers]
print('current_digit = ' + str(current_digit))
print('powers[digit_of_powers] = ' + str(powers[digit_of_powers]))
print('')
digit_thatll_go_in_digits = 1
while current_digit == powers[digit_of_powers]:
digit_thatll_go_in_digits += 1
digit_of_powers += 1
print('digit_thatll_go_in_digits = ' + str(digit_thatll_go_in_digits))
print('digits_of_powers = ' + str(digit_of_powers))
print(digits)
print('while ' + str(digit_of_powers) + ' != ' + str(len(powers)))
print('while ' + str(current_digit) + ' == ' + str(powers[digit_of_powers]))
print('')
digits.append(digit_thatll_go_in_digits)
print('fin du while')
print('')
print('this last line never executes for some reason')
You are increasing (conditionally) digit_of_powers twice, but condition is exact value while digit_of_powers != len(powers): (not equal)
It means that your code can jump over this condition and run further.
For example, if len(powers) == 10, digit_of_powers + 1 + 1 will increase from 9 to 11 and can be never the same.
Try this:
while digit_of_powers <= len(powers): (if it starts with 1)
or
while digit_of_powers < len(powers): (if it starts with 0)
I need to create a percentage increase in python.
My code is as follows:
(x = 135,000)
x = x_1.strip()
xspl = x.split(",")
i=0
for i in range(len(xspl)-1):
if i == 0:
xnum = xspl[i].join(xspl[i+1])
else:
xnum = xnum.join(xspl[i])
calcnum2 = (int(xnum)-xPrev/xPrev)*100
k=0
for k in range(len(str((calcnum2)))):
if str(calcnum2)[k] == '.': #looks for decimal place to make 2 d.p.
subnum2 = str(calcnum2)[:k+3]
break
else:
pass
print(deceased,'(+',subnum2 + '%)')
xPrev = int(xnum)
However, it does not make the number to 2 decimal places and actually outputs:
(+ 61356135100.0%)
Does anyone know what is happening here?
I have a search algorithm that looks for combinations of add and multiply functions to reach a certain range of number from a certain range of numbers. It is searching for the shortest program, a program being a something like AAMMA where the initial number is added, added, multiplied, multiplied, add where the ending number is in the range r to s. It has to work for every number in the starting range p to q.
The input is a and m, what you are adding and multiplying by(num+a), (num*m) for each function. What I am doing is trying every combination of functions until I find one that works, stopping that branch if it gets too big. If I find "program" that works I try the program on all of the other numbers in the starting range. It does this until either it finds no branches that don't reach the range without going over.
I know the search isn't super typical, but I don't think there is a possibility for duplicates so I didn't include a found list.
It works for smaller ranges and inputs like
Problem3("1 2 2 3 10 20")
but for larger ranges, it just takes forever my test case is
Problem3("8 13 28 91 375383947 679472915")
which I haven't even seen complete. What is my best approach from here, multithreading(hope not), making my inner functions faster somehow or just scraping this approach.
def Problem3(s):
a,m,p,q,r,s = list(map(int, s.split(" ")))
print(str(a) + "-C-" + str(m) + " processor")
print("Input guarenteed between " + str(p) + " and " + str(q))
print("Output is real number between " + str(r) + " and " + str(s))
open_set = queue.Queue()
# curr path depth
open_set.put([p, "", 0])
while not open_set.empty():
subroot = open_set.get()
multiCurr = subroot[0] * m
addCurr = subroot[0] + a
depth = subroot[2] + 1
if r <= addCurr <= s:
truePath = True
#If we find a working path, we need to check if it works for the other things
path = subroot[1] + "A"
for x in range(p, q+1):
for op in path:
if op == "A":
x += a
if op == "M":
x *= m
if r <= x <= s:
pass
else:
truePath = False
break
if truePath:
print("Found " + path + " at depth " + str(depth) + " with starting number " + str(p) + ", output " + str())
if r <= multiCurr <= s:
truePath = True
path = subroot[1] + "M"
for x in range(p, q+1):
for op in path:
if op == "A":
x += a
if op == "M":
x *= m
if r <= x <= s:
pass
else:
truePath = False
break
if truePath:
print("Found " + path + " at depth " + str(depth) + " with starting number " + str(p) + ", output " + str())
if addCurr > s and multiCurr > s:
pass
elif multiCurr > s:
open_set.put([addCurr, subroot[1] + "A", depth])
elif addCurr > s:
open_set.put([multiCurr, subroot[1] + "M", depth])
else:
open_set.put([multiCurr, subroot[1] + "M", depth])
open_set.put([addCurr, subroot[1] + "A", depth])
You don't need to test every value in the range(p, q + 1) sequence. You only need to test for p and q. If it works for the lowest and the highest number, it'll work for all the values in between, because the problem has been reduced to just multiplication and addition. You really only need to test the progress of program(q), keeping it below s, until you have created the shortest program that puts program(p) at or above r.
However, this isn't really a great problem for breath-first search; your second example would require testing 17.6 trillion possible states; the shortest solution is 44 characters long, so a breath-first search would explore 2 ** 44 states, so 17,592,186,044,416 to be exact! Even using a compiled programming language like C would take a long, long time to find the solution using such a search. Instead, you can just generate the string using a bit of math.
You can calculate the maximum number of multiplications needed here with int(math.log(s // q, m)), that's the number of times you can multiply with m when starting at q and still stay below s. You can't ever use more multiplications! With math.ceil(math.log(r / p, m)) you can find the minimum number of multiplications that would put p at or above r. To minimise the program length, pick the lower value of those two numbers.
Then, start fitting in A additions, before each M multiplication. Do so by taking i as the number of M characters that are to follow, then dividing both r and s by m ** i. These inform the number a additions to p and q that together with the subsequent multiplications bring it closest to r and s; the difference with the current p and q let you calculate the minimum number of A characters you can insert here to keep within the [r, s] range. For p, round up, for q, round down.
Repeat this procedure for every subsequent M operation, updating the p and q values with the results each time:
import math
def problem3(s):
a, m, p, q, r, s = map(int, s.split())
p_mult = math.ceil(math.log(math.ceil(r / p), m))
q_mult = int(math.log(s // q, m))
mult = min(p_mult, q_mult)
program = []
for i in range(mult, -1, -1):
p_additions = math.ceil((math.ceil(r / (m ** i)) - p) / a)
q_additions = ((s // (m ** i)) - q) // a
additions = min(p_additions, q_additions)
program += [additions * 'A']
if i:
p, q = (p + (additions * a)) * m, (q + (additions * a)) * m
program += ['M']
return ''.join(program)
This is a closed-form solution, no search needed. The result is guaranteed to be the shortest:
>>> problem3("1 2 2 3 10 20")
'AMM'
>>> problem3("8 13 28 91 375383947 679472915")
'AAAAAAMAAMAAAAAAAAAAAMAAAAAMAAAMAAAAMAAAAAAA'
I just made a function to generate a list of running ids between a given range. IDs begin with an alphabet and follow with 5 numbers (e.g. A00002). The function below works, but I was wondering if there was a cleaner way to do this. Thanks!
def running_ids(start, end):
list = []
start = int(start[1:])
end = int(end[1:])
steps = end - start
def zeros(n):
zeros = 5 - len(str(n))
return zeros
while start <= end:
string = "A" + "0"*zeros(start) + str(start)
list.append(string)
start += 1
return list
print running_ids('A00001', 'A00005')
['A00001', 'A00002', 'A00003', 'A00004', 'A00005']
Use a generator. This way you can generate the numbers as needed and not store them all at once. It also maintains the state of your counter, useful if you start building large projects and you forget to add one to your index. It's a very powerful way of programming in Python:
def running_id():
n = 1
while True:
yield 'A{0:05d}'.format(n)
n += 1
C = running_id()
for n in xrange(5):
print next(C)
Giving:
A00001
A00002
A00003
A00004
A00005
You could just use simple builtin string formatting:
>>> 'A%05d'%1
'A00001'
>>> 'A{0:05d}'.format(1)
'A00001'
You can use the builtin format method
print "A" + format(1, "05d") # A00001
print "A" + format(100, "05d") # A00100
Or you can use str.zfill method like this
print "A" + str(1).zfill(5) # A00001
print "A" + str(100).zfill(5) # A00100
def running_ids(start, end):
t = start[0]
low = int(start[1:])
high = int(end[1:]) + 1
res = []
for x in range(low, high):
res.append(t + '{0:05d}'.format(x))
return res
print(running_ids('A00001', 'A00005'))
I'm trying to write a function that calls a function (roll die() which rolls a die 1000 times and counts on a list [1,2,3,4,5,6] so an outcome might be [100,200,100,300,200,100]) and tells it to run it x amount of times. It seems my code is printing it over and over again x times
#simulate rolling a six-sided die multiple tiems, and tabulate the results using a list
import random #import from the library random so you can generate a random int
def rollDie():
#have 6 variables and set the counter that equals 0
one = 0
two = 0
three = 0
four = 0
five = 0
six = 0
#use a for loop to code how many times you want it to run
for i in range(0,1000):
#generate a random integer between 1 and 6
flip = int(random.randint(1,6))
# the flip variable is the the number you rolled each time
#Every number has its own counter
#if the flip is equal to the corresponding number, add one
if flip == 1:
one = one + 1
elif flip == 2:
two = two + 1
elif flip == 3:
three = three + 1
elif flip == 4:
four = four + 1
elif flip == 5:
five = five + 1
elif flip == 6:
six = six + 1
#return the new variables as a list
return [one,two,three,four,five,six]
the new function that I am having problems with is:
def simulateRolls(value):
multipleGames = rollDie() * value
return multipleGames
I would like to see a result like this if you typed in 4 for value
[100,300,200,100,100,200]
[200,300,200,100,100,100]
[100,100,100,300,200,200]
[100,100,200,300,200,100]
Can someone guide me in the right direction?
You can get what you want like this:
def simulateRolls(value):
multipleGames = [rollDie() for _ in range(value)]
return multipleGames
By the way, your original function seems to work perfectly fine, but if you're interested, you can remove some redundancy like this:
def rollDie():
#have 6 variables and set the counter that equals 0
results = [0] * 6
#use a for loop to code how many times you want it to run
for i in range(0,1000):
#generate a random integer between 1 and 6
flip = int(random.randint(1,6))
# the flip variable is the the number you rolled each time
results[flip - 1] += 1
return results
The line
multipleGames = rollDie() * value
will evaluate rollDie() once and multiply the result by value.
To instead repeat the call value times do this.
return [rollDie() for i in xrange(value)]
You can also simplify your rollDie function by working with a list throughout
import random #import from the library random so you can generate a random int
def rollDie():
result = [0] * 6
for i in range(0,1000):
result[random.randint(0,5)] += 1
return result