Game AI & Unity/L-system algorithm

[Plants and Python][prac8] 함수와 프랙탈 2

bay07 2024. 3. 29. 10:11

#4 transform_sequence

#4 
def transform_sequence(sequence, transformations):
    return ''.join(transformations.get(c, c) for c in sequence)
transform_sequence(sequence, transformations) 주어진 시퀀스를 규칙에 따라 변환한다
sequence: 변환될 시퀀스
transformations: 변환 규칙을 포함하는 딕셔너리
transformations.get(c, c)
시퀀스의 문자 c에 대해 변환 사전에서 해당 문자의 변환을 찾는다
만약 변환이 없으면 원래 문자 c를 반환한다
for c in sequence 시퀀스의 각 문자에 대해 반복한다
join() 변환된 문자들을 이어붙여서 하나의 문자열로 만든다

 

#5 transform_multiple

#5
def transform_multiple(sequence, transformations, iterations):
    for _ in range(iterations):
        sequence = transform_sequence(sequence, transformations)
    return sequence

 

transform_multiple(sequence, transformations, iterations) 주어진 시퀀스를 지정된 횟수만큼 변환하고
최종 변환된 시퀀스를 반환한다

이전에 정의한 transform_sequence 함수를 사용하여
여러 번의 반복(iterations)을 수행하는 함수


sequence : 변환될 시퀀스
transformations : 변환 규칙을 포함하는 딕셔너리
iterations : 변환을 반복할 횟수
for _ in range(iterations) 반복
transform_sequence(sequence, transformations) transform_sequence 함수를 사용하여 시퀀스에 변환을 적용한다. 즉, 시퀀스의 각 문자에 대해 지정된 변환을 적용하여 새로운 시퀀스를 생성한다. 
return sequence 변환된 시퀀스를 반환한다.

 

 

#7 l_plot

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

 

def l_plot(axiom, transformations, iterations=0, angle=45, lw=0.5) 주어진 L-시스템의 초기 axiom에 대해 변환(transformations)을 적용한다. 이 후 해당 시스템을 거북이 그래픽으로 출력한다. 

axiom :  L-시스템의 초기 값
transformations

iterations : 반복 횟수
angle : 각도 
lw : 선의 굵기
turtle_program = transform_multiple(axiom, transformations, iterations) 주어진 axiom을 transform_multiple 함수를 사용하여 변환한다.  지정된 반복 횟수만큼. 이렇게 변환된 시퀀스가 거북이 프로그램을 표현한다.
coords = branching_turtle_to_coords(turtle_program, angle) 변환된 시퀀스를 거북이 프로그램으로 해석하여
좌표를 생성한다.
branching_turtle_to_coords(turtle_program, angle) 거북이 그래픽을 생성하는 데 필요한 좌표를 얻을 수 있는 함수 
plot_coords(coords, lw=lw, bare_plot=True) 생성된 좌표를 사용하여 거북이 그래픽을 플로팅함
lw : 선의 굵기
bare_plot : 그래픽 영역의 경계 관련

   

 

▷ 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/