-
-
Save silvasur/565419 to your computer and use it in GitHub Desktop.
| #!/usr/bin/env python3 | |
| #-*- coding: utf-8 -*- | |
| # Very simple tetris implementation | |
| # | |
| # Control keys: | |
| # Down - Drop stone faster | |
| # Left/Right - Move stone | |
| # Up - Rotate Stone clockwise | |
| # Escape - Quit game | |
| # P - Pause game | |
| # Return - Instant drop | |
| # | |
| # Have fun! | |
| # NOTE: If you're looking for the old python2 version, see | |
| # <https://gist.github.com/silvasur/565419/45a3ded61b993d1dd195a8a8688e7dc196b08de8> | |
| # Copyright (c) 2010 "Laria Carolin Chabowski"<me@laria.me> | |
| # | |
| # Permission is hereby granted, free of charge, to any person obtaining a copy | |
| # of this software and associated documentation files (the "Software"), to deal | |
| # in the Software without restriction, including without limitation the rights | |
| # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
| # copies of the Software, and to permit persons to whom the Software is | |
| # furnished to do so, subject to the following conditions: | |
| # | |
| # The above copyright notice and this permission notice shall be included in | |
| # all copies or substantial portions of the Software. | |
| # | |
| # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
| # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
| # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
| # THE SOFTWARE. | |
| from random import randrange as rand | |
| import pygame, sys | |
| # The configuration | |
| cell_size = 18 | |
| cols = 10 | |
| rows = 22 | |
| maxfps = 30 | |
| colors = [ | |
| (0, 0, 0 ), | |
| (255, 85, 85), | |
| (100, 200, 115), | |
| (120, 108, 245), | |
| (255, 140, 50 ), | |
| (50, 120, 52 ), | |
| (146, 202, 73 ), | |
| (150, 161, 218 ), | |
| (35, 35, 35) # Helper color for background grid | |
| ] | |
| # Define the shapes of the single parts | |
| tetris_shapes = [ | |
| [[1, 1, 1], | |
| [0, 1, 0]], | |
| [[0, 2, 2], | |
| [2, 2, 0]], | |
| [[3, 3, 0], | |
| [0, 3, 3]], | |
| [[4, 0, 0], | |
| [4, 4, 4]], | |
| [[0, 0, 5], | |
| [5, 5, 5]], | |
| [[6, 6, 6, 6]], | |
| [[7, 7], | |
| [7, 7]] | |
| ] | |
| def rotate_clockwise(shape): | |
| return [ | |
| [ shape[y][x] for y in range(len(shape)) ] | |
| for x in range(len(shape[0]) - 1, -1, -1) | |
| ] | |
| def check_collision(board, shape, offset): | |
| off_x, off_y = offset | |
| for cy, row in enumerate(shape): | |
| for cx, cell in enumerate(row): | |
| try: | |
| if cell and board[ cy + off_y ][ cx + off_x ]: | |
| return True | |
| except IndexError: | |
| return True | |
| return False | |
| def remove_row(board, row): | |
| del board[row] | |
| return [[0 for i in range(cols)]] + board | |
| def join_matrixes(mat1, mat2, mat2_off): | |
| off_x, off_y = mat2_off | |
| for cy, row in enumerate(mat2): | |
| for cx, val in enumerate(row): | |
| mat1[cy+off_y-1 ][cx+off_x] += val | |
| return mat1 | |
| def new_board(): | |
| board = [ | |
| [ 0 for x in range(cols) ] | |
| for y in range(rows) | |
| ] | |
| board += [[ 1 for x in range(cols)]] | |
| return board | |
| class TetrisApp(object): | |
| def __init__(self): | |
| pygame.init() | |
| pygame.key.set_repeat(250,25) | |
| self.width = cell_size*(cols+6) | |
| self.height = cell_size*rows | |
| self.rlim = cell_size*cols | |
| self.bground_grid = [[ 8 if x%2==y%2 else 0 for x in range(cols)] for y in range(rows)] | |
| self.default_font = pygame.font.Font( | |
| pygame.font.get_default_font(), 12) | |
| self.screen = pygame.display.set_mode((self.width, self.height)) | |
| pygame.event.set_blocked(pygame.MOUSEMOTION) # We do not need | |
| # mouse movement | |
| # events, so we | |
| # block them. | |
| self.next_stone = tetris_shapes[rand(len(tetris_shapes))] | |
| self.init_game() | |
| def new_stone(self): | |
| self.stone = self.next_stone[:] | |
| self.next_stone = tetris_shapes[rand(len(tetris_shapes))] | |
| self.stone_x = int(cols / 2 - len(self.stone[0])/2) | |
| self.stone_y = 0 | |
| if check_collision(self.board, | |
| self.stone, | |
| (self.stone_x, self.stone_y)): | |
| self.gameover = True | |
| def init_game(self): | |
| self.board = new_board() | |
| self.new_stone() | |
| self.level = 1 | |
| self.score = 0 | |
| self.lines = 0 | |
| pygame.time.set_timer(pygame.USEREVENT+1, 1000) | |
| def disp_msg(self, msg, topleft): | |
| x,y = topleft | |
| for line in msg.splitlines(): | |
| self.screen.blit( | |
| self.default_font.render( | |
| line, | |
| False, | |
| (255,255,255), | |
| (0,0,0)), | |
| (x,y)) | |
| y+=14 | |
| def center_msg(self, msg): | |
| for i, line in enumerate(msg.splitlines()): | |
| msg_image = self.default_font.render(line, False, | |
| (255,255,255), (0,0,0)) | |
| msgim_center_x, msgim_center_y = msg_image.get_size() | |
| msgim_center_x //= 2 | |
| msgim_center_y //= 2 | |
| self.screen.blit(msg_image, ( | |
| self.width // 2-msgim_center_x, | |
| self.height // 2-msgim_center_y+i*22)) | |
| def draw_matrix(self, matrix, offset): | |
| off_x, off_y = offset | |
| for y, row in enumerate(matrix): | |
| for x, val in enumerate(row): | |
| if val: | |
| pygame.draw.rect( | |
| self.screen, | |
| colors[val], | |
| pygame.Rect( | |
| (off_x+x) * | |
| cell_size, | |
| (off_y+y) * | |
| cell_size, | |
| cell_size, | |
| cell_size),0) | |
| def add_cl_lines(self, n): | |
| linescores = [0, 40, 100, 300, 1200] | |
| self.lines += n | |
| self.score += linescores[n] * self.level | |
| if self.lines >= self.level*6: | |
| self.level += 1 | |
| newdelay = 1000-50*(self.level-1) | |
| newdelay = 100 if newdelay < 100 else newdelay | |
| pygame.time.set_timer(pygame.USEREVENT+1, newdelay) | |
| def move(self, delta_x): | |
| if not self.gameover and not self.paused: | |
| new_x = self.stone_x + delta_x | |
| if new_x < 0: | |
| new_x = 0 | |
| if new_x > cols - len(self.stone[0]): | |
| new_x = cols - len(self.stone[0]) | |
| if not check_collision(self.board, | |
| self.stone, | |
| (new_x, self.stone_y)): | |
| self.stone_x = new_x | |
| def quit(self): | |
| self.center_msg("Exiting...") | |
| pygame.display.update() | |
| sys.exit() | |
| def drop(self, manual): | |
| if not self.gameover and not self.paused: | |
| self.score += 1 if manual else 0 | |
| self.stone_y += 1 | |
| if check_collision(self.board, | |
| self.stone, | |
| (self.stone_x, self.stone_y)): | |
| self.board = join_matrixes( | |
| self.board, | |
| self.stone, | |
| (self.stone_x, self.stone_y)) | |
| self.new_stone() | |
| cleared_rows = 0 | |
| while True: | |
| for i, row in enumerate(self.board[:-1]): | |
| if 0 not in row: | |
| self.board = remove_row( | |
| self.board, i) | |
| cleared_rows += 1 | |
| break | |
| else: | |
| break | |
| self.add_cl_lines(cleared_rows) | |
| return True | |
| return False | |
| def insta_drop(self): | |
| if not self.gameover and not self.paused: | |
| while(not self.drop(True)): | |
| pass | |
| def rotate_stone(self): | |
| if not self.gameover and not self.paused: | |
| new_stone = rotate_clockwise(self.stone) | |
| if not check_collision(self.board, | |
| new_stone, | |
| (self.stone_x, self.stone_y)): | |
| self.stone = new_stone | |
| def toggle_pause(self): | |
| self.paused = not self.paused | |
| def start_game(self): | |
| if self.gameover: | |
| self.init_game() | |
| self.gameover = False | |
| def run(self): | |
| key_actions = { | |
| 'ESCAPE': self.quit, | |
| 'LEFT': lambda:self.move(-1), | |
| 'RIGHT': lambda:self.move(+1), | |
| 'DOWN': lambda:self.drop(True), | |
| 'UP': self.rotate_stone, | |
| 'p': self.toggle_pause, | |
| 'SPACE': self.start_game, | |
| 'RETURN': self.insta_drop | |
| } | |
| self.gameover = False | |
| self.paused = False | |
| dont_burn_my_cpu = pygame.time.Clock() | |
| while 1: | |
| self.screen.fill((0,0,0)) | |
| if self.gameover: | |
| self.center_msg("""Game Over!\nYour score: %d | |
| Press space to continue""" % self.score) | |
| else: | |
| if self.paused: | |
| self.center_msg("Paused") | |
| else: | |
| pygame.draw.line(self.screen, | |
| (255,255,255), | |
| (self.rlim+1, 0), | |
| (self.rlim+1, self.height-1)) | |
| self.disp_msg("Next:", ( | |
| self.rlim+cell_size, | |
| 2)) | |
| self.disp_msg("Score: %d\n\nLevel: %d\ | |
| \nLines: %d" % (self.score, self.level, self.lines), | |
| (self.rlim+cell_size, cell_size*5)) | |
| self.draw_matrix(self.bground_grid, (0,0)) | |
| self.draw_matrix(self.board, (0,0)) | |
| self.draw_matrix(self.stone, | |
| (self.stone_x, self.stone_y)) | |
| self.draw_matrix(self.next_stone, | |
| (cols+1,2)) | |
| pygame.display.update() | |
| for event in pygame.event.get(): | |
| if event.type == pygame.USEREVENT+1: | |
| self.drop(False) | |
| elif event.type == pygame.QUIT: | |
| self.quit() | |
| elif event.type == pygame.KEYDOWN: | |
| for key in key_actions: | |
| if event.key == eval("pygame.K_" | |
| +key): | |
| key_actions[key]() | |
| dont_burn_my_cpu.tick(maxfps) | |
| if __name__ == '__main__': | |
| App = TetrisApp() | |
| App.run() |
is it possible to make that .py file to desktop app??
@Wax30d I mean, it's an application that runs on a desktop, so it kinda is a desktop app, right? 😃
If you want to bundle the whole application up, so users don't have to install python and pygame, here are some possible options: On Linux you might try to make it a Flatpak app, for Windows there is py2exe. No idea about macOS or other operating systems.
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
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 > 100000:
counter = 0
if counter % (fps // game.level // 2) == 0 or pressing_down:
if game.state == "start":
game.go_down()
for event in pygame.event.get():
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])
pygame.display.flip()
clock.tick(fps)
pygame.quit()
Hey if you like my code, you can also visit my repo

@Dilovan200 Without seeing the error messages, nobody will be able to help you. Can you copy the error messages here or post a screenshot? Maybe then someone might be able to help you. Also not sure, what this has to do with visual studio?