Saving a large turtle graphics image from the entire canvas - python-3.x

I've been looking around for a few hours, and I couldn't find any solutions for this specific problem. I did see one person who asked the same question, but they didn't provide code, and so didn't get an answer. My problem is this:
I have a program that sends the turtle left and right randomly for a set number of turns. The turning part works, but when I try to save the canvas, it only saves the visible part, which often cuts things off. I have tried increasing the size of the setup canvas, as well as the screen capture, but the saved file always ends up in the top left corner, and so gets cut off. I'm attaching my entire program (it's short, don't worry), because I'm not sure exactly what aspect needs to change.
Any help would be greatly appreciated!
import turtle
import random
'''
Takes a variable, number, of how many random turns the turtle should make and a variable filenumber,
which is used to save multiple different iterations of the program per program execution
'''
def left_or_right(number,filenumber):
# Counters to make sure the turtle doesn't turn too many times
count = 0
subright = 0
subleft = 0
#sets up screen
win_width, win_height, bg_color = 10000, 10000,'white'
turtle.setup()
turtle.screensize(win_width, win_height,bg_color)
# Clears the screen, sets the turtle in the middle of the screen, drops the pen and hides the
# Turtle. If you want to see the turtles do the drawing, turn turtle.tracer to True, and
# uncomment out turtle.speed('fastest')
turtle.clear()
turtle.home()
turtle.hideturtle()
turtle.pendown()
turtle.speed('fastest')
turtle.tracer(False)
# A for loop for the turtle's turns
for i in range(number):
# Calls decider to you can get a random direction every time
decider = random.randint(0, 1)
# in order to minimize the turtle just going around in circles,
# if the turtle has made more that 3 of the same turn, turn it the other way
# the next to if statements deal with the turtle turning right too many times
if decider == 1 and subright <= 3:
turtle.right(90)
turtle.forward(20)
count += 1
subright += 1
elif decider == 1 and subright > 3:
turtle.left(90)
turtle.forward(20)
count += 1
subright = 0
# The next two if statements make sure the turtle doesn't turn right too many times
elif decider == 0 and subleft <= 3:
turtle.left(90)
turtle.forward(20)
count += 1
subleft += 1
elif decider == 0 and subleft > 3:
turtle.right(90)
turtle.forward(20)
count += 1
subleft = 0
# if the number of turns is equal to what the user inputed, stop making the turns
# and update the screen
if count == number:
turtle.penup()
turtle.update()
# Take a screen capture of the screen and saves it to where the python file is
ts = turtle.getscreen()
ts.getcanvas().postscript(file=filenumber,height=10000, width=10000)
# turtle.done() is here as a debugging tool. If you set the number of files you're
# generating to one, you can keep the turtle window open to check that the file correctly
# copied the turtle screen
#turtle.done()
''' Takes a variable, filenumber, which is the number of generated files you want'''
def filegen(filenumber):
for i in range(filenumber):
# Calls the left or right function as many times as you told it to
# Note: this is where the left or right function get's its turn number parameters
left_or_right(10000,i)
def main():
# calls filegen as many times as you want it to
filegen(4)
if __name__ == '__main__':
main()

Related

Having problems with thrust and acceleration in python turtle module

I am trying to code a boat that keeps its momentum after letting go of "w". However, i also want it to slow down gradually after letting go of "w". I have gotten a decent boat working but sometimes when I press "w" after going a certain direction, the boat goes flying. Is there any way to add a top speed or make it slow down?
self.thrust = 0.0
self.acceleration = 0.0001
self.dx += math.cos(math.radians(self.heading)) * self.thrust
self.dy += math.sin(math.radians(self.heading)) * self.thrust
def accelerate(self):
self.thrust += self.acceleration
def decelerate(self):
self.thrust = 0
If you want it to slow down gradually when you aren't pressing "w", then you may want it to go at the same speed, or faster. This code will work for it to go at the same speed. This should work in any Python IDE.
Suppose your boat is a turtle.
import turtle
Win = turtle.screen()
Boat = turtle.Turtle()
If you want it to also look like a Boat, you can do:
screen.adshape(Saved Document Direction)
Boat.shape(Saved Document Direction)
Otherwise, you can create your own shapes.
Now, we want it to go at a constant speed, while you press "w":
So:
def Constant_Speed():
Boat.speed(Speed You Want it to Go)
Win.listen()
Win.onkeypress(Constant_Speed, "w")
Otherwise, it should slow down.
Initial_Speed = Initial Speed
Boat.speed(Initial_Speed)
Initial_Speed *= Fraction of what you want it to be in/decimal
So, this should work if you replace with your variables:
import turtle
Win = turtle.screen()
Boat = turtle.Turtle()
screen.adshape(Saved Document Direction)
Boat.shape(Saved Document Direction)
def Constant_Speed():
Boat.speed(Speed You Want it to Go)
Win.listen()
Win.onkeypress(Constant_Speed, "w")
Initial_Speed = Initial Speed
Boat.speed(Initial_Speed)
Initial_Speed *= Fraction of what you want it to be in/decimal and must be less than 1
But what if you want it to go faster, not at a constant speed?
Then go to the def Constant_Speed() part.
You can rename it: def Go_Faster()
Now, the code:
Speed = Initial_Speed
Boat.speed(Speed)
Speed *= Times you want to increase speed by
Also:
Change the last line to:
Initial_Speed2 = Initial Speed * Fraction of what you want it to be in/decimal and must be less than 1
With your variables.
Now, this should work:
import turtle
Win = turtle.screen()
Boat = turtle.Turtle()
screen.adshape(Saved Document Direction)
Boat.shape(Saved Document Direction)
def Go_Faster():
Speed = Initial_Speed()
Boat.speed(Speed)
Speed *= Times you want to increase by
Win.listen()
Win.onkeypress(Constant_Speed, "w")
Initial_Speed = Initial Speed
Boat.speed(Initial_Speed)
Initial_Speed2 = Initial Speed * Fraction of what you want it to be in/decimal and must be less than 1

Remove elements while in a for loop

I have a simpel Card Game, which I am currently working on for my thesis.
The Rules are simpel. You have a deck of 52 Cards, from 1 to 10 and jack, queen, knight.
You draw a card from your Deck. If its a Number it gets added to your Account. If you draw a jack, queen or knight, your account gets reset to 0. After every draw you can decide if you want to draw again or stop.
For this game, i programmed a code with the help of this site.
It should give the probability, that you draw exactly "target".
So for example, the probability to draw, so that you have 1 Point in your account,
is 4/52, since you have four 1´s. The Programm does give me exactly this value.
But. The probabiltity, that you have exactly 2 points in your account is
4/52 + 4/52*3/51. You can either draw a 2 with prob of 4/52 or a 1 and another 1 with prob 4/52*3/51.
Here the code messes up. It calculates the probability to have exactly 2 points in your account as
4/52 + 4/52*4/51 and i dont get why?
Can anyone help me?
import collections
import numpy as np
def probability(n, s, target):
prev = {0: 1} # previous roll is 0 for first time
for q in range(n):
cur = collections.defaultdict(int) # current probability
for r, times in prev.items():
cards = [card for card in range(1, 11)] * 4
for i in cards[:]:
cards.remove(i)
# if r occurred `times` times in the last iteration then
# r+i have `times` more possibilities for the current iteration.
cur[r + i] += times
prev = cur # use this for the next iteration
return (cur[t]*np.math.factorial(s-n)) / (np.math.factorial(s))
if __name__ == '__main__':
s = 52
for target in range(1, 151):
prob = 0
for n in range(1, 52):
prob += probability(n, s, target)
print(prob)
EDIT: I am fairly sure, that the line
for i in [i for i in cards]:
is the problem. Since cards.remove(i) removes the drawn card, but i doesnt care and can draw it anyway.
EDIT 2: Still searching. I tried the suggestions in this two qestions
How to remove list elements in a for loop in Python?
and
How to remove items from a list while iterating?
Nothing worked so far as it should.
I'm assuming with probability(n, s, target) you want to calculate the probability if you draw exactly n out of s cards that the sum of values is exactly target.
Then you will have a problem with n>=2. If I understand this right, for every iteration in the loop
for q in range(n):
you save in cur[sum] the number of ways to reach sum after drawing one card (p=0), two cards (p=1) and so on. But when you set p=1 you don't "remember" which card you have already drawn as you set
cards = [i for i in range(1, 11)] * 4
afterwards. So if you have drawn a "1" first (four possibilities) you have again still four "1"s you can draw out of your deck, which will give you your 4/52*4/51.
As a side note:
Shouldn't there be some kind of check if i==11 since that should reset your account?
I have solved it. After like a 4 Days.
This is the Code:
import numpy as np
def probability(cards, target, with_replacement = False):
x = 0 if with_replacement else 1
def _a(idx, l, r, t):
if t == sum(l):
r.append(l)
elif t < sum(l):
return
for u in range(idx, len(cards)):
_a(u + x, l + [cards[u]], r, t)
return r
return _a(0, [], [], target)
if __name__ == '__main__':
s = 52 # amount of cards in your deck
cards = [c for c in range(1, 11)] * 4
prob = 0
for target in range(1, 151): # run till 150 points
prob = probability(cards, target, with_replacement = False)
percentage = 0
for i in range(len(prob)):
percentage += np.math.factorial(len(prob[i])) * np.math.factorial(s-len(prob[i]))/(np.math.factorial(s))
print(percentage)
This Code is the Solution to my Question. Therefore this Thread can be closed.
For those who want to know, what it does as a tl;dr version.
You have a List (in this case Cards). The Code gives you every possible Combination of Elements in the List such as the Sum over the elements equals the target Value. Furthermore it also gives the Probability in the above mentioned Cardgame to draw a specific Value. The above mentioned game is basically the pig dice game but with cards.

How can I efficiently update my dynamic 'day/night' lighting system, with python?

I need more efficient code which does the same thing I already have, but better.
I made a dynamic lighting system for my game. The way I currently have it programmed, the lighting values update each hour.
The time is blitted onto a monitor in-game and 'self.custom' is used in screen.fill() before a background with transparent sky (which also changes colour) is placed in front of it.
But I only wrote it this way as a prototype to test other features faster. It looks messy as code and I would also rather have the sky fluidly changing after every 56 ticks (minimum possible), rather than in larger time blocks of 600 ticks.
I divided 14400 by 255 (RGB values range) to get 56 (as an int) but my brain's fried and I can't think what I need to do with those values.
Here's the way it currently looks -
if self.time in range(0, 599):
self.showTime = '12 AM'
self.custom = (0,0,0)
elif self.time in range(600, 1199):
self.custom = (24,24,24)
self.showTime = '1 AM'
...
etc...
I hope I explained well enough what the problem is and what I want?
You could define everything up front (either as a dict, as I've done here, or just as a tuple/list):
timeData = [
{'showTime': '12 AM', 'custom': (0,0,0)},
{'showTime': '1 AM', 'custom': (24,24,24)},
...
]
and then use integer division to check what index in that list the time should correspond to:
idx = (self.time // 56) % len(timeData) # 0 if time < 56
# 1 if 56 <= time < 112
# ...
self.showTime = timeData[idx]['showTime']
self.custom = timeData[idx]['custom']
That's assuming that you're setting custom manually, and not doing a solid gradient from black to white. If you are, then you could omit putting that in timeData, and just calculate it based on idx, which would be conceptually easier than doing it based directly on self.time:
self.custom = (20 * idx,) * 3 # make 3-tuple with 3 of the same value
If you want a gradient effect, you could calculate it every time you want the sky to update.
if self.time < (14400/2): #If the time is before midday
self.rgb_value = int(((14400/2)/255)*self.time) #Set the sky colour to a value between 0 and 255, where 0 is at midnight and 255 is at midday.
elif self.time == (14400/2): #If the time is midday
self.rgb_value = 255 #Midday is full brightness
elif self.time > (14400/2) and self.time < 14400: #If the time is after midday
self.rgb_value = int(((14400/2)/255)*-(self.time-14400)) #The code is similar to before midday, but subtract the full length from self.time, and invert the result, to get the time until midnight.
elif self.time == 14400: #If the time is midnight
self.rgb_value = 0 #It is dark at midnight
self.custom = (self.rgb_value,self.rgb_value,self.rgb_value) #Convert the value into a colour.
For the clock display, you can have a list like:
clockoptions = [ (0,599,"12 AM"),
(600,1199,"1 AM"),
...
]
and pull values from it every time the clock is updated using the code
for opt in clockoptions:
if self.time >= opt[0] and self.time <= opt[1]:
self.showTime = opt[2]
break #Stop the loop from continuing to iterate unnecessarily.
This code is untested but I hope this helps.

How do stop my character from going through the ground

So i am trying to make a fighting game and i have fixed so i can jump and so on by making my y speed += 1 every frame to make it act like gravity and when i press the jump key the y speed -=14. But when i use higher than -=14 for example -=20 the character clips through the ground.
i am using this kind off collison detection
collisions = pygame.sprite.spritecollide(self, object_list, False)
for col in collisions:
if type(col) == Solid:
if (self.rect.top < col.rect.bottom and self.rect.bottom >
col.rect.bottom):
self.rect.top = col.rect.bottom
if (self.rect.bottom > col.rect.top and self.rect.y < col.rect.top):
self.rect.bottom = col.rect.top
self.yspeed = 0
self.jump = False
I guess that your fighter is falling so fast that it passes the platform in one update of the loop...
There are a few ways to solve this issue, the most simple one is to update its position a few times and check for collisions each time...
#example ...
for i in range(4): # split the change into smaller steps ...
self.rect.y += self.velocity_y /4.0
collisions = pygame.sprite.spritecollide(self, object_list, False)
... #all your collisions checks here ...

New to Python 3 - Trying to get results to print in table

I am new to Python and am having issues getting information to print in a table once 'n' or 'N'is entered. The code is below. I am probably missing something simple but have not been able to figure it out. Any help is appreciated.
Here is the result. As you can see, even after N is printed, it continues to ask for speed input:
Enter the speed in MPH.50
Enter the time travelled in hours.3
Do you have another calculation to enter? (Enter y for yes or N for no: )y
Enter the speed in MPH.60
Enter the time travelled in hours.4
Do you have another calculation to enter? (Enter y for yes or N for no: )y
Enter the speed in MPH.75
Enter the time travelled in hours.3
Do you have another calculation to enter? (Enter y for yes or N for no: )n
Enter the speed in MPH.
' # This program will calculate the distance a vehicle has travelled
# in miles using speed (mph) and the number of hours travelled.
# Create a variable to represent the maxium travel time in hours.
max_travel = 9
min_travel = 1
# Create a variable to represent the maximum speed.
max_speed = 120
# Create a variable to represent the minimum speed.
min_speed = 1
#Define a variable to represent continuation of the program
another = ["y", "Y"]
# Create a variable for saved results to be printed in table
results = []
# main module
def main():
# Get the speed in MPH.
speed = int(input('Enter the speed in MPH.'))
# Validate that the speed entered is not out of range.
while speed > max_speed or speed < min_speed:
if speed > max_speed:
print('ERROR: the speed entered must be a lower number between 1 and 120.')
speed = int(input('Enter a lower speed in MPH.'))
if speed < min_speed:
print('ERROR: the speed entered must be a higher number between 1 and 120.')
speed = int(input('Enter a higher speed in MPH.'))
# Ask user to input travel time in hours
travel_time = int(input('Enter the time travelled in hours.'))
# Validate that the time travelled is within the range of 1 to 9 hours.
while travel_time > max_travel or travel_time < min_travel:
if travel_time > max_travel:
print('ERROR: the time must be a lower number between 1 and 9.')
travel_time = int(input('Enter a different time travelled in hours.'))
# Validate that the time travelled is within the range of 1 to 9 hours.
if travel_time < min_travel:
print('ERROR: the time must be a higher number between 1 and 9.')
travel_time = int(input('Enter a different time travelled in hours.'))
# This will cause the loop, with the exception of the first loop,
# to depend on a 'y' or 'Y' entry to enter any additional entries.
first = False
# Calculate again?
another = input('Do you have another calculation to enter? ' + \
'(Enter y for yes or N for no: )')
# This loop will continue until something other
# than 'y' or 'Y' is entered when prompted.
while another == 'y' or 'Y':
main()
# Calculations saved for table
input_tuple =speed, travel_time
# Print the column headings in a table.
# Print the time travelled and the
# result of the distance calculation
print()
print('Hours\t\tDistance')
print('---------------------')
# Print saved entries and calculations in table
if another !='y' or 'Y':
for input_tuple in results:
# Calculate the distance travelled
distance = speed * travel_time
print("'%s'\t\t'%s'" %(travel_time, distance))
# Call the main function.
def main():
"""
"""'
Beware that the code comes with many indentation errors. Having said that you should at least correct
while another == 'y' or 'Y'
to
while another == 'y' or another == 'Y'
indeed or 'Y' always evaluates to True

Resources