290 lines
9.0 KiB
Python
290 lines
9.0 KiB
Python
"""
|
||
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"])
|