tetris.py
0.02MB
* 클로드 & 코파일럿이 함께 만든 Tetris 파이썬 코드입니다.
* 전 파이썬의 기본문법만 알고 있어요.
* 아직 완성도는 부족하지만 수정하면서 게임하시기에는 재미있을 꺼예요.
(이상한 블록을 추가 할 수도 있구요. ㅎ)
# Description: 테트리스 게임을 구현한 코드입니다.
import pygame
import random
import time
# 초기화
pygame.init()
# 색상 정의
COLORS = {
'BLACK': (0, 0, 0),
'WHITE': (255, 255, 255),
'GRAY': (128, 128, 128),
'LIGHT_GRAY': (192, 192, 192),
'RED': (255, 0, 0),
'GREEN': (0, 255, 0),
'BLUE': (0, 0, 255),
'CYAN': (0, 255, 255),
'MAGENTA': (255, 0, 255),
'YELLOW': (255, 255, 0),
'ORANGE': (255, 165, 0)
}
# 테트리미노 모양 정의
SHAPES = [
[[1, 1, 1, 1]], # I
[[1, 1], [1, 1]], # O
[[1, 1, 1], [0, 1, 0]], # T
[[1, 1, 1], [1, 0, 0]], # L
[[1, 1, 1], [0, 0, 1]], # J
[[1, 1, 0], [0, 1, 1]], # S
[[0, 1, 1], [1, 1, 0]] # Z
]
class Tetris:
def __init__(self):
self.width = 600
self.height = 600
self.grid_size = 25
self.grid_width = 10
self.grid_height = 20
self.screen = pygame.display.set_mode((self.width, self.height))
pygame.display.set_caption('Tetris')
# 게임 상태 초기화
self.reset_game()
self.game_state = "START" # START, PLAYING, PAUSED, GAMEOVER
def reset_game(self):
# 게임 보드 초기화
self.board = [[0] * self.grid_width for _ in range(self.grid_height)]
self.current_piece = None
self.next_piece = self.new_piece()
self.held_piece = None
self.can_hold = True
self.score = 0
self.level = 1
self.lines_cleared = 0
self.show_ghost = True
self.base_fall_time = 1.0
self.fall_time = self.base_fall_time
self.last_fall = time.time()
def new_piece(self):
# 새로운 테트리미노 생성
shape = random.choice(SHAPES)
color = random.choice(list(COLORS.values())[4:]) # 기본 색상 제외
return {
'shape': shape,
'color': color,
'x': self.grid_width // 2 - len(shape[0]) // 2,
'y': 0,
'rotation': 0
}
def draw_text(self, text, size, color, x, y, center=True):
# 텍스트를 화면에 그림
font = pygame.font.Font(None, size)
text_surface = font.render(text, True, color)
if center:
text_rect = text_surface.get_rect(center=(x, y))
else:
text_rect = text_surface.get_rect(topleft=(x, y))
self.screen.blit(text_surface, text_rect)
return text_rect.bottom
def draw_info_box(self, title, content, x, y, width, height):
# 정보 박스를 그림
pygame.draw.rect(self.screen, COLORS['WHITE'], (x, y, width, height), 1)
title_y = self.draw_text(title, 24, COLORS['WHITE'], x + width//2, y - 15)
if content:
for i in range(len(content['shape'])):
for j in range(len(content['shape'][0])):
if content['shape'][i][j]:
pygame.draw.rect(self.screen, content['color'],
(x + (width - len(content['shape'][0]) * self.grid_size)//2 + j * self.grid_size,
y + (height - len(content['shape']) * self.grid_size)//2 + i * self.grid_size,
self.grid_size - 1, self.grid_size - 1))
def draw(self):
# 화면을 검은색으로 채움
self.screen.fill(COLORS['BLACK'])
# 게임 상태가 "START"일 때
if self.game_state == "START":
# "TETRIS" 텍스트를 화면 중앙에 그림
self.draw_text("TETRIS", 72, COLORS['WHITE'], self.width//2, self.height//3, center=True)
# 깜박이는 효과로 "PRESS ANY KEY TO START" 텍스트를 화면 중앙에 그림
if int(time.time() * 2) % 2:
self.draw_text("PRESS ANY KEY TO START", 36, COLORS['WHITE'], self.width//2, self.height//2, center=True)
pygame.display.flip()
return
# 게임 상태가 "PAUSED"일 때
if self.game_state == "PAUSED":
# "PAUSED" 텍스트를 화면 중앙에 그림
self.draw_text("PAUSED", 72, COLORS['WHITE'], self.width//2, self.height//2, center=True)
pygame.display.flip()
return
# 게임 상태가 "GAMEOVER"일 때
if self.game_state == "GAMEOVER":
# "GAME OVER" 텍스트를 화면 중앙에 그림
self.draw_text("GAME OVER", 72, COLORS['RED'], self.width//2, self.height//3, center=True)
# "Press R to Restart or Q to Quit" 텍스트를 화면 중앙에 그림
self.draw_text("Press R to Restart or Q to Quit", 36, COLORS['WHITE'], self.width//2, self.height//2, center=True)
pygame.display.flip()
return
# 게임 보드의 왼쪽 상단 좌표 계산
board_left = (self.width - self.grid_width * self.grid_size) // 2
board_top = (self.height - self.grid_height * self.grid_size) // 2
# 게임 보드 배경을 그림
pygame.draw.rect(self.screen, (30,30,30),
(board_left - 1, board_top - 1,
self.grid_width * self.grid_size + 2,
self.grid_height * self.grid_size + 2))
# 보드에 있는 기존 블록들을 그림
for y in range(self.grid_height):
for x in range(self.grid_width):
if self.board[y][x]:
pygame.draw.rect(self.screen, self.board[y][x],
(board_left + x * self.grid_size,
board_top + y * self.grid_size,
self.grid_size - 1, self.grid_size - 1))
# 고스트 블록을 그림
if self.show_ghost and self.current_piece:
ghost_y = self.get_ghost_position()
for i in range(len(self.current_piece['shape'])):
for j in range(len(self.current_piece['shape'][0])):
if self.current_piece['shape'][i][j]:
pygame.draw.rect(self.screen, COLORS['GRAY'],
(board_left + (self.current_piece['x'] + j) * self.grid_size,
board_top + (ghost_y + i) * self.grid_size,
self.grid_size - 1, self.grid_size - 1), 1)
# 현재 블록을 그림
if self.current_piece:
for i in range(len(self.current_piece['shape'])):
for j in range(len(self.current_piece['shape'][0])):
if self.current_piece['shape'][i][j]:
pygame.draw.rect(self.screen, self.current_piece['color'],
(board_left + (self.current_piece['x'] + j) * self.grid_size,
board_top + (self.current_piece['y'] + i) * self.grid_size,
self.grid_size - 1, self.grid_size - 1))
# 정보 패널의 왼쪽 상단 좌표 계산
info_left = board_left + (self.grid_width + 1) * self.grid_size
info_top = board_top
box_size = self.grid_size * 4
# NEXT 박스를 그림
self.draw_info_box("NEXT", self.next_piece, info_left, info_top, box_size, box_size)
# HOLD 박스를 그림
self.draw_info_box("HOLD", self.held_piece, info_left, info_top + box_size + 30, box_size, box_size)
# 컨트롤 정보를 그림
controls_y = info_top + 2 * box_size + 60
self.draw_text("H: Hold", 24, COLORS['WHITE'], info_left + box_size//2, controls_y, True)
self.draw_text("G: Ghost", 24, COLORS['WHITE'], info_left + box_size//2, controls_y + 30, True)
# 레벨과 점수를 그림
level_y = controls_y + 80
self.draw_text(f"LEVEL: {self.level}", 24, COLORS['WHITE'], info_left + box_size//2, level_y, True)
self.draw_text(f"SCORE: {self.score}", 24, COLORS['WHITE'], info_left + box_size//2, level_y + 30, True)
# 화면 업데이트
pygame.display.flip()
def run(self):
clock = pygame.time.Clock()
running = True
while running:
if self.game_state == "START":
self.draw()
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
elif event.type == pygame.KEYDOWN:
self.game_state = "PLAYING"
self.current_piece = self.new_piece()
continue
if self.game_state == "GAMEOVER":
self.draw()
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_r:
self.reset_game()
self.game_state = "PLAYING"
self.current_piece = self.new_piece()
elif event.key == pygame.K_q:
running = False
continue
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_p:
self.game_state = "PAUSED" if self.game_state == "PLAYING" else "PLAYING"
elif self.game_state == "PLAYING":
if event.key == pygame.K_LEFT:
if self.valid_move(self.current_piece,
self.current_piece['x'] - 1,
self.current_piece['y']):
self.current_piece['x'] -= 1
elif event.key == pygame.K_RIGHT:
if self.valid_move(self.current_piece,
self.current_piece['x'] + 1,
self.current_piece['y']):
self.current_piece['x'] += 1
elif event.key == pygame.K_DOWN:
if self.valid_move(self.current_piece,
self.current_piece['x'],
self.current_piece['y'] + 1):
self.current_piece['y'] += 1
elif event.key == pygame.K_UP:
rotated = self.rotate_piece(self.current_piece)
if self.valid_move({'shape': rotated,
'x': self.current_piece['x'],
'y': self.current_piece['y']},
self.current_piece['x'],
self.current_piece['y']):
self.current_piece['shape'] = rotated
elif event.key == pygame.K_SPACE:
while self.valid_move(self.current_piece,
self.current_piece['x'],
self.current_piece['y'] + 1):
self.current_piece['y'] += 1
elif event.key == pygame.K_h:
self.hold_piece()
elif event.key == pygame.K_g:
self.show_ghost = not self.show_ghost
if self.game_state == "PLAYING":
if time.time() - self.last_fall > self.fall_time:
if self.valid_move(self.current_piece,
self.current_piece['x'],
self.current_piece['y'] + 1):
self.current_piece['y'] += 1
else:
for i in range(len(self.current_piece['shape'])):
for j in range(len(self.current_piece['shape'][0])):
if self.current_piece['shape'][i][j]:
self.board[self.current_piece['y'] + i][self.current_piece['x'] + j] = self.current_piece['color']
self.clear_lines()
self.current_piece = self.next_piece
self.next_piece = self.new_piece()
self.can_hold = True
if not self.valid_move(self.current_piece,
self.current_piece['x'],
self.current_piece['y']):
self.game_state = "GAMEOVER"
self.last_fall = time.time()
self.draw()
clock.tick(60)
pygame.quit()
# [이전에 정의된 나머지 메서드들은 그대로 유지]
def rotate_piece(self, piece):
shape = piece['shape']
#시계 방향 회전
#return [[shape[y][x] for y in range(len(shape)-1, -1, -1)] for x in range(len(shape[0]))]
# 시계 반대방향으로 회전
return [[shape[y][x] for y in range(len(shape))] for x in range(len(shape[0])-1, -1, -1)]
def valid_move(self, piece, x, y):
for i in range(len(piece['shape'])):
for j in range(len(piece['shape'][0])):
if piece['shape'][i][j]:
new_x = x + j
new_y = y + i
if (new_x < 0 or new_x >= self.grid_width or
new_y >= self.grid_height or
(new_y >= 0 and self.board[new_y][new_x])):
return False
return True
def get_ghost_position(self):
if not self.current_piece:
return None
ghost_piece = self.current_piece.copy()
ghost_y = ghost_piece['y']
while self.valid_move(ghost_piece, ghost_piece['x'], ghost_y + 1):
ghost_y += 1
return ghost_y
def hold_piece(self):
if not self.can_hold:
return
if self.held_piece is None:
self.held_piece = self.current_piece
self.current_piece = self.next_piece
self.next_piece = self.new_piece()
else:
self.held_piece, self.current_piece = self.current_piece, self.held_piece
self.current_piece['x'] = self.grid_width // 2 - len(self.current_piece['shape'][0]) // 2
self.current_piece['y'] = 0
self.can_hold = False
def clear_lines(self):
# lines = 0
# y = self.grid_height - 1
# while y >= 0:
# if all(self.board[y]):
# lines += 1
# del self.board[y]
# self.board.insert(0, [0] * self.grid_width)
# else:
# y -= 1
# if lines > 0:
# score_multiplier = {1: 100, 2: 300, 3: 500, 4: 800}
# self.score += score_multiplier.get(lines, 1000) * self.level
# self.lines_cleared += lines
# self.level = min(20, 1 + self.lines_cleared // 10)
# self.fall_time = self.base_fall_time * (0.8 ** (self.level - 1))
lines = 0
new_board = [row for row in self.board if any(cell == 0 for cell in row)]
lines = self.grid_height - len(new_board)
new_board = [[0] * self.grid_width for _ in range(lines)] + new_board
if lines > 0:
self.board = new_board
score_multiplier = {1: 100, 2: 300, 3: 500, 4: 800}
self.score += score_multiplier.get(lines, 1000) * self.level
self.lines_cleared += lines
self.level = min(20, 1 + self.lines_cleared // 10)
self.fall_time = self.base_fall_time * (0.8 ** (self.level - 1))
if __name__ == '__main__':
game = Tetris()
game.run()
|
'IT 관련 > 기타' 카테고리의 다른 글
세계시간 코드 설명 (0) | 2025.03.14 |
---|---|
세계시간 (0) | 2025.03.14 |
Python에서 외부 모듈을 가져오는 방법 정리 (0) | 2025.03.11 |
간단 버전 flappy bird (html) (0) | 2025.02.28 |
Claude 가 만들어 준 Tetris (웹버젼) (0) | 2025.02.18 |