目录
俄罗斯方块简易版 pygame
控制下落时间:
fall_interval = 0.2
import pygame
import random
import time
# 初始化 Pygame
pygame.init()
# 颜色定义
COLORS = {'I': (0, 255, 255), # 青色
'O': (255, 255, 0), # 黄色
'T': (128, 0, 128), # 紫色
'J': (0, 0, 255), # 蓝色
'L': (255, 165, 0), # 橙色
'S': (0, 255, 0), # 绿色
'Z': (255, 0, 0), # 红色
'background': (0, 0, 0), 'grid': (40, 40, 40)}
# 游戏区域尺寸
WIDTH, HEIGHT = 10, 20
CELL_SIZE = 30
SCREEN_WIDTH = CELL_SIZE * (WIDTH + 6)
SCREEN_HEIGHT = CELL_SIZE * HEIGHT
# 方块形状定义
SHAPES = {'I': [[1, 1, 1, 1]], 'O': [[1, 1], [1, 1]], 'T': [[0, 1, 0], [1, 1, 1]], 'J': [[1, 0, 0], [1, 1, 1]], 'L': [[0, 0, 1], [1, 1, 1]], 'S': [[0, 1, 1], [1, 1, 0]], 'Z': [[1, 1, 0], [0, 1, 1]]}
class Tetris:
def __init__(self):
self.screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
pygame.display.set_caption("俄罗斯方块")
self.clock = pygame.time.Clock()
self.board = [[None for _ in range(WIDTH)] for _ in range(HEIGHT)]
self.current_piece = None
self.next_piece = None
self.score = 0
self.game_over = False
self.spawn_new_piece()
def spawn_new_piece(self):
if self.next_piece is None:
shapes = list(SHAPES.keys())
self.current_piece = Piece(random.choice(shapes), (WIDTH // 2 - 2, 0))
self.next_piece = Piece(random.choice(shapes), (WIDTH + 1, 2))
else:
self.current_piece = self.next_piece
self.next_piece = Piece(random.choice(list(SHAPES.keys())), (WIDTH + 1, 2))
self.current_piece.pos = (WIDTH // 2 - 2, 0)
if self.check_collision(self.current_piece.shape, self.current_piece.pos):
self.game_over = True
def check_collision(self, shape, offset):
off_x, off_y = offset
for y, row in enumerate(shape):
for x, cell in enumerate(row):
if cell:
px = x + off_x
py = y + off_y
if px < 0 or px >= WIDTH or py >= HEIGHT:
return True
if py >= 0 and self.board[py][px] is not None:
return True
return False
def rotate_piece(self):
new_shape = list(zip(*self.current_piece.shape[::-1]))
if not self.check_collision(new_shape, self.current_piece.pos):
self.current_piece.shape = new_shape
def move(self, dx):
new_pos = (self.current_piece.pos[0] + dx, self.current_piece.pos[1])
if not self.check_collision(self.current_piece.shape, new_pos):
self.current_piece.pos = new_pos
def hard_drop(self):
while not self.check_collision(self.current_piece.shape, (self.current_piece.pos[0], self.current_piece.pos[1] + 1)):
self.current_piece.pos = (self.current_piece.pos[0], self.current_piece.pos[1] + 1)
self.place_piece()
def place_piece(self):
shape = self.current_piece.shape
pos = self.current_piece.pos
for y, row in enumerate(shape):
for x, cell in enumerate(row):
if cell:
px = x + pos[0]
py = y + pos[1]
if 0 <= px < WIDTH and 0 <= py < HEIGHT:
self.board[py][px] = self.current_piece.color
self.clear_lines()
self.spawn_new_piece()
def clear_lines(self):
lines_cleared = 0
new_board = []
for row in self.board:
if None not in row:
lines_cleared += 1
else:
new_board.append(row)
self.score += [0, 100, 300, 500, 800][lines_cleared]
self.board = [[None] * WIDTH for _ in range(lines_cleared)] + new_board
def draw(self):
self.screen.fill(COLORS['background'])
# 绘制游戏区域
for y in range(HEIGHT):
for x in range(WIDTH):
color = self.board[y][x] or COLORS['grid']
pygame.draw.rect(self.screen, color, (x * CELL_SIZE, y * CELL_SIZE, CELL_SIZE - 1, CELL_SIZE - 1))
# 绘制当前方块
if self.current_piece:
for y, row in enumerate(self.current_piece.shape):
for x, cell in enumerate(row):
if cell:
px = (x + self.current_piece.pos[0]) * CELL_SIZE
py = (y + self.current_piece.pos[1]) * CELL_SIZE
pygame.draw.rect(self.screen, self.current_piece.color, (px, py, CELL_SIZE - 1, CELL_SIZE - 1))
# 绘制下一个方块预览
next_x = (WIDTH + 1) * CELL_SIZE
pygame.draw.rect(self.screen, (255, 255, 255), (next_x, 50, 100, 100), 2)
if self.next_piece:
for y, row in enumerate(self.next_piece.shape):
for x, cell in enumerate(row):
if cell:
px = next_x + x * CELL_SIZE
py = 50 + y * CELL_SIZE
pygame.draw.rect(self.screen, self.next_piece.color, (px, py, CELL_SIZE - 1, CELL_SIZE - 1))
# 绘制分数
font = pygame.font.Font(None, 36)
text = font.render(f"Score: {self.score}", True, (255, 255, 255))
self.screen.blit(text, (next_x, 200))
pygame.display.flip()
def run(self):
last_fall = time.time()
fall_interval = 0.5
while not self.game_over:
dt = time.time() - last_fall
self.clock.tick(30)
# 自动下落
if dt > fall_interval:
if not self.check_collision(self.current_piece.shape, (self.current_piece.pos[0], self.current_piece.pos[1] + 1)):
self.current_piece.pos = (self.current_piece.pos[0], self.current_piece.pos[1] + 1)
else:
self.place_piece()
last_fall = time.time()
# 事件处理
for event in pygame.event.get():
if event.type == pygame.QUIT:
self.game_over = True
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
self.move(-1)
elif event.key == pygame.K_RIGHT:
self.move(1)
elif event.key == pygame.K_UP:
self.rotate_piece()
elif event.key == pygame.K_SPACE:
self.hard_drop()
self.draw()
pygame.quit()
class Piece:
def __init__(self, shape_type, pos):
self.shape = SHAPES[shape_type]
self.color = COLORS[shape_type]
self.pos = pos # (x, y)
if __name__ == "__main__":
game = Tetris()
game.run()
需求:
游戏界面由20行×10列的可视区域组成,7种不同形状的四格方块(I/T/O/J/L/S/Z型)随机从顶部生成下落(具体形状如下图所示),并且在一个方块生成后,玩家可以知道下一个方块的形状。
• 横向范围:X轴区间 [0, 9](共10列)
• 纵向范围:Y轴区间 [0, 19](共20行,Y=0为底部,Y=19为顶部)• 死亡判定线:Y ≥ 15(当方块堆叠高度触达此线时游戏结束)
在本问题中玩家使用的是简化版的操作规则,只能进行以下三种操作:
• 横向移动:左右平移• 旋转操作:支持0°、90°、180°、270°四向旋转• 瞬间落地:瞬间抵达当前可到达的最底部位置
当一行及以上(Y轴坐标相同)的全部位置被完全填充时,这些行将被消除,并且玩家将根据同时消除的行数获得分数:
• 单行消除:100分• 双行消除:300分• 三行消除:500分• 四行消除:800分
OJ版输入
第一行为两个单字符,即So和S1(So、S €{I,T,O,J,L,S,Z})。So和S1.分别表示第一个要下落的方块和第二个要下落的方块的形状。交互过程中,你每次依次输出一个方块的放置方案。在你每次输出放置方块的方案后,交互程序将再给你一行新的输入,该输入为一个单字符,即S:(S:€{I,T,O,J,工,S,Z,X,E}表示一个新的下个要下落的方块的形状。若S为x表示x前边的方块是最后
一个方块,程序应该在输出最后一个方块的放置方案后结束。若S为E表示玩家的放置方案已导致游戏结束(堆叠高度触达死亡判定线),程序应直接退出。测试数据均采用随机种子生成,且保证输入数据的总长度(即掉落的方块总数)小于1.000.000.
QJ版本 deepseek:
import sys
# 定义每个方块的各种旋转形态的相对坐标(dx, dy)
tetrominoes = {
'I': [
[(0, 0), (1, 0), (2, 0), (3, 0)], # 旋转0度
[(1, -1), (1, 0), (1, 1), (1, 2)], # 旋转90度
[(0, 0), (1, 0), (2, 0), (3, 0)], # 旋转180度
[(1, -1), (1, 0), (1, 1), (1, 2)] # 旋转270度
],
'O': [
[(0, 0), (1, 0), (0, 1), (1, 1)] for _ in range(4)
],
'T': [
[(0, 0), (1, 0), (2, 0), (1, 1)], # 旋转0度
[(1, -1), (1, 0), (1, 1), (0, 0)], # 旋转90度
[(0, 0), (1, 0), (2, 0), (1, -1)], # 旋转180度
[(1, -1), (1, 0), (1, 1), (2, 0)] # 旋转270度
],
'S': [
[(0, 1), (1, 1), (1, 0), (2, 0)], # 旋转0度
[(1, -1), (1, 0), (0, 0), (0, 1)], # 旋转90度
[(0, 1), (1, 1), (1, 0), (2, 0)], # 旋转180度
[(1, -1), (1, 0), (0, 0), (0, 1)] # 旋转270度
],
'Z': [
[(0, 0), (1, 0), (1, 1), (2, 1)], # 旋转0度
[(1, -1), (0, 0), (1, 0), (0, 1)], # 旋转90度
[(0, 0), (1, 0), (1, 1), (2, 1)], # 旋转180度
[(1, -1), (0, 0), (1, 0), (0, 1)] # 旋转270度
],
'J': [
[(0, 0), (0, 1), (1, 1), (2, 1)], # 旋转0度
[(1, -1), (2, -1), (1, 0), (1, 1)], # 旋转90度
[(0, 0), (1, 0), (2, 0), (2, -1)], # 旋转180度
[(0, 1), (1, 1), (0, 0), (0, 2)] # 旋转270度
],
'L': [
[(0, 1), (1, 1), (2, 1), (2, 0)], # 旋转0度
[(1, -1), (1, 0), (1, 1), (0, 1)], # 旋转90度
[(0, 0), (0, 1), (1, 0), (2, 0)], # 旋转180度
[(1, -1), (2, -1), (1, 0), (1, 1)] # 旋转270度
]
}
def main():
# 初始化游戏区域
grid = [[False for _ in range(10)] for _ in range(20)]
existing_heights = [-1] * 10
score = 0
# 读取初始输入
line = sys.stdin.readline().strip()
if not line:
return
s0, s1 = line.split()
current_piece = s0
next_piece = s1
while True:
best_move = None
best_score = -1
best_lines = -1
best_height = 20 # 用较低的堆叠高度更优
for rotate in range(4):
if current_piece not in tetrominoes:
break
blocks = tetrominoes[current_piece][rotate]
dx_list = [dx for dx, dy in blocks]
dy_list = [dy for dx, dy in blocks]
min_dx = min(dx_list)
max_dx = max(dx_list)
x_shift_min = max(0 - min_dx, 0)
x_shift_max = min(9 - max_dx, 9)
if x_shift_min > x_shift_max:
continue
for x_shift in range(x_shift_min, x_shift_max + 1):
x_coords = [x_shift + dx for dx in dx_list]
if any(x < 0 or x >= 10 for x in x_coords):
continue
required_y0 = []
for i in range(4):
x = x_coords[i]
dy = dy_list[i]
required_y0.append(existing_heights[x] - dy)
y0 = max(required_y0)
y_coords = [y0 + dy_list[i] for i in range(4)]
if any(y < 0 or y >= 20 for y in y_coords):
continue
if any(y >= 15 for y in y_coords):
continue
# 模拟放置到临时网格
temp_grid = [row.copy() for row in grid]
valid = True
for x, y in zip(x_coords, y_coords):
if y < 0 or y >= 20 or x < 0 or x >= 10:
valid = False
break
if temp_grid[y][x]:
valid = False
break
temp_grid[y][x] = True
if not valid:
continue
# 检查哪些行被消除
lines_cleared = 0
filled_y = set(y_coords)
for y in filled_y:
if 0 <= y < 20 and all(temp_grid[y][x] for x in range(10)):
lines_cleared += 1
current_score = 0
if lines_cleared == 1:
current_score = 100
elif lines_cleared == 2:
current_score = 300
elif lines_cleared == 3:
current_score = 500
elif lines_cleared == 4:
current_score = 800
max_y = max(y_coords) if y_coords else 0
if current_score > best_score or (current_score == best_score and max_y < best_height) or (current_score == best_score and max_y == best_height and (best_move is None or x_shift < best_move[1] or (x_shift == best_move[1] and rotate < best_move[0]))):
best_score = current_score
best_move = (rotate, x_shift)
best_height = max_y
best_lines = lines_cleared
if best_move is None:
print("E")
return
rotate, x_shift = best_move
print(f"{rotate} {x_shift}")
sys.stdout.flush()
# 更新实际网格
blocks = tetrominoes[current_piece][rotate]
dx_list = [dx for dx, dy in blocks]
dy_list = [dy for dx, dy in blocks]
x_coords = [x_shift + dx for dx in dx_list]
required_y0 = []
for i in range(4):
x = x_coords[i]
dy = dy_list[i]
required_y0.append(existing_heights[x] - dy)
y0 = max(required_y0)
y_coords = [y0 + dy for dy in dy_list]
for x, y in zip(x_coords, y_coords):
if 0 <= y < 20 and 0 <= x < 10:
grid[y][x] = True
if any(y >= 15 for y in y_coords):
return
# 处理行消除
lines_to_clear = []
for y in range(20):
if all(grid[y][x] for x in range(10)):
lines_to_clear.append(y)
if lines_to_clear:
lines_to_clear.sort(reverse=True)
for y in lines_to_clear:
del grid[y]
grid.insert(0, [False]*10)
existing_heights = [-1] * 10
for x in range(10):
for y in range(19, -1, -1):
if grid[y][x]:
existing_heights[x] = y
break
else:
# 更新 existing_heights
for x in range(10):
max_y = -1
for y in range(20):
if grid[y][x]:
max_y = y
existing_heights[x] = max_y
# 读取下一个方块
next_input = sys.stdin.readline().strip()
if next_input == 'X':
break
elif next_input == 'E':
return
current_piece = next_input
if __name__ == "__main__":
main()
QJ版本 gpt:
import sys
BOARD_WIDTH = 10
BOARD_HEIGHT = 20
DEATH_LINE = 15
SCORES = [0, 100, 300, 500, 800] # 行消除得分:1行~4行
BLOCKS = {
'I': [
[(0, 1), (1, 1), (2, 1), (3, 1)],
[(2, 0), (2, 1), (2, 2), (2, 3)],
[(0, 2), (1, 2), (2, 2), (3, 2)],
[(1, 0), (1, 1), (1, 2), (1, 3)],
],
'O': [
[(1, 0), (2, 0), (1, 1), (2, 1)] for _ in range(4)
],
'T': [
[(1, 0), (0, 1), (1, 1), (2, 1)],
[(1, 0), (1, 1), (1, 2), (2, 1)],
[(0, 1), (1, 1), (2, 1), (1, 2)],
[(1, 0), (0, 1), (1, 1), (1, 2)],
],
'S': [
[(1, 0), (2, 0), (0, 1), (1, 1)],
[(1, 0), (1, 1), (2, 1), (2, 2)],
[(1, 1), (2, 1), (0, 2), (1, 2)],
[(0, 0), (0, 1), (1, 1), (1, 2)],
],
'Z': [
[(0, 0), (1, 0), (1, 1), (2, 1)],
[(2, 0), (1, 1), (2, 1), (1, 2)],
[(0, 1), (1, 1), (1, 2), (2, 2)],
[(1, 0), (0, 1), (1, 1), (0, 2)],
],
'J': [
[(0, 0), (0, 1), (1, 1), (2, 1)],
[(1, 0), (2, 0), (1, 1), (1, 2)],
[(0, 1), (1, 1), (2, 1), (2, 2)],
[(1, 0), (1, 1), (0, 2), (1, 2)],
],
'L': [
[(2, 0), (0, 1), (1, 1), (2, 1)],
[(1, 0), (1, 1), (1, 2), (2, 2)],
[(0, 1), (1, 1), (2, 1), (0, 2)],
[(0, 0), (1, 0), (1, 1), (1, 2)],
]
}
class Tetris:
def __init__(self):
self.board = [[0] * BOARD_WIDTH for _ in range(BOARD_HEIGHT)]
self.score = 0
def can_place(self, shape, x, y):
for dx, dy in shape:
nx, ny = x + dx, y + dy
if nx < 0 or nx >= BOARD_WIDTH or ny < 0 or ny >= BOARD_HEIGHT:
return False
if self.board[ny][nx]:
return False
return True
def find_drop_y(self, shape, x):
for y in range(BOARD_HEIGHT - 1, -1, -1):
if self.can_place(shape, x, y):
return y
return -1
def drop(self, shape_name):
best_x = None
best_rot = None
best_y = -1
for rot in range(4):
shape = BLOCKS[shape_name][rot]
max_dx = max(dx for dx, _ in shape)
for x in range(BOARD_WIDTH - max_dx):
y = self.find_drop_y(shape, x)
if y == -1:
continue
if y > best_y or (y == best_y and (best_x is None or x < best_x)):
best_x = x
best_rot = rot
best_y = y
return best_x, best_rot
def place_block(self, shape_name, x, rot):
shape = BLOCKS[shape_name][rot]
y = self.find_drop_y(shape, x)
if y == -1:
return False # 无法放置
for dx, dy in shape:
self.board[y + dy][x + dx] = 1
return True
def clear_lines(self):
new_board = []
cleared = 0
for row in self.board:
if all(row):
cleared += 1
else:
new_board.append(row)
while len(new_board) < BOARD_HEIGHT:
new_board.insert(0, [0] * BOARD_WIDTH)
self.board = new_board
self.score += SCORES[cleared]
def is_game_over(self):
for y in range(DEATH_LINE, BOARD_HEIGHT):
if any(self.board[y][x] for x in range(BOARD_WIDTH)):
return True
return False
def play(self):
s0, s1 = input().strip().split()
curr, next_shape = s0, s1
while True:
# 放置当前方块
x, rot = self.drop(curr)
if x is None or rot is None:
print("0 0")
sys.stdout.flush()
return
print(f"{x} {rot}")
sys.stdout.flush()
# 落地并消除
placed = self.place_block(curr, x, rot)
self.clear_lines()
# 判定是否死亡
if self.is_game_over():
return
# 读取下一个方块
curr = input().strip()
if curr == 'X':
# 最后一个,放置完就退出
x, rot = self.drop(next_shape)
if x is None or rot is None:
print("0 0")
sys.stdout.flush()
return
print(f"{x} {rot}")
sys.stdout.flush()
self.place_block(next_shape, x, rot)
self.clear_lines()
return
elif curr == 'E':
return
else:
curr, next_shape = next_shape, curr
if __name__ == "__main__":
game = Tetris()
game.play()