Dragon Curve in Python - python

I created a program to draw a dragon curve using turtle graphics.. but my result doesn't really look like the picture does in the link:
One problem I noticed is that I want to save the produced string into the variable newWord.. but I can't use newWord as a parameter in my function drawit, which actually draws lines based on the string. When I try to do that I get the error "global variable newWord not defined." So in my code I just copied the output of newWord to be drawn, without actually passing the variable that I wanted to pass.
I'm not sure if the problem is with my createWord function or if I'm just not 'drawing enough' in drawit.
import turtle
def createWord(max_it, axiom, proc_rules):
word = axiom
t = 1
while (t < max_it):
word = rewrite(word, proc_rules)
t=t+1
newWord = word
def rewrite(word, proc_rules):
wordList = list(word)
for i in range(len(wordList)):
curChar = wordList[i]
if curChar in proc_rules:
wordList[i] = proc_rules[curChar]
return "".join(wordList)
def drawit(newWord, d, angle):
newWordLs = list(newWord)
for i in range(len(newWordLs)):
cur_Char = newWordLs[i]
if cur_Char == 'F':
turtle.forward(d)
elif cur_Char == '+':
turtle.right(angle)
elif cur_Char == '-':
turtle.left(angle)
else:
i = i+1
#sample test of dragon curve
def main():
createWord(10, 'FX', {'X':'X+YF','Y':'FX-Y'})
drawit('FX+YF+FX-YF+FX+YF-FX-YF+FX+YF+FX-YF-FX+YF-FX-YF', 20, 90)
if __name__=='__main__': main()

newWord is locally scoped inside of createWord(), so after createWord() is finished, newWord disappears.
Consider creating newWord in the global scope so you can modify it with createWord - or better yet, let createWord() return a value, and set newWord to that value.
I would think that printing "word" and then using it as a parameter in drawit would result in the same thing as using a variable.
It does, but if you want to change the length of your dragon curve, you'll have to copy/paste the string every time instead of simply changing the value of max_it.
Edit: My solution with some sexy recursion (=
import turtle
def dragon_build(turtle_string, n):
""" Recursively builds a draw string. """
""" defining f, +, -, as additional rules that don't do anything """
rules = {'x':'x+yf', 'y':'fx-y','f':'f', '-':'-', '+':'+'}
turtle_string = ''.join([rules[x] for x in turtle_string])
if n > 1: return dragon_build(turtle_string, n-1)
else: return turtle_string
def dragon_draw(size):
""" Draws a Dragon Curve of length 'size'. """
turtle_string = dragon_build('fx', size)
for x in turtle_string:
if x == 'f': turtle.forward(20)
elif x == '+': turtle.right(90)
elif x == '-': turtle.left(90)
def main():
n = input("Size of Dragon Curve (int): ")
dragon_draw(n)
if __name__ == '__main__': main()

Related

I try to do a TicTacToe project myself, but the py close after i enter the very first input

the window of game.py I try out some of the python beginner project to practise my sense of coding.
And after i followed the youtube video step by step, i started to debug and play the
TicTacToe. It closed right after i input my first square/input. But i don't understand
where it goes wrong. I just start fighting with coding, i don't mind to get slap right out
of my face right now. Please, go easy on me. It keeps drive me to the wall.
#Player.py ||||
import math
import random
class Player:
def __init__(self,letter):
self.letter = letter
def get_move(self,game):
pass
class RandomComputerPlayer(Player):
def __init__(self, letter):
super().__init__(letter)
def get_move(self,game):
square = random.choice(game.available_moves())
return square
class HumanPlayer(Player):
def __init__(self, letter):
super().__init__(letter)
def get_move(self,game):
valid_square = False
val = None
while not valid_square:
square = input(self.letter + '\'s turn. Input move (0-8):')
try:
val = int(square)
if val not in game.available_moves():
raise ValueError
valid_square = True
except ValueError:
print('Invalid square. Try again.')
return val
And here's game.py:
#game.py ||||
import time
from player import HumanPlayer, RandomComputerPlayer
class TicTacToe:
def __init__(self):
self.board = [' ' for _ in range(9)]
self.current_winner = None
def print_board(self):
for row in [self.board[i*3:(i+1)*3] for i in range(3)]:
print('| ' + ' | ' .join(row) + ' |')
#staticmethod
def print_board_nums():
# 0 | 1 | 2 etc
number_board = [[str(i) for i in range(j*3, (j+1)*3)] for j in range (3)]
for row in number_board:
print('| ' + ' | '.join(row) + ' |')
def available_moves(self):
moves = []
for (i, x) in enumerate(self.board):
if spot == ' ':
moves.append(i)
def empty_squares(self):
return ' ' in self.board
def num_empty_squares(self):
return len(self.available_moves())
def make_move(self, square, letter):
if self.board[square] == ' ':
self.board[square] = letter
if self.winner(square, letter):
self.current_winner = letter
return True
return False
def winner(self, square, letter):
# winner if 3 in a row anywhere, check all of the possiblity
row_ind = square // 3
row = self.board[row_ind*3 : (row_ind + 1) * 3]
if all ([spot == letter for spot in row]):
return True
col_ind = square % 3
column = [self.board[col_ind + i*3] for i in range(3)]
if all ([spot == letter for spot in column]):
return True
# check diagonals
if square % 2 == 0:
diagonal1 = [self.board[i] for i in[0,4,8]]
if all ([spot == letter for spot in diagonal1]):
return True
diagonal2 = [self.board[i] for i in[2,4,6]]
if all ([spot == letter for spot in diagonal2]):
return True
# if all of the possibility not happen
return False
def play(game, x_player, o_player, print_game = True):
# returns the winner of the game! or None for a tie
if print_game:
game.print_board_nums()
letter = 'X'
while game.empty_squares():
if letter == '0':
square = o_player.get_move(game)
else:
square = x_player.get_move(game)
if game.make_move(square, letter):
if print_game:
print(letter + ' makes a move to square {square}')
game.print_board()
print('') # empty line
if game.current_winner:
if print_game:
print(letter + 'wins!')
return letter
letter = 'O' if letter == 'X' else 'X'
# if letter == 'X':
# letter = 'O'
# else:
# letter = 'X'
time.sleep(0.8)
if print_game:
print('It\'s a tie!')
if __name__ == '__main__':
x_player = HumanPlayer('X')
o_player = RandomComputerPlayer('O')
t = TicTacToe()
play(t, x_player, o_player, print_game = True)
When I copied the code and ran it locally on my computer, the traceback showed that there was an error in game.py, specifically in your available_moves() function.
def available_moves(self):
moves = []
for (i, x) in enumerate(self.board):
if spot == ' ':
moves.append(i)
The traceback specifically says, NameError: name 'spot' is not defined, which is true since spot is not defined. I am assuming spot and x are supposed to mean the same here since you are looking at the square on your Tic-Tac-Toe board. Also, this function should probably return moves; otherwise, any other function calling available_moves() is going to get a value of type None instead of the list of available moves.
def available_moves(self):
moves = []
# iterate through all spots on board
for (i, spot) in enumerate(self.board):
# if a spot is empty, add its index to moves
if spot == ' ':
moves.append(i)
return moves
Also I've been absolutely crushing myself against myself playing this game so thanks for that!
Edit: Just noticed after posting this that Tim Roberts basically summed up my answer. Oops.

Why won't my while loop break in Tictactoe?

I am writing code to a basic tictactoe game, but I am having trouble with a certain part of my code when trying to get it to break out of the while loop.
I have a list (= board) that contains 10 items = 'space'. The fullBoardCheck function should return a boolean = True when the condition is met, otherwise False.
Within initializeGame, the while loop is set to continue while gameStatus = False. However, once I run the game and fill out 9 spaces of the Board, gameStatus changes to True but it does not break out of the loop.
I cannot find what I am missing, and would appreciate any help you could offer.
Thanks
def placeMarkerO(board, position):
board[position] = 'O'
return board
def takeTurnO(board):
print("It's O's turn!")
wantedPosition = int(input('O, where would you like to go? (1-9): '))
while not spaceCheck(board, wantedPosition):
wantedPosition = int(input('This space is taken. Please choose an EMPTY space: '))
return wantedPosition
def fullBoardCheck(board):
# Returns true or false boolean checking if board is full
return len([x for x in board if x == " "]) == 1
def initializeGame():
board = [' '] * 10
gameStatus = False
while gameStatus == False:
drawBoard(board)
gameStatus = fullBoardCheck(board)
position = takeTurnX(board)
placeMarkerX(board, position)
drawBoard(board)
fullBoardCheck(board)
position = takeTurnO(board)
placeMarkerO(board, position)
You need to change the fullBoardCheck function:
def fullBoardCheck(board):
return len([x for x in board if x == ' ']) == 0
You checked if the len([x for x in board if x == ' ']) == 1, however, you need to check if the length is 0 because you want to return whether the board is completely full.
Good Luck!

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))

Calling Methods From Class Not Working

I have made a sonar finding game and some functions for it. I have put these functions into a class and now I want to call them so I can play the game, however when I define the class call it now returns things to me like game.getNewBoard() takes 0 positional arguments and tells me I have given it one when I have not and so on. Any help would be appreciated.
# Sonar
import random
import sys
class OceanTreasure:
def drawBoard(board):
# Draw the board data structure.
hline = ' ' # initial space for the numbers down the left side of the board
for i in range(1, 6):
hline += (' ' * 9) + str(i)
# print the numbers across the top
print(hline)
print(' ' + ('0123456789' * 6))
print()
# print each of the 15 rows
for i in range(15):
# single-digit numbers need to be padded with an extra space
if i < 10:
extraSpace = ' '
else:
extraSpace = ''
print('%s%s %s %s' % (extraSpace, i, getRow(board, i), i))
# print the numbers across the bottom
print()
print(' ' + ('0123456789' * 6))
print(hline)
def getRow(board, row):
# Return a string from the board data structure at a certain row.
boardRow = ''
for i in range(60):
boardRow += board[i][row]
return boardRow
def getNewBoard():
# Create a new 60x15 board data structure.
board = []
for x in range(60): # the main list is a list of 60 lists
board.append([])
for y in range(15): # each list in the main list has 15 single-character strings
# I thought about using different char to make it more readble?? Admit it, it looks dull with just these ~
if random.randint(0, 1) == 0:
board[x].append('~')
else:
board[x].append('~')
return board
def getRandomChests(numChests):
# Create a list of chest data structures (two-item lists of x, y int coordinates)
chests = []
for i in range(numChests):
chests.append([random.randint(0, 59), random.randint(0, 14)])
return chests
def isValidMove(x, y):
# Return True if the coordinates are on the board, otherwise False.
return x >= 0 and x <= 59 and y >= 0 and y <= 14
def makeMove(board, chests, x, y):
# Change the board data structure with a sonar device character. Remove treasure chests
# from the chests list as they are found. Return False if this is an invalid move.
# Otherwise, return the string of the result of this move.
if not isValidMove(x, y):
return False
smallestDistance = 100 # any chest will be closer than 100.
for cx, cy in chests:
if abs(cx - x) > abs(cy - y):
distance = abs(cx - x)
else:
distance = abs(cy - y)
if distance < smallestDistance: # we want the closest treasure chest.
smallestDistance = distance
if smallestDistance == 0:
# xy is directly on a treasure chest!
chests.remove([x, y])
return 'You have found a sunken treasure chest!'
else:
if smallestDistance < 10:
board[x][y] = str(smallestDistance)
return 'Treasure detected at a distance of %s from the sonar device.' % (smallestDistance)
else:
board[x][y] = 'O'
return 'Sonar did not detect anything. All treasure chests out of range.'
def enterPlayerMove():
# Let the player type in her move. Return a two-item list of int xy coordinates.
print('Where do you want to drop the next sonar device? (0-59 0-14) (or type quit)')
while True:
move = input()
if move.lower() == 'quit':
print('Thanks for playing!')
sys.exit()
move = move.split()
if len(move) == 2 and move[0].isdigit() and move[1].isdigit() and isValidMove(int(move[0]), int(move[1])):
return [int(move[0]), int(move[1])]
print('Enter a number from 0 to 59, a space, then a number from 0 to 14.')
def playAgain():
# This function returns True if the player wants to play again, otherwise it returns False.
print('Do you want to play again? (yes or no)')
return input().lower().startswith('y')
print('S O N A R !')
print()
while True:
# game setup
game=OceanTreasure()
sonarDevices = 20
theBoard = game.getNewBoard()
theChests = getRandomChests(3)
drawBoard(theBoard)
previousMoves = []
while sonarDevices > 0:
# Start of a turn:
# sonar device/chest status
if sonarDevices > 1: extraSsonar = 's'
else: extraSsonar = ''
if len(theChests) > 1: extraSchest = 's'
else: extraSchest = ''
print('You have %s sonar device%s left. %s treasure chest%s remaining.' % (sonarDevices, extraSsonar, len(theChests), extraSchest))
x, y = enterPlayerMove()
previousMoves.append([x, y]) # we must track all moves so that sonar devices can be updated.
moveResult = makeMove(theBoard, theChests, x, y)
if moveResult == False:
continue
else:
if moveResult == 'You have found a sunken treasure chest!':
# update all the sonar devices currently on the map.
for x, y in previousMoves:
makeMove(theBoard, theChests, x, y)
drawBoard(theBoard)
print(moveResult)
if len(theChests) == 0:
print('You have found all the sunken treasure chests! Congratulations and good game!')
break
sonarDevices -= 1
if sonarDevices == 0:
print('We\'ve run out of sonar devices! Now we have to turn the ship around and head')
print('for home with treasure chests still out there! Game over.')
print(' The remaining chests were here:')
for x, y in theChests:
print(' %s, %s' % (x, y))
if not playAgain():
sys.exit() #I thought this is a better way than just break or make false, correct me if I am wrong
Every class method in Python receives the instance it is called from as the first parameter automatically. That means, that the first parameter is always self:
def drawBoard(self, board):

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