I'm trying to emulate a really simple version of the gamble game "Crash", where there's a number that increases every second and it's also the multiplier of your credits. So if you put in 50 credits and the multiplier goes to 3.30, you will get 50*3.30=165 credits. The number randomly crashes, and if you did not withdraw your money, you lose them.
from random import randrange, randint
crash_max_range = 50
crash_min_range = 0
multiplier_crash = list(range(crash_min_range, crash_max_range))
multiplier_crash = [float(i) for i in multiplier_crash]
print(*multiplier_crash, sep="\n")
The main thing that i'm struggling with is printing the float list which should look like
0
0.01
0.02
0.03
etc.. (every number on a new line)
I don't also know how to increase the chance that it will crash like 70% of the time at a low range because obviously the player can't always win.
Could you help me with that?
For a simulation you would normally use a loop that does one step at a time. I suggest using an infinite loop and a break statement on a random condition.
Inside this loop you will only need to print a single value in every print. You should use the str.format() method for any new code.
The code might then look like this:
import random
multiplier = 1.00
while True:
print('{:.2f}'.format(multiplier))
if random.random() < 0.1:
break
multiplier += 0.01
print('CRASH')
The above example is not perfect, because floating point errors accumulate when it is run for a long time. It might be better to use an integer and scale it for output.
Using itertools you can do it like this.
import itertools
import random
for i in itertools.count(100):
multiplier = float(i) / 100.0
print('{:.2f}'.format(multiplier))
if random.random() < 0.1:
break
print('CRASH')
This could be further simplified using generator expressions. However, the code might be less clear when you are just beginning pyhton.
import itertools
import random
for multiplier in (float(i) / 100.0 for i in itertools.count(100)):
print('{:.2f}'.format(multiplier))
if random.random() < 0.1:
break
print('CRASH')
I'm not clear on the crashing story, but if you're wanting the float list to be printed in increments of .01 up to like that, one thing you could do is to change these two lines like this:
multiplier_crash = list(range(crash_min_range, crash_max_range * 100))
multiplier_crash = [float(i) / 100 for i in multiplier_crash]
That will print the initial 0 as 0.0, though ... if you want numbers like 0 and 1 and so on to print without the trailing .0 as in your example, one way you could do that would be to replace the second line above like this:
multiplier_crash = ["{:,g}".format(float(i) / 100) for i in multiplier_crash]
Related
I am currently working on a program to calculate 100,000 digits of the first sophomore's dream constant, I1. It's given by the sum below.
After about 10,000 terms in this series it gets quite slow. I opted to write the program so small because I wanted to see how small I could make it
from decimal import *
def sophodream(a):
s,i,t=0,1,int(a*1.5)
while i<t:
print(i)
n,d=Decimal(pow(-1,i+1)),Decimal(i**i)
f=n/d
s+=f
i+=1
return s
I would like to know if there are any ways to speed this up aside from multithreading/multiprocessing. I find that when I do series like these in threaded pieces the accuracy of them gets lower.
There are some minor changes / simplifications that can be made to your code but as has already been noted, you're working (at times) with some very big numbers.
from decimal import getcontext, Decimal
def sophodream(a):
s, p = 0, 1
getcontext().prec = a
for i in range(1, int(a * 1.5)):
s += p / Decimal(i**i)
p = -p
return s
print(sophodream(100))
Output:
0.7834305107121344070592643865269754694076819901469309582554178227016001845891404456248642049722689389
Obviously just a very short version to prove functionality
I've been running some code for an hour or so using a rand.int function, where the code models a dice's roll, where the dice has ten faces, and you have to roll it six times in a row, and each time it has to roll the same number, and it is tracking how many tries it takes for this to happen.
success = 0
times = 0
count = 0
total = 0
for h in range(0,100):
for i in range(0,10):
times = 0
while success == 0:
numbers = [0,0,0,0,0,0,0,0,0,0]
for j in range(0,6):
x = int(random.randint(0,9))
numbers[x] = 1
count = numbers.count(1)
if count == 1:
success = 1
else:
times += 1
print(i)
total += times
success = 0
randtst = open("RandomTesting.txt", "a" )
randtst.write(str(total / 10)+"\n")
randtst.close()
And running this code, this has been going into a file, the contents of which is below
https://pastebin.com/7kRK1Z5f
And taking the average of these numbers using
newtotal = 0
totalamounts = 0
with open ('RandomTesting.txt', 'rt') as rndtxt:
for myline in rndtxt: ,
newtotal += float(myline)
totalamounts += 1
print(newtotal / totalamounts)
Which returns 742073.7449342106. This number is incorrect, (I think) as this is not near to 10^6. I tried getting rid of the contents and doing it again, but to no avail, the number is nowhere near 10^6. Can anyone see a problem with this?
Note: I am not asking for fixes to the code or anything, I am asking whether something has gone wrong to get the above number rather that 100,000
There are several issues working against you here. Bottom line up front:
your code doesn't do what you described as your intent;
you currently have no yardstick for measuring whether your results agree with the theoretical answer; and
your expectations regarding the correct answer are incorrect.
I felt that your code was overly complex for the task you were describing, so I wrote my own version from scratch. I factored out the basic experiment of rolling six 10-sided dice and checking to see if the outcomes were all equal by creating a list of length 6 comprised of 10-sided die rolls. Borrowing shamelessly from BoarGules' comment, I threw the results into a set—which only stores unique elements—and counted the size of the set. The dice are all the same value if and only if the size of the set is 1. I kept repeating this while the number of distinct elements was greater than 1, maintaining a tally of how many trials that required, and returned the number of trials once identical die rolls were obtained.
That basic experiment is then run for any desired number of replications, with the results placed in a numpy array. The resulting data was processed by numpy and scipy to yield the average number of trials and a 95% confidence interval for the mean. The confidence interval uses the estimated variability of the results to construct a lower and an upper bound for the mean. The bounds produced this way should contain the true mean for 95% of estimates generated in this way if the underlying assumptions are met, and address the second point in my BLUF.
Here's the code:
import random
import scipy.stats as st
import numpy as np
NUM_DIGITS = 6
SAMPLE_SIZE = 1000
def expt():
num_trials = 1
while(len(set([random.randrange(10) for _ in range(NUM_DIGITS)])) > 1):
num_trials += 1
return num_trials
data = np.array([expt() for _ in range(SAMPLE_SIZE)])
mu_hat = np.mean(data)
ci = st.t.interval(alpha=0.95, df=SAMPLE_SIZE-1, loc=mu_hat, scale=st.sem(data))
print(mu_hat, ci)
The probability of producing 6 identical results of a particular value from a 10-sided die is 10-6, but there are 10 possible particular values so the overall probability of producing all duplicates is 10*10-6, or 10-5. Consequently, the expected number of trials until you obtain a set of duplicates is 105. The code above took a little over 5 minutes to run on my computer, and produced 102493.559 (96461.16185897154, 108525.95614102845) as the output. Rounding to integers, this means that the average number of trials was 102493 and we're 95% confident that the true mean lies somewhere between 96461 and 108526. This particular range contains 105, i.e., it is consistent with the expected value. Rerunning the program will yield different numbers, but 95% of such runs should also contain the expected value, and the handful that don't should still be close.
Might I suggest if you're working with whole integers that you should be receiving a whole number back instead of a floating point(if I'm understanding what you're trying to do.).
##randtst.write(str(total / 10)+"\n") Original
##randtst.write(str(total // 10)+"\n")
Using a floor division instead of a division sign will round down the number to a whole number which is more idea for what you're trying to do.
If you ARE using floating point numbers, perhaps using the % instead. This will not only divide your number, but also ONLY returns the remainder.
% is Modulo in python
// is floor division in python
Those signs will keep your numbers stable and easier to work if your total returns a floating point integer.
If this isn't the case, you will have to account for every number behind the decimal to the right of it.
And if this IS the case, your result will never reach 10x^6 because the line for totalling your value is stuck in a loop.
I hope this helps you in anyway and if not, please let me know as I'm also learning python.
I'm having some trouble in my pygame application that I'm making. There are buttons in the menu that change how fast my simulation runs (by changing speed in clock.tick(speed*10)). This, however, also slows down the rate that the menu buttons respond. If I ingame set speed anywhere lower than 0.5 the speed and play/pause buttons take up to five seconds to register a click. So I tried creating my own way to work around this:
speed = 1 # defined previously ingame
timeSlow = 0
timeSlowGoal = 0
while True: # game loop
if speed < 1:
timeSlowGoal = reciprocal(speed) # well here's my problem
else:
timeSlowGoal = -1
if timeSlowGoal != -1:
if timeSlow >= timeSlowGoal:
timeSlow = 0
# more code that actually does stuff
else:
timeSlow += 1
# doesn't match, try again
In python, there are tricks like int(),string(), and float() to change a variable. Of course, reciprocal() doesn't work. Is there some sort of function like these that gets the reciprocal of a number, (which in this case is always a decimal) or do I need to just do some fancy math to get it?
(of course if all of this is unnecessary and you have a better solution to my first problem let me know)
EDIT: Okay, there is a very simple solution to this that I overlooked. 1/n is always the reciprocal of n. There's no need for a reciprocal() function because it's so simple. That's what I get for forgetting elementary school math.
Assuming you are using Python 3, change
timeSlowGoal = reciprocal(speed)
to
timeSlowGoal = 1 / speed
Just make sure that you don't try to do that if speed is zero.
I do not know why you are having such a huge piece of code, because Reciprocal of a number can be simply mentioned as: 1/n
So, your reciprocal function can be simply written as:
def reciprocal(n):
return 1.0 / n
Here, I am using 1.0/n instead 1/n as in python for the resultant of division to be fraction, either numerator or denominator should have fraction value.
Sample run:
>>> reciprocal(3)
0.3333333333333333
>>> reciprocal(0.3333333)
3.00000030000003 # Not '3' because of the loss in the precision of value entered
>>> reciprocal(reciprocal(3))
3.0 # Doing reciprocal twice returns "3"
I have a function and I want to let it do things only in 12% of the cases I call it.
I already wrote a function that works, but it's not accurate enough.
Example in Python:
# probability to execute the function is 50%
percent_probability = 50
frequency = 100 / percent_probability
r = random.randint(1, frequency)
if r == 1:
my_function()
This works for percentages like 10%, 20%, etc. but not for 33% because it gets rounded.
How can I do this properly?
I would use random.random() for this, like so:
if random.random() < anz_prozent_wahrscheinlichkeit / 100.:
execute my function()
This uses floating-point maths and is therefore not restricted to integer percentages (for example, anz_prozent_wahrscheinlichkeit = 0.1 would work correctly).
This should do the trick:
r = random.randrange(0, 100)
if r < 12:
my_function()
The easiest method consists in getting a random number between 0 and 1 with random.random() and checking whether it is smaller than 0.12. This is a general method (it also works for percentages with a decimal part…).
i am having trouble figuring out why my timer is not reaching zero when i run it. I am trying to get the window to close when a=0 but a keeping decreasing to negative digits why please? This is my codes
def close_timer(self):
global a
a = float(a - 0.1)
self.labeltext.set(str(("%.1f" % (a))))
a = float(a)
print a
print (a == 0)
if a == 0:
self.canvas.after(100)
self.root.destroy()
self.root.after(100,self.close_timer)
Floating point number math is generally inaccurate - you can't represent a decimal 0.1 in binary floating points exactly, therefore you'll never reach 0:
>>> a = 1
>>> while a > 0:
... a = a - 0.1
... print(repr(a))
...
0.9
0.8
0.7000000000000001
0.6000000000000001
0.5000000000000001
0.40000000000000013
0.30000000000000016
0.20000000000000015
0.10000000000000014
1.3877787807814457e-16
-0.09999999999999987
Use if abs(a) < 0.000001: or something similar.
It's always dangerous to compare floats with fixed values unless you know and mitigate the consequences.
Most likely, your value is getting down to something like:
0.099999923354
as imprecision is gradually injected into your value every time you subtract 0.1 (which is not directly representable in IEEE754).
Then, when you subtract the final 0.1, you get something like:
-0.00000005345
which is not equal to zero.
Quickest fix is to probably change your zero check to be:
if a <= 0:
so that small errors are irrelevant, other than possibly taking an extra cycle (probably a tenth of a second) if it reaches 0.0000001 where it should be zero, for example.
If you want to ensure you don't take that extra cycle and you're confident that the gradually introduced error won't be too large, just change it to:
if a <= 0.0003:
or something similar.