How to implement variables into function names - python

I'm making a sudoku board using turtle in python. Right now I'm having a little trouble trying to figure out how to let the program easily check which box I am looking at. I have 5 grids in different positions. The game will automatically pick one to play. Since each grid is in a different position, I have to be careful where I have my turtle positioned. I have 16 functions that calculate where I want my turtle cursor to be to draw the number.
#Below is a guide to where each box is relative to its position on the grid.
#To find center of the box, add 75 to x and 20 to y.
#Box(1,1) = x, y Box(1,2) = x+150, y Box(1,3) = x+300, y Box(1,4) = x+450, y
#Box(2,1) = x, y-150 Box(2,2) = x+150, y-150 Box(2,3) = x+300, y-150 Box(2,4) = x+450, y-150
#Box(3,1) = x, y-300 Box(3,2) = x+150, y-300 Box(3,3) = x+300, y-300 Box(3,4) = x+450, y-300
#Box(4,1) = x, y-450 Box(4,2) = x+150, y-450 Box(4,3) = x+300, y-450 Box(4,4) = x+450, y-450
def box1_1(x, y):
return(x+75, y+20)
def box1_2(x, y):
return(x+225, y+20)
def box1_3(x, y):
return(x+375, y+20)
def box1_4(x, y):
return(x+525, y+20)
def box2_1(x, y):
return(x+75, y-130)
def box2_2(x, y):
return(x+225, y-130)
def box2_3(x, y):
return(x+375, y-130)
def box2_4(x, y):
return(x+525, y-130)
def box3_1(x, y):
return(x+75, y-280)
def box3_2(x, y):
return(x+225, y-280)
def box3_3(x, y):
return(x+375, y-280)
def box3_4(x, y):
return(x+525, y-280)
def box4_1(x, y):
return(x+75, y-430)
def box4_2(x, y):
return(x+225, y-430)
def box4_3(x, y):
return(x+375, y-430)
def box4_4(x, y):
return((x+525, y-430))
I can get the boards to be drawn how I want and the given numbers are also drawn correctly. I want the user to have the option to play with real time correction or play traditionally where they can enter all the values and the game will check if their solution is correct. The problem I am running into is during the part where the user enters in their desired number into a box. Right now I have:
def playSudoku():
playboard = []
board1 = [[0,0,0,3],[0,1,0,4],[4,2,0,1],[0,3,4,0]]
board2 = [[4,3,0,0],[1,0,3,0],[0,0,2,0],[2,1,0,0]]
board3 = [[0,4,0,1],[3,0,3,0],[1,0,0,4],[0,2,1,0]]
board4 = [[1,0,3,0],[0,4,2,1],[0,0,0,2],[0,0,4,0]]
board5 = [[0,4,3,2],[3,0,0,0],[4,0,0,0],[0,0,4,1]]
boardchoice = random.randint(1,5)
if boardchoice == 1:
drawBoard1()
playboard = board1
posx = -900
posy = 850
elif boardchoice == 2:
drawBoard2()
playboard = board2
posx = -200
posy = 850
elif boardchoice == 3:
drawBoard3()
playboard = board3
posx = 500
posy = 850
elif boardchoice == 4:
drawBoard4()
playboard = board4
posx = -500
posy = 100
else:
drawBoard5()
playboard = board5
posx = 200
posy = 100
rtc = turtle.textinput("Sudoku", "Do you want to play with real time correction?")
if rtc == 'y':
for i in range (0,3):
for j in range (0,3):
if playboard[i][j] != 0:
pass
num = turtle.numinput('Sudoku', 'Enter a number for box[' + str(i) + ',' + str(j) + ']?: ', minval=1, maxval=4)
turtle.goto(box[i]_[j](posx,posy))
turtle.write(str(num), move=True, align="center", font=("Times New Roman", 24))
I want to bring attention specifically to this line
turtle.goto(box[i]_[j](posx,posy))
The reason why each board has a different posx and posy is because they sit in different spots on the turtle grid. So as you saw above, I have functions with names "boxA _ B" where A and B are the position numbers for the box. I know that what I wrote doesn't work (I tried it too, just in case), but I was wondering if there was a python function out there that would let me do what I'm trying to achieve.
In my loop, whatever i and j are, I would like my my program to use box[i]_[j].
I apologize if this is poorly worded. If more clarification is needed, I will eagerly tell you. I was just hoping someone out there knows what I'm looking for.

You should probably define the box function like this.
def box(i, j, x, y):
return (x + 150*j - 75, y - 150*i + 170)
Then just call box(i, j, posx, posy) instead.

Although in this particular case writing a generic box() function as shown in the other answer would be the best approach since the function's result can be determined via a relatively simply formula from the i and j arguments. However in more general circumstances where that's not true, you'd want to use something like a dictionary to map the different possible combinations to the desired function. Below is how that could have been to solve your problem.
First add a dictionary to associate the different argument values with the corresponding function:
box_map = {
(1, 1): box1_1,
(1, 2): box1_2,
(1, 3): box1_3,
(1, 4): box1_4,
(2, 1): box2_1,
(2, 2): box2_2,
(2, 3): box2_3,
(2, 4): box2_4,
(3, 1): box3_1,
(3, 2): box3_2,
(3, 3): box3_3,
(3, 4): box3_4,
(4, 1): box4_1,
(4, 2): box4_2,
(4, 3): box4_3,
(4, 4): box4_4,
}
Next would be to modify the playSudoku() function to use it to lookup the function to call:
...
rtc = turtle.textinput("Sudoku", "Do you want to play with real time correction?")
if rtc == 'y':
for i in range (0,3):
for j in range (0,3):
if playboard[i][j] != 0:
pass
num = turtle.numinput('Sudoku', 'Enter a number for box[' + str(i) + ',' + str(j) + ']?: ', minval=1, maxval=4)
# turtle.goto(box[i]_[j](posx, posy))
turtle.goto(box_map[i, j](posx, posy))
turtle.write(str(num), move=True, align="center", font=("Times New Roman", 24))

Related

Python Canvas bbox returns None

so i am making a game (Minecraft 2D (scuffed edition)) and if you are underground in a cave, i want the background to be dark, not that you can see the sun if you are in a cave, so what i do is i want to check for the lowest grass block on screen (witch is ground level)
and then place the cave background atthat location, but when i trie to get the bbox or the coords of a block object on the canvas, it just gives me None.
So i have this now:
(the camera function gets run every time the player moves)
def camera(self):
for i in self.block_sprites:
self.canvas.delete(i.get_image())
for i in self.sprites:
self.canvas.delete(i)
self.draw_current_pos()
self.draw_background()
def add_block_sprite(self, x, y, block_type):
self.current_sprite = Block(x, y, self, block_type)
self.block_sprites.append(self.current_sprite)
def draw_current_pos(self):
self.sprites = []
self.block_sprites = []
for x in range(0, 20):
for y in range(0, 21):
if self.world.world[self.posx+x][self.posy+y] == 0 :
continue
else:
self.add_block_sprite(x, y, self.world.world[self.posx + x][self.posy + y])
def draw_background(self):
grass_y = 1000
test_for_grass = False
for block in self.block_sprites:
if block.get_type() == 1:
print(self.canvas.bbox(block)) #prints "None"
if self.canvas.bbox(block)[1] > grass_y: ####error here####
grass_y = self.canvas.coords(block)[1]
test_for_grass = True
if not test_for_grass and self.posy < 30:
grass_y = 1000 - grass_y
cave = self.canvas.create_image(0, grass_y, image=self.cavebg, anchor="nw")
self.sprites.append(cave)
Do you know what the problem is?
I hope you can help!
(if this it to little code for the problem tell me)

Why is my loop still running? (Python Zelle Graphics)

I'm trying to figure out why the while loop in one of my functions is still running even after the points in my graphics are equal, which is when I set it to stop. Is there anything I'm doing wrong? I've tried to switch other things around to get it to work but no luck.
It's for a game--when the character reaches the endbox the loop needs to break, but it isn't doing that after I explicitly coded it to. It's in the second function I have:
from graphics import *
def field():
#creating the window
win = GraphWin('The Field',400,400)
win.setBackground('white')
#drawing the grid
boxlist = []
for i in range(0,400,40):
for j in range(0,400,40):
box = Rectangle(Point(i,j),Point(i+40,j+40))
box.setOutline('light gray')
box.draw(win)
boxlist.append(box)
#creating other boxes
startbox = Rectangle(Point(0,0),Point(40,40))
startbox.setFill('lime')
startbox.setOutline('light gray')
startbox.draw(win)
endbox = Rectangle(Point(360,360),Point(400,400))
endbox.setFill('red')
endbox.setOutline('light gray')
endbox.draw(win)
boxlist.append(startbox)
boxlist.append(endbox)
#creating Pete
pete = Rectangle(Point(2,2),Point(38,38))
pete.setFill('gold')
pete.draw(win)
return win,boxlist,pete
def move(win2,boxlist,pete,endbox):
peteloc = pete.getCenter()
#creating loop to move pete
while peteloc != endbox.getCenter():
click = win2.getMouse()
x = click.getX()
y = click.getY()
peteloc = pete.getCenter()
petex = peteloc.getX()
petey = peteloc.getY()
#moving pete
if x>=petex+20 and y<=petey+20 and y>=petey-20:
pete.move(40,0)
elif x<=petex-20 and y<=petey+20 and y>=petey-20:
pete.move(-40,0)
elif y>=petey+20 and x<=petex+20 and x>=petex-20:
pete.move(0,40)
elif y<=petey-20 and x<=petex+20 and x>=petex-20:
pete.move(0,-40)
peteloc = pete.getCenter()
# The main function
def main():
win2,boxlist,pete = field()
endbox = boxlist[len(boxlist)-1]
move(win2,boxlist,pete,endbox)
main()
I think maybe it is caused by precision of float. I guess pete.getCenter() and endbox.getCenter() are something like [float, float], you should avoid using != between float, such as 1.0000001 is not equal to 1.
So even if the character reaches the endbox, the position will still get a little float bias.
So you can change a != b to abs(a - b) > acceptable_error when the error is acceptable. Sample code is like:
# while peteloc != endbox.getCenter():
while abs(peteloc.getX() - endbox.getCenter().getX()) > 0.01 and abs(peteloc.getY() - endbox.getCenter().getY()) > 0.01:
Hope that will help you.
Zelle graphics Point objects don't appear to ever compare as equal:
>>> from graphics import *
>>> a = Point(100, 100)
>>> b = Point(100, 100)
>>> a == b
False
>>>
We have to extract coordinates and do our own comparison. Although #recnac provides a workable solution (+1), I'm going to suggest a more general one. We'll create a distance() method that's valid for any object that inherits from _BBox, which includes Rectangle, Oval, Circle and Line:
def distance(bbox1, bbox2):
c1 = bbox1.getCenter()
c2 = bbox2.getCenter()
return ((c2.getX() - c1.getX()) ** 2 + (c2.getY() - c1.getY()) ** 2) ** 0.5
We can now measure the distance between objects, horizontally, vertically and diagonally. Since your boxes are moving twenty pixels at a time, we can assume that if they are withing 1 pixel of each other, they are in the same location. Your code rewritten to use the distance() method and other tweaks:
from graphics import *
def field(win):
# drawing the grid
boxlist = []
for i in range(0, 400, 40):
for j in range(0, 400, 40):
box = Rectangle(Point(i, j), Point(i + 40, j + 40))
box.setOutline('light gray')
box.draw(win)
boxlist.append(box)
# creating other boxes
startbox = Rectangle(Point(0, 0), Point(40, 40))
startbox.setFill('lime')
startbox.setOutline('light gray')
startbox.draw(win)
boxlist.append(startbox)
endbox = Rectangle(Point(360, 360), Point(400, 400))
endbox.setFill('red')
endbox.setOutline('light gray')
endbox.draw(win)
boxlist.append(endbox)
# creating Pete
pete = Rectangle(Point(2, 2), Point(38, 38))
pete.setFill('gold')
pete.draw(win)
return boxlist, pete
def distance(bbox1, bbox2):
c1 = bbox1.getCenter()
c2 = bbox2.getCenter()
return ((c2.getX() - c1.getX()) ** 2 + (c2.getY() - c1.getY()) ** 2) ** 0.5
def move(win, pete, endbox):
# creating loop to move pete
while distance(pete, endbox) > 1:
click = win.getMouse()
x, y = click.getX(), click.getY()
peteloc = pete.getCenter()
petex, petey = peteloc.getX(), peteloc.getY()
# moving pete
if x >= petex + 20 and petey - 20 <= y <= petey + 20:
pete.move(40, 0)
elif x <= petex - 20 and petey - 20 <= y <= petey + 20:
pete.move(-40, 0)
elif y >= petey + 20 and petex - 20 <= x <= petex + 20:
pete.move(0, 40)
elif y <= petey - 20 and petex - 20 <= x <= petex + 20:
pete.move(0, -40)
# The main function
def main():
# creating the window
win = GraphWin('The Field', 400, 400)
win.setBackground('white')
boxlist, pete = field(win)
endbox = boxlist[-1]
move(win, pete, endbox)
main()

Implementing a parametric L-system using python

I have been working on an implementation of a parametric L-system with python. My case is a 2D tree therefore i am using python turtle library. I wrote this simple code for a non-parametric L-system which it works pretty good. Here is my code:
import turtle as T
class LSystem:
def __init__(self, axiom, width, length, angle):
self.axiom = axiom
self.state = axiom
self.width = width
self.length = length
self.angle = angle
self.rules = {}
T.pensize(self.width)
def add_rules(self, *rules):
for arg in rules:
self.rules[arg[0]] = arg[-1]
def single_generation(self):
next_state = ""
for char in self.state:
if char in self.rules:
next_state += self.rules[char]
else:
next_state += char
self.state = next_state
def set_turtle(self, my_tuple):
T.up()
T.goto(my_tuple[0], my_tuple[1])
T.seth(my_tuple[2])
T.down()
def length_function(self, r):
self.length *= r
def width_function(self, q, e):
self.width *= q**e
def draw_turtle(self):
turtle_state = []
# ***************
T.tracer(0, 0)
T.down()
T.ht()
T.speed(0)
T.seth(90)
# ***************
for move in self.state:
if move == "[":
turtle_state.append((T.xcor(), T.ycor(), T.heading(), T.pensize()))
elif move == "]":
xcor, ycor, head, wid = turtle_state.pop()
self.set_turtle((xcor, ycor, head))
self.width = wid
elif move == 'F':
T.fd(self.length)
T.pensize(self.width)
elif move == '+':
T.left(self.angle)
elif move == '-':
T.right(self.angle)
T.getscreen()
T.done()
if __name__ == '__main__':
my_axiom = "A"
my_width = 10
my_length = 60
my_angle = 33.5
LSys = LSystem(my_axiom, my_width, my_length, my_angle)
my_rule = ("A", "F[+A][-A]")
LSys.add_rules(my_rule)
LSys.single_generation()
LSys.single_generation()
LSys.single_generation()
LSys.single_generation()
LSys.single_generation()
LSys.draw_turtle()
The problem is this code is working for a simple non-parametric L-system but i want to decrease diameter and length of my tree in each step. I have wrote two functions for this, length_function and width_functionbut i don't know where or how to use it. Here is my L-system rules and axiom:
A(s,w) ------> F(s,w)[+A(s*r1, w* q^e)][-A(s*r2, w* (1-q)^e]
axiom = "A(s0, w0)"
The values for r1, r2, q, e are known. also the s0 & w0 are known. I don't want to store the values of these parameters in a string format, i want them in a list or array but i don't know how. Here is a picture of the tree i'm trying to draw vs what my code draws:
You correctly store the pensize when you encounter a '[' but you do not reduce it.
Do something like:
if move == "[":
self.width *= 0.95
turtle_state.append((T.xcor(), T.ycor(), T.heading(), self.width))

Python find closest turtle via mouse click

I'm in the process of creating a minesweeper style game using a turtle-based grid setup. I need to find the closest cell within the grid and reveal the icon located under it whether that be a bomb or a number icons. I'm not looking to make it exact, I just need the mouse click to find the nearest cell in the grid even if the click isn't directly on the board. Currently my code only reveals the icon of the last turtle created on the board and then does nothing else with further clicks.
What can I do to make it recognize the real closest click and do it multiple times until the last bomb is found?
import random
import turtle
import cell
class Game:
def __init__(self, size):
registershapes()
self.__boardsize = size
self.__boardlist = []
self.__bombnum = 0
self.__probe = 0
self.__probelist = []
offset = (size-1) * 17
for x in range(size):
for y in range(size):
t = cell.Cell(x,y)
t.up()
t.shape('question.gif')
t.goto(y*34-offset, offset-x*34)
self.__boardlist.append(t)
def hideMines(self, num):
if num > self.__boardsize ** 2:
return False
self.__bombnum = num
self.__rnums = []
i = 0
while i < self.__bombnum:
currentnum = random.randrange(0, (self.__boardsize**2) - 1)
if currentnum not in self.__rnums:
self.__rnums.append(currentnum)
i += 1
return True
def probe(self, x, y):
for t in self.__boardlist:
pos = t.position()
distx = abs(x - pos[0])
disty = abs(y - pos[1])
distfinal = (distx ** 2 + disty ** 2) ** 0.5
curdist = 0
if curdist < distfinal:
curdist = distfinal
closest = t
if closest in self.__probelist:
return (self.__probe, self.__bombnum)
elif closest in self.__rnums:
closest.shape("bomb.gif")
self.__bombnum -= 1
self.__probe += 1
self.__probelist.append(closest)
return (self.__probe, self.__bombnum)
else:
closest.shape("0.gif")
self.__probe += 1
self.__probelist.append(closest)
return (self.__probe, self.__bombnum)
def registershapes():
wn = turtle.Screen()
wn.register_shape('0.gif')
wn.register_shape('1.gif')
wn.register_shape('2.gif')
wn.register_shape('3.gif')
wn.register_shape('4.gif')
wn.register_shape('5.gif')
wn.register_shape('6.gif')
wn.register_shape('7.gif')
wn.register_shape('8.gif')
wn.register_shape('9.gif')
wn.register_shape('bomb.gif')
wn.register_shape('question.gif')
I believe you're approaching this problem the wrong way. You're activating screen.onclick() and trying to map it to a turtle. Instead, activate turtle.onclick() on the individual turtles, deactivating it when a turtle is selected. Then you don't have to search for the turtle in question, and not actively ignore turtles that have already been selected.
Below is my rework of your code from this and your previous question into an example you can run. I had to guess about the definition of the Cell class:
from turtle import Turtle, Screen
import random
class Cell(Turtle):
def __init__(self, number):
super().__init__("question.gif")
self.__number = number
self.penup()
def number(self):
return self.__number
class Game:
def __init__(self, size):
registershapes()
self.__boardsize = size
self.__boardlist = []
self.__bombnum = 0
self.__probe = 0
self.__rnums = None
offset = (size - 1) * 17
for y in range(size):
for x in range(size):
t = Cell(x + y * size)
t.goto(x * 34 - offset, offset - y * 34)
t.onclick(lambda x, y, self=t: closure(self))
self.__boardlist.append(t)
def hideMines(self, num):
if num > self.__boardsize ** 2:
return False
self.__bombnum = num
self.__rnums = []
i = 0
while i < self.__bombnum:
currentnum = random.randrange(0, self.__boardsize ** 2 - 1)
if currentnum not in self.__rnums:
self.__rnums.append(currentnum)
i += 1
return True
def probe(self, closest):
closest.onclick(None)
if closest.number() in self.__rnums:
closest.shape("bomb.gif")
self.__bombnum -= 1
else:
closest.shape("0.gif")
self.__probe += 1
return (self.__probe, self.__bombnum)
def registershapes():
screen.register_shape('0.gif')
# ...
screen.register_shape('bomb.gif')
screen.register_shape('question.gif')
def closure(closest):
_, rem = mine.probe(closest)
if rem == 0:
over = screen.textinput("Text Input", "Would you like to play again? (Y)es or (N)o")
if over.upper() == 'Y':
main()
else:
screen.bye()
def main():
global mine
board = screen.numinput("Numeric Input", "Enter desired board size: ")
mine = Game(int(board))
nummine = screen.numinput("Numeric Input", "Enter desired number of mines: ")
mine.hideMines(int(nummine))
screen = Screen()
mine = None
main()
screen.mainloop()

How can I get my user input to run from my class? [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago.
Improve this question
bob = Turtle()
bob.shape("turtle")
class SimpleDraw(Turtle):
def __init__(Turtle):
bob = Turtle
def draw_square(bob, length):
'''This function draws a regular square'''
for i in range(4):
bob.forward(length)
bob.left(90)
def draw_polygon(bob, n, length):
'''This function draws a regular polygon'''
angle = 360.0 / n
for i in range(n):
bob.forward(length)
bob.left(angle)
def draw_circle (t, r):
circumference = 2 * math.pi * r
n = 50
length = circumference / n
polygon (t, n, length)
drawObj = SimpleDraw
drawObj.draw_polygon
drawObj.draw_circle
drawObj.draw_square
def testSimpleDraw():
number = raw_input('Please choose a draw option: \
1-draw square \
2-draw polygon \
3-draw circle \
0-to exit');
if number == 0:
exit()
else:
if number == 1:
drawObj.draw_square(bob, 5)
else:
if number == 2:
drawObj.draw_polygon(bob, 7, 70)
else:
if number == 3:
drawObj.draw_circle(50, 50)
if __name__ == '__main__':
testSimpleDraw()
drawObj = SimpleDraw needs to be changed to drawObj = SimpleDraw()
That's how you instantiate a class. You are assigning the SimpleDraw class to drawObj - drawObj is the same as SimpleDraw class not an instance of SimpleDraw in your code.
In this line:
drawObj = SimpleDraw
you assign the class SimpleDraw to the name drawObj. Instead, you should create an instance of the class to assign:
drawObj = SimpleDraw() # note parentheses
You don't need the __init__ in your SimpleDraw class; you inherit this from Turtle. It is conventional to call the first argument to instance methods self, rather than bob! For example:
def draw_square(self, length):
'''This function draws a regular square'''
for i in range(4):
self.forward(length)
self.left(90)
You will need to adjust your draw_circle method to correctly call the draw_polygon method:
def draw_circle(self, r, n=50):
circumference = 2 * math.pi * r
length = circumference / n
self.draw_polygon(n, length)
Note that you can use elif to simplify your code:
if number == 0:
...
elif number == 1:
...
I'm going to take a guess at what you're trying to do. First, lets rewrite this code and I'll explain the changes as we go along.
class SimpleDraw(Turtle):
# No __init__ need, calls __init__ of subclass implicitly
# So self refers to an instance of Turtle
# Since all your code essentially makes use of the same thing, lets create
# a generic base draw.
def draw_generic(self, angle, length, n):
for i in range(n):
self.forward(length)
self.left(angle)
def draw_square(self, length):
# Notice self instead of bob, this is how you refer to the instance
# of the class that has been created.
"""
This function draws a regular square.
"""
self.draw_generic(90, length, 4) # Note, self implicitly passed
def draw_polygon(self, n, length):
"""
This function draws a regular polygon
"""
angle = 360.0 / n
self.draw_generic(angle, length, n)
def draw_circle(self, t, r):
circumference = 2 * math.pi * r
n = 50
length = circumference / n
self.draw_polygon(t, n, length) # Note: draw_polygon instead of polygon
def test_simple_draw():
# Note the lowercase and underscores, this preferred by PEP 8
# http://stackoverflow.com/questions/8908760/should-i-use-camel-case-or-underscores-in-python
options = ["1 - draw square", "2 - draw polygon", "3 - draw circle", "0 -exit"]
msg = "Please choose a draw option:\n %s" % ("\n".join(options))
# Note that number is a string, so we have to try and coerce it to an int, and
# validate this as well.
number = None
while number is None:
try:
number = raw_input(msg)
number = int(number)
if 0 > number or 3 < number:
raise ValueError # Not a valid option
except ValueError: # If the coercion fails
print "%s is not a valid option. Please re-enter." % number
number = None # Set to None so we loop again
# Now we have the number, and it's actually a number.
# You make a lot of use of else, which can be replaced by elif, which is the
# like else but specifies a condition; a union of if and else
drawObj = SimpleDraw() # We create our object here, note braces for instantiation
if number == 0:
exit()
elif number == 1:
drawObj.draw_square(5)
elif number == 2:
drawObj.draw_polygon(7, 70)
else: # We can have confidence in this value because of our checks above
drawObj.draw_circle(50, 50)
if __name__ == "__main__":
test_simple_draw()
Now This code gets across the idea that you initially wanted, but makes use of the class inheritance that you were originally trying to use.
Further sources for reference:
Classes: http://docs.python.org/2/tutorial/classes.html
import math
import random
import turtle
class SimpleTurtle(turtle.Turtle):
# There is no need to override the default __init__
# Also, making the self argument 'bob' is just irritating -
# everyone expects to see 'self', why mess us up?
def draw_polygon(self, num_sides, side_length):
"""
Draw an n-sided regular polygon
"""
angle = 360. / num_sides
for side in range(num_sides):
self.forward(side_length)
self.left(angle)
def draw_square(self, side_length):
"""
Draw a square
"""
self.draw_polygon(4, side_length)
def draw_circle(self, radius, num_sides=60):
"""
Draw a circle
"""
angle = 360. / num_sides
side_length = 2. * radius * math.sin(math.radians(angle))
self.draw_polygon(num_sides, side_length)
def get_int(prompt, lo=None, hi=None):
while True:
try:
val = int(raw_input(prompt))
if (lo is None or lo <= val) and (hi is None or val <= hi):
return val
except ValueError:
pass
def do_menu(prompt, options):
print(prompt)
for i,opt in enumerate(options, 1):
print(" {:>2}: {}".format(i, opt))
return get_int("? ", 1, len(options)) - 1
def test_SimpleTurtle():
bob = SimpleTurtle(shape="turtle")
while True:
choice = do_menu("Please choose a draw option:", ["draw a square", "draw a polygon", "draw a circle", "quit"])
if choice == 0:
side_length = random.randint(10, 50)
bob.draw_square(side_length)
elif choice == 1:
sides = random.randint(5, 12)
side_length = random.randint(6, 30)
bob.draw_polygon(sides, side_length)
elif choice == 2:
radius = random.randint(8, 40)
bob.draw_circle(radius)
else:
break
if __name__ == '__main__':
test_SimpleTurtle()

Categories