here2share

# tk_Colorful_Tetris.py

Sep 10th, 2025 (edited)
179
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 13.79 KB | None | 0 0
  1. # tk_Colorful_Tetris.py ZZZ
  2.  
  3. import tkinter as tk
  4. import random
  5. import json
  6. import os
  7. import time
  8.  
  9. BOARD_WIDTH = 10
  10. BOARD_HEIGHT = 20
  11. BLOCK_SIZE = 30
  12. SHAPES = [
  13.     [[1, 1, 1, 1]],
  14.     [[1, 1], [1, 1]],
  15.     [[1, 1, 1], [1, 0, 0]],
  16.     [[1, 1, 1], [0, 0, 1]],
  17.     [[1, 1, 0], [0, 1, 1]],
  18.     [[0, 1, 1], [1, 1, 0]]
  19. ]
  20. COLORS = ['cyan', 'yellow', 'purple', 'orange', 'blue', 'green', 'red']
  21.  
  22. board = [[0 for _ in range(BOARD_WIDTH)] for _ in range(BOARD_HEIGHT)]
  23. current_piece = None
  24. next_piece = None
  25. highscore = 0
  26. score = 0
  27. lines_cleared = 0
  28. ai_countdown = 0
  29. mode = "player"
  30. ai_weights = {
  31.     'lines': 1.0,
  32.     'height': -0.5,
  33.     'holes': -0.7,
  34.     'bumpiness': -0.3
  35. }
  36. ai_countdown_timer = None
  37. game_timer = None
  38.  
  39. AI_PATH = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'tetris.json')
  40.  
  41. def load_data():
  42.     global highscore, ai_weights
  43.     if os.path.exists(AI_PATH):
  44.         try:
  45.             with open(AI_PATH, 'r') as f:
  46.                 data = json.load(f)
  47.                 highscore = data.get("highscore", 0)
  48.                 ai_weights = data.get("ai_weights", ai_weights)
  49.         except Exception:
  50.             pass
  51.  
  52. def save_data():
  53.     with open(AI_PATH, 'w') as f:
  54.         json.dump({"highscore": highscore, "ai_weights": ai_weights}, f)
  55.  
  56. def save_highscore():
  57.     save_data()
  58.  
  59. def create_piece():
  60.     i = random.randint(0, len(SHAPES)-1)
  61.     shape = [row[:] for row in SHAPES[i]]
  62.     color = COLORS[i]
  63.     return {'shape': shape, 'color': color, 'x': BOARD_WIDTH // 2 - len(shape[0]) // 2, 'y': 0}
  64.  
  65. def rotate_piece(piece):
  66.     shape = piece['shape']
  67.     rotated = [list(row) for row in zip(*shape[::-1])]
  68.     return rotated
  69.  
  70. def collision(piece, dx=0, dy=0, test_shape=None):
  71.     shape = test_shape if test_shape else piece['shape']
  72.     for y, row in enumerate(shape):
  73.         for x, cell in enumerate(row):
  74.             if cell:
  75.                 nx = piece['x'] + x + dx
  76.                 ny = piece['y'] + y + dy
  77.                 if nx < 0 or nx >= BOARD_WIDTH or ny >= BOARD_HEIGHT:
  78.                     return True
  79.                 if ny >= 0 and board[ny][nx]:
  80.                     return True
  81.     return False
  82.  
  83. def merge(piece):
  84.     for y, row in enumerate(piece['shape']):
  85.         for x, cell in enumerate(row):
  86.             if cell and piece['y'] + y >= 0:
  87.                 board[piece['y'] + y][piece['x'] + x] = piece['color']
  88.  
  89. def clear_lines():
  90.     global board, score, lines_cleared
  91.     new_board = [row for row in board if any(cell == 0 for cell in row)]
  92.     cleared = BOARD_HEIGHT - len(new_board)
  93.     for _ in range(cleared):
  94.         new_board.insert(0, [0]*BOARD_WIDTH)
  95.     if cleared:
  96.         score += cleared * 100
  97.         lines_cleared += cleared
  98.     board = new_board
  99.  
  100. def get_board_stats(test_board):
  101.     heights = [0]*BOARD_WIDTH
  102.     holes = 0
  103.     bumpiness = 0
  104.     for x in range(BOARD_WIDTH):
  105.         col_height = 0
  106.         block_found = False
  107.         for y in range(BOARD_HEIGHT):
  108.             if test_board[y][x]:
  109.                 if not block_found:
  110.                     col_height = BOARD_HEIGHT - y
  111.                     block_found = True
  112.             elif block_found:
  113.                 holes += 1
  114.         heights[x] = col_height
  115.     for i in range(BOARD_WIDTH-1):
  116.         bumpiness += abs(heights[i] - heights[i+1])
  117.     total_height = sum(heights)
  118.     return total_height, holes, bumpiness
  119.  
  120. def simulate_drop(piece, x, rotation):
  121.     test_piece = {'shape': [row[:] for row in piece['shape']],
  122.                   'color': piece['color'],
  123.                   'x': x, 'y': 0}
  124.     for _ in range(rotation):
  125.         test_piece['shape'] = rotate_piece(test_piece['shape'])
  126.    
  127.     if collision(test_piece, dx=0, dy=0):
  128.         return -1, float('inf'), float('inf'), float('inf'), test_piece
  129.    
  130.     while not collision(test_piece, dy=1):
  131.         test_piece['y'] += 1
  132.    
  133.     test_board = [row[:] for row in board]
  134.     for y, row in enumerate(test_piece['shape']):
  135.         for xx, cell in enumerate(row):
  136.             if cell:
  137.                 by = test_piece['y'] + y
  138.                 bx = test_piece['x'] + xx
  139.                 if 0 <= by < BOARD_HEIGHT and 0 <= bx < BOARD_WIDTH:
  140.                     test_board[by][bx] = 1
  141.    
  142.     lines = 0
  143.     temp_board = [r[:] for r in test_board]
  144.     for y in range(BOARD_HEIGHT-1, -1, -1):
  145.         if all(temp_board[y]):
  146.             lines += 1
  147.             del temp_board[y]
  148.             temp_board.insert(0, [0]*BOARD_WIDTH)
  149.    
  150.     height, holes, bumpiness = get_board_stats(temp_board)
  151.     return lines, height, holes, bumpiness, test_piece
  152.  
  153. def ai_best_move():
  154.     best_score = -float('inf')
  155.     best_move = (current_piece['x'], 0)
  156.     piece = {'shape': [row[:] for row in current_piece['shape']],
  157.              'color': current_piece['color'],
  158.              'x': 0, 'y': 0}
  159.    
  160.     for rotation in range(4):
  161.         shape = piece['shape']
  162.         width = len(shape[0])
  163.         for x in range(-min([i for i, v in enumerate(shape[0]) if v]), BOARD_WIDTH - width + 1):
  164.             lines, height, holes, bumpiness, _ = simulate_drop(piece, x, rotation)
  165.            
  166.             if lines == -1:
  167.                 continue
  168.                
  169.             score_eval = (lines * ai_weights['lines'] +
  170.                           height * ai_weights['height'] +
  171.                           holes * ai_weights['holes'] +
  172.                           bumpiness * ai_weights['bumpiness'])
  173.            
  174.             if score_eval > best_score:
  175.                 best_score = score_eval
  176.                 best_move = (x, rotation)
  177.        
  178.         piece['shape'] = rotate_piece(piece)
  179.    
  180.     return best_move
  181.  
  182. def draw():
  183.     game_canvas.delete('all')
  184.     for y in range(BOARD_HEIGHT):
  185.         for x in range(BOARD_WIDTH):
  186.             color = board[y][x]
  187.             if color:
  188.                 game_canvas.create_rectangle(
  189.                     x*BLOCK_SIZE, y*BLOCK_SIZE,
  190.                     (x+1)*BLOCK_SIZE, (y+1)*BLOCK_SIZE,
  191.                     fill=color, outline='black'
  192.                 )
  193.     if current_piece:
  194.         for y, row in enumerate(current_piece['shape']):
  195.             for x, cell in enumerate(row):
  196.                 if cell:
  197.                     game_canvas.create_rectangle(
  198.                         (current_piece['x']+x)*BLOCK_SIZE,
  199.                         (current_piece['y']+y)*BLOCK_SIZE,
  200.                         (current_piece['x']+x+1)*BLOCK_SIZE,
  201.                         (current_piece['y']+y+1)*BLOCK_SIZE,
  202.                         fill=current_piece['color'], outline='black'
  203.                     )
  204.     game_canvas.create_text(5, 5, anchor='nw', text=f"Score: {score}\nLines: {lines_cleared}", fill='white', font=('Arial', 14))
  205.     next_canvas.delete('all')
  206.     next_canvas.create_text(5, 5, anchor='nw', text=f"Highscore:\n {highscore}", fill='yellow', font=('Arial', 14))
  207.     if next_piece:
  208.         shape = next_piece['shape']
  209.         color = next_piece['color']
  210.         offset_x = (6 - len(shape[0])) // 2
  211.         offset_y = (6 - len(shape)) // 2
  212.         for y, row in enumerate(shape):
  213.             for x, cell in enumerate(row):
  214.                 if cell:
  215.                     next_canvas.create_rectangle(
  216.                         (x+offset_x)*BLOCK_SIZE,
  217.                         (y+offset_y)*BLOCK_SIZE + 30,
  218.                         (x+offset_x+1)*BLOCK_SIZE,
  219.                         (y+offset_y+1)*BLOCK_SIZE + 30,
  220.                         fill=color, outline='black'
  221.                     )
  222.     if mode == "ai" and ai_countdown > 0:
  223.         next_canvas.create_text(90, 70, text=f"AI Restart: {ai_countdown}", fill='red', font=('Arial', 18), anchor='n')
  224.  
  225. def cancel_all_timers():
  226.     global game_timer, ai_countdown_timer
  227.     if game_timer:
  228.         root.after_cancel(game_timer)
  229.         game_timer = None
  230.     if ai_countdown_timer:
  231.         root.after_cancel(ai_countdown_timer)
  232.         ai_countdown_timer = None
  233.  
  234. def on_key(event):
  235.     global current_piece
  236.     if mode != "player" or not current_piece:
  237.         return
  238.     if event.keysym == 'Left':
  239.         if not collision(current_piece, dx=-1):
  240.             current_piece['x'] -= 1
  241.     elif event.keysym == 'Right':
  242.         if not collision(current_piece, dx=1):
  243.             current_piece['x'] += 1
  244.     elif event.keysym == 'Down':
  245.         if not collision(current_piece, dy=1):
  246.             current_piece['y'] += 1
  247.     elif event.keysym == 'Up':
  248.         rotated = rotate_piece(current_piece)
  249.         if not collision(current_piece, test_shape=rotated):
  250.             current_piece['shape'] = rotated
  251.     elif event.keysym == 'space':
  252.         while not collision(current_piece, dy=1):
  253.             current_piece['y'] += 1
  254.     draw()
  255.  
  256. def end_game():
  257.     global highscore
  258.     if score > highscore:
  259.         highscore = score
  260.         save_highscore()
  261.     draw()
  262.     game_canvas.create_text(BOARD_WIDTH*BLOCK_SIZE//2, BOARD_HEIGHT*BLOCK_SIZE//2, text="GAME OVER", fill='red', font=('Arial', 24, 'bold'))
  263.  
  264. def player_game_step():
  265.     global current_piece, next_piece, score, lines_cleared, highscore, game_timer
  266.     if not current_piece:
  267.         return
  268.     if not collision(current_piece, dy=1):
  269.         current_piece['y'] += 1
  270.     else:
  271.         merge(current_piece)
  272.         clear_lines()
  273.         if score > highscore:
  274.             highscore = score
  275.             save_highscore()
  276.         current_piece = next_piece
  277.         next_piece = create_piece()
  278.         if collision(current_piece):
  279.             end_game()
  280.             return
  281.     draw()
  282.     if current_piece:
  283.         game_timer = root.after(500, player_game_step)
  284.  
  285. def start_player_game():
  286.     global board, score, lines_cleared, current_piece, next_piece, mode
  287.     cancel_all_timers()
  288.     mode = "player"
  289.     board = [[0 for _ in range(BOARD_WIDTH)] for _ in range(BOARD_HEIGHT)]
  290.     score = 0
  291.     lines_cleared = 0
  292.     current_piece = create_piece()
  293.     next_piece = create_piece()
  294.     draw()
  295.     root.after(1, player_game_step)
  296.  
  297. ai_move_plan = None
  298. ai_move_step = 0
  299. ai_drop_step = 0
  300.  
  301. def ai_prepare_move():
  302.     global ai_move_plan, ai_move_step, ai_drop_step
  303.     x_target, rot_target = ai_best_move()
  304.     ai_move_plan = {'x': x_target, 'rot': rot_target}
  305.     ai_move_step = 0
  306.     ai_drop_step = 0
  307.  
  308. def ai_animate_move():
  309.     global ai_move_plan, ai_move_step, ai_drop_step, current_piece, next_piece, score, lines_cleared, game_timer
  310.    
  311.     if not current_piece or ai_move_plan is None:
  312.         return
  313.    
  314.     if ai_move_step < ai_move_plan['rot']:
  315.         rotated = rotate_piece(current_piece)
  316.         if not collision(current_piece, test_shape=rotated):
  317.             current_piece['shape'] = rotated
  318.             ai_move_step += 1
  319.         else:
  320.             ai_move_step = ai_move_plan['rot']
  321.         draw()
  322.         game_timer = root.after(100, ai_animate_move)
  323.         return
  324.    
  325.     if current_piece['x'] < ai_move_plan['x']:
  326.         if not collision(current_piece, dx=1):
  327.             current_piece['x'] += 1
  328.         elif current_piece['x'] < ai_move_plan['x'] - 1:
  329.             current_piece['x'] += 1
  330.         draw()
  331.         game_timer = root.after(50, ai_animate_move)
  332.         return
  333.     elif current_piece['x'] > ai_move_plan['x']:
  334.         if not collision(current_piece, dx=-1):
  335.             current_piece['x'] -= 1
  336.         elif current_piece['x'] > ai_move_plan['x'] + 1:
  337.             current_piece['x'] -= 1
  338.         draw()
  339.         game_timer = root.after(50, ai_animate_move)
  340.         return
  341.    
  342.     if not collision(current_piece, dy=1):
  343.         current_piece['y'] += 1
  344.         draw()
  345.         game_timer = root.after(30, ai_animate_move)
  346.         return
  347.    
  348.     merge(current_piece)
  349.     clear_lines()
  350.     if lines_cleared and random.random() < 0.1:
  351.         for k in ai_weights:
  352.             ai_weights[k] += random.uniform(-0.05, 0.05)
  353.         save_data()
  354.    
  355.     current_piece = next_piece
  356.     next_piece = create_piece()
  357.     if collision(current_piece):
  358.         end_game()
  359.         start_ai_countdown()
  360.         return
  361.    
  362.     ai_prepare_move()
  363.     draw()
  364.     game_timer = root.after(100, ai_animate_move)
  365.  
  366. def ai_game_step():
  367.     ai_prepare_move()
  368.     ai_animate_move()
  369.  
  370. def start_ai_game():
  371.     global board, score, lines_cleared, current_piece, next_piece, mode
  372.     cancel_all_timers()
  373.     mode = "ai"
  374.     board = [[0 for _ in range(BOARD_WIDTH)] for _ in range(BOARD_HEIGHT)]
  375.     score = 0
  376.     lines_cleared = 0
  377.     current_piece = create_piece()
  378.     next_piece = create_piece()
  379.     draw()
  380.     root.after(1, ai_game_step)
  381.  
  382. def start_ai_countdown():
  383.     global ai_countdown, ai_countdown_timer
  384.     ai_countdown = 6
  385.     if ai_countdown_timer:
  386.         root.after_cancel(ai_countdown_timer)
  387.     ai_countdown_tick()
  388.  
  389. def ai_countdown_tick():
  390.     global ai_countdown, ai_countdown_timer
  391.     if ai_countdown > 0:
  392.         draw()
  393.         ai_countdown -= 1
  394.         ai_countdown_timer = root.after(1000, ai_countdown_tick)
  395.     else:
  396.         ai_countdown_timer = None
  397.         start_ai_game()
  398.  
  399. if __name__ == "__main__":
  400.     load_data()
  401.     root = tk.Tk()
  402.     root.title("Colorful Tetris")
  403.     root.geometry("+0+0")
  404.     frame = tk.Frame(root)
  405.     frame.pack()
  406.     game_canvas = tk.Canvas(frame, width=BOARD_WIDTH*BLOCK_SIZE, height=BOARD_HEIGHT*BLOCK_SIZE, bg='black')
  407.     game_canvas.pack(side='left')
  408.     right_frame = tk.Frame(frame)
  409.     right_frame.pack(side='top', padx=20)
  410.     next_canvas = tk.Canvas(right_frame, width=6*BLOCK_SIZE, height=6*BLOCK_SIZE, bg='gray20')
  411.     next_canvas.pack(side='top', pady=10)
  412.     btn_frame = tk.Frame(right_frame)
  413.     btn_frame.pack(side='top', pady=10)
  414.     btn_player = tk.Button(btn_frame, text="Player Restart", command=start_player_game, width=15)
  415.     btn_player.pack(side='top', pady=5)
  416.     btn_ai = tk.Button(btn_frame, text="AI", command=start_ai_game, width=15)
  417.     btn_ai.pack(side='top', pady=5)
  418.     root.bind("<Key>", on_key)
  419.     root.focus_set()
  420.     start_player_game()
  421.     root.mainloop()
Advertisement
Add Comment
Please, Sign In to add comment