20244206 2024-2025-2 《Python程序设计》实验四报告
课程:《Python程序设计》
班级: 2442
姓名: 郭玮轩
学号:20244206
实验教师:王志强
实验日期:2025年5月13日
必修/选修: 公选课
一.实验内容
Python的综合应用 2048小游戏
二. 实验过程及结果
(一)初始化设置:设置游戏的基本参数,如颜色方案、字体等
(二)主界面:包含标题、分数显示和游戏说明。

(三)菜单栏设置:添加了重置游戏和撤销一步的按钮
(四)创建游戏网格:使用 tkinter 的 Frame 和 Label 组件创建游戏网格,并根据数字大小设置不同的颜色。
(五)更新重置
(六)游戏胜利/失败:显示胜利消息并允许继续游戏,当无法移动时显示游戏结束消息。
(七)源代码
import tkinter as tk import random import copy class Game2048: def __init__(self, master): self.master = master self.master.title("2048游戏") self.master.geometry("400x500") self.master.resizable(False, False) self.master.configure(bg="#faf8ef") # 确保中文显示正常 self.font_family = "SimHei" # ===== 初始化设置 ===== self.initialize_settings() # ===== 游戏数据 ===== self.initialize_game_data() # ===== 创建主界面 ===== self.create_main_interface() # ===== 初始化游戏 ===== self.reset_game() def initialize_settings(self): """初始化游戏设置""" # 颜色设置 self.bg_color = "#faf8ef" self.grid_color = "#bbada0" self.empty_cell_color = "#cdc1b4" # 数字颜色映射 self.cell_colors = { 0: "#cdc1b4", 2: "#eee4da", 4: "#ede0c8", 8: "#f2b179", 16: "#f59563", 32: "#f67c5f", 64: "#f65e3b", 128: "#edcf72", 256: "#edcc61", 512: "#edc850", 1024: "#edc53f", 2048: "#edc22e" } # 数字字体颜色映射 self.text_colors = { 0: "#cdc1b4", 2: "#776e65", 4: "#776e65", 8: "#f9f6f2", 16: "#f9f6f2", 32: "#f9f6f2", 64: "#f9f6f2", 128: "#f9f6f2", 256: "#f9f6f2", 512: "#f9f6f2", 1024: "#f9f6f2", 2048: "#f9f6f2" } def initialize_game_data(self): """初始化游戏数据""" self.grid = [[0 for _ in range(4)] for _ in range(4)] self.score = 0 self.high_score = 0 self.game_over = False self.game_won = False self.undo_grid = None self.undo_score = 0 def create_main_interface(self): """创建主界面""" # ===== 标题和分数框架 ===== self.create_header_section() # ===== 菜单栏设置 ===== self.create_menu_section() # ===== 游戏说明 ===== self.create_instruction_section() # ===== 游戏地图创建 ===== self.create_game_grid() # 绑定键盘事件 self.master.bind("", self.key_press) def create_header_section(self): """创建标题和分数区域""" header_frame = tk.Frame(self.master, bg=self.bg_color) header_frame.pack(fill=tk.X, padx=20, pady=10) # 标题 title_label = tk.Label(header_frame, text="2048", font=(self.font_family, 40, "bold"), bg=self.bg_color, fg="#776e65") title_label.pack(side=tk.LEFT) # 分数框架 score_frame = tk.Frame(header_frame, bg=self.grid_color, padx=10, pady=5) score_frame.pack(side=tk.RIGHT, padx=(10, 0)) tk.Label(score_frame, text="分数", font=(self.font_family, 12), bg=self.grid_color, fg="#eee4da").pack() self.score_label = tk.Label(score_frame, text="0", font=(self.font_family, 18, "bold"), bg=self.grid_color, fg="white") self.score_label.pack() # 最高分框架 high_score_frame = tk.Frame(header_frame, bg=self.grid_color, padx=10, pady=5) high_score_frame.pack(side=tk.RIGHT) tk.Label(high_score_frame, text="最高分", font=(self.font_family, 12), bg=self.grid_color, fg="#eee4da").pack() self.high_score_label = tk.Label(high_score_frame, text="0", font=(self.font_family, 18, "bold"), bg=self.grid_color, fg="white") self.high_score_label.pack() def create_menu_section(self): """创建菜单栏""" button_frame = tk.Frame(self.master, bg=self.bg_color) button_frame.pack(fill=tk.X, padx=20, pady=5) # 重置按钮 self.reset_button = tk.Button(button_frame, text="重置游戏", font=(self.font_family, 12), bg="#8f7a66", fg="white", command=self.reset_game) self.reset_button.pack(side=tk.LEFT, padx=(0, 10)) # 撤销按钮 self.undo_button = tk.Button(button_frame, text="撤销一步", font=(self.font_family, 12), bg="#8f7a66", fg="white", command=self.undo_move) self.undo_button.pack(side=tk.LEFT) def create_instruction_section(self): """创建游戏说明""" self.instruction_label = tk.Label(self.master, text="使用方向键移动数字。相同数字合并后会相加。尝试得到2048!", font=(self.font_family, 12), bg=self.bg_color, fg="#776e65") self.instruction_label.pack(padx=20, pady=5) def create_game_grid(self): """创建游戏网格""" # ===== 游戏地图创建 ===== self.grid_frame = tk.Frame(self.master, bg=self.grid_color, padx=10, pady=10) self.grid_frame.pack(padx=20, pady=10, fill=tk.BOTH, expand=True) # ===== 游戏地图绘制 ===== self.cell_frames = [] self.cell_labels = [] for i in range(4): row_frames = [] row_labels = [] for j in range(4): cell_frame = tk.Frame(self.grid_frame, width=80, height=80, bg=self.empty_cell_color) cell_frame.grid(row=i, column=j, padx=5, pady=5, sticky="nsew") cell_frame.grid_propagate(False) cell_label = tk.Label(cell_frame, text="", font=(self.font_family, 24, "bold"), bg=self.empty_cell_color, fg="#776e65") cell_label.place(relx=0.5, rely=0.5, anchor="center") row_frames.append(cell_frame) row_labels.append(cell_label) self.cell_frames.append(row_frames) self.cell_labels.append(row_labels) # 确保网格单元格大小一致 for i in range(4): self.grid_frame.grid_rowconfigure(i, weight=1) self.grid_frame.grid_columnconfigure(i, weight=1) def update_display(self): """更新游戏界面显示""" # 更新分数 self.score_label.config(text=str(self.score)) self.high_score_label.config(text=str(self.high_score)) # 更新网格 for i in range(4): for j in range(4): value = self.grid[j] self.cell_labels[j].config( text="" if value == 0 else str(value), bg=self.cell_colors.get(value, "#ff0000"), fg=self.text_colors.get(value, "white") ) self.cell_frames[j].config(bg=self.cell_colors.get(value, "#ff0000")) def reset_game(self): """重置游戏状态""" # 关闭可能存在的消息框 if hasattr(self, 'overlay'): self.overlay.destroy() self.initialize_game_data() self.add_new_tile() self.add_new_tile() self.update_high_score() self.update_display() def add_new_tile(self): """在随机位置添加新的数字2或4""" empty_cells = [(i, j) for i in range(4) for j in range(4) if self.grid[j] == 0] if empty_cells: i, j = random.choice(empty_cells) self.grid[j] = 2 if random.random() < 0.9 else 4 def update_high_score(self): """更新最高分""" if self.score > self.high_score: self.high_score = self.score # ===== 判断游戏胜利条件 ===== def check_game_won(self): """检查游戏是否胜利""" for i in range(4): for j in range(4): if self.grid[j] >= 2048: return True return False def check_game_over(self): """检查游戏是否结束""" # 检查是否有空单元格 for i in range(4): for j in range(4): if self.grid[j] == 0: return False # 检查是否有相邻相同的数字 for i in range(4): for j in range(3): if self.grid[j] == self.grid[j + 1]: return False for i in range(3): for j in range(4): if self.grid[j] == self.grid[i + 1][j]: return False return True def save_state(self): """保存当前游戏状态用于撤销""" self.undo_grid = copy.deepcopy(self.grid) self.undo_score = self.score def undo_move(self): """撤销上一步操作""" if self.undo_grid is not None: # 关闭可能存在的消息框 if hasattr(self, 'overlay'): self.overlay.destroy() self.grid = self.undo_grid self.score = self.undo_score self.game_over = False self.game_won = False self.update_display() # ===== 游戏逻辑(移动、合并) ===== def move_left(self): moved = False for i in range(4): for j in range(1, 4): if self.grid[j] != 0: k = j while k > 0 and self.grid[k - 1] == 0: k -= 1 if k != j: self.grid[k] = self.grid[j] self.grid[j] = 0 moved = True if k > 0 and self.grid[k - 1] == self.grid[k]: self.grid[k - 1] *= 2 self.score += self.grid[k - 1] self.grid[k] = 0 moved = True return moved def move_right(self): moved = False for i in range(4): for j in range(2, -1, -1): if self.grid[j] != 0: k = j while k < 3 and self.grid[k + 1] == 0: k += 1 if k != j: self.grid[k] = self.grid[j] self.grid[j] = 0 moved = True if k < 3 and self.grid[k + 1] == self.grid[k]: self.grid[k + 1] *= 2 self.score += self.grid[k + 1] self.grid[k] = 0 moved = True return moved def move_up(self): moved = False for j in range(4): for i in range(1, 4): if self.grid[j] != 0: k = i while k > 0 and self.grid[k - 1][j] == 0: k -= 1 if k != i: self.grid[k][j] = self.grid[j] self.grid[j] = 0 moved = True if k > 0 and self.grid[k - 1][j] == self.grid[k][j]: self.grid[k - 1][j] *= 2 self.score += self.grid[k - 1][j] self.grid[k][j] = 0 moved = True return moved def move_down(self): moved = False for j in range(4): for i in range(2, -1, -1): if self.grid[j] != 0: k = i while k < 3 and self.grid[k + 1][j] == 0: k += 1 if k != i: self.grid[k][j] = self.grid[j] self.grid[j] = 0 moved = True if k < 3 and self.grid[k + 1][j] == self.grid[k]: self.grid[k + 1][j] *= 2 self.score += self.grid[k + 1][j] self.grid[k] = 0 moved = True return moved # ===== 游戏胜利处理 ===== def show_win_message(self): """显示游戏胜利消息""" self.overlay = tk.Toplevel(self.master) self.overlay.geometry(f"{400}x{500}+{self.master.winfo_x()}+{self.master.winfo_y()}") self.overlay.configure(bg="white") self.overlay.attributes("-alpha", 0.7) self.overlay.overrideredirect(True) tk.Label(self.overlay, text="恭喜你,胜利了!", font=(self.font_family, 30, "bold"), bg="white", fg="#776e65").place(relx=0.5, rely=0.4, anchor="center") tk.Label(self.overlay, text="继续游戏以获得更高分数...", font=(self.font_family, 16), bg="white", fg="#776e65").place(relx=0.5, rely=0.5, anchor="center") tk.Button(self.overlay, text="重置游戏", font=(self.font_family, 16), bg="#8f7a66", fg="white", command=self.reset_game).place( relx=0.5, rely=0.6, anchor="center") # ===== 游戏失败处理 ===== def show_game_over_message(self): """显示游戏结束消息""" self.overlay = tk.Toplevel(self.master) self.overlay.geometry(f"{400}x{500}+{self.master.winfo_x()}+{self.master.winfo_y()}") self.overlay.configure(bg="white") self.overlay.attributes("-alpha", 0.7) self.overlay.overrideredirect(True) tk.Label(self.overlay, text="游戏结束!", font=(self.font_family, 30, "bold"), bg="white", fg="#776e65").place(relx=0.5, rely=0.5, anchor="center") tk.Button(self.overlay, text="重置游戏", font=(self.font_family, 16), bg="#8f7a66", fg="white", command=self.reset_game).place( relx=0.5, rely=0.6, anchor="center") def key_press(self, event): """处理键盘按键事件""" if self.game_over: if event.keysym == 'r': self.reset_game() return self.save_state() moved = False if event.keysym == 'Left' or event.keysym == 'a': moved = self.move_left() elif event.keysym == 'Right' or event.keysym == 'd': moved = self.move_right() elif event.keysym == 'Up' or event.keysym == 'w': moved = self.move_up() elif event.keysym == 'Down' or event.keysym == 's': moved = self.move_down() elif event.keysym == 'r': self.reset_game() return elif event.keysym == 'u': self.undo_move() return if moved: self.add_new_tile() self.game_won = self.check_game_won() self.game_over = self.check_game_over() self.update_high_score() self.update_display() if self.game_won and not hasattr(self, 'overlay'): self.show_win_message() if self.game_over and not hasattr(self, 'overlay'): self.show_game_over_message() if __name__ == "__main__": root = tk.Tk() game = Game2048(root) root.mainloop()
(八)运行视频
三. 实验过程中遇到的问题和解决过程
1问题:游戏中的标题、按钮文字和提示信息显示为方块,无法正常显示中文
问题解决方案:在代码中指定支持中文的字体,如黑体 self.font_family = "SimHei" # 设置字体为黑体 title_label = tk.Label(header_frame, text="2048", font=(self.font_family, 40, "bold"))
2问题:撤销功能失效
问题解决方案:优化状态管理 def save_state(self): self.undo_grid = copy.deepcopy(self.grid) self.undo_score = self.score
总结
通过开发这个 2048 游戏,我深刻体会到了 Python 在游戏开发中的强大能力。虽然通过大数据模型进行游戏开发需要处理很多底层细节,但它提供了丰富的功能,使我们能够实现各种复杂的游戏逻辑。 在实现过程中,我不仅巩固了 Python 的基础知识,还学习了如何设计和组织一个完整的项目。面向对象编程的思想在这里尤为重要,通过将游戏的不同部分封装成类和方法,使代码结构清晰,易于维护和扩展。
从实验一一路走过,无论是实验一的熟悉环境、编写简单程序,实验二对计算机程序的编写,还是实验三扮演服务端和客户端进行通信,都极大程度上提高了我应用Pycharm的能力,也促成了本次实验的综合运用~
未来,我希望有机会进一步精进技术,使Python为我所用,期待在更多领域探索 Python 的可能性!
最后!感谢老师的悉心教导,尊滴很喜欢您课堂上轻松愉快却又干货满满的氛围,您辛苦啦!!!! 感恩相遇,完结撒花✿✿ヽ(°▽°)ノ✿
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |