3.检查合法移动
在本章中,我们将编写用于检查的函数:
- 如果下一步在棋盘之外
- 是否有棋子可以被吃掉。
- 棋子类型是否允许下一步棋。
- 用户是否允许进行操作(基于棋子的颜色)。
- ...您还可以添加其他自定义校验功能。
编写校验函数
我们需要在 move_system
中添加一些检查函数。这些函数将有助于确保下一步移动是被允许的。
- 查看下一个位置该类型的棋子是否可以移动。
fn is_right_piece_move(
maybe_piece: Option<PieceType>, curr_position: (u32, u32), next_position: (u32, u32)
) -> bool {}
- 看看下一个位置是否还在棋盘上。
fn is_out_of_board(next_position: (u32, u32)) -> bool{}
- 看看尝试这个动作的人是否在正确的时间且以正确的阵营移动棋子。
fn is_correct_turn(maybe_piece: PieceType, caller: ContractAddress, game_id: felt252) -> bool{}
- 您还可以添加其他检查功能,以额外确保移动是允许的。
编写了这些校验函数之后,就可以在主 move_system
函数中使用它们。您可以决定如何设置它们以及使用哪些。我们将举例说明:
fn execute(
ctx: Context,
curr_position: (u32, u32),
next_position: (u32, u32),
caller: ContractAddress,
game_id: felt252
) {
//… upper code is the same
//Check if next_position is out of board or not
assert(is_out_of_board(next_position), ‘Should be inside board’);
//Check if this is the right piece type move
assert(
is_right_piece_move(current_square.piece, curr_position, next_position),
‘Should be right piece move’
);
let target_piece = current_square.piece;
// make current_square piece none and move piece to next_square
current_square.piece = Option::None(());
let mut next_square = get!(ctx.world, (game_id, next_x, next_y), (Square));
//Check the piece already in next_suqare
let maybe_next_square_piece = next_square.piece;
match maybe_next_square_piece {
Option::Some(maybe_piece) => {
if is_piece_is_mine(maybe_piece) {
panic(array![‘Already same color piece exist’])
} else {
//Occupy the piece
next_square.piece = target_piece;
}
},
//if not exist, then just move the original piece
Option::None(_) => {
next_square.piece = target_piece;
},
};
// … below code is the same
}
测试每个函数
由于我们有不同的校验函数,因此需要对每个函数进行测试。为了方便起见,我们可以在许多测试中使用相同的部分。
首先,创建一个名为 init_world_test
的辅助函数。这会返回一个 IWorldDispatcher
,我们可以在移动系统测试中多次使用它。
#[test]
#[available_gas(3000000000000000)]
fn init_world_test() -> IWorldDispatcher {
let white = starknet::contract_address_const::<0x01>();
let black = starknet::contract_address_const::<0x02>();
// components
let mut components = array::ArrayTrait::new();
components.append(game::TEST_CLASS_HASH);
components.append(game_turn::TEST_CLASS_HASH);
components.append(square::TEST_CLASS_HASH);
//systems
let mut systems = array::ArrayTrait::new();
systems.append(initiate_system::TEST_CLASS_HASH);
systems.append(move_system::TEST_CLASS_HASH);
let world = spawn_test_world(components, systems);
let mut calldata = array::ArrayTrait::<core::felt252>::new();
calldata.append(white.into());
calldata.append(black.into());
world.execute(‘initiate_system’.into(), calldata);
world
}
这样,我们的主 test_move
函数就会变得更简单。
#[test]
#[available_gas(3000000000000000)]
fn test_move() {
let white = starknet::contract_address_const::<0x01>();
let black = starknet::contract_address_const::<0x02>();
let world = init_world_test();
let game_id = pedersen(white.into(), black.into());
// other codes are same
}
现在我们可以进行测试,如果尝试不允许的动作,测试就会显示错误。让我们创建一个 test_piecetype_illegal
函数。这将检查你在移动系统中实现的 is_right_piece_move
函数是否正常工作。
#[test]
#[should_panic]
fn test_piecetype_ilegal() {
let white = starknet::contract_address_const::<0x01>();
let black = starknet::contract_address_const::<0x02>();
let world = init_world_test();
let game_id = pedersen(white.into(), black.into());
let b1 = get!(world, (game_id, 1, 0), (Square));
match b1.piece {
Option::Some(piece) => {
assert(piece == PieceType::WhiteKnight, ‘should be White Knight’);
},
Option::None(_) => assert(false, ‘should have piece’),
};
// Knight cannot move to that square
let mut move_calldata = array::ArrayTrait::<core::felt252>::new();
move_calldata.append(1);
move_calldata.append(0);
move_calldata.append(2);
move_calldata.append(3);
move_calldata.append(white.into());
move_calldata.append(game_id);
world.execute(‘move_system’.into(), move_calldata);
}
最后进行测试。这些测试应能发现错误动作并反馈错误信息。
需要帮助?
如果您遇到困难,请随时到 Dojo 社区 提问!
您可以在这里找到第 3 章的 答案。