import pygame import random colors = [ (0, 0, 0), (120, 37, 179), (100, 179, 179), (80, 34, 22), (80, 134, 22), (180, 34, 22), (180, 34, 122), ] class Figure: x = 0 y = 0 figures = [ [[1, 5, 9, 13], [4, 5, 6, 7]], [[4, 5, 9, 10], [2, 6, 5, 9]], [[6, 7, 9, 10], [1, 5, 6, 10]], [[1, 2, 5, 9], [0, 4, 5, 6], [1, 5, 9, 8], [4, 5, 6, 10]], [[1, 2, 6, 10], [5, 6, 7, 9], [2, 6, 10, 11], [3, 5, 6, 7]], [[1, 4, 5, 6], [1, 4, 5, 9], [4, 5, 6, 9], [1, 5, 6, 9]], [[1, 2, 5, 6]], ] def __init__(self, x, y): self.x = x self.y = y self.type = random.randint(0, len(self.figures) - 1) self.color = random.randint(1, len(colors) - 1) self.rotation = 0 def image(self): return self.figures[self.type][self.rotation] def rotate(self): self.rotation = (self.rotation + 1) % len(self.figures[self.type]) class Tetris: level = 2 score = 0 state = "start" field = [] height = 0 width = 0 x = 100 y = 60 zoom = 20 figure = None def __init__(self, height, width): self.height = height self.width = width self.field = [] self.score = 0 self.state = "start" for i in range(height): new_line = [] for j in range(width): new_line.append(0) self.field.append(new_line) def new_figure(self): self.figure = Figure(3, 0) def intersects(self): intersection = False for i in range(4): for j in range(4): if i * 4 + j in self.figure.image(): if i + self.figure.y > self.height - 1 or \ j + self.figure.x > self.width - 1 or \ j + self.figure.x < 0 or \ self.field[i + self.figure.y][j + self.figure.x] > 0: intersection = True return intersection def break_lines(self): lines = 0 for i in range(1, self.height): zeros = 0 for j in range(self.width): if self.field[i][j] == 0: zeros += 1 if zeros == 0: lines += 1 for i1 in range(i, 1, -1): for j in range(self.width): self.field[i1][j] = self.field[i1 - 1][j] self.score += lines ** 2 def go_space(self): while not self.intersects(): self.figure.y += 1 self.figure.y -= 1 self.freeze() def go_down(self): self.figure.y += 1 if self.intersects(): self.figure.y -= 1 self.freeze() def freeze(self): for i in range(4): for j in range(4): if i * 4 + j in self.figure.image(): self.field[i + self.figure.y][j + self.figure.x] = self.figure.color self.break_lines() self.new_figure() if self.intersects(): self.state = "gameover" def go_side(self, dx): old_x = self.figure.x self.figure.x += dx if self.intersects(): self.figure.x = old_x def rotate(self): old_rotation = self.figure.rotation self.figure.rotate() if self.intersects(): self.figure.rotation = old_rotation class Event(): type = None key = None def __init__(self, type, key): self.type = type self.key = key counter = 0 def intersects(game_field, x, y, game_width, game_height, game_figure_image): intersection = False for i in range(4): for j in range(4): if i * 4 + j in game_figure_image: if i + y > game_height - 1 or \ j + x > game_width - 1 or \ j + x < 0 or \ game_field[i + y][j + x] > 0: intersection = True return intersection def simulate(game_field, x, y, game_width, game_height, game_figure_image): while not intersects(game_field, x, y, game_width, game_height, game_figure_image): y += 1 y -= 1 height = game_height holes = 0 filled = [] breaks = 0 for i in range(game_height-1, -1, -1): it_is_full = True prev_holes = holes for j in range(game_width): u = '_' if game_field[i][j] != 0: u = "x" for ii in range(4): for jj in range(4): if ii * 4 + jj in game_figure_image: if jj + x == j and ii + y == i: u = "x" if u == "x" and i < height: height = i if u == "x": filled.append((i, j)) for k in range(i, game_height): if (k, j) not in filled: holes += 1 filled.append((k,j)) else: it_is_full = False if it_is_full: breaks += 1 holes = prev_holes return holes, game_height-height-breaks def best_rotation_position(game_field, game_figure, game_width, game_height): best_height = game_height best_holes = game_height*game_width best_position = None best_rotation = None for rotation in range(len(game_figure.figures[game_figure.type])): fig = game_figure.figures[game_figure.type][rotation] for j in range(-3, game_width): if not intersects( game_field, j, 0, game_width, game_height, fig): holes, height = simulate( game_field, j, 0, game_width, game_height, fig ) if best_position is None or best_holes > holes or \ best_holes == holes and best_height > height: best_height = height best_holes = holes best_position = j best_rotation = rotation return best_rotation, best_position def run_ai(game_field, game_figure, game_width, game_height): global counter counter += 1 if counter < 3: return [] counter = 0 rotation, position = best_rotation_position(game_field, game_figure, game_width, game_height) if game_figure.rotation != rotation: e = Event(pygame.KEYDOWN, pygame.K_UP) elif game_figure.x < position: e = Event(pygame.KEYDOWN, pygame.K_RIGHT) elif game_figure.x > position: e = Event(pygame.KEYDOWN, pygame.K_LEFT) else: e = Event(pygame.KEYDOWN, pygame.K_SPACE) return [e] # Initialize the game engine pygame.init() # Define some colors BLACK = (0, 0, 0) WHITE = (255, 255, 255) GRAY = (128, 128, 128) size = (400, 500) screen = pygame.display.set_mode(size) pygame.display.set_caption("Tetris") # Loop until the user clicks the close button. done = False clock = pygame.time.Clock() fps = 25 game = Tetris(20, 10) counter = 0 pressing_down = False while not done: if game.figure is None: game.new_figure() counter += 1 if counter > 1000000: counter = 0 if counter % (fps // game.level // 2) == 0 or pressing_down: if game.state == "start": game.go_down() for event in list(pygame.event.get()) + run_ai(game.field, game.figure, game.width, game.height): if event.type == pygame.QUIT: done = True if event.type == pygame.KEYDOWN: if event.key == pygame.K_UP: game.rotate() if event.key == pygame.K_DOWN: pressing_down = True if event.key == pygame.K_LEFT: game.go_side(-1) if event.key == pygame.K_RIGHT: game.go_side(1) if event.key == pygame.K_SPACE: game.go_space() if event.key == pygame.K_ESCAPE: game.__init__(20, 10) if event.type == pygame.KEYUP: if event.key == pygame.K_DOWN: pressing_down = False screen.fill(WHITE) for i in range(game.height): for j in range(game.width): pygame.draw.rect(screen, GRAY, [game.x + game.zoom * j, game.y + game.zoom * i, game.zoom, game.zoom], 1) if game.field[i][j] > 0: pygame.draw.rect(screen, colors[game.field[i][j]], [game.x + game.zoom * j + 1, game.y + game.zoom * i + 1, game.zoom - 2, game.zoom - 1]) if game.figure is not None: for i in range(4): for j in range(4): p = i * 4 + j if p in game.figure.image(): pygame.draw.rect(screen, colors[game.figure.color], [game.x + game.zoom * (j + game.figure.x) + 1, game.y + game.zoom * (i + game.figure.y) + 1, game.zoom - 2, game.zoom - 2]) font = pygame.font.SysFont('Calibri', 25, True, False) font1 = pygame.font.SysFont('Calibri', 65, True, False) text = font.render("Score: " + str(game.score), True, BLACK) text_game_over = font1.render("Game Over", True, (255, 125, 0)) text_game_over1 = font1.render("Press ESC", True, (255, 215, 0)) screen.blit(text, [0, 0]) if game.state == "gameover": screen.blit(text_game_over, [20, 200]) screen.blit(text_game_over1, [25, 265]) game.__init__(20, 10) pygame.display.flip() clock.tick(fps) pygame.quit()