Game AI & Unity/L-system algorithm
[Plants and Python][prac9] 함수와 프랙탈 3
bay07
2024. 3. 29. 10:23
#6 branching_turtle_to_coords
#6
def branching_turtle_to_coords(turtle_program, turn_amount=45):
saved_states = list()
state = (0, 0, 90)
yield (0, 0)
for command in turtle_program:
x, y, angle = state
if command.lower() in 'abcdefghijklmnopqrstuvwxyz':
state = (x - cos(angle * DEGREES_TO_RADIANS),
y + sin(angle * DEGREES_TO_RADIANS),
angle)
if command.islower():
yield (float('nan'), float('nan'))
yield (state[0], state[1])
elif command == '+':
state = (x, y, angle + turn_amount)
elif command == '-':
state = (x, y, angle - turn_amount)
elif command == '[':
saved_states.append(state)
elif command == ']':
state = saved_states.pop()
yield (float('nan'), float('nan'))
x, y, _ = state
yield (x, y)
branching_turtle_to_coords(turtle_program, turn_amount=45) | 주어진 거북이 프로그램(turtle_program)을 해석하여 좌표로 변환한다 turtle_program : 거북이 프로그램을 나타내는 문자열, 거북이의 이동 및 회전 명령을 포함 turn_amount : 거북이가 회전할 각도, 기본값은 45도 |
saved_states = list() | 이동 전의 거북이 상태를 저장하는 빈 리스트 |
state = (0, 0, 90) | 초기 거북이 상태를 설정 초기 위치는 (0, 0)이며, 초기 각도는 90도(위쪽 방향) |
yield (0, 0) | 초기 위치를 좌표로 출력 |
x, y, angle = state | 현재 거북이의 위치와 각도를 state에서 가져온다 |
if command.lower() in 'abcdefghijklmnopqrstuvwxyz' | 현재 명령이 이동 명령인 경우 소문자 알파벳은 거북이를 이동시키는 명령을 나타낸다 |
state = (x - cos(angle * DEGREES_TO_RADIANS), y + sin(angle * DEGREES_TO_RADIANS), angle) | 거북이의 새로운 위치를 계산 이동은 현재 각도에 따라 코사인과 사인 함수를 사용하여 계산된다 |
if command.islower() | 이동 명령이 소문자인 경우, 선을 그리는 도중에 선을 중단하도록 <gap>을 출력한다. 프랙탈을 그릴 때 끊어진 선을 나타냄 |
yield (state[0], state[1]) | 이동에 따른 새로운 위치를 좌표로 출력 |
elif command == '+': | 현재 명령이 시계 방향으로 회전하는 명령인 경우 |
state = (x, y, angle + turn_amount) | 거북이의 새로운 각도를 계산하여 회전한다 |
elif command == '-': | 반시계 방향으로 회전하는 명령인 경우 |
state = (x, y, angle - turn_amount) | 거북이의 새로운 각도를 계산하여 회전한다 |
elif command == '[': | 현재 명령이 상태를 저장하는 명령인 경우 |
saved_states.append(state) | 현재 거북이의 상태를 저장한다 |
elif command == ']' | 현재 명령이 이전 상태로 돌아가는 명령인 경우 |
state = saved_states.pop() | 이전에 저장된 상태로 거북이의 상태를 복원한다 |
yield (float('nan'), float('nan')) | 선을 그리는 중간에 끊어진 부분을 나타내기 위해 <gap>을 출력한다 |
x, y, _ = state | 이전 상태에서의 x, y 좌표와 각도를 가져온다 _는 사용되지 않는 변수 각도를 가져올 필요가 없기 때문에 사용되었다 |
yield (x, y) | 전 상태로 돌아간 거북이의 위치를 출력 [ 명령 이후의 명령을 처리하기 위해 이전 위치로 거북이를 이동시키는 것 |
▷ data code 1
더보기
axiom = 'F-F-F-F'
production_rules = {'F':'F+FF-FF-F-F+F+FF-F-F+F+FF+FF-F'}
iterations = 2
angle = 90
axiom = '-F'
production_rules = {'F':'F+F-F-F+F'}
iterations = 4
angle = 90
axiom = 'F+F+F+F'
production_rules = {'F':'F+f-FF+F+FF+Ff+FF-f+FF-F-FF-Ff-FFF', 'f':'ffffff'}
iterations = 2
angle = 90
axiom = 'F-F-F-F'
production_rules = {'F':'FF-F-F-F-F-F+F'}
iterations = 4
angle = 90
axiom = 'F-F-F-F'
production_rules = {'F':'FF-F-F-F-FF'}
iterations = 4
angle = 90
axiom = 'F-F-F-F'
production_rules = {'F':'FF-F+F-F-FF'}
iterations = 3
angle = 90
axiom = 'F-F-F-F'
production_rules = {'F':'FF-F--F-F'}
iterations = 4
angle = 90
axiom = 'F-F-F-F'
production_rules = {'F':'F-FF--F-F'}
iterations = 5
angle = 90
axiom = 'F-F-F-F'
production_rules = {'F':'F-F+F-F-F'}
iterations = 4
angle = 90
▷ data code 2
더보기
axiom = 'L'
production_rules = {'L':'L+R+', 'R':'-L-R'}
iterations = 10
angle = 90
axiom = 'R'
production_rules = {'L':'R+L+R', 'R':'L-R-L'}
iterations = 6
angle = 60
axiom = 'L'
production_rules = {'L':'L+R++R-L--LL-R+', 'R':'-L+RR++R+L--L-R'}
iterations = 4
angle = 60
axiom = '-R'
production_rules = {'L':'LL-R-R+L+L-R-RL+R+LLR-L+R+LL+R-LR-R-L+L+RR-',
'R':'+LL-R-R+L+LR+L-RR-L-R+LRR-L-RL+L+R-R-L+L+RR'}
iterations = 2
angle = 90
▷ 전체 코드
더보기
import matplotlib.pyplot as plt
%matplotlib inline
nan = float('nan')
#1
def plot_coords(coords, lw=0.5, bare_plot=True):
if bare_plot:
# Turns off the axis markers.
plt.axis('off')
# Ensures equal aspect ratio.
plt.axes().set_aspect('equal', 'datalim')
# Converts a list of coordinates into
# lists of X and Y values, respectively.
X, Y = zip(*coords)
# Draws the plot.
plt.plot(X, Y, lw=lw, c='k')
#2
from math import pi, sin, cos
DEGREES_TO_RADIANS = pi / 180
def turtle_to_coords(turtle_program, turn_amount=45):
# The state variable tracks the current location and angle of the turtle.
# The turtle starts at (0, 0) facing up (90 degrees).
state = (0.0, 0.0, 90.0)
# Throughout the turtle's journey, we "yield" its location. These coordinate
# pairs become the path that plot_coords draws.
yield (0.0, 0.0)
# Loop over the program, one character at a time.
for command in turtle_program:
x, y, angle = state
# Move turtle forward
if command in 'Ff':
state = (x - cos(angle * DEGREES_TO_RADIANS),
y + sin(angle * DEGREES_TO_RADIANS),
angle)
if command == 'f':
# Insert a break in the path so that
# this line segment isn't drawn.
yield (float('nan'), float('nan'))
yield (state[0], state[1])
# Turn turtle clockwise without moving
elif command == '+':
state = (x, y, angle + turn_amount)
# Turn turtle counter-clockwise without moving
elif command == '-':
state = (x, y, angle - turn_amount)
# Note: We silently ignore unknown commands
#3
from math import isnan
def print_coords(coords):
for (x, y) in coords:
if isnan(x):
print('<gap>')
else:
print('({:.2f}, {:.2f})'.format(x, y))
#4
def transform_sequence(sequence, transformations):
return ''.join(transformations.get(c, c) for c in sequence)
#5
def transform_multiple(sequence, transformations, iterations):
for _ in range(iterations):
sequence = transform_sequence(sequence, transformations)
return sequence
#6
def branching_turtle_to_coords(turtle_program, turn_amount=45):
saved_states = list()
state = (0, 0, 90)
yield (0, 0)
for command in turtle_program:
x, y, angle = state
# Move forward (matches a-j and A-J)
if command.lower() in 'abcdefghijklmnopqrstuvwxyz':
state = (x - cos(angle * DEGREES_TO_RADIANS),
y + sin(angle * DEGREES_TO_RADIANS),
angle)
# Add a break in the line if command matches a-j
if command.islower():
yield (float('nan'), float('nan'))
yield (state[0], state[1])
# Turn clockwise
elif command == '+':
state = (x, y, angle + turn_amount)
# Turn counterclockwise
elif command == '-':
state = (x, y, angle - turn_amount)
# Remember current state
elif command == '[':
saved_states.append(state)
# Return to previous state
elif command == ']':
state = saved_states.pop()
yield (float('nan'), float('nan'))
x, y, _ = state
yield (x, y)
# Note: We silently ignore unknown commands
#7
def l_plot(axiom, transformations, iterations=0, angle=45, lw=0.5):
turtle_program = transform_multiple(axiom, transformations, iterations)
coords = branching_turtle_to_coords(turtle_program, angle)
plot_coords(coords, lw=lw, bare_plot=True)
# 예시
axiom = 'F-F-F-F'
production_rules = {'F':'F+FF-FF-F-F+F+FF-F-F+F+FF+FF-F'}
iterations = 2
angle = 90
# 함수 불러오기
# Plot the L-system fractal
l_plot(axiom, production_rules, iterations, angle)
* 참고
https://nbviewer.org/github/DanChitwood/PlantsAndPython/blob/master/PlantsAndPython6_STUDENT_Functions_and_Fractals.ipynb
https://nbviewer.org/github/DanChitwood/PlantsAndPython/tree/master/