Skip to content

Commit

Permalink
[Example/CLI] Tic-tac-toe (MystenLabs#18557)
Browse files Browse the repository at this point in the history
## Description

Write a CLI to talk to the shared and multi-sig tic-tac-toe example
Move packages.

## Test plan

Manual testing:

```
$ tic-tac-toe view 0xab06bb92cc1e6c95f9e6eed7e6c01fade6bb5eaa241e2100eb54d914597295ed
                                X | O |
                               ---+---+---
                                O | X |
                               ---+---+---
                                  |   | X

    X: <address>
 -> O: <address>
 GAME: 0xab06bb92cc1e6c95f9e6eed7e6c01fade6bb5eaa241e2100eb54d914597295ed
ADMIN: <public key>

                                 X WINS!
```

Also, confirmed that the CLI works with the React front-end.

## Stack

- MystenLabs#18525 
- MystenLabs#18526 

---

## Release notes

Check each box that your changes affect. If none of the boxes relate to
your changes, release notes aren't required.

For each box you select, include information after the relevant heading
that describes the impact of your changes that a user might notice and
any actions they must take to implement updates.

- [ ] Protocol: 
- [ ] Nodes (Validators and Full nodes): 
- [ ] Indexer: 
- [ ] JSON-RPC: 
- [ ] GraphQL:
- [ ] CLI: 
- [ ] Rust SDK:
  • Loading branch information
amnn authored and tx-tomcat committed Jul 29, 2024
1 parent 64b13f1 commit a2a0a20
Show file tree
Hide file tree
Showing 12 changed files with 1,226 additions and 3 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
resolver = "2"

exclude = [
"examples/tic-tac-toe/cli",
"external-crates/move/crates/bytecode-interpreter-crypto",
"external-crates/move/crates/bytecode-verifier-libfuzzer",
"external-crates/move/crates/bytecode-verifier-tests",
Expand Down
2 changes: 2 additions & 0 deletions examples/tic-tac-toe/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
cli/localnet.env
cli/Cargo.lock
18 changes: 18 additions & 0 deletions examples/tic-tac-toe/cli/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
[package]
name = "tic-tac-toe"
edition = "2021"
version = "0.1.0"

[dependencies]
anyhow = "1.0.86"
bcs = "0.1.6"
clap = { version = "4.5", features = ["derive", "env", "wrap_help"] }
dirs = "5.0.1"
fastcrypto = "0.1.8"
move-core-types = { path = "../../../external-crates/move/crates/move-core-types" }
serde = { version = "1.0.203", features = ["derive"] }
shared-crypto = { path = "../../../crates/shared-crypto" }
sui-keys = { path = "../../../crates/sui-keys" }
sui-sdk = { path = "../../../crates/sui-sdk" }
sui-types = { path = "../../../crates/sui-types" }
tokio = { version = "1.38.0", features = ["time"] }
80 changes: 80 additions & 0 deletions examples/tic-tac-toe/cli/src/board.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
// Copyright (c) Mysten Labs, Inc.
// SPDX-License-Identifier: Apache-2.0

use serde::Deserialize;
use std::fmt;
use sui_types::base_types::{ObjectID, SuiAddress};

#[derive(Deserialize)]
pub(crate) struct Board {
pub id: ObjectID,
pub marks: Vec<u8>,
pub turn: u8,
pub x: SuiAddress,
pub o: SuiAddress,
}

#[derive(Eq, PartialEq)]
pub(crate) enum Player {
X,
O,
}

impl Board {
pub(crate) fn next_player(&self) -> Player {
if self.turn % 2 == 0 {
Player::X
} else {
Player::O
}
}

pub(crate) fn prev_player(&self) -> Player {
if self.turn % 2 == 0 {
Player::O
} else {
Player::X
}
}
}

impl fmt::Display for Board {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let m = |i: usize| match self.marks[i] {
0 => ' ',
1 => 'X',
2 => 'O',
_ => unreachable!(),
};

writeln!(f, "{: >31} {} | {} | {}", ' ', m(0), m(1), m(2))?;
writeln!(f, "{: >31}---+---+---", ' ')?;
writeln!(f, "{: >31} {} | {} | {}", ' ', m(3), m(4), m(5))?;
writeln!(f, "{: >31}---+---+---", ' ')?;
writeln!(f, "{: >31} {} | {} | {}", ' ', m(6), m(7), m(8))?;
writeln!(f)?;

use Player as P;
let next = self.next_player();

write!(f, "{}", if next == P::X { " -> " } else { " " })?;
writeln!(f, "X: {}", self.x)?;

write!(f, "{}", if next == P::O { " -> " } else { " " })?;
writeln!(f, "O: {}", self.o)?;

let with_prefix = true;
write!(f, " GAME: {}", self.id.to_canonical_display(with_prefix))?;

Ok(())
}
}

impl fmt::Display for Player {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Player::X => write!(f, "X"),
Player::O => write!(f, "O"),
}
}
}
Loading

0 comments on commit a2a0a20

Please sign in to comment.