2. 해외선물/2-2. 해외선물 알고리즘 연구

(해외선물 자동매매) 차트 지지/저항 구하기 (2) 벽돌깨기 게임 학습하기

봄이오네 2024. 10. 5. 08:00
반응형

 

목 차
1. 들어가며
2. 사전설명
   1) 패턴을 파악하는 발상
   2) 텍스트에 내용 쓰기/추가/읽기 구현하기
3. 코드설명
4. 전체코드
5. 마치며

 

 

1. 들어가며

지난 글에서는 pygame 라이브러리를 활용하여 벽돌깨기 게임을 구현해 보았다. pygame 라이브러리 설명까지 더해지니 글이 상당히 길었다. 여기에서는 이전 글에서 설명한 코드의 설명은 생략하고, 추가되는 내용만 설명하고자 한다.

 

이번 글에서는 공(ball)으로 벽돌(brick)을 깨는 코드를 학습한 데이터를 텍스트(text)로 보내는 방법에 대해 알아본다.

 

필자는 구글 딥마인드(Google Deep Mind) 기업의 알파고를 구현하는 코드에 관심이 많다. 이세돌 9단과의 바둑 대결에서 어떻게 학습을 시켰으며, 학습된 데이터를 어떻게 다시 활용하는지에 대해 알아보려고 했으나, 코드를 제대로 이해할 수 없었다.

 

코딩으로 이렇다할 진전이 없으니, 약간은 답답했다. 그런데, 딥마인드(Google Deep Mind)에서 아타리 회사의 벽돌깨기 게임을 하는 영상을 보게 되었다. 뭔가 도움 받을게 있지 않을까?

위의 영상(Q-learning)처럼 벽돌 왼쪽/오른쪽에 구멍을 내고, 공을 상단으로 올려서 벽돌을 깨는 코드는 구현하기 힘들었다. 다만, 게임이 한번도 아래(bottom)로 빠지지 않으면서 벽돌을 다 깨는 코드는 구현할 수 있었다.

 

이 글에서는 사용자(user)가 게임을 진행할 때, 공의 흐름(pattern)을 기록하는 것을 설명하고, 다음 글에서는  공의 흐름에 따라 패들(paddle)이 이동하는 것을 구현할 것이다.

 

양해말씀 : '알고리즘'이라는 거창한 단어보다는, '패턴'이라는 단어를 사용하고자 한다. 기대가 크면 실망도 큰법이다. 편하게 글을 읽어주셨으면 한다.

 

원본 코드의 출처는 아래와 같다.

   ※ ai-creator 님 코드 출처 : https://ai-creator.tistory.com/534

   ※ 토닥토닥 파이썬 출처   : https://wikidocs.net/65737

 

파일은 이 글의 맨 하단에 업로드해 두었다.

 


2. 사전설명

1) 패턴을 파악하는 발상

지난 글에서 벽돌깨기 깨기 게임의 핵심은 공이 벽돌/벽/패들에 부딪힌 경우, x축, y축 방향을 각각 바꾼다는 것이다.

ball_dx = -ball_dx      # 공이 벽돌/벽/패들에 부딪힌 경우, x축이 바뀐다.
ball_dy = -ball_dy      # 공이 벽돌/벽/패들에 부딪힌 경우, y축이 바뀐다.

 

 

자, 생각을 해보자! 공의 이동 경로는 1차 방정식( y= ax + b )이라고 생각하자. 바로 위의 코드를 잘 보면, x = -x이고 y = -y가 되는 것을 알 수 있다. 입사각이라는 복잡한 개념보다는 1차 방법식이라고 생각해 보자.

 

그림1-1. 패턴을 구현하는 원리

 

 

<그림1-1>처럼 공이 ③의 경로로 이동한다면, ① 및 ② 지점을 지나간 후, ④의 패널과 부딪히고 팅겨간다. 공의 이동 경로가 1차 함수(y=ax + b)라면 우리가 ① 및 ② 지점의 (x1, y1), (x2, y2)를 안다면, 기울기 a, y절편 b를 알 수 있다. 하지만, 굳이 우리는 기울기 a, y절편 b를 알 필요는 없다. 왜? 공이 ④의 위치에 있을 때, 패널이 ④에 있으면 공을 패널을 팅겨 낼 수 있기 때문이다.

 

그림1-2. 패턴을 text에 구현한 결과

 

공의 경로를 < 그림1-2 >와 같이 text에 기록하였다. 리스트 내에는 총 6개의 숫자가 등장한다.

[458, 408, 498, 448, 372, 1]을 이해해보자. 

[ x1 ,  y1 ,   x2 ,   y2,   x3, 기타]로 구성된다.

 

< 그림1-1 >의 ①지점을 (x1,y1), ②지점을 (x2, y2)라고 하고, ④지점의 x축을 x3로 표현하였다. 마지막 숫자 1은... 원래는 학습을 위한 보상의 개념으로 넣어두었는데, 활용하지 않는다. 리스트 내에서 없애 주려다, 그냥 남겨두었다. (숫자 1은 신경쓸 필요 없다)

 

나중에 설명하겠지만, 굳이 y1, y2를 구할 필요는 없다. 우리는 x1,x2를 기반으로 x3(④)의 위치를 찾을 것이다.

 

※ 결론 : 볼의 y축에 따른 x축의 위치를 파악하여, 공이 x3 위치에 올 때, 패널도 x3 위치에 오면 된다. 여기서는 공의 x1, x2에 따른 공의 x3 위치를 찾아, 텍스트에 기록할 것이다.

 

2) 텍스트에 내용 쓰기/추가/읽기 구현하기

패턴의 내용을 텍스트에 기록하는 방법을 알아보자. 위에서 말한 6가지(x1, y1, x2, y2, x3,1)를 텍스트에 기록할 것이다.

 

텍스트에 기록하는 방법은 아래 링크로 대체하고자 한다. 글이 너무 길어질 것 같다.

 ※ 파이썬 내용을 텍스트에 기록하는 방법 : https://codechacha.com/ko/python-read-write-file/#google_vignette

 

필자가 여기서 사용하는 코드는 크게 3가지이다. 코드는 아래와 같다.

  • f = open('bricks_ai.txt', r) : 텍스트 내용 읽기
  • f = open('bricks_ai.txt', r) : 텍스트에 내용 추가하기
  • f = open('bricks_ai.txt', r) : 텍스트에 쓰기

위의 3가지를 어디에 사용할까? 텍스트에 읽기/추가/쓰기은 많이 들어봤을 것이다. 벽돌깨기는 1차 함수(y = ax + b)로 이루어진다. 공이 벽돌을 깨면, 어느 순간 동일 경로를 지나갈 것이고, 패널의 위치도 어느 정도는 예상된다.

 

  • 텍스트 쓰기 : 만들어진 패턴을 텍스트에 기록한다
  • 텍스트 추가 : 신규 패턴을 추가하되, 기존에 그 패턴이 그 텍스트에 있으면, "추가"하지 않는다.
  • 텍스트 읽기 : "텍스트 추가"에서 "그 패턴이 텍스트에 있으면"을 판단하려면, 패턴이 있는지 없는지 확인해야 한다. 이 때 활용하는 것이 "텍스트 읽기"를 통해 파일을 파이참으로 가지고 와서 "새로운 패턴"의 존재 여부를 판단해야 한다. 즉, "텍스트 읽기"는 텍스트 파일을 파이참으로 가져와서, 동일한 패턴이 있는지 판단하기 위해 필요하다.

 

글을 쓴 시점에서 조금 아쉬운건, 불필요한 패턴을 "텍스트 추가"하지 않은건 좋은데, 보상점수(+1)를 주면 어땠을까 생각이 된다. 근데 실제로 게임을 진행해 보면, 보상점수(+1)은 굳이 필요가 없다. 어차피 우리는 1차 함수(y=ax+b)로 고정적으로 움직이는 공을 패들로 팅겨낸다. (=즉, 공을 팅겨낼 때 x축, y축의 부호만 바꾸어서 팅긴다)

 

위의 < 그림1-1 >과 같이 경로를 정해서 들어오는데, 내가 달리 패들을 움직인다고 그 방향이 달라질까? 물론 패들(paddle)의 측면으로 팅겨내는 방법이 있는데... 어느 정도는 현실과 타협했다. 패들의 측면(side)으로 공을 쳐내는 것까지 구현하면... 내 본연의 벽돌깨기 코드 공부 목적이 사라진다. 해외선물 자동매매를 위해서 벽돌깨기를 공부하고 있다. 이 이상의 코드 구현은 불필요하다고 생각이 들어, 보상점수(+1)을 더이상 생각하지 않았다.

 

더보기

if os.path.isfile(dir):
    f = open('bricks_ai.txt', 'r') # 텍스트 내용 읽기
    x_position_file = f.readlines()
    f.close()
    
if os.path.isfile(dir):
    f = open('bricks_ai.txt', 'a')      # 텍스트에 내용 추가하기
    f.write(bricks_ai_data)
    f.close()
    
else:
    f = open('bricks_ai.txt', 'w')      # 텍스트에 신규로 기록하기
    f.write(bricks_ai_data)
    f.close()

 


3. 코드설명

이전 글(직접 플레이)에서의 코드는 157줄이었다. 이번 글의 코드는 232줄이다. 75줄이 추가된 점을 고려하여, 이전 글에서 설명했던 내용은 설명을 생략한다. 추가된 코드 위주로 설명한다.

 

이전글에서 추가된 코드 : < 그림 2-2 >의 58줄~62줄, < 그림 2-3 >의 68줄~96줄, < 그림 2-4 >의 98줄~106줄, < 그림 2-7 >의 213줄~227줄 등 4곳이다. (추가된 코드만 확인하여도 될 것 같다.

 

그림2-1. 벽돌깨기 게임의 초기화한다.

 

1줄~34줄 : pygame 라이브러리를 활용하여 벽돌깨기 게임을 실행하기 위한 변수들을 선언한다.

 

그림2-2. 벽돌게임 진행을 위해 벽돌, 공 등을 설정한다.

 

36줄~54줄 : 벽돌, 공, 패들을 정의한다.

58줄~59줄 : < 그림1-1 >의 ① 및 ②의 x축의 값을 저장할 리스트를 선언한다.

61줄 : 100줄에서 y위치가 780일때 x 좌표를 저장한다. 참고로 화면은 가로 600, 세로 800이다. 공의 y위치가 780일 때, x축의 위치에 패들이 있으면 패들이 공을 팅겨낼 수 있다.

 

그림2-3. 공의 흐름에 따른 패턴을 파악한다.

 

자, 여기서부터 패턴(알고리즘)을 구현하는 코드이다.

우리는 47줄에서 1프레임당 x축은 10픽셀이 움직이도록 설정하였다. 또한 50줄에서도 y축도 10픽셀이 움직인다.

여기서 알 수 있는건, 게임화면의 세로가 800픽셀일 때, 볼의 중심(center_y)가 400~410일 때 x축을 구한다는 것이다.

다시한번 말하지만, x와 y는 132줄~144줄에 따라, 1차 함수(y=x + b)로 움직인다. (기울기가 1이다)

 

69줄~71줄 : ball의 y축 중심(ball.centery)이 0~400이상일 때 2개의 리스트를 초기화한다.

이유는? 공은 위 → 아래로 이동할 수도 있지만, 공이 패들에 팅겨 아래 → 위로 이동하는 경우가 있다. 우리가 만들고 싶은 데이터는 위에서 아래로 이동할 때의 y축 400~410, 440~450일때의 x축 데이터가 필요하다. 아래 → 위로 이동할 때의 400~410, 440~450의 데이터를 초기화하여 텍스트(break_ai.txt)에 넣지 않는다.

 

말이 조금 어렵다. 풀어서 다시 한번 이야기해 본다. 공은 하염없이 움직인다. 

우리는 볼의 y축 중심(ball.centery)을 활용하여, ball.centery가 y축이 400~410일 때의 x1, y축이 440~450일 때의 x2인 점을 알고 싶다.

 

공이 아래로 갈 때도 게임화면의 y축 400~410, 440~450을 지나지만, 공이 패널에 팅겨 위로 올라 갈때도 y축 400~410, 440~450을 지나간다. 여기서 우리는 공이 위에서 아래로 이동할 때의 y축 400~410, 440~450 데이터만을 활용하겠다는 것이다. 이유는? 공이 위에서 아래로 내려올 때, 볼이 y축 780에서 위치할 때의 x축 위치에 패들을 위치시켜, 공-패들이 충돌하도록 만들어서, 공을 팅겨낼 것이기 때문이다.

 

즉, 공이 위에서 아래로 내려갈 때는 패들의 위치(y축 780)를 위해 데이터가 필요하지만, 아래에서 위로 공이 이동할 때는 패들의 위치와 상관없으므로 데이터를 수집하지 않겠다는 것이다.

 

73줄~ 85줄 : y축 400~410픽셀, 440~450일 때 공(ball)의 x축, 축 중심을 리스트에 담는다.

87줄 : 볼의 y축 중심(ball.centery)가 470~480이고, 리스트의 갯수(x1,y1,x2,y2)가 4개일 때,

88줄~93줄 : 파이참을 실행한 폴더에 bricks_ai.txt 파일이 있으면, 내용을 불러와서, x_position_file에 담는다.

95줄~96줄 : 73줄~85줄에 담은 리스트(x1,y1,x2,y2) 중 볼의 중심(ball.centery)이 400~410일때의 x1을 upper_point_1, 440~450일 때의 x2를 upper_point_2에 담는다.

 

그림2-4. 벽돌깨기 게임의 패들 움직임을 설정한다.

 


98줄~101줄 : 92줄에서 텍스트에 있는 내용을 불러왔고, 그 내용을 for 문으로 돌린다.

99줄 : 이미 저장된 x1 데이터(eval(i)[0])가 95줄의 현재 x1과 비교하여, -5 ~ 5사이에 있고,

100줄 : 이미 저장된 x2 데이터(eval(i)[2])가 96줄의 현재 x2과 비교하여, -5 ~ 5사이에 있으면,

101줄 : break_ai.txt에 저장된 데이터의 5번째 데이터에  alghorism_x_postion에 담는다.

105줄~106줄 : 게임화면의 세로길이가 800일 때, 공의 y축 중심(ball.centery)가 765~775일 때의 볼의 x축 중심(ball.centerx)값을 리스트에 담는다.

 

그림2-5. 공이 벽, 패들에 부딪혔을 때를 설정한다.

 

132줄~166줄 : 공이 벽면에 부딪히거나, 공과 벽돌이 충돌한 경우를 코드로 작성한다.

 

그림2-6. 게임 종료 및 게임화면에 출력하는 내용을 설정한다.

 

168줄~200줄 : 공이 패들과 충돌한 경우, 화면에 포인트 및 시간 등을 출력하는 코드이다.

 

그림2-7. 패턴을 텍스트 파일에 보내는 내용이다.

 

213줄~225줄 : 알고리즘(패턴)을 텍스트에 쓰기(w) 및 추가(a)의 형태로 내용을 보낸다.

215줄이 핵심이다. 215줄을 천천히 확인해 보자. 215줄에서 만들어진 데이터를 220줄/224줄에서 텍스트로 보낸다.

bricks_ai_data = "%s %d, %d, %d,%d, %d, %d %s\n" % ("[",brick_list_second[0], brick_list_second[1], brick_list_second[2], brick_list_second[3], brick_list_second[4], 1,"]")

 

텍스트에 들어가는 데이터는 아래 < 그림3 >과 같다. (그림1-2의 그림을 여기에서 다시 쓴다)

< 그림3 >에서 데이터는 [458, 408, 498, 448, 372, 1]이다.

 

"리스트열림 + 6개 숫자 + 리스트 닫힘"으로 이루어지는 구조이다. 태형을 분석해 보자.

리스트 열림(문자), 6개 숫자(int), 리스트 닫힘(문자)이다. → 총 8개의 데이터이다. 마지막에 "\n"을 넣은 이유는 "\ㅜ"이 없으면, 텍스트 파일 내, 각 데이터들이 붙여서 나온다. (가독성을 위해 "\n"을 넣었다)

 

문자는 "%s", 숫자는 "%d"로 형태를 정해준 후 8개 데이터를 텍스트에 담는다. 리스트 태형으로 담기 위해, ①"[" , ② 6개(73줄~85줄에서 저장한 x1, y1, x2, y2 및 100줄(470~480)일 때의 볼의 x 위치, 보상점수), ⑧"]"의 8개 데이터를 텍스트에 담는다.

 

그림3. 패턴을 text에 구현한 결과

 

 

 


4. 전체코드

패턴을 텍스트에 기록하는 이 글의 코드는 총 232줄이다. 이전 글에서 사용자가 직접 벽돌을 깨는 코드는 157줄이었다. 패턴을 기록하기 위해 75줄이 늘어난 것을 확인할 수 있다.

 

더보기
# 1. pygame 선언
import pygame
import time
import sys
import os

# 2. pygame 초기화
pygame.init()

# 3. pygame에 사용되는 전역변수 선언
BLACK = (0, 0, 0)
RED = (255, 0, 0)
GREEN = (0, 255, 0)
BLUE = (0, 0, 255)
WHITE = (255, 255, 255)
YELLOW = (255, 255, 0)
large_font = pygame.font.SysFont(None, 72)
small_font = pygame.font.SysFont(None, 36)
screen_width = 600
screen_height = 800
screen = pygame.display.set_mode((screen_width, screen_height))

clock = pygame.time.Clock()

# 4. pygame 무한루프
def runGame():
    ### 벽돌/공/패널 초기화 ###
    score = 0
    missed = 0
    SUCCESS = 1
    FAILURE = 2
    game_over = 0

    start_time = time.time()  # 191줄

    bricks = []
    COLUMN_COUNT = 8
    ROW_COUNT = 7
    for column_index in range(COLUMN_COUNT):
        for row_index in range(ROW_COUNT):
            brick = pygame.Rect(column_index * (60 + 10) + 35, row_index * (16 + 5) + 35, 60, 16)
            bricks.append(brick)

    ball = pygame.Rect(screen_width // 2, 250, 16, 16)  # pygame.Rect(x시작좌표, y시작좌표, x오른쪽 이동, y아래로 이동)

    ### 최초 공 이동
    ball_dx = 10  # 기본 이동 속도
    # ball_dx = 5     # 기본 이동 속도

    ball_dy = 10  # 기본 이동 속도
    # ball_dy = 5    # 기본 이동 속도           # 최초 시작할 때 공이 아래로 이동한다.

    paddle = pygame.Rect(screen_width // 2 - 80 // 2, screen_height - 16, 80, 16)
    paddle_dx = 0  # 패들은 좌우로만 이동

    #### 초기화 끝 ####

    brick_list_first = []               # 69줄~85줄까지의 데이터로 공의 x좌표를 리스트에 담는다.
    brick_list_second = []              # 69줄~85줄까지의 데이터로 공의 x좌표를 리스트에 담는다.

    global alghorism_x_position
    alghorism_x_position = 0

    while True:
        clock.tick(30)  # 초당 30프레임 설정 (초당 30번의 화면을 띄워준다) / FPS 설정 (Frame Per Second)
        screen.fill(BLACK)

        ### 공이 스크린 기준 400~410 및 440~450 사이를 지나갈 때, 패널의 예측 위치를 설정
        if 0 <= ball.centery < 400:
            brick_list_first = []
            brick_list_second = []

        elif brick_list_first == [] and 400 <= ball.centery <= 410:  # 400일 때도 체크
            brick_list_first.append(ball.centerx)
            brick_list_first.append(ball.centery)

            brick_list_second.append(ball.centerx)
            brick_list_second.append(ball.centery)

        elif brick_list_first != [] and 440 <= ball.centery <= 450:  # 400일 때도 체크
            brick_list_first.append(ball.centerx)
            brick_list_first.append(ball.centery)

            brick_list_second.append(ball.centerx)
            brick_list_second.append(ball.centery)

        if len(brick_list_first) == 4 and 470 < ball.centery <= 480  :  # 공이 450 ~ 550을 지날 때, 공의 y가 780인 위치에 패널이 이동한다.
            dir = './bricks_ai.txt'

            if os.path.isfile(dir):
                f = open('bricks_ai.txt', 'r')
                x_position_file = f.readlines()
                f.close()

                upper_point_1 = brick_list_first[0]  # 공의 궤적1
                upper_point_2 = brick_list_first[2]  # 공의 궤적2

                for i in x_position_file:
                    if (-5 <= eval(i)[0] - upper_point_1 <= 5) and (-5 <= eval(i)[2] - upper_point_2 <= 5):
                        alghorism_x_position = eval(i)[4]       # 공의 y위치가 780일 때의 x축 좌표를 찾으면 종료(break)
                        break

            brick_list_first = []

        if brick_list_second != [] and 765 <= ball.centery <= 775 : # 400일 때도 체크
            brick_list_second.append(ball.centerx)

        for event in pygame.event.get():
            if event.type == pygame.QUIT:  # 창 닫기 버튼을 눌렀을 떄
                pygame.quit()
                sys.exit()
                # break

            elif event.type == pygame.KEYDOWN:   # 키를 눌렀을 때
                if event.key == pygame.K_LEFT:      # 패들의 왼쪽 이동속도
                    # paddle_dx = -5
                    paddle_dx = -10
                elif event.key == pygame.K_RIGHT:      # 패들의 오른쪽 이동속도
                    # paddle_dx = 5
                    paddle_dx = 10
            elif event.type == pygame.KEYUP:        # 키를 눌렀다가 뗐을 때
                if event.key == pygame.K_LEFT:      # 눌러졌던 키보드가 다시 떨어졌을 때, 패들의 이동 속도를 0으로 설정하여 키보드로 더이상 움직이지 않게 한다.
                    paddle_dx = 0
                elif event.key == pygame.K_RIGHT:
                    paddle_dx = 0

        paddle.left += paddle_dx  # 해당 이동속도를 패들의 위치 값인 left에 적용하여 이후 패들을 화면에 출력할 때, 이동 거리를 움직이도록 합니다.

        ball.left += ball_dx
        ball.top += ball_dy

        if ball.left <= 0:  # 공이 왼쪽 벽면을 닿은 경우
            ball.left = 0
            ball_dx = -ball_dx
        elif ball.left >= screen_width - ball.width:  # 공이 오른쪽 벽면에 닿은 경우
            ball.left = screen_width - ball.width
            ball_dx = -ball_dx
        if ball.top < 0:  # 공이 천장에 닿은 경우
            ball.top = 0
            ball_dy = -ball_dy
        elif ball.top >= screen_height:  # 공이 바닥에 닿은 경우 (=missed 인 경우)
            missed += 1
            ball.left = screen_width // 2 - ball.width // 2
            ball.top = screen_height // 2 - ball.width // 2

            ball_dy = -ball_dy  # 공이 위로 간다. (missed가 났을 때, 공이 위쪽으로 움직인다)

        if missed >= 3:
            game_over = FAILURE
            print("10초 대기")
            time.sleep(10)
            # pygame.quit()
            # sys.exit()

        if paddle.left < 0:  # 이동한 패들이 좌우 벽면을 벗어나지 않게 설정하도록 하는 코드입니다
            paddle.left = 0
        elif paddle.left > screen_width - paddle.width:
            paddle.left = screen_width - paddle.width

        # 공과 벽돌 충돌 처리
        for brick in bricks:  # 공과 벽돌의 충돌을 감지하는 라인
            if ball.colliderect(brick):
                bricks.remove(brick)
                ball_dy = -ball_dy  # 공이 방향을 바꾼다.
                score += 1
                break

        if ball.colliderect(paddle):  # 공이 벽면이 아닌 패들에 충돌했을 때 이동 방향을 뒤집어 주도록하는 코드입니다
            ball_dy = -ball_dy
            if ball.centerx <= paddle.left or ball.centerx > paddle.right:  # 공이 패들의 좌,우측 벽면에 닿았을 경우를 감지하며, 이때 x 이동 방향을 뒤집어 준다.
                ball_dx = ball_dx * -1

        if len(bricks) == 0:
            print('success')
            game_over = SUCCESS

        # 화면 그리기
        for brick in bricks:  # bricks 리스트들의 모든 벽돌들을 출력하도록 합니다.
            pygame.draw.rect(screen, GREEN, brick)

        if game_over == 0:  # 게임 종료이면(0이면), 공을 화면에 출력한다.
            pygame.draw.circle(screen, WHITE, (ball.centerx, ball.centery), ball.width // 2)
            # 첫 번째 값은 화면, 두 번째 값은 색, 세 번째 값은 중심 좌표, 네 번째 값은 반지름, 다섯 번째 값은 선 굵기. 
            # 선 굵기는 생략 가능하고 기본 값은 0이며 색이 채워짐

        pygame.draw.rect(screen, BLUE, paddle)  # 패들을 출력한다.

        ### 소요되는 시간을 출력한다.
        end_time = time.time()
        game_time = int(end_time - start_time)  # 초 단위      # 34줄

        ### 화면에 포인트 및 미스(missed)를 출력한다.
        score_image = small_font.render('Point {}'.format(score), True, YELLOW)
        screen.blit(score_image, (10, 10))

        game_time_image = small_font.render('time {}'.format(game_time), True, YELLOW)  # 73줄
        screen.blit(game_time_image, game_time_image.get_rect(right=screen_width // 2 + 80, top=10))

        ball_speed_image = small_font.render('speed {}'.format(abs(ball_dx)), True, YELLOW)  # 73줄
        screen.blit(ball_speed_image, ball_speed_image.get_rect(right=screen_width // 2 - 40, top=10))

        missed_image = small_font.render('Missed {}'.format(missed), True, YELLOW)
        screen.blit(missed_image, missed_image.get_rect(right=screen_width - 10, top=10))

        if game_over > 0:
            if game_over == SUCCESS:
                success_image = large_font.render('성공', True, RED)
                screen.blit(success_image, success_image.get_rect(centerx=screen_width // 2, centery=screen_height // 2))
            elif game_over == FAILURE:
                failure_image = large_font.render('실패', True, RED)
                screen.blit(failure_image, failure_image.get_rect(centerx=screen_width // 2, centery=screen_height // 2))

        if len(brick_list_second) == 6:          # 5개가 들어가야 할거 같은데, y가 "760~780"인 경우에는 x 좌표가 2개가 나온다.
            ### 알고리즘을 텍스트(text)에 보내기
            bricks_ai_data = "%s %d, %d, %d,%d, %d, %d %s\n" % ("[",brick_list_second[0], brick_list_second[1], brick_list_second[2], brick_list_second[3], brick_list_second[4], 1,"]")
            dir = './bricks_ai.txt'

            if os.path.isfile(dir):
                f = open('bricks_ai.txt', 'a')      # 추가
                f.write(bricks_ai_data)
                f.close()
            else:
                f = open('bricks_ai.txt', 'w')      # 쓰기
                f.write(bricks_ai_data)
                f.close()

            brick_list_second = []

        pygame.display.update()

runGame()
pygame.quit()

 


5. 마치며

위의 코드는 벽돌깨기 게임의 볼의 특정위치(y축)에서 x위치를 텍스트에 담는 것에 의의가 있다. 게임이 진행될 때, 어떤 기록이 텍스트에 기록되고, 그 기록된 기록을 읽어와서 활용하는 것이 중요하다.

 

이 글에서 알 수 있는건, 어떻게 데이터를 텍스트에 저장하고, 그 내용을 활용(읽어오는 것)하는지에 대한 내용이다. 데이터를 만들고, 활용하는 방법은 숙지하는게 좋아 보인다.

 

bricksbreak_test_12(pattern_making).py
0.01MB

 

다음 글에서는 게임규칙만 넣어주고, pc가 자동으로 벽돌을 깨는 코드를 구현할 예정이다.

 

반응형