如何实现带历史记录功能的控制台2048游戏
如何实现带历史记录功能的控制台2048游戏
2048 是一款经典的单人益智游戏,玩家通过合并相同的方块以达成目标分数(2048)。本文将介绍如何在原版 Python 控制台 2048 游戏的基础上增加 游戏历史记录功能,使玩家能够保存每一局的游戏记录、恢复未完成的游戏,并查看历史分数和状态。
通过这篇文章,你将学会如何通过文件管理来持久化游戏数据,保存每一局游戏的操作步骤、网格状态、得分等信息,并且在需要时恢复游戏状态。
1. 游戏历史记录管理
为了让玩家能够查看并管理自己的游戏历史,我们将每局游戏的相关数据(例如:分数、网格状态等)保存到本地文件中。历史记录包括了每局游戏的操作步骤、分数、移动后的网格状态等。
关键点:
- 游戏ID生成:每局游戏会生成一个唯一的 ID,基于当前的时间戳。
- CSV 文件记录:每一步游戏操作(包括方块的移动、得分和网格变化)会记录到 CSV 文件中。
- JSON 文件记录:游戏的完整状态(例如:网格、分数、胜利状态等)会保存到 JSON 文件中,以供后续恢复。
代码实现:
import csv
import json
import datetime
import osclass Console2048WithHistory:def __init__(self, grid_size=4):# 初始化游戏设置self.history_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "game_history")self.history_file = Noneself.game_id = Noneself.game_start_time = Noneself.current_move = 0if not os.path.exists(self.history_dir):os.makedirs(self.history_dir)def start_new_game(self):"""开始新游戏并记录历史"""self.game_id = datetime.datetime.now().strftime("%Y%m%d_%H%M%S_%f")self.game_start_time = datetime.datetime.now()game_dir = os.path.join(self.history_dir, self.game_id)os.makedirs(game_dir, exist_ok=True)self.history_file = os.path.join(game_dir, "history.csv")with open(self.history_file, 'w', newline='', encoding='utf-8') as f:writer = csv.writer(f)writer.writerow(["步数", "操作类型", "操作得分", "总分", "移动后的网格状态", "随机添加后的网格状态"])
2. 游戏状态保存与加载
为了增强用户体验,我们增加了游戏状态的保存与加载功能。每次玩家执行操作后,游戏的网格状态、分数等信息会保存为 JSON 文件。这样即使玩家退出游戏,下一次启动时也可以继续之前的游戏。
关键点:
- 状态保存:每执行一步操作后,游戏状态(如网格、分数等)会保存在 JSON 文件中。
- 状态恢复:游戏支持恢复最近未完成的游戏,通过加载保存的状态继续游戏。
代码实现:
def save_game_state(self):"""保存游戏状态"""if not self.game_id:returngame_dir = os.path.join(self.history_dir, self.game_id)state_file = os.path.join(game_dir, "game_state.json")game_state = {"grid": self.grid,"score": self.score,"best_score": self.best_score,"game_over": self.game_over,"won": self.won,"current_move": self.current_move,"last_updated": datetime.datetime.now().isoformat()}try:with open(state_file, 'w', encoding='utf-8') as f:json.dump(game_state, f, ensure_ascii=False, indent=2)except IOError as e:passdef load_game_state(self, game_id):"""加载指定游戏ID的状态"""game_dir = os.path.join(self.history_dir, game_id)state_file = os.path.join(game_dir, "game_state.json")if not os.path.exists(state_file):return Falsetry:with open(state_file, 'r', encoding='utf-8') as f:game_state = json.load(f)self.game_id = game_idself.grid = game_state.get('grid', [[0] * self.grid_size for _ in range(self.grid_size)])self.score = game_state.get('score', 0)self.best_score = game_state.get('best_score', 0)self.game_over = game_state.get('game_over', False)self.won = game_state.get('won', False)self.current_move = game_state.get('current_move', 0)return Trueexcept (json.JSONDecodeError, IOError) as e:return False
3. 游戏历史记录查看与管理
我们通过读取 index.json 文件来查看最近未完成的游戏,玩家可以选择加载最新的未完成游戏。这样玩家可以继续上一次的游戏,而不必从头开始。
关键点:
- 未完成游戏索引:通过读取
index.json文件,可以查看所有未完成的游戏。 - 加载历史游戏:玩家可以选择继续最近的一局未完成的游戏,恢复之前的网格状态和分数。
代码实现:
def get_last_unfinished_game(self):"""获取最后一个未完成的游戏"""index_file = os.path.join(self.history_dir, "index.json")if not os.path.exists(index_file):return Nonetry:with open(index_file, 'r', encoding='utf-8') as f:index_data = json.load(f)unfinished_games = [game for game in index_data if not game.get('is_completed', False)]if not unfinished_games:return Noneunfinished_games.sort(key=lambda x: x.get('last_updated', ''), reverse=True)return unfinished_games[0]except (json.JSONDecodeError, IOError) as e:return None
4. 游戏退出与数据更新
当玩家退出游戏时,我们会更新游戏的索引,确保当前游戏数据被及时保存。退出时,游戏的状态会标记为未完成,玩家可以随时恢复上次的状态。
关键点:
- 游戏结束时更新索引:每当一局游戏结束时,游戏的结果会更新到
index.json文件中。 - 游戏退出时保存未完成状态:当玩家退出时,游戏状态会被标记为未完成,以便玩家以后继续。
代码实现:
def update_index(self, is_completed=None):"""更新目录文档"""if not self.game_id or not self.game_start_time:returnindex_file = os.path.join(self.history_dir, "index.json")# 读取现有索引index_data = []if os.path.exists(index_file):try:with open(index_file, 'r', encoding='utf-8') as f:index_data = json.load(f)except (json.JSONDecodeError, IOError) as e:index_data = []completed_status = is_completed if is_completed is not None else (self.game_over or self.won)# 创建或更新当前游戏的索引条目game_info = {"game_id": self.game_id,"start_time": self.game_start_time.isoformat(),"score": self.score,"best_score": self.best_score,"is_completed": completed_status,"last_updated": datetime.datetime.now().isoformat()}# 更新索引文件try:with open(index_file, 'w', encoding='utf-8') as f:json.dump(index_data, f, ensure_ascii=False, indent=2)except IOError as e:pass
5. 示例文件内容
- index.json:记录游戏的基本信息,包括游戏ID、开始时间、分数等。
[{"game_id": "20251115_011133_522512","start_time": "2025-11-15T01:11:33.522512","score": 2940,"best_score": 2940,"is_completed": false,"last_updated": "2025-11-15T01:16:45.692189"},{"game_id": "20251115_022750_959447","start_time": "2025-11-15T02:27:50.959447","score": 1164,"best_score": 12060,"is_completed": true,"last_updated": "2025-11-15T02:33:44.991410"}
]
- best_score.json:记录游戏的最佳分数。
{"best_score": 12060
}
- game_state.json:记录每局游戏的完整状态,包括网格、分数、是否结束等。
{"grid": [[2, 4, 8, 4],[16, 32, 16, 2],[8, 16, 64, 8],[32, 64, 32, 2]],"score": 1164,"best_score": 12060,"game_over": false,"won": false,"current_move": 139,"last_updated": "2025-11-15T02:33:44.965340"
}
- history.csv:记录每一步操作的信息,包括步数、操作类型、得分等。
步数,操作类型,操作得分,总分,移动后的网格状态,随机添加后的网格状态
1,初始状态,0,0,"[[0, 2, 4, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]","[[0, 2, 4, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]"
2,向down移动,0,0,"[[0, 2, 4, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]","[[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [2, 2, 4, 0]]"
3,向left移动,4,4,"[[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [2, 2, 4, 0]]","[[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 2], [4, 4, 0, 0]]"
6. 总结
通过这些新增的功能,我们不仅让 2048 游戏 更具交互性,还提升了用户体验。通过游戏历史记录功能,玩家可以查看过往的游戏数据,恢复未完成的游戏,或继续挑战更高的分数。
