增加L0训练阶段的MCTS部分
This commit is contained in:
289
tests/test_game_engine.py
Normal file
289
tests/test_game_engine.py
Normal file
@@ -0,0 +1,289 @@
|
||||
"""
|
||||
2048游戏引擎测试
|
||||
|
||||
验证新游戏引擎的功能和正确性
|
||||
"""
|
||||
|
||||
import numpy as np
|
||||
import pytest
|
||||
from game import Game2048, GameState
|
||||
|
||||
|
||||
class TestGame2048:
|
||||
"""2048游戏引擎测试类"""
|
||||
|
||||
def setup_method(self):
|
||||
"""测试前的设置"""
|
||||
self.game = Game2048(height=4, width=4, seed=42)
|
||||
|
||||
def test_initialization(self):
|
||||
"""测试游戏初始化"""
|
||||
game = Game2048(height=3, width=4, seed=123)
|
||||
|
||||
assert game.height == 3
|
||||
assert game.width == 4
|
||||
assert game.score == 0
|
||||
assert game.moves == 0
|
||||
assert not game.is_over
|
||||
|
||||
# 应该有两个初始数字
|
||||
non_zero_count = np.count_nonzero(game.board)
|
||||
assert non_zero_count == 2
|
||||
|
||||
# 初始数字应该是1或2(对数形式的2或4)
|
||||
non_zero_values = game.board[game.board != 0]
|
||||
assert all(val in [1, 2] for val in non_zero_values)
|
||||
|
||||
def test_move_row_left(self):
|
||||
"""测试行向左移动逻辑"""
|
||||
# 测试简单移动
|
||||
row = np.array([0, 1, 0, 2])
|
||||
result, score = self.game._move_row_left(row)
|
||||
expected = np.array([1, 2, 0, 0])
|
||||
np.testing.assert_array_equal(result, expected)
|
||||
assert score == 0
|
||||
|
||||
# 测试合并
|
||||
row = np.array([1, 1, 2, 2])
|
||||
result, score = self.game._move_row_left(row)
|
||||
expected = np.array([2, 3, 0, 0])
|
||||
np.testing.assert_array_equal(result, expected)
|
||||
# 分数应该是 2^2 + 2^3 = 4 + 8 = 12
|
||||
assert score == 12
|
||||
|
||||
# 测试复杂情况
|
||||
row = np.array([1, 1, 1, 1])
|
||||
result, score = self.game._move_row_left(row)
|
||||
expected = np.array([2, 2, 0, 0])
|
||||
np.testing.assert_array_equal(result, expected)
|
||||
# 分数应该是 2^2 + 2^2 = 4 + 4 = 8
|
||||
assert score == 8
|
||||
|
||||
def test_move_directions(self):
|
||||
"""测试四个方向的移动"""
|
||||
# 创建特定的棋盘状态
|
||||
game = Game2048(height=3, width=3, seed=42)
|
||||
game.board = np.array([
|
||||
[1, 0, 1],
|
||||
[0, 2, 0],
|
||||
[1, 0, 1]
|
||||
])
|
||||
|
||||
initial_score = game.score
|
||||
|
||||
# 测试向左移动
|
||||
game_left = game.copy()
|
||||
success = game_left.move(2) # 左
|
||||
assert success
|
||||
|
||||
# 测试向右移动
|
||||
game_right = game.copy()
|
||||
success = game_right.move(3) # 右
|
||||
assert success
|
||||
|
||||
# 测试向上移动
|
||||
game_up = game.copy()
|
||||
success = game_up.move(0) # 上
|
||||
assert success
|
||||
|
||||
# 测试向下移动
|
||||
game_down = game.copy()
|
||||
success = game_down.move(1) # 下
|
||||
assert success
|
||||
|
||||
# 所有移动都应该改变棋盘状态
|
||||
assert not np.array_equal(game.board, game_left.board)
|
||||
assert not np.array_equal(game.board, game_right.board)
|
||||
assert not np.array_equal(game.board, game_up.board)
|
||||
assert not np.array_equal(game.board, game_down.board)
|
||||
|
||||
def test_score_calculation(self):
|
||||
"""测试分数计算"""
|
||||
game = Game2048(height=2, width=2, seed=42)
|
||||
|
||||
# 设置特定棋盘状态
|
||||
game.board = np.array([
|
||||
[1, 2], # 2, 4
|
||||
[3, 4] # 8, 16
|
||||
])
|
||||
|
||||
# 计算累积分数
|
||||
total_score = game.calculate_total_score()
|
||||
|
||||
# 根据论文公式:V(N) = (log2(N) - 1) * N
|
||||
# V(2) = 0, V(4) = 4, V(8) = 16, V(16) = 48
|
||||
expected = 0 + 4 + 16 + 48
|
||||
assert total_score == expected
|
||||
|
||||
def test_game_over_detection(self):
|
||||
"""测试游戏结束检测"""
|
||||
game = Game2048(height=2, width=2, seed=42)
|
||||
|
||||
# 设置无法移动的棋盘
|
||||
game.board = np.array([
|
||||
[1, 2], # 2, 4
|
||||
[3, 4] # 8, 16
|
||||
])
|
||||
|
||||
game._check_game_over()
|
||||
assert game.is_over
|
||||
|
||||
# 测试可以移动的棋盘
|
||||
game.board = np.array([
|
||||
[1, 1], # 2, 2 (可以合并)
|
||||
[3, 4] # 8, 16
|
||||
])
|
||||
game.is_over = False
|
||||
|
||||
game._check_game_over()
|
||||
assert not game.is_over
|
||||
|
||||
def test_valid_moves(self):
|
||||
"""测试有效移动检测"""
|
||||
game = Game2048(height=2, width=2, seed=42)
|
||||
|
||||
# 设置可以向所有方向移动的棋盘
|
||||
game.board = np.array([
|
||||
[1, 0],
|
||||
[0, 1]
|
||||
])
|
||||
|
||||
valid_moves = game.get_valid_moves()
|
||||
assert len(valid_moves) == 4 # 所有方向都可以移动
|
||||
|
||||
# 设置无法移动的棋盘
|
||||
game.board = np.array([
|
||||
[1, 2],
|
||||
[3, 4]
|
||||
])
|
||||
|
||||
valid_moves = game.get_valid_moves()
|
||||
assert len(valid_moves) == 0 # 无法移动
|
||||
|
||||
def test_board_display(self):
|
||||
"""测试棋盘显示"""
|
||||
game = Game2048(height=2, width=2, seed=42)
|
||||
|
||||
# 设置对数形式的棋盘
|
||||
game.board = np.array([
|
||||
[0, 1], # 0, 2
|
||||
[2, 3] # 4, 8
|
||||
])
|
||||
|
||||
display_board = game.get_board_display()
|
||||
expected = np.array([
|
||||
[0, 2],
|
||||
[4, 8]
|
||||
])
|
||||
|
||||
np.testing.assert_array_equal(display_board, expected)
|
||||
|
||||
def test_max_tile(self):
|
||||
"""测试最大数字获取"""
|
||||
game = Game2048(height=2, width=2, seed=42)
|
||||
|
||||
game.board = np.array([
|
||||
[1, 2], # 2, 4
|
||||
[3, 4] # 8, 16
|
||||
])
|
||||
|
||||
max_tile = game.get_max_tile()
|
||||
assert max_tile == 16
|
||||
|
||||
def test_state_management(self):
|
||||
"""测试游戏状态管理"""
|
||||
game = Game2048(height=2, width=2, seed=42)
|
||||
|
||||
# 获取初始状态
|
||||
initial_state = game.get_state()
|
||||
assert isinstance(initial_state, GameState)
|
||||
assert initial_state.score == game.score
|
||||
assert initial_state.moves == game.moves
|
||||
assert np.array_equal(initial_state.board, game.board)
|
||||
|
||||
# 执行移动
|
||||
move_success = game.move(2) # 左移
|
||||
|
||||
# 获取新状态
|
||||
new_state = game.get_state()
|
||||
|
||||
# 只有移动成功时才检查移动次数
|
||||
if move_success:
|
||||
assert new_state.moves == initial_state.moves + 1
|
||||
assert not np.array_equal(new_state.board, initial_state.board)
|
||||
else:
|
||||
# 如果移动失败,尝试其他方向
|
||||
for direction in range(4):
|
||||
if game.move(direction):
|
||||
new_state = game.get_state()
|
||||
assert new_state.moves == initial_state.moves + 1
|
||||
assert not np.array_equal(new_state.board, initial_state.board)
|
||||
break
|
||||
|
||||
# 恢复状态
|
||||
game.set_state(initial_state)
|
||||
assert game.score == initial_state.score
|
||||
assert game.moves == initial_state.moves
|
||||
np.testing.assert_array_equal(game.board, initial_state.board)
|
||||
|
||||
def test_copy_functionality(self):
|
||||
"""测试游戏复制功能"""
|
||||
game = Game2048(height=3, width=3, seed=42)
|
||||
|
||||
# 执行一些操作
|
||||
game.move(2)
|
||||
game.move(0)
|
||||
|
||||
# 创建副本
|
||||
game_copy = game.copy()
|
||||
|
||||
# 验证副本
|
||||
assert game_copy.height == game.height
|
||||
assert game_copy.width == game.width
|
||||
assert game_copy.score == game.score
|
||||
assert game_copy.moves == game.moves
|
||||
assert game_copy.is_over == game.is_over
|
||||
np.testing.assert_array_equal(game_copy.board, game.board)
|
||||
|
||||
# 修改副本不应影响原游戏
|
||||
game_copy.move(1)
|
||||
assert game_copy.moves != game.moves
|
||||
|
||||
def test_different_board_sizes(self):
|
||||
"""测试不同大小的棋盘"""
|
||||
# 测试3x3棋盘
|
||||
game_3x3 = Game2048(height=3, width=3, seed=42)
|
||||
assert game_3x3.board.shape == (3, 3)
|
||||
|
||||
# 测试2x4矩形棋盘
|
||||
game_2x4 = Game2048(height=2, width=4, seed=42)
|
||||
assert game_2x4.board.shape == (2, 4)
|
||||
|
||||
# 测试移动功能
|
||||
success = game_3x3.move(2)
|
||||
assert isinstance(success, bool)
|
||||
|
||||
success = game_2x4.move(0)
|
||||
assert isinstance(success, bool)
|
||||
|
||||
def test_spawn_probability(self):
|
||||
"""测试数字生成概率"""
|
||||
# 测试只生成2的情况
|
||||
game_only_2 = Game2048(height=4, width=4, spawn_prob_4=0.0, seed=42)
|
||||
|
||||
# 重置并检查生成的数字
|
||||
game_only_2.reset()
|
||||
non_zero_values = game_only_2.board[game_only_2.board != 0]
|
||||
assert all(val == 1 for val in non_zero_values) # 只有1(对数形式的2)
|
||||
|
||||
# 测试只生成4的情况
|
||||
game_only_4 = Game2048(height=4, width=4, spawn_prob_4=1.0, seed=42)
|
||||
game_only_4.reset()
|
||||
non_zero_values = game_only_4.board[game_only_4.board != 0]
|
||||
assert all(val == 2 for val in non_zero_values) # 只有2(对数形式的4)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
# 运行测试
|
||||
print("运行2048游戏引擎测试...")
|
||||
pytest.main([__file__, "-v"])
|
||||
Reference in New Issue
Block a user