Skip to content

Commit

Permalink
chess:
Browse files Browse the repository at this point in the history
  • Loading branch information
ponderingdemocritus committed Dec 8, 2023
2 parents c847a7f + 9145df8 commit 3949fc6
Show file tree
Hide file tree
Showing 9 changed files with 383 additions and 310 deletions.
6 changes: 3 additions & 3 deletions src/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,9 +80,9 @@
- [Onchain Chess](./tutorial/onchain-chess/README.md)
- [0. Setup](./tutorial/onchain-chess/0-setup.md)
- [1. Initiate](./tutorial/onchain-chess/1-action.md)
- [2. Move](./tutorial/onchain-chess/2-legal.md)
- [3. Check Legal Move](./tutorial/onchain-chess/3-test.md)
- [4. Test Chess](./tutorial/onchain-chess/4-utils.md)
- [2. Check Legal Move](./tutorial/onchain-chess/2-legal.md)
- [3. Move](./tutorial/onchain-chess/3-move.md)
- [4. Test Chess](./tutorial/onchain-chess/4-test.md)
- [Deploy using Slot](./tutorial/deploy-using-slot/main.md)

---
Expand Down
151 changes: 50 additions & 101 deletions src/tutorial/onchain-chess/0-setup.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,23 +24,51 @@ sozo init

## Cleaning Up the Boilerplate

The project comes with a lot of boilerplate codes. Clear it all. Make sure both `models.cairo` and `systems.cairo` files are empty. In this tutorial, we won't be creating a `systems.cairo` nor the `src/systems` folder, you can delete both (highly optional, folder structure is entirely up to you). instead, we'll be creating a file named `actions_contract.cairo`, this is where our game logic/contract will reside.
The project comes with a lot of boilerplate codes. Clear it all. Make sure both `actions.cairo`, `models.cairo` and `utils.cairo` files are empty. Then create a new empty `tests.cairo` file in your `/src` directory.

Remodel your`lib.cairo`, to look like this :

```rust,ignore
mod models;
mod actions_contract;
mod actions;
mod utils;
mod tests;
```

Make sure your `Scarb.toml` looks like this:

```toml
[package]
cairo-version = "2.3.0"
name = "dojo_chess"
version = "0.3.15"

[cairo]
sierra-replace-ids = true

[dependencies]
dojo = { git = "https://github.com/dojoengine/dojo", version = "0.3.15" }

[[target.dojo]]

[tool.dojo]
initializer_class_hash = "0xbeef"

[tool.dojo.env]
rpc_url = "http://localhost:5050/"
# Default account for katana with seed = 0
account_address = "0x517ececd29116499f4a1b64b094da79ba08dfd54a3edaa316134c41f8160973"
private_key = "0x1800000000300000180000000000030000000000003006001800006600"

```

Compile your project with:

```sh
sozo build
```

## Basic components
## Basic Models

While there are many ways to design a chess game using the ECS model, we'll follow this approach:

Expand Down Expand Up @@ -111,7 +139,7 @@ You would probably faced some trait implementation errors, which you can impleme
#[derive(Model, Drop, Serde)]
struct Square {
#[key]
game_id: felt252,
game_id: u32,
#[key]
x: u32,
#[key]
Expand All @@ -137,23 +165,25 @@ enum PieceType {
}
```

Complied? Great! then let's move on. If not fix other issues as above, so that you can run the `sozo build` command successfully.

## Run test
## Basic systems

Before proceeding to the next chapter, remember that `sozo build` and `sozo test` are important steps to ensure your code is correct.
Starting from the next chapter, you will implement the `actions.cairo` file. This is where our game logic/contract will reside.

Run sozo test. Did you face any errors?
For now, `actions.cairo` should look like this:

```sh
error: Trait has no implementation in context:
```rust,ignore
#[dojo::contract]
mod actions {
}
```

```sh
error: Variable not dropped. Trait has no implementation in context:
```
It should be noted that Systems function are contract methods, by implication, rather than implementing the game logic in systems, we are implementing it in a contract.

## Compile your project

For the no implementation error, implement the PrintTrait to run `sozo test` successfully. For the not dropped error, add the Drop trait. Address other errors by adding derives or implementing them on a case-by-case basis.
Now try `sozo build` to build.

Complied? Great! then let's move on. If not fix try issues, so that you can run the `sozo build` command successfully.

## Add more models

Expand Down Expand Up @@ -193,16 +223,12 @@ This tutorial is extracted from [here](https://github.com/Akinbola247/chess-dojo
<summary>Click to see full `models.cairo` code</summary>

```rust,ignore
use array::ArrayTrait;
use debug::PrintTrait;
use starknet::ContractAddress;
use dojo::database::schema::{SchemaIntrospection, Ty, Enum, serialize_member_type};
#[derive(Model, Drop, Serde)]
struct Square {
#[key]
game_id: felt252,
game_id: u32,
#[key]
x: u32,
#[key]
Expand Down Expand Up @@ -236,9 +262,8 @@ enum Color {
#[derive(Model, Drop, Serde)]
struct Game {
/// game id, computed as follows pedersen_hash(player1_address, player2_address)
#[key]
game_id: felt252,
game_id: u32,
winner: Color,
white: ContractAddress,
black: ContractAddress
Expand All @@ -247,89 +272,13 @@ struct Game {
#[derive(Model, Drop, Serde)]
struct GameTurn {
#[key]
game_id: felt252,
game_id: u32,
turn: Color
}
//printing trait for debug
impl ColorPrintTrait of PrintTrait<Color> {
#[inline(always)]
fn print(self: Color) {
match self {
Color::White(_) => {
'White'.print();
},
Color::Black(_) => {
'Black'.print();
},
Color::None(_) => {
'None'.print();
},
}
}
}
impl BoardPrintTrait of PrintTrait<(u32, u32)> {
#[inline(always)]
fn print(self: (u32, u32)) {
let (x, y): (u32, u32) = self;
x.print();
y.print();
}
}
impl PieceTypePrintTrait of PrintTrait<PieceType> {
#[inline(always)]
fn print(self: PieceType) {
match self {
PieceType::WhitePawn(_) => {
'WhitePawn'.print();
},
PieceType::WhiteKnight(_) => {
'WhiteKnight'.print();
},
PieceType::WhiteBishop(_) => {
'WhiteBishop'.print();
},
PieceType::WhiteRook(_) => {
'WhiteRook'.print();
},
PieceType::WhiteQueen(_) => {
'WhiteQueen'.print();
},
PieceType::WhiteKing(_) => {
'WhiteKing'.print();
},
PieceType::BlackPawn(_) => {
'BlackPawn'.print();
},
PieceType::BlackKnight(_) => {
'BlackKnight'.print();
},
PieceType::BlackBishop(_) => {
'BlackBishop'.print();
},
PieceType::BlackRook(_) => {
'BlackRook'.print();
},
PieceType::BlackQueen(_) => {
'BlackQueen'.print();
},
PieceType::BlackKing(_) => {
'BlackKing'.print();
},
PieceType::None(_) => {
'None'.print();
},
}
}
}
```

</details>

This tutorial is extracted from [here](https://github.com/dojoengine/origami/tree/main/dojo-chess)

Congratulations! You've completed the basic setup for building an on-chain chess game 🎉
32 changes: 14 additions & 18 deletions src/tutorial/onchain-chess/1-action.md
Original file line number Diff line number Diff line change
@@ -1,30 +1,29 @@
# 1. Action_Contract
# 1. Actions

This chapter will address implementing `action_contract.cairo`, which spawns the game & squares containing pieces and also allow players to move pieces.
This chapter will address implementing `actions.cairo`, which spawns the game & squares containing pieces and also allow players to move pieces.

## What is `action_contract`?
## What is `actions` contract?

To play chess, you need, to start game, spawn the pieces, and move around the board. the `action_contract` has two dominant functions `spawn_game` function which spawns the game entity and places each
piece in its proper position on the board and the `move` funtion which allows pieces to be moved around the board.
To play chess, you need, to start game, spawn the pieces, and move around the board. the `actions` contract has two dominant functions `spawn` function which spawns the game entity, places each piece in its proper position on the board and returns the game_id, and the `move` funtion which allows pieces to be moved around the board.

<p align="center">
<img src="../../images/board.png" alt="image" width="300" height="auto">

## Requirements

_Copy the unit tests below and paste them at the bottom of your `action_contract.cairo` file._
1. Write an interface for the `actions` contract on top of your code. In this case, `move` and `spawn`

1. Write an interface for the `initiate_system` contract and define your functions. In this case, `move` and `spawn_game`
```rust,ignore
use starknet::ContractAddress;
```shell
#[starknet::interface]
trait IActions<ContractState> {
fn move(
self: @ContractState,
curr_position: (u32, u32),
next_position: (u32, u32),
caller: ContractAddress, //player
game_id: felt252
game_id: u32
);
fn spawn_game(
self: @ContractState, white_address: ContractAddress, black_address: ContractAddress,
Expand All @@ -34,8 +33,8 @@ _Copy the unit tests below and paste them at the bottom of your `action_contract

2. Bring in required imports into the contract and initialize storage with the `world_dispatcher` in it like this :

```shell
#[dojo::contract]
```rust,ignore
#[starknet::contract]
mod actions {
use dojo::world::{IWorldDispatcher, IWorldDispatcherTrait};
use debug::PrintTrait;
Expand All @@ -54,14 +53,14 @@ should be noted that `actions` is the contract name.

3. Write a `spawn_game` function that accepts the `white address`, and `black address` as input and set necessary states using `set!(...)`.Implement the game entity, comprised of the `Game` model and `GameTurn` model we created in the `models.cairo` and Implement the square entities from a1 to h8 containing the correct `PieceType` in the `spawn_game` fn.

```shell
```rust,ignore
#[external(v0)]
impl PlayerActionsImpl of IActions<ContractState> {
fn spawn_game(
self: @ContractState, white_address: ContractAddress, black_address: ContractAddress
) {
) -> u32 {
let world = self.world_dispatcher.read();
let game_id = pedersen::pedersen(white_address.into(), black_address.into());
let game_id = world.uuid();
set!(
world,
(
Expand All @@ -72,16 +71,13 @@ should be noted that `actions` is the contract name.
black: black_address,
}, GameTurn {
game_id: game_id, turn: Color::White(()),
},
}
)
);
set!(world, (Square { game_id: game_id, x: 0, y: 0, piece: PieceType::WhiteRook }));

set!(world, (Square { game_id: game_id, x: 0, y: 1, piece: PieceType::WhitePawn }));

set!(world, (Square { game_id: game_id, x: 1, y: 6, piece: PieceType::BlackPawn }));

set!(world, (Square { game_id: game_id, x: 1, y: 0, piece: PieceType::WhiteKnight }));
//the rest of the positions on the board goes here....
Expand Down
14 changes: 10 additions & 4 deletions src/tutorial/onchain-chess/2-legal.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
# 2. Check Legal Move
# 2. Utils and Legal Moves

In this chapter, we'll make functions to check:
In order to keep our code has dry as possible, we decide to modularize some functions. Those functions are the ones we import from `utils.cairo` into `actions.cairo`.

```rust,ignore
use dojo_chess::utils::{is_out_of_board, is_right_piece_move, is_piece_is_mine};
```

This functions will check:

- If the next move goes outside the board.
- If there's a piece that can be captured.
Expand All @@ -23,7 +29,7 @@ We need to add some check functions in `actions` contract. These will help make
2. See if the next spot is still on the board.

```rust,ignore
fn is_out_of_board(next_position: (u32, u32)) -> bool {
fn is_out_of_board(next_position: (u32, u32)) -> bool {
let (n_x, n_y) = next_position;
if n_x > 7 || n_x < 0 {
return false;
Expand All @@ -45,7 +51,7 @@ We need to add some check functions in `actions` contract. These will help make

4. see if it's the right move

```rust,ignore
```c
fn is_right_piece_move(
maybe_piece: PieceType, curr_position: (u32, u32), next_position: (u32, u32)
) -> bool {
Expand Down
Loading

0 comments on commit 3949fc6

Please sign in to comment.