Анализ ошибки в коде для генерации фракталов с помощью системы Лиденмайера
Я разрабатывал класс для рисования фрактальных фигур, используя L-систему (систему Лиденмайера). В реализации возникла ошибка выполнения, требующая детального разбора.
Исходный код
Приведу ключевые фрагменты моего класса instinctTurtle, унаследованного от turtle.Turtle:
class instinctTurtle(turtle.Turtle):
axiom = ''
turtleX = 0
turtleY = 0
turtleRotate = 0.0
teta = 0
lenght = 0
def __init__(self, shape="classic", undobuffersize=1000, visible=False):
super().__init__(shape, undobuffersize, visible)
def setDrawingParameters(self, teta=60, lenght=10, axiom='F++F++F',
newF='F-F++F-F', newB='B', newK='K'):
self.teta = teta
self.lenght = lenght
self.axiom = axiom
self.newF = newF
self.newB = newB
self.newK = newK
def createInstinct(self, deep=1):
self.instinct = ''
for i in range(deep):
for j in range(len(self.axiom)):
instinct = ''
match self.axiom[j]:
case 'F':
instinct += self.newF
case 'B':
instinct += self.newB
case 'K':
instinct += self.newK
case _:
instinct += self.axiom[j]
self.axiom = instinct
def runInstinct(self):
for i in range(len(self.axiom)):
cmd = self.axiom[i]
match cmd:
case 'F':
self.forward(self.lenght)
case 'B':
self.up()
self.forward(self.lenght)
self.down()
case '+':
self.right(self.teta)
case '-':
self.left(self.teta)
case '[':
self.turtleX = self.xcor()
self.turtleY = self.ycor()
self.turtleRotate = self.heading()
case ']':
self.setx(self.turtleX)
self.sety(self.turtleY)
self.setheading(self.turtleRotate)Проблема при выполнении
При запуске следующего кода:
N = instinctTurtle()
N.setDrawingParameters()
N.createInstinct(3)
N.runInstinct()Возникает ошибка:
Traceback (most recent call last):
File "E:\Python\Библиотеки\turtleGeometry\src\turtleGeometry\main.py", line 142, in
N.createInstinct(3)
File "E:\Python\Библиотеки\turtleGeometry\src\turtleGeometry\main.py", line 108, in createInstinct
match self.axiom[j]:
IndexError: string index out of rangeДиагностика проблемы
Основная ошибка находится в методе createInstinct. Рассмотрим логику работы этого метода:
- Внешний цикл
for i in range(deep)должен выполнить заданное количество итераций (в данном случае 3) - Внутренний цикл
for j in range(len(self.axiom))проходит по символам аксиомы - Проблема возникает из-за того, что внутри внутреннего цикла происходит перезапись
self.axiom = instinct
Это приводит к следующему:
- На первой итерации внешнего цикла (i=0) длина аксиомы равна 7 ('F++F++F')
- Внутренний цикл начинает обрабатывать символы, но после обработки первого символа 'F' аксиома заменяется на строку 'F-F++F-F'
- Когда внутренний цикл пытается обратиться к
self.axiom[1], строка уже имеет другую длину и содержимое - Если новая строка короче исходной, возникает IndexError
Дополнительные наблюдения
Мои эксперименты подтверждают эту гипотезу:
- При замене
self.axiom[j]наself.axiom[0]программа рисует одну итерацию, затем зависает - При использовании индекса 1 возникает та же ошибка IndexError
- Ошибка связана не с работой
range, а с изменением строки во время итерации по ней
Рекомендации по исправлению
Для корректной работы метода createInstinct необходимо:
- Создавать новую строку для каждой итерации внешнего цикла
- Не изменять исходную строку во время итерации по ней
- Использовать временную переменную для накопления результата
Примечание: Перехожу на Python с JavaScript, поэтому в коде присутствует camelCase. Прошу отнестись с пониманием к стилистическим особенностям.