I'm trying to approximate pi using a monte carlo with turtles in python. The code is running well but I've got a problem, my "approximations" are all terribly wrong. I' always get values smaller than 1 so??? My code is here below
import turtle
import math
import random
fred = turtle.Turtle()
fred.speed(0)
fred.up()
wn = turtle.Screen()
wn.setworldcoordinates(-1,-1,1,1)
numdarts = int(input("How many darts will you throw"))
for i in range(numdarts):
x = random.random()
y = random.random()
numIncircle = 0
if i == 0 or i == 1:
fred.up()
fred.goto(x, y)
if fred.distance(0, 0) <= 1:
numIncircle += 1
fred.color("Indianred")
fred.stamp()
fred.up()
else:
numIncircle += 0
fred.color("cyan")
fred.stamp()
fred.up()
else:
fred.goto(x, y)
if fred.distance(0, 0) <= 1:
numIncircle += 1
fred.color("Indianred")
fred.stamp()
fred.up()
else:
numIncircle += 0
fred.color("cyan")
fred.stamp()
fred.up()
piapproximation = float(float(numIncircle) / float(numdarts)) * 4
print piapproximation
wn.exitonclick()
You're setting numIncircle = 0 inside your for loop, effectively losing count each time.
Occasionally it'll count the last one, so the approximation will be 1 / number of darts * 4. This will happen with frequency pi / 4 ≈ 0.78539816339.
Here is my suggestion:
import turtle
import math
import random
fred = turtle.Turtle()
fred.speed(0)
fred.up()
wn = turtle.Screen()
wn.setworldcoordinates(-1,-1,1,1)
numdarts = int(input("How many darts will you throw"))
// this MUST come before the for loop
numIncircle = 0
for i in range(numdarts):
x = random.random() * 2 - 1
y = random.random() * 2 - 1
if i == 0 or i == 1:
fred.up()
fred.goto(x, y)
if fred.distance(0, 0) <= 1:
numIncircle += 1
fred.color("Indianred")
fred.stamp()
fred.up()
else:
numIncircle += 0
fred.color("cyan")
fred.stamp()
fred.up()
else:
fred.goto(x, y)
if fred.distance(0, 0) <= 1:
numIncircle += 1
fred.color("Indianred")
fred.stamp()
fred.up()
else:
numIncircle += 0
fred.color("cyan")
fred.stamp()
fred.up()
piapproximation = float(float(numIncircle) / float(numdarts)) * 4
print piapproximation
wn.exitonclick()
Related
This is a physics simulation constraining balls in a circular area.
I made the original code in Scratch and converted it to Python in Pygame.
When I run the simulation, all the balls were shaking, compared to the original code.
I constrained the velocity to be maximum 20, but it didn't help.
I created substeps for each frame, but that wasn't helping either.
import pygame
import math
import random
screen = pygame.display.set_mode((16*120,9*120))
pygame.display.set_caption('')
clock = pygame.time.Clock()
mx = 16*60
my = 9*60
global x
global y
x = []
y = []
xv = []
yv = []
prevx = []
prevy = []
for i in range(20):
x.append(random.randint(-200,200))
y.append(random.randint(-200,200))
xv.append(0)
yv.append(0)
prevx.append(0)
prevy.append(0)
r = 25
size = 300
sub = 20
maxvel = 20
global dist
global dx
global dy
global d
#points at something
def pointat(px,py):
global d
dx = px-x[i]
dy = py-y[i]
if dy == 0:
if dx < 0:
d = -90
else:
d = 90
else:
if dy < 0:
d = 180+math.atan(dx/dy)
else:
d = math.atan(dx/dy)
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
exit()
screen.fill((10,10,10))
pygame.draw.circle(screen,(100,100,100),(mx,my),size)
for i in range(len(x)):
pygame.draw.circle(screen,(255,255,255),(mx+x[i],my+y[i]*-1),r)
for i in range(len(x)):
prevx[i] = x[i]
prevy[i] = y[i]
for j in range(sub):
x[i] += xv[i]/sub
y[i] += yv[i]/sub
y[i] -= 1/sub
a = 0
for k in range(len(x)-1):
if a == i:
a += 1
dist = math.sqrt(((x[i]-x[a])*(x[i]-x[a]))+((y[i]-y[a])*(y[i]-y[a])))
if dist < r*2:
pointat(x[a],y[a])
x[i] += (math.sin(d)*(dist-(r*2)))
y[i] += (math.cos(d)*(dist-(r*2)))
x[a] -= (math.sin(d)*(dist-(r*2)))
y[a] -= (math.cos(d)*(dist-(r*2)))
dist = math.sqrt((x[i]*x[i])+(y[i]*y[i]))
if dist > size-r:
pointat(0,0)
x[i] += (math.sin(d)*(dist-(size-r)))
y[i] += (math.cos(d)*(dist-(size-r)))
a += 1
xv[i] = x[i]-prevx[i]
yv[i] = y[i]-prevy[i]
if xv[i] > maxvel:
xv[i] = maxvel
if xv[i] < -maxvel:
xv[i] = -maxvel
if yv[i] > maxvel:
yv[i] = maxvel
if yv[i] < -maxvel:
yv[i] = -maxvel
pygame.display.update()
clock.tick(60)
The angle of the trigonometric functions in the math module is measured in Radian, but not in Degrees. d should not be a global variable, you can just return the angle from pointat:
def pointat(px,py):
dx = px-x[i]
dy = py-y[i]
if dy == 0:
if dx < 0:
d = -math.pi/2
else:
d = math.pi/2
else:
if dy < 0:
d = math.pi+math.atan(dx/dy)
else:
d = math.atan(dx/dy)
return d
while True:
# [...]
for i in range(len(x)):
# [...]
for j in range(sub):
# [...]
for k in range(len(x)-1):
if a == i:
a += 1
dist = math.sqrt(((x[i]-x[a])*(x[i]-x[a]))+((y[i]-y[a])*(y[i]-y[a])))
if dist < r*2:
d = pointat(x[a],y[a])
x[i] += (math.sin(d)*(dist-(r*2)))
y[i] += (math.cos(d)*(dist-(r*2)))
x[a] -= (math.sin(d)*(dist-(r*2)))
y[a] -= (math.cos(d)*(dist-(r*2)))
dist = math.sqrt((x[i]*x[i])+(y[i]*y[i]))
if dist > size-r:
d = pointat(0,0)
x[i] += (math.sin(d)*(dist-(size-r)))
y[i] += (math.cos(d)*(dist-(size-r)))
a += 1
Overall, the code in the loops can be simplified a lot. I suggest to refactor your code as follows:
while True:
# [...]
for i in range(len(x)):
prevx[i] = x[i]
prevy[i] = y[i]
for j in range(sub):
x[i] += xv[i]/sub
y[i] += yv[i]/sub
y[i] -= 1/sub
for a in range(len(x)):
if a == i:
continue
dx = x[i]-x[a]
dy = y[i]-y[a]
dist = math.sqrt(dx*dx + dy*dy)
if dist < r*2 and dist != 0:
x[i] -= dx/dist * (dist-r*2)
y[i] -= dy/dist * (dist-r*2)
x[a] += dx/dist * (dist-r*2)
y[a] += dy/dist * (dist-r*2)
dist = math.sqrt(x[i]*x[i] + y[i]*y[i])
if dist > size-r:
x[i] -= x[i]/dist * (dist-(size-r))
y[i] -= y[i]/dist * (dist-(size-r))
xv[i] = max(-maxvel, min(maxvel, x[i]-prevx[i]))
yv[i] = max(-maxvel, min(maxvel, y[i]-prevy[i]))
I've been working on a program for the Microbit inspired by some basic blocks script I saw a few years back. The functionality of the AI controlled pixel and the player controlled pixel work as intended--which one annoying, and game breaking bug--the player ship resets to its spawn position whenever the AI ship completes its function.
I suspect this is because I have an assigned position for the ship in the beginning of the code, where it is then modified in the function itself. Removing this results in an error where a variable is not referenced--however, I cannot leave the problem alone. I welcome any guidance. The code is below.
from microbit import *
import random
enemyXpos = 4
playerXpos = 2
while True:
display.set_pixel(enemyXpos,0,4)
display.set_pixel(playerXpos,4,6)
def laser(laserXpos, laserYpos):
laserXpos = playerXpos
laserYpos = 3
for i in range (4):
display.set_pixel(laserXpos,laserYpos,9)
if laserYpos > 0:
display.set_pixel(laserXpos,laserYpos,0)
laserYpos -= 1
display.set_pixel(laserXpos,laserYpos,9)
if laserYpos == 0 and laserXpos == enemyXpos:
display.show(all_booms, delay=200)
score = score + 1
continue
elif laserYpos == 0:
display.set_pixel(bombXpos,bombYpos,0)
laserYpos = newlaserYpos
sleep (200)
def enemy_left(enemyXpos, playerXpos):
enemyXpos = 4
for i in range (4):
display.clear()
enemyXpos -= 1
display.set_pixel(enemyXpos,0,4)
display.set_pixel(playerXpos,4,6)
if button_a.is_pressed() and button_b.is_pressed():
laser(laserXpos,laserYpos)
elif button_a.is_pressed() and playerXpos > 0:
playerXpos -= 1
elif button_b.is_pressed() and playerXpos < 4:
playerXpos += 1
sleep(200)
def enemy_right(enemyXpos, playerXpos):
enemyXpos = 0
for i in range (4):
display.clear()
enemyXpos += 1
display.set_pixel(enemyXpos,0,4)
display.set_pixel(playerXpos,4,6)
if button_a.is_pressed() and button_b.is_pressed():
laser(laserXpos,laserYpos)
elif button_a.is_pressed() and playerXpos > 0:
playerXpos -= 1
elif button_b.is_pressed() and playerXpos < 4:
playerXpos += 1
sleep(200)
enemy_left(enemyXpos, playerXpos)
enemy_right(enemyXpos, playerXpos)
Im getting this error when inputting my code in codewars. "Traceback:in module
in damaged_or_sunk
IndexError: list index out of range". However, when I try my code in spyder3, it works just fine. there are no indicators as to where this error is in the function damaged_or_sunk though.
def damaged_or_sunk (board, attacks):
a = sum(x.count(1) for x in board)
b = sum(x.count(2) for x in board)
c = sum(x.count(3) for x in board)
a1 = 0
b1 = 0
c1 = 0
points = 0
sunk = 0
damaged = 0
not_touched = 0
for each in attacks:
rand_row = each[0]
rand_col = each[1]
if board[rand_row][rand_col] == 1:
a1 += 1
elif board[rand_row][rand_col] == 2:
b1 += 1
elif board[rand_row][rand_col] == 3:
c1 += 1
else:
pass
if a1 == a:
points += 1
sunk += 1
elif a1 == 0:
points -= 1
not_touched += 1
else:
points += 0.5
damaged += 1
if b1 == b:
points += 1
sunk += 1
elif b1 == 0:
points -= 1
not_touched += 1
else:
points += 0.5
damaged += 1
if c1 == c:
points += 1
sunk += 1
elif c1 == 0:
points -= 1
not_touched += 1
else:
points += 0.5
damaged += 1
return '{\'sunk\': %s, \'damaged\': %s, \'not_touched\': %s, \'points\': %s}' %(sunk, damaged, not_touched, points)
The couples in attacks contains (x, y) coordinates which must be list index.
I make the assumption that they are randomly generated, make sure that:
0 <= x < len(board[0])
0 <= y < len(board)
all( len(board[0]) == len(board[row]) for row in board)
At the moment, I managed to code, successfully, a simulation for a work that I need to do. However, I'm fairly new to python. And so, I'm now in the process of making the simulation more efficient.
For instance:
if random.random() < mm:
z = numpy.random.choice(pat)
if random.random() < 0.5:
if random.random() < mut:
if maleadult[z][0] == 0:
malejuv[y][x][0] = 1
elif maleadult[z][0] == 1:
malejuv[y][x][0] = 0
else:
malejuv[y][x][0] = maleadult[z][0]
else:
if random.random() < mut:
if femaleadult[z][0] == 0:
malejuv[y][x][0] = 1
elif femaleadult[z][0] == 1:
malejuv[y][x][0] = 0
else:
malejuv[y][x][0] = femaleadult[z][0]
if random.random() < 0.5:
if random.random() < mut:
if maleadult[z][1] == 0:
malejuv[y][x][1] = 1
elif maleadult[z][1] == 1:
malejuv[y][x][1] = 0
else:
malejuv[y][x][1] = maleadult[z][1]
else:
if random.random() < mut:
if femaleadult[z][1] == 0:
malejuv[y][x][1] = 1
elif femaleadult[z][1] == 1:
malejuv[y][x][1] = 0
else:
malejuv[y][x][1] = femaleadult[z][0]
where:
mm - male dispersal,
mf - female dispersal,
mut - mutations,
pat - patch,
maleadult - adult male,
femaleadult - adult female,
malejuv - juvenile male,
femalejuv - juvenile female.
As you can see, the code is big. And this is only for males and when they disperse. The rest of the code is very similar. These are standard genetic and demographic processes - but I feel like this can be improved. I feel like these processes are simple enough, so maybe code as big as this is not necessary.
Does anyone have any ideas to shorten this and, by consequence, making it more efficient?
Your example does not have any loops but it looks like it could be simplified by one:
if random.random() < mm:
z = numpy.random.choice(pat)
for i in range(2):
if random.random() < 0.5:
if random.random() < mut:
if maleadult[z][i] == 0:
malejuv[y][x][i] = 1
elif maleadult[z][i] == 1:
malejuv[y][x][i] = 0
else:
malejuv[y][x][i] = maleadult[z][i]
else:
if random.random() < mut:
if femaleadult[z][i] == 0:
malejuv[y][x][i] = 1
elif femaleadult[z][i] == 1:
malejuv[y][x][i] = 0
else:
malejuv[y][x][i] = femaleadult[z][i]
It is also possible to pass a mutable object as reference to a function which can modify it, which allows further reduction of almost redundant code. I've added some data to test it:
#!python3
#coding=utf-8
import random
maleadult = [[["male adult"], ["another male adult"], ]]
femaleadult = [[["female adult"], ["another female adult"], ]]
malejuv = [[[["male juv"],["another male juv"]]]]
mut = 0.5
mm = 1.0
x = 0
y = 0
z = 0
def some_logic(a, j):
""" does something """
if random.random() < mut:
if a[z][i] == 0:
j[y][x][i] = 1
elif a[z][i] == 1:
j[y][x][i] = 0
# added!
else:
j[y][x][i] = 0
else:
j[y][x][i] = a[z][i]
if random.random() < mm:
z = 0 #numpy.random.choice(pat)
for i in range(2):
print(i)
if random.random() < 0.5:
some_logic(maleadult, malejuv)
else:
some_logic(femaleadult, malejuv)
print(maleadult)
print(malejuv)
print(femaleadult)
Long time user, first time asker. Just started using pygame and need some help as right now, my game isn't working as there seems to be a problem with the program choosing a gradient for the ball, and the ball now seems to go in a straight line across the x axis. The code is below, thanks in advance for any help
from pygame import *
import time
import random
init()
width = 1000
height = 1000
screen = display.set_mode((width,height))
display.set_caption('Graphics')
ball1 = Rect(10,10,40,40)
ball1dx = 2
ball1dy = 3
ball2 = Rect(500,500,40,40)
gradient = [-0.25,-0.5,-0.75,-1]
ran = 0
endProgram = False
a = 0
d = 0
w = 0
s = 0
while not endProgram:
for e in event.get():
if e.type == KEYUP:
if (e.key == K_a):
a = True
d = False
w = False
s = False
if (e.key == K_d):
d = True
a = False
w = False
s = False
if (e.key == K_w):
w = True
a = False
d = False
s = False
if (e.key == K_s):
s = True
a = False
d = False
w = False
if a:
ball2.x -= 1
if d:
ball2.x += 1
if w:
ball2.y -= 1
if s:
ball2.y += 1
ball1.move_ip(ball1dx,ball1dy)
if ball1.y < 0 or ball1.y > height - 40:
ran = random.random()
ball1dy *= random.choice(gradient)
if ball1.x < 0 or ball1.x > width - 40:
ran = random.random()
ball1dx *= random.choice(gradient)
screen.fill((0,0,200))
draw.ellipse(screen, (0,255,0), ball1)
draw.ellipse(screen, (255,0,0),ball2)
display.update()
I don't know what you were expecting but if you keep multiplying a number by a fraction between 1 and 0 you will start to approach 0 and essentially get 0. If you add a print statement after you pick the gradient you will see that your number is quickly heading towards zero.
-1.5
-0.5
0.5
-0.375
0.28125
-0.2109375
0.158203125
-0.0791015625
0.059326171875
-0.0296630859375
0.0222473144531
-0.0111236572266
.
.
.
-1.28840161923e-281
6.44200809614e-282
-3.22100404807e-282
3.22100404807e-282
I'm assuming you are just trying to get the ball to bounce around screen which you can do by just multiplying by -1. If you want variable speed while bouncing you will have to set up a range for min and max speed and only multiply by your gradient if it doesn't exceed those boundaries. You could do it like this
ball1.move_ip(ball1dx,ball1dy)
if ball1.y < 0 or ball1.y > height - 40:
choice = random.choice(gradient)
if abs(ball1dy*choice) < 5 and abs(ball1dy*choice) > 0.25:
ball1dy *= choice
else:
ball1dy*=-1
if ball1.x < 0 or ball1.x > width - 40:
choice = random.choice(gradient)
if abs(ball1dx*choice) < 5 and abs(ball1dx*choice) > 0.25:
ball1dx *= choice
else:
ball1dx*=-1
As a side note you can condense your if statements by changing them all to False right before the ifs and then only switching one to True like so
for e in event.get():
if e.type == KEYUP:
w = False
a = False
s = False
d = False
if (e.key == K_a):
a = True
if (e.key == K_d):
d = True
if (e.key == K_w):
w = True
if (e.key == K_s):
s = True