ㅁ 개요
O 프로그램 소개
- 이번 내용은 약 1주일전 출시된 그록3를 활용하여 출시 당시 시연했던 테트리스+비주얼드 게임을 5분 내외로 만는 방법에 대하여 알아보겠습니다.
1.아래 사이트에 접속 후 왼쪽 메뉴에서 'Grok' 를 클릭 합니다.

2. 아래와 같이 'Grok3 beta'가 선택된 상태에서 "테스트리와 ~~~" 요청 글을 입력합니다.

소스코드 1(12-2.py)
import pygame
import random
# 초기화
pygame.init()
# 화면 설정
WIDTH, HEIGHT = 400, 600
GRID_SIZE = 30
GRID_WIDTH = WIDTH // GRID_SIZE
GRID_HEIGHT = HEIGHT // GRID_SIZE
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Tetris Gems")
# 색상 정의
COLORS = [(255, 0, 0), (0, 255, 0), (0, 0, 255), (255, 255, 0)] # 빨강, 초록, 파랑, 노랑
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
# 테트리스 블록 모양 (7가지 테트로미노)
SHAPES = [
[[1, 1, 1, 1]], # I
[[1, 1], [1, 1]], # O
[[0, 1, 0], [1, 1, 1]], # T
[[0, 1, 1], [1, 1, 0]], # S
[[1, 1, 0], [0, 1, 1]], # Z
[[1, 0, 0], [1, 1, 1]], # J
[[0, 0, 1], [1, 1, 1]] # L
]
# 게임 보드 초기화
board = [[None for _ in range(GRID_WIDTH)] for _ in range(GRID_HEIGHT)]
# 블록 클래스
class Block:
def __init__(self):
self.shape = random.choice(SHAPES)
self.colors = [[random.choice(COLORS) if cell else None for cell in row] for row in self.shape]
self.x = GRID_WIDTH // 2 - len(self.shape[0]) // 2
self.y = 0
def draw(self):
for i, row in enumerate(self.shape):
for j, cell in enumerate(row):
if cell:
pygame.draw.rect(screen, self.colors[i][j],
(self.x * GRID_SIZE + j * GRID_SIZE,
self.y * GRID_SIZE + i * GRID_SIZE,
GRID_SIZE - 1, GRID_SIZE - 1))
def move(self, dx, dy):
self.x += dx
self.y += dy
def rotate(self):
# 90도 회전 (행렬 전치 후 좌우 반전)
new_shape = [[self.shape[len(self.shape) - 1 - j][i] for j in range(len(self.shape))]
for i in range(len(self.shape[0]))]
new_colors = [[self.colors[len(self.shape) - 1 - j][i] for j in range(len(self.shape))]
for i in range(len(self.shape[0]))]
old_shape, old_colors = self.shape, self.colors
self.shape, self.colors = new_shape, new_colors
if self.collides():
self.shape, self.colors = old_shape, old_colors # 충돌 시 회전 취소
def collides(self):
for i, row in enumerate(self.shape):
for j, cell in enumerate(row):
if cell:
new_x = self.x + j
new_y = self.y + i
if (new_x < 0 or new_x >= GRID_WIDTH or
new_y >= GRID_HEIGHT or
(new_y >= 0 and board[new_y][new_x] is not None)):
return True
return False
def place(self):
for i, row in enumerate(self.shape):
for j, cell in enumerate(row):
if cell:
board[self.y + i][self.x + j] = self.colors[i][j]
# 매치-3 체크 및 제거
def check_matches():
matches = []
# 가로 체크
for i in range(GRID_HEIGHT):
for j in range(GRID_WIDTH - 2):
if (board[i][j] and board[i][j + 1] and board[i][j + 2] and
board[i][j] == board[i][j + 1] == board[i][j + 2]):
matches.extend([(i, j), (i, j + 1), (i, j + 2)])
# 세로 체크
for i in range(GRID_HEIGHT - 2):
for j in range(GRID_WIDTH):
if (board[i][j] and board[i + 1][j] and board[i + 2][j] and
board[i][j] == board[i + 1][j] == board[i + 2][j]):
matches.extend([(i, j), (i + 1, j), (i + 2, j)])
# 매치 제거
for i, j in matches:
board[i][j] = None
# 블록 아래로 떨어뜨리기
for j in range(GRID_WIDTH):
for i in range(GRID_HEIGHT - 1, -1, -1):
if board[i][j] is None:
for k in range(i - 1, -1, -1):
if board[k][j] is not None:
board[i][j] = board[k][j]
board[k][j] = None
break
# 메인 게임 루프
def main():
clock = pygame.time.Clock()
current_block = Block()
fall_time = 0
fall_speed = 500 # 밀리초 단위
running = True
while running:
fall_time += clock.get_rawtime()
clock.tick(60)
# 이벤트 처리
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT and not current_block.collides():
current_block.move(-1, 0)
if current_block.collides():
current_block.move(1, 0)
if event.key == pygame.K_RIGHT and not current_block.collides():
current_block.move(1, 0)
if current_block.collides():
current_block.move(-1, 0)
if event.key == pygame.K_DOWN:
current_block.move(0, 1)
if current_block.collides():
current_block.move(0, -1)
current_block.place()
check_matches()
current_block = Block()
if event.key == pygame.K_UP: # 위쪽 화살표로 회전
current_block.rotate()
# 블록 자동 하강
if fall_time >= fall_speed:
current_block.move(0, 1)
if current_block.collides():
current_block.move(0, -1)
current_block.place()
check_matches()
current_block = Block()
fall_time = 0
# 화면 그리기
screen.fill(BLACK)
for i in range(GRID_HEIGHT):
for j in range(GRID_WIDTH):
if board[i][j]:
pygame.draw.rect(screen, board[i][j],
(j * GRID_SIZE, i * GRID_SIZE, GRID_SIZE - 1, GRID_SIZE - 1))
current_block.draw()
pygame.display.flip()
pygame.quit()
if __name__ == "__main__":
main()
3.위의 소스코드를 복사하여 비주얼스튜디오코드 등 편집기에 붙여넣고 실행하면 아래와 같이 실행되는 것을 볼 수 있습니다. 하지만, 화살표 아래키를 눌러도 즉시 블록이 내려가지 않습니다.

4.위 3의 단점을 보완하기위해 다시 그록3에게 아래와 같이 보완요청을 합니다.
"화살표 아래키 ~~~"

소스코드 2 (12-3.py)
import pygame
import random
# 초기화
pygame.init()
# 화면 설정
WIDTH, HEIGHT = 400, 600
GRID_SIZE = 30
GRID_WIDTH = WIDTH // GRID_SIZE
GRID_HEIGHT = HEIGHT // GRID_SIZE
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Tetris Gems")
# 색상 정의
COLORS = [(255, 0, 0), (0, 255, 0), (0, 0, 255), (255, 255, 0)] # 빨강, 초록, 파랑, 노랑
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
# 테트리스 블록 모양 (7가지 테트로미노)
SHAPES = [
[[1, 1, 1, 1]], # I
[[1, 1], [1, 1]], # O
[[0, 1, 0], [1, 1, 1]], # T
[[0, 1, 1], [1, 1, 0]], # S
[[1, 1, 0], [0, 1, 1]], # Z
[[1, 0, 0], [1, 1, 1]], # J
[[0, 0, 1], [1, 1, 1]] # L
]
# 게임 보드 초기화
board = [[None for _ in range(GRID_WIDTH)] for _ in range(GRID_HEIGHT)]
# 블록 클래스
class Block:
def __init__(self):
self.shape = random.choice(SHAPES)
self.colors = [[random.choice(COLORS) if cell else None for cell in row] for row in self.shape]
self.x = GRID_WIDTH // 2 - len(self.shape[0]) // 2
self.y = 0
def draw(self):
for i, row in enumerate(self.shape):
for j, cell in enumerate(row):
if cell:
pygame.draw.rect(screen, self.colors[i][j],
(self.x * GRID_SIZE + j * GRID_SIZE,
self.y * GRID_SIZE + i * GRID_SIZE,
GRID_SIZE - 1, GRID_SIZE - 1))
def move(self, dx, dy):
self.x += dx
self.y += dy
def rotate(self):
# 90도 회전 (행렬 전치 후 좌우 반전)
new_shape = [[self.shape[len(self.shape) - 1 - j][i] for j in range(len(self.shape))]
for i in range(len(self.shape[0]))]
new_colors = [[self.colors[len(self.shape) - 1 - j][i] for j in range(len(self.shape))]
for i in range(len(self.shape[0]))]
old_shape, old_colors = self.shape, self.colors
self.shape, self.colors = new_shape, new_colors
if self.collides():
self.shape, self.colors = old_shape, old_colors # 충돌 시 회전 취소
def collides(self):
for i, row in enumerate(self.shape):
for j, cell in enumerate(row):
if cell:
new_x = self.x + j
new_y = self.y + i
if (new_x < 0 or new_x >= GRID_WIDTH or
new_y >= GRID_HEIGHT or
(new_y >= 0 and board[new_y][new_x] is not None)):
return True
return False
def place(self):
for i, row in enumerate(self.shape):
for j, cell in enumerate(row):
if cell:
board[self.y + i][self.x + j] = self.colors[i][j]
def drop(self):
# 블록을 바닥까지 즉시 내리기
while not self.collides():
self.y += 1
self.y -= 1 # 충돌 직전 위치로 되돌리기
self.place()
# 매치-3 체크 및 제거
def check_matches():
matches = []
# 가로 체크
for i in range(GRID_HEIGHT):
for j in range(GRID_WIDTH - 2):
if (board[i][j] and board[i][j + 1] and board[i][j + 2] and
board[i][j] == board[i][j + 1] == board[i][j + 2]):
matches.extend([(i, j), (i, j + 1), (i, j + 2)])
# 세로 체크
for i in range(GRID_HEIGHT - 2):
for j in range(GRID_WIDTH):
if (board[i][j] and board[i + 1][j] and board[i + 2][j] and
board[i][j] == board[i + 1][j] == board[i + 2][j]):
matches.extend([(i, j), (i + 1, j), (i + 2, j)])
# 매치 제거
for i, j in matches:
board[i][j] = None
# 블록 아래로 떨어뜨리기
for j in range(GRID_WIDTH):
for i in range(GRID_HEIGHT - 1, -1, -1):
if board[i][j] is None:
for k in range(i - 1, -1, -1):
if board[k][j] is not None:
board[i][j] = board[k][j]
board[k][j] = None
break
# 메인 게임 루프
def main():
clock = pygame.time.Clock()
current_block = Block()
fall_time = 0
fall_speed = 500 # 밀리초 단위
running = True
while running:
fall_time += clock.get_rawtime()
clock.tick(60)
# 이벤트 처리
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT and not current_block.collides():
current_block.move(-1, 0)
if current_block.collides():
current_block.move(1, 0)
if event.key == pygame.K_RIGHT and not current_block.collides():
current_block.move(1, 0)
if current_block.collides():
current_block.move(-1, 0)
if event.key == pygame.K_DOWN:
# 아래 키로 즉시 드롭
current_block.drop()
check_matches()
current_block = Block()
if event.key == pygame.K_UP: # 위쪽 화살표로 회전
current_block.rotate()
# 블록 자동 하강
if fall_time >= fall_speed:
current_block.move(0, 1)
if current_block.collides():
current_block.move(0, -1)
current_block.place()
check_matches()
current_block = Block()
fall_time = 0
# 화면 그리기
screen.fill(BLACK)
for i in range(GRID_HEIGHT):
for j in range(GRID_WIDTH):
if board[i][j]:
pygame.draw.rect(screen, board[i][j],
(j * GRID_SIZE, i * GRID_SIZE, GRID_SIZE - 1, GRID_SIZE - 1))
current_block.draw()
pygame.display.flip()
pygame.quit()
if __name__ == "__main__":
main()
수정된 부분

5. 위 4에서 나온 코드를 복사하여 code편집기에 붙여넣고 실행합니다.
그러면 아래와 같이 실행되는데, 화살표 아래키를 눌렀을때 즉시 아래로 내려가는 것을 확인할 수 있습니다.
하지만 블록이 아래로 내려가는 속도가 너무 느려 게임이 재미가 없습니다.

6. 위 5번의 단점인 블록의 하강 속도를 증가시키키 위해 아래와 같이 그록3에게 요청합니다.
"내려가는 속도가~~"

소스코드 3( (12-4.py, 최종 코드)
import pygame
import random
# 초기화
pygame.init()
# 화면 설정
WIDTH, HEIGHT = 400, 600
GRID_SIZE = 30
GRID_WIDTH = WIDTH // GRID_SIZE
GRID_HEIGHT = HEIGHT // GRID_SIZE
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Tetris Gems")
# 색상 정의
COLORS = [(255, 0, 0), (0, 255, 0), (0, 0, 255), (255, 255, 0)] # 빨강, 초록, 파랑, 노랑
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
# 테트리스 블록 모양 (7가지 테트로미노)
SHAPES = [
[[1, 1, 1, 1]], # I
[[1, 1], [1, 1]], # O
[[0, 1, 0], [1, 1, 1]], # T
[[0, 1, 1], [1, 1, 0]], # S
[[1, 1, 0], [0, 1, 1]], # Z
[[1, 0, 0], [1, 1, 1]], # J
[[0, 0, 1], [1, 1, 1]] # L
]
# 게임 보드 초기화
board = [[None for _ in range(GRID_WIDTH)] for _ in range(GRID_HEIGHT)]
# 블록 클래스
class Block:
def __init__(self):
self.shape = random.choice(SHAPES)
self.colors = [[random.choice(COLORS) if cell else None for cell in row] for row in self.shape]
self.x = GRID_WIDTH // 2 - len(self.shape[0]) // 2
self.y = 0
def draw(self):
for i, row in enumerate(self.shape):
for j, cell in enumerate(row):
if cell:
pygame.draw.rect(screen, self.colors[i][j],
(self.x * GRID_SIZE + j * GRID_SIZE,
self.y * GRID_SIZE + i * GRID_SIZE,
GRID_SIZE - 1, GRID_SIZE - 1))
def move(self, dx, dy):
self.x += dx
self.y += dy
def rotate(self):
# 90도 회전 (행렬 전치 후 좌우 반전)
new_shape = [[self.shape[len(self.shape) - 1 - j][i] for j in range(len(self.shape))]
for i in range(len(self.shape[0]))]
new_colors = [[self.colors[len(self.shape) - 1 - j][i] for j in range(len(self.shape))]
for i in range(len(self.shape[0]))]
old_shape, old_colors = self.shape, self.colors
self.shape, self.colors = new_shape, new_colors
if self.collides():
self.shape, self.colors = old_shape, old_colors # 충돌 시 회전 취소
def collides(self):
for i, row in enumerate(self.shape):
for j, cell in enumerate(row):
if cell:
new_x = self.x + j
new_y = self.y + i
if (new_x < 0 or new_x >= GRID_WIDTH or
new_y >= GRID_HEIGHT or
(new_y >= 0 and board[new_y][new_x] is not None)):
return True
return False
def place(self):
for i, row in enumerate(self.shape):
for j, cell in enumerate(row):
if cell:
board[self.y + i][self.x + j] = self.colors[i][j]
def drop(self):
# 블록을 바닥까지 즉시 내리기
while not self.collides():
self.y += 1
self.y -= 1 # 충돌 직전 위치로 되돌리기
self.place()
# 매치-3 체크 및 제거
def check_matches():
matches = []
# 가로 체크
for i in range(GRID_HEIGHT):
for j in range(GRID_WIDTH - 2):
if (board[i][j] and board[i][j + 1] and board[i][j + 2] and
board[i][j] == board[i][j + 1] == board[i][j + 2]):
matches.extend([(i, j), (i, j + 1), (i, j + 2)])
# 세로 체크
for i in range(GRID_HEIGHT - 2):
for j in range(GRID_WIDTH):
if (board[i][j] and board[i + 1][j] and board[i + 2][j] and
board[i][j] == board[i + 1][j] == board[i + 2][j]):
matches.extend([(i, j), (i + 1, j), (i + 2, j)])
# 매치 제거
for i, j in matches:
board[i][j] = None
# 블록 아래로 떨어뜨리기
for j in range(GRID_WIDTH):
for i in range(GRID_HEIGHT - 1, -1, -1):
if board[i][j] is None:
for k in range(i - 1, -1, -1):
if board[k][j] is not None:
board[i][j] = board[k][j]
board[k][j] = None
break
# 메인 게임 루프
def main():
clock = pygame.time.Clock()
current_block = Block()
fall_time = 0
fall_speed = 50 # 속도 증가: 500ms -> 200ms (0.2초)
running = True
while running:
fall_time += clock.get_rawtime()
clock.tick(60)
# 이벤트 처리
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT and not current_block.collides():
current_block.move(-1, 0)
if current_block.collides():
current_block.move(1, 0)
if event.key == pygame.K_RIGHT and not current_block.collides():
current_block.move(1, 0)
if current_block.collides():
current_block.move(-1, 0)
if event.key == pygame.K_DOWN:
# 아래 키로 즉시 드롭
current_block.drop()
check_matches()
current_block = Block()
if event.key == pygame.K_UP: # 위쪽 화살표로 회전
current_block.rotate()
# 블록 자동 하강
if fall_time >= fall_speed:
current_block.move(0, 1)
if current_block.collides():
current_block.move(0, -1)
current_block.place()
check_matches()
current_block = Block()
fall_time = 0
# 화면 그리기
screen.fill(BLACK)
for i in range(GRID_HEIGHT):
for j in range(GRID_WIDTH):
if board[i][j]:
pygame.draw.rect(screen, board[i][j],
(j * GRID_SIZE, i * GRID_SIZE, GRID_SIZE - 1, GRID_SIZE - 1))
current_block.draw()
pygame.display.flip()
pygame.quit()
if __name__ == "__main__":
main()
수정된 부분
> 수정된 코드는 fall_speed=500 -> fall_speed=50 로 변경하여 하강 속도를 높였습니다.

7.위 6의 수정된 소스코드를 복사 후 code 등에 붙여넣어 실행하면 아래와 같이 실행되는데,
이제 하강 속도가 많이 빨라 졌습니다.

위와 같이 그록3에게 만들고 싶은 코드를 요청하고, 실행 후 부족한 내용이 있으면 다시 요청하고~~실행하고를
몇번 반복하면 원하는 코드를 제대로 만들어 볼 수 있었습니다.
아쉬운 점은 코드를 x.com에서 바로 실행할 수 있었으면 더욱 빠르게 테스트 해볼 수 있었을 것 같은데, 아직 해당 기능은 없는 것으로 보입니다.
좋았던 점은 다른 ai챗봇 보다 코드가 월등히 정교하고, 디테일이 굉장한 강점으로 보였습니다. 그 만큼 시간을 절약할 수 있고, 노가다(?)를 덜 할 수 있게 도와주는 AI챗봇으로 보입니다.
우리 게시글에 있는 무료AI챗봇 순위에서 당당히 1위를 줄 수 있을 것 같습니다.
https://pagichacha.tistory.com/376
현재 그록3 베타는 무료로 풀려 있으므로 많이 사용해 보시면 좋을 것 같습니다.
(단, 사용량 제한은 있으나, 그런데로 충분히 테스트할 정도는 되는것 같습니다.)
오늘은 여기까지이며, 댓글과 하트는 제가 이글을 지속할 수 있게 해주는 힘이 됩니다.
감사합니다.
'파이썬 AI 실습 > 그록3로 5분만에 테트리스+비주얼드 게임만들기' 카테고리의 다른 글
그록3로 5분만에 지구와 화성 사이를 오가는 3D 플롯 만들기 (0) | 2025.03.01 |
---|