Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import curses
- import random
- import time
- # Tetrimino shapes
- SHAPES = [
- [[1, 1, 1, 1]], # I
- [[1, 1], [1, 1]], # O
- [[0, 1, 0], [1, 1, 1]], # T
- [[1, 0, 0], [1, 1, 1]], # L
- [[0, 0, 1], [1, 1, 1]], # J
- [[0, 1, 1], [1, 1, 0]], # S
- [[1, 1, 0], [0, 1, 1]] # Z
- ]
- PIECE_NAMES = ["I", "O", "T", "L", "J", "S", "Z"]
- class Tetris:
- def __init__(self, screen):
- self.screen = screen
- self.screen.nodelay(1)
- self.screen.timeout(500)
- curses.curs_set(0)
- self.width = 10
- self.height = 20
- self.board = [[0] * self.width for _ in range(self.height)]
- self.current_piece = None
- self.current_x = 0
- self.current_y = 0
- self.next_piece = None
- self.score = 0
- self.placed_pieces = []
- self.layout_width = 8 # Width of the layout area for pieces
- self.layout_height = 16 # Height of the layout area for pieces
- self.layout_bottom = self.height - self.layout_height
- self.new_piece()
- self.last_time = time.time()
- self.fall_speed = 0.5 # Speed of automatic fall in seconds
- def new_piece(self):
- if self.next_piece is None:
- self.current_piece = random.choice(SHAPES)
- else:
- self.current_piece = self.next_piece
- self.next_piece = random.choice(SHAPES)
- self.current_x = (self.width - self.layout_width) // 2 + len(self.current_piece[0]) // 2
- self.current_y = -len(self.current_piece) # Start above the screen
- if self.check_collision(self.current_x, self.current_y, self.current_piece):
- self.end_game()
- def rotate_piece(self):
- self.current_piece = [list(row) for row in zip(*self.current_piece[::-1])]
- if self.check_collision(self.current_x, self.current_y, self.current_piece):
- # If rotation causes collision, revert rotation
- self.current_piece = [list(row) for row in zip(*self.current_piece[::-1])][::-1]
- def check_collision(self, x, y, piece):
- for i, row in enumerate(piece):
- for j, cell in enumerate(row):
- if cell and (y + i >= self.height or x + j < 0 or x + j >= self.width or self.board[y + i][x + j]):
- return True
- return False
- def fix_piece(self):
- for i, row in enumerate(self.current_piece):
- for j, cell in enumerate(row):
- if cell:
- self.board[self.current_y + i][self.current_x + j] = 1
- piece_name = PIECE_NAMES[SHAPES.index(self.current_piece)]
- self.placed_pieces.append(piece_name)
- self.clear_lines()
- self.new_piece()
- def clear_lines(self):
- new_board = [row for row in self.board if any(cell == 0 for cell in row)]
- lines_cleared = self.height - len(new_board)
- if lines_cleared == 1:
- self.score += 1
- elif lines_cleared == 2:
- self.score += 2
- elif lines_cleared == 3:
- self.score += 3
- elif lines_cleared == 4:
- self.score += 4
- while len(new_board) < self.height:
- new_board.insert(0, [0] * self.width)
- self.board = new_board
- def move(self, dx, dy):
- if not self.check_collision(self.current_x + dx, self.current_y + dy, self.current_piece):
- self.current_x += dx
- self.current_y += dy
- def drop(self):
- if not self.check_collision(self.current_x, self.current_y + 1, self.current_piece):
- self.current_y += 1
- else:
- self.current_y = self.layout_bottom + self.layout_height - len(self.current_piece) # Stop at the bottom of the layout
- self.fix_piece()
- def end_game(self):
- self.screen.addstr(self.height // 2, self.width // 2 - 5, "Game Over!")
- self.screen.refresh()
- time.sleep(2)
- curses.endwin()
- exit(0)
- def draw(self):
- self.screen.clear()
- # Calculate the start position for centering
- max_y, max_x = self.screen.getmaxyx()
- start_y = max_y // 2 - 12
- start_x = max_x // 2 - 16
- # Draw the border and the layout
- layout = [
- " ┌───────────────┬──────┐ ",
- " │SCORE:^^^^^^^^^│ NEXT │ ",
- " ├───────────────┤ │ ",
- " │ │ ~~~~ │ ",
- " │ │ ~~~~ │ ",
- " │ ├──────┤ ",
- " │ │$$$$$$│ ",
- " │ │$$$$$$│ ",
- " │ │$$$$$$│ ",
- " │ │$$$$$$│ ",
- " │ │$$$$$$│ ",
- " │ │$$$$$$│ ",
- " │ │$$$$$$│ ",
- " │ │$$$$$$│ ",
- " │ │$$$$$$│ ",
- " │ │$$$$$$│ ",
- " │ │$$$$$$│ ",
- " └───────────────┴──────┘ "
- ]
- for i, line in enumerate(layout):
- self.screen.addstr(start_y + i, start_x, line)
- # Draw the score
- score_str = f"{self.score:^9}"
- self.screen.addstr(start_y + 1, start_x + 8, score_str)
- # Draw the next piece
- next_piece = self.next_piece
- for i, row in enumerate(next_piece):
- for j, cell in enumerate(row):
- if cell:
- self.screen.addstr(start_y + 4 + i, start_x + 19 + j, "X")
- # Draw the placed pieces names
- for i, piece_name in enumerate(self.placed_pieces[-10:]):
- self.screen.addstr(start_y + 7 + i, start_x + 19, piece_name)
- # Draw the board and current piece
- for y, row in enumerate(self.board):
- for x, cell in enumerate(row):
- if cell:
- if start_y + 6 + y < max_y and start_x + x < max_x:
- self.screen.addstr(start_y + 6 + y, start_x + x, "X")
- for i, row in enumerate(self.current_piece):
- for j, cell in enumerate(row):
- if cell:
- draw_y = start_y + 6 + self.current_y + i
- draw_x = start_x + self.current_x + j
- if draw_y < max_y and draw_x < max_x and draw_y >= start_y and draw_x >= start_x:
- self.screen.addstr(draw_y, draw_x, "X")
- self.screen.refresh()
- def run(self):
- while True:
- current_time = time.time()
- if current_time - self.last_time > self.fall_speed:
- self.drop()
- self.last_time = current_time
- self.draw()
- event = self.screen.getch()
- if event == curses.KEY_LEFT:
- self.move(-1, 0)
- elif event == curses.KEY_RIGHT:
- self.move(1, 0)
- elif event == curses.KEY_DOWN:
- self.drop()
- elif event == curses.KEY_UP:
- self.rotate_piece()
- def main(stdscr):
- game = Tetris(stdscr)
- game.run()
- curses.wrapper(main)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement