deepseek写程序了 - block puzzle game

STEM版,合并数学,物理,化学,科学,工程,机械。不包括生物、医学相关,和计算机相关内容。

版主: verdeliteTheMatrix

头像
TheMatrix楼主
论坛支柱
论坛支柱
2024年度优秀版主
TheMatrix 的博客
帖子互动: 266
帖子: 13400
注册时间: 2022年 7月 26日 00:35

#41 Re: deepseek写程序了 - block puzzle game

帖子 TheMatrix楼主 »

自己不能截获事件流这件事,对BNF的实现还是有影响的。但是只影响一个函数。就是下面这个。

代码: 全选

def click_drag_release():
    #because we don't control receiving mouse events
    #need to break the click_drag_release cycle
    """
        click_drag_release: click_a_preview_block, drag_a_block*, release_a_block

        if click_a_preview_block():
            while drag_a_block(): pass
            release_a_block()
    """
    if click_a_preview_block(): pass
    if drag_a_block(): pass
    if release_a_block(): pass
    

以下是完整的版本:

init:

代码: 全选

"""
game: game_init, game_going+

game_init: game_static_init, generate_preview_blocks

game_going: null_mouse_event
game_going: click_drag_release

click_drag_release: click_a_preview_block, drag_a_block*, release_a_block

click_a_preview_block: MOUSE_CLICK, mouse_click_effect

drag_a_block: MOUSE_MOVE, mouse_drag_effect
mouse_drag_effect: not_fit_in_board, drag_block
mouse_drag_effect: fit_in_board, show_fit_in, drag_block

release_a_block: MOUSE_RELEASE, mouse_release_effect
mouse_release_effect: not_fit_in_board, go_back_to_preview
mouse_release_effect: fit_in_board, update_board, update_preview
update_preview: update_preview_blocks, update_game_over
update_preview_blocks: no_preview_blocks, generate_preview_blocks

"""

import tkinter as tk
import random

class BlockPuzzle:
    def __init__(self):
        pass

def game_init():
    game_static_init()
    generate_preview_blocks()
    
def game_static_init():
    game_init_layout()
    game_init_canvas()
    set_game_blocks()
    game_init_board()

    game.game_over = False
    game.dragging = False
    game.fit_in = False
    game.board_state = [
        [{"occupied": False} 
         for i in range(8)]
        for j in range(8) ]

def game_going(event):
    game.event = event
    click_drag_release()

def click_drag_release():
    #because we don't control receiving mouse events
    #need to break the click_drag_release cycle
    """
        click_drag_release: click_a_preview_block, drag_a_block*, release_a_block

        if click_a_preview_block():
            while drag_a_block(): pass
            release_a_block()
    """
    if click_a_preview_block(): pass
    if drag_a_block(): pass
    if release_a_block(): pass

def game_init_layout():
    game.game_bg_color = "#1A2B3C"
    game.cell_color = game.game_bg_color
    game.grid_color = "#708090"

    game.padx = 100
    game.top_section_pady = 20
    game.board_pady = 20
    game.preview_pady = 20
    game.bottom_pady = 20

    game.cell_size = 50
    game.preview_cell_size = 24
    game.grid_border = 1
    game.board_n_cell = 8
    game.board_size = game.cell_size * game.board_n_cell

    game.top_section_x = game.padx
    game.top_section_y = game.top_section_pady
    game.top_section_height = 100
    game.top_section_width = game.board_size

    game.board_x = game.padx
    game.board_y = game.top_section_y + game.top_section_height + game.board_pady

    game.preview_x = game.padx
    game.preview_y = game.board_y + game.board_size + game.preview_pady
    game.preview_width = game.board_size
    game.preview_height = game.board_size // 2

    game.canvas_width = 2 * game.padx + game.board_size
    game.canvas_height = game.preview_y + game.preview_height + game.bottom_pady
    
    game.preview_one_size = 5* game.preview_cell_size
    game.preview_padx = 10
    xx = game.preview_width - 3* game.preview_one_size - 2* game.preview_padx
    assert(xx % 2 == 0)
    game.preview_lr_padx = xx // 2
    game.preview_one_x = [
        game.preview_x + game.preview_lr_padx +
        i* (game.preview_one_size + game.preview_padx) 
        for i in range(3)]
    game.preview_one_y = game.preview_y

def game_init_canvas():
    root.title("Block Puzzle")
    root.resizable(False, False)
    game.canvas = tk.Canvas(
        root, 
        bg=game.game_bg_color, 
        highlightthickness=0, 
        width=game.canvas_width, 
        height=game.canvas_height,
        )
    game.canvas.pack()
    game.canvas.bind("<Button-1>", game_going)
    game.canvas.bind("<B1-Motion>", game_going)
    game.canvas.bind("<ButtonRelease-1>", game_going)

def variation_blocks():
    def rotate(p):
        x,y = p
        return -y,x

    def normalize(block):
        min_x = min(dx for dx,dy in block)
        min_y = min(dy for dx,dy in block)
        nblock = [(dx-min_x, dy-min_y) for dx,dy in block]
        return nblock

    def variation_block(block):
        nblocks = []
        nb = block
        for i in range(4):
            nb = sorted(nb)
            nblocks.append(tuple(nb))
            nb = [rotate(c) for c in nb]
            nb = normalize(nb)
        nblocks = list(set(nblocks))
        return nblocks

    game.tetris_blocks = []
    for block in game.base_tetris_blocks:
        nblocks = variation_block(block["shape"])
        game.tetris_blocks += [{"shape": b, "color": block["color"]} for b in nblocks]

def set_game_blocks():
    game.base_tetris_blocks = [
        {"shape": [(0, 0), (0, 1), (0, 2), (0, 3)], "color": "#6DB3AC"},  # I (4-square)
        {"shape": [(0, 0), (0, 1), (1, 0), (1, 1)], "color": "#F0F000"},  # O
        {"shape": [(0, 0), (1, 0), (1, 1), (2, 0)], "color": "#BD4DF5"},  # T
        {"shape": [(0, 1), (0, 2), (1, 0), (1, 1)], "color": "#00F000"},  # S
        {"shape": [(0, 0), (0, 1), (1, 1), (1, 2)], "color": "#F00000"},  # Z
        {"shape": [(0, 0), (1, 0), (2, 0), (2, 1)], "color": "#699EEB"},  # J
        {"shape": [(0, 1), (1, 1), (2, 0), (2, 1)], "color": "#F0A000"},  # L
        
        # Custom blocks
        {"shape": [(0, 0)], "color": "#F09050"},  # 1-square
        {"shape": [(0, 0), (0, 1)], "color": "#6FEA85"},  # 2-square
        {"shape": [(0, 0), (0, 1), (0, 2)], "color": "#B34DB3"},  # 3-line
        {"shape": [(0, 0), (0, 1), (1, 1)], "color": "#A5B350"},  # L-3
        
        # 5-square blocks
        {"shape": [(0, 0), (0, 1), (0, 2), (0, 3), (0, 4)], "color": "#D0603C"},  # 5-line (Dark Turquoise)
        {"shape": [(0, 0), (0, 1), (0, 2), (1, 2), (2, 2)], "color": "#C8BA4A"},  # Right-angle (Red)
        
        # 9-square block
        {"shape": [
            (0, 0), (0, 1), (0, 2),
            (1, 0), (1, 1), (1, 2),
            (2, 0), (2, 1), (2, 2)
            ], "color": "#FFD700"}  # 3x3 (Gold)
        
        ]
    variation_blocks()

def game_init_board():
    #board grids
    for row in range(8):
        for col in range(8):
            x1 = col * game.cell_size + game.board_x
            y1 = row * game.cell_size + game.board_y
            x2 = x1+ game.cell_size -1
            y2 = y1+ game.cell_size -1
            game.canvas.create_rectangle(
            x1,y1,x2,y2, 
            fill=game.cell_color,
            outline=game.grid_color,
            width=game.grid_border,
                )

    #board outer border
    game.canvas.create_rectangle(
        game.board_x-1,
        game.board_y-1,
        game.board_x+game.board_size,
        game.board_y+game.board_size,
        #fill=game.cell_color,
        outline=game.grid_color,
        width=game.grid_border,
        )

Mouse Click:

代码: 全选

######################
#Mouse Click
######################

def click_a_preview_block():
    if valid_mouse_click_event():
        mouse_click_effect()
        return True
    return False

def valid_mouse_click_event():
    event_type = tk.EventType(game.event.type).name
    if event_type != "ButtonPress":
        return False

    game.preview_clicked_on = -1
    for i in range(3):
        x1 = game.preview_one_x[i]
        x2 = x1+ game.preview_one_size
        y1 = game.preview_one_y
        y2 = y1+ game.preview_one_size
        if x1 <= game.event.x < x2 and y1 <= game.event.y < y2:
            game.preview_clicked_on = i
            break

    if game.preview_clicked_on == -1:
        return False
    if not game.preview_blocks_present[i]:
        return False
    if game.preview_blocks_dead[i]:
        return False

    print("mouse click on ", game.preview_clicked_on)
    return True

def mouse_click_effect():
    i = game.preview_clicked_on

    #enlarge the preview block

    #delete the smaller preview block
    for rect in game.preview_blocks_rect[i]:
        game.canvas.delete(rect)

    game.dragging = True
    game.fit_in = False
    game.dragging_last_x = game.event.x
    game.dragging_last_y = game.event.y

    #enlarge the preview block
    block = game.tetris_blocks[game.preview_blocks[i]]
    nx = max(dx for dx,dy in block["shape"]) +1
    ny = max(dy for dx,dy in block["shape"]) +1
    center_x = game.preview_one_x[i]+game.preview_one_size//2
    game.dragging_block_x = center_x - nx * game.cell_size //2
    game.dragging_block_y = game.preview_one_y - ny* game.cell_size

    #block_nx, block_ny = game.block_nxy()
    game.dragging_block_nx = -1
    game.dragging_block_ny = -1

    game.dragging_block_rect = []
    for dx,dy in block["shape"]:
        x1 = dx* game.cell_size + game.dragging_block_x
        y1 = dy* game.cell_size + game.dragging_block_y
        x2 = x1+ game.cell_size -1
        y2 = y1+ game.cell_size -1
        game.dragging_block_rect.append(
            game.canvas.create_rectangle(
                x1,y1,x2,y2,
                fill=block["color"],
                outline=game.game_bg_color,
                width=game.grid_border,
                ))

Mouse Move:

代码: 全选

######################
#Mouse Move
######################

def drag_a_block():
    if valid_dragging_event():
        mouse_drag_effect()
        return True
    return False

def valid_dragging_event():
    event_type = tk.EventType(game.event.type).name
    if event_type != "Motion":
        return False
    if not game.dragging:
        return False
    return True

def block_nxy():
    block_x = game.dragging_block_x - game.board_x
    block_y = game.dragging_block_y - game.board_y
    block_nx = block_x // game.cell_size
    block_ny = block_y // game.cell_size
    block_rx = block_x % game.cell_size
    block_ry = block_y % game.cell_size
    if block_rx > game.cell_size //2:
        block_nx += 1
    if block_ry > game.cell_size //2:
        block_ny += 1
    return block_nx, block_ny
         
def mouse_drag_effect():
    #move the dragging block
    move_x = game.event.x - game.dragging_last_x
    move_y = game.event.y - game.dragging_last_y
    game.dragging_last_x = game.event.x
    game.dragging_last_y = game.event.y
    for rect in game.dragging_block_rect:
        game.canvas.move(rect, move_x, move_y)

    #pre-fit-in block
    game.dragging_block_x += move_x
    game.dragging_block_y += move_y
    block_nx, block_ny = block_nxy()

    #skip if no change in fit-in block
    if block_nx == game.dragging_block_nx and block_ny == game.dragging_block_ny:
        return

    #fit-in block moved
    
    #remove previous fit-in block
    if game.fit_in:
        for rect in game.fit_in_rect:
            game.canvas.delete(rect)

    #calculate the size of the dragging block
    game.dragging_block_nx = block_nx
    game.dragging_block_ny = block_ny
    block = game.tetris_blocks[game.preview_blocks[game.preview_clicked_on]]
    max_x = max(dx for dx,dy in block["shape"])
    max_y = max(dy for dx,dy in block["shape"])
    
    #outside of the board --> not fit-in
    if (game.dragging_block_nx < 0
        or game.dragging_block_nx +max_x >= 8
        or game.dragging_block_ny < 0
        or game.dragging_block_ny +max_y >= 8):
        game.fit_in = False
        return
    
    #board occupied --> not fit-in
    for dx,dy in block["shape"]:
        x = dx+ game.dragging_block_nx
        y = dy+ game.dragging_block_ny
        if game.board_state[x][y]["occupied"]:
            game.fit_in = False
            return

    #fit in board
    game.fit_in = True
    game.fit_in_rect = put_board_block(game.preview_clicked_on, "red")

    #fit-in block created after the dragging block
    #need bring the dragging block up
    for rect in game.dragging_block_rect:
        game.canvas.lift(rect)

Mouse Release:

代码: 全选

######################
#Mouse Release
######################

def release_a_block():
    if valid_mouse_release_event():
        mouse_release_effect()
        return True
    return False

def valid_mouse_release_event():
    event_type = tk.EventType(game.event.type).name
    if event_type != "ButtonRelease":
        return False
    if not game.dragging:
        return False
    return True

def mouse_release_effect():
    #remove the dragging block
    for rect in game.dragging_block_rect:
        game.canvas.delete(rect)

    if not game.fit_in:
        go_back_to_preview()
    else:
        update_board()
        update_preview()

    game.fit_in = False
    game.dragging = False

def go_back_to_preview():
    put_preview_block(game.preview_clicked_on)

def update_board():
    #put the block in board by removing the temp fit-in block then put the real block
    for rect in game.fit_in_rect:
        game.canvas.delete(rect)

    block_rect = put_board_block(game.preview_clicked_on, game.grid_color)

    #update board occupied state
    block = game.tetris_blocks[game.preview_blocks[game.preview_clicked_on]]
    for n,(dx,dy) in enumerate(block["shape"]):
        cell = game.board_state[game.dragging_block_nx+dx][game.dragging_block_ny+dy]
        cell["occupied"] = True
        cell["rect"] = block_rect[n]

    #check row and col that can be cleared
    full_cols = [x for x in range(8) if all([cell["occupied"] for cell in game.board_state[x]])]
    full_rows = [y for y in range(8) if all([row[y]["occupied"] for row in game.board_state])]
    to_be_cleared = set([(x,y) for x in full_cols for y in range(8)] 
                        + [(x,y) for y in full_rows for x in range(8)])
    for x,y in to_be_cleared:
        game.canvas.delete(game.board_state[x][y]["rect"])
        game.board_state[x][y]["occupied"] = False

def update_preview():
    update_preview_blocks()
    update_game_over()

def no_preview_blocks():
    return not any(game.preview_blocks_present)

def update_preview_blocks():
    #the particular preview block is gone
    game.preview_blocks_present[game.preview_clicked_on] = False

    if no_preview_blocks():
        generate_preview_blocks()
    
    for i in range(3):
        if game.preview_blocks_present[i]:
            block = game.tetris_blocks[game.preview_blocks[i]]["shape"]
            if dead_block(block):
                if not game.preview_blocks_dead[i]:
                    for rect in game.preview_blocks_rect[i]:
                        game.canvas.delete(rect)
                    put_preview_block(i, "dimgray")
                    game.preview_blocks_dead[i] = True
            else:
                if game.preview_blocks_dead[i]:
                    for rect in game.preview_blocks_rect[i]:
                        game.canvas.delete(rect)
                    put_preview_block(i)
                    game.preview_blocks_dead[i] = False

def dead_block(block):
    for x in range(8):
        for y in range(8):
            if all([x+dx in range(8) and y+dy in range(8) 
                    and not game.board_state[x+dx][y+dy]["occupied"] for dx,dy in block]):
                return False
    return True

def update_game_over():
    preview_blocks = [i for i in range(3) if game.preview_blocks_present[i]]
    game.game_over = all([game.preview_blocks_dead[i] for i in preview_blocks])
    if game.game_over:
        game.game_over = True
        game.canvas.create_text(
            game.top_section_x+ game.top_section_width //2, 
            game.top_section_y+ game.top_section_height //2, 
            text="GAME OVER", 
            fill="white", 
            font=("Arial", 16),
            anchor="center",
            )

utility and main:

代码: 全选

######################
#utility
######################

#this function is reused by fit-in temp block and dropped block
def put_board_block(i, color):
    block = game.tetris_blocks[game.preview_blocks[i]]
    block_rect = []
    for dx,dy in block["shape"]:
        x1 = dx+game.dragging_block_nx
        x1 = x1* game.cell_size + game.board_x
        y1 = dy+game.dragging_block_ny
        y1 = y1* game.cell_size + game.board_y
        x2 = x1 + game.cell_size -1
        y2 = y1 + game.cell_size -1
        block_rect.append(
            game.canvas.create_rectangle(
                x1,y1,x2,y2,
                fill=block["color"],
                outline=color,
                width=game.grid_border
                ))
    return block_rect

def generate_preview_blocks():
    nblock = len(game.tetris_blocks)
    game.preview_blocks = [random.choice(range(nblock)) for i in range(3)]
    game.preview_blocks_present = [True for i in range(3)]
    game.preview_blocks_dead = [False for i in range(3)]
    game.preview_blocks_rect = [[] for i in range(3)]
    for i in range(3):
        put_preview_block(i)

def put_preview_block(i, color=None):
    block = game.tetris_blocks[game.preview_blocks[i]]
    if color is None:
        color = block["color"]
    nx = max(dx for dx,dy in block["shape"])+1
    ny = max(dy for dx,dy in block["shape"])+1
    xx = game.preview_one_size - nx*game.preview_cell_size
    assert(xx % 2 == 0)
    yy = game.preview_one_size - ny*game.preview_cell_size
    assert(yy % 2 == 0)
    for dx,dy in block["shape"]:
        x1 = dx* game.preview_cell_size + game.preview_one_x[i] + xx//2
        y1 = dy* game.preview_cell_size + game.preview_one_y + yy//2
        x2 = x1+ game.preview_cell_size -1
        y2 = y1+ game.preview_cell_size -1
        game.preview_blocks_rect[i].append(
            game.canvas.create_rectangle(
                x1,y1,x2,y2,
                fill=color,
                outline=game.game_bg_color,
                width=game.grid_border,
                ))

if __name__ == "__main__":
    root = tk.Tk()
    game = BlockPuzzle()
    game_init()
    root.mainloop()


标签/Tags:
上理夏潼
职业作家
职业作家
帖子互动: 70
帖子: 669
注册时间: 2025年 2月 18日 18:40

#42 Re: deepseek写程序了 - block puzzle game

帖子 上理夏潼 »

红烛歌楼 写了: 2025年 2月 11日 20:37 程序猿要失业了,尤其是游戏编程!
咱们程序员辛辛苦苦起早贪黑的开发出AI让自己失业了 :shock: :shock:
头像
TheMatrix楼主
论坛支柱
论坛支柱
2024年度优秀版主
TheMatrix 的博客
帖子互动: 266
帖子: 13400
注册时间: 2022年 7月 26日 00:35

#43 Re: deepseek写程序了 - block puzzle game

帖子 TheMatrix楼主 »

TheMatrix 写了: 2025年 3月 2日 18:48
以下是完整的版本:
图片
头像
TheMatrix楼主
论坛支柱
论坛支柱
2024年度优秀版主
TheMatrix 的博客
帖子互动: 266
帖子: 13400
注册时间: 2022年 7月 26日 00:35

#44 Re: deepseek写程序了 - block puzzle game

帖子 TheMatrix楼主 »

TheMatrix 写了: 2025年 3月 2日 18:51 图片
再加上score。手撸成这样就差不多了。

回头看看deepseek能不能写出函数来。不过有一定困难。我这个程序虽然分解为函数了,但是有很多class variable,相当于global variable。不知道算不算紧耦合。

图片
头像
TheMatrix楼主
论坛支柱
论坛支柱
2024年度优秀版主
TheMatrix 的博客
帖子互动: 266
帖子: 13400
注册时间: 2022年 7月 26日 00:35

#45 Re: deepseek写程序了 - block puzzle game

帖子 TheMatrix楼主 »

加了一些方块。还可以旋转了:

图片

图片
上次由 TheMatrix 在 2025年 3月 5日 21:41 修改。
原因: 未提供修改原因
头像
TheMatrix楼主
论坛支柱
论坛支柱
2024年度优秀版主
TheMatrix 的博客
帖子互动: 266
帖子: 13400
注册时间: 2022年 7月 26日 00:35

#46 Re: deepseek写程序了 - block puzzle game

帖子 TheMatrix楼主 »

图片
回复

回到 “STEM”