3.检查合法移动

在本章中,我们将编写用于检查的函数:

  • 如果下一步在棋盘之外
  • 是否有棋子可以被吃掉。
  • 棋子类型是否允许下一步棋。
  • 用户是否允许进行操作(基于棋子的颜色)。
  • ...您还可以添加其他自定义校验功能。

编写校验函数

我们需要在 move_system 中添加一些检查函数。这些函数将有助于确保下一步移动是被允许的。

  1. 查看下一个位置该类型的棋子是否可以移动。
  fn is_right_piece_move(
        maybe_piece: Option<PieceType>, curr_position: (u32, u32), next_position: (u32, u32)
    ) -> bool {}
  1. 看看下一个位置是否还在棋盘上。
  fn is_out_of_board(next_position: (u32, u32)) -> bool{}
  1. 看看尝试这个动作的人是否在正确的时间且以正确的阵营移动棋子。
 fn is_correct_turn(maybe_piece: PieceType, caller: ContractAddress, game_id: felt252) -> bool{}
  1. 您还可以添加其他检查功能,以额外确保移动是允许的。

编写了这些校验函数之后,就可以在主 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 章的 答案