Remove unused
This commit is contained in:
parent
ee0972d096
commit
2513fa2e17
|
@ -1,31 +0,0 @@
|
|||
[package]
|
||||
name = "mia-game"
|
||||
readme = "README.md"
|
||||
version.workspace = true
|
||||
description.workspace = true
|
||||
homepage.workspace = true
|
||||
repository.workspace = true
|
||||
documentation.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
|
||||
[features]
|
||||
abi = ["pbc_contract_common/abi", "pbc_contract_codegen/abi", "pbc_traits/abi", "create_type_spec_derive/abi", "pbc_lib/abi", "pbc_zk/abi"]
|
||||
plus_metadata = []
|
||||
|
||||
[lib]
|
||||
path = "src/lib.rs"
|
||||
crate-type = ['rlib', 'cdylib']
|
||||
|
||||
[package.metadata.zk]
|
||||
zk-compute-path = "src/zk_compute.rs"
|
||||
|
||||
[dependencies]
|
||||
pbc_contract_common.workspace = true
|
||||
pbc_traits.workspace = true
|
||||
pbc_lib.workspace = true
|
||||
read_write_rpc_derive.workspace = true
|
||||
read_write_state_derive.workspace = true
|
||||
create_type_spec_derive.workspace = true
|
||||
pbc_contract_codegen.workspace = true
|
||||
pbc_zk.workspace = true
|
|
@ -1,43 +0,0 @@
|
|||
# Mia Gaming Contract
|
||||
|
||||
## Rules
|
||||
|
||||
3 or more players, all start with 6 lives.
|
||||
|
||||
The complete order of rolls (from highest to lowest):
|
||||
|
||||
21 (Mia), 31 (Little Mia), 66, 55, 44, 33, 22, 11, 65, 64, 63, 62, 61, 54, 53, 52, 51, 43, 42, 41, 32
|
||||
|
||||
### Order of actions
|
||||
|
||||
The first player rolls the dice and keeps their value concealed from the other players.
|
||||
|
||||
The player then has three choices:
|
||||
|
||||
- Tell the truth and announce what has been rolled.
|
||||
- Lie and announce a greater value than that rolled.
|
||||
- Lie and announce a lesser value.
|
||||
|
||||
The concealed dice are then passed to the next player in a clockwise fashion.
|
||||
|
||||
The receiving player now has two options:
|
||||
|
||||
- Believe the passer, roll the dice and pass it on, announcing a higher value—with or without looking at them.
|
||||
- Call the passer a liar and look at the dice.
|
||||
If the dice show a lesser value than that announced, the passer loses a life and the receiving player starts a new round.
|
||||
However, if the dice show a greater or equal value, the current player loses a life and the next player starts a new round.
|
||||
|
||||
**Note:**
|
||||
Each player must always announce a value greater than or equal to the previous value announced.
|
||||
|
||||
##### Mia announced
|
||||
|
||||
If Mia is announced, the next player has two choices:
|
||||
|
||||
- They may give up without looking at the dice and lose one life.
|
||||
- They may look at the dice. If it was a Mia, they lose two lives.
|
||||
If it wasn't, the previous player loses two lives.
|
||||
|
||||
### Winning the game
|
||||
|
||||
Last remaining player is the winner.
|
|
@ -1,572 +0,0 @@
|
|||
#![doc = include_str!("../README.md")]
|
||||
#![allow(unused_variables)]
|
||||
|
||||
#[macro_use]
|
||||
extern crate pbc_contract_codegen;
|
||||
extern crate pbc_contract_common;
|
||||
extern crate pbc_lib;
|
||||
|
||||
mod zk_compute;
|
||||
|
||||
use create_type_spec_derive::CreateTypeSpec;
|
||||
use pbc_contract_common::address::Address;
|
||||
use pbc_contract_common::context::ContractContext;
|
||||
use pbc_contract_common::events::EventGroup;
|
||||
use pbc_contract_common::sorted_vec_map::{SortedVecMap, SortedVecSet};
|
||||
use pbc_contract_common::zk::{SecretVarId, ZkInputDef, ZkState, ZkStateChange};
|
||||
use pbc_traits::ReadWriteState;
|
||||
use pbc_zk::{Sbi8, SecretBinary};
|
||||
use read_write_rpc_derive::ReadWriteRPC;
|
||||
use read_write_state_derive::ReadWriteState;
|
||||
|
||||
/**
|
||||
* Metadata information associated with each individual variable.
|
||||
*/
|
||||
#[derive(ReadWriteState, ReadWriteRPC, Debug)]
|
||||
#[repr(u8)]
|
||||
pub enum SecretVarType {
|
||||
#[discriminant(0)]
|
||||
/// Randomness used for dice throws.
|
||||
Randomness {},
|
||||
#[discriminant(1)]
|
||||
/// Result of dice throws.
|
||||
ThrowResult {},
|
||||
}
|
||||
|
||||
/// The state of the Mia game, which is persisted on-chain.
|
||||
#[state]
|
||||
pub struct MiaState {
|
||||
// The current amount of randomness contributions received for a dice throw.
|
||||
nr_of_randomness_contributions: u32,
|
||||
// The number of players at the start of the game.
|
||||
nr_of_players_at_the_start: u32,
|
||||
// The player currently throwing the dice and declaring a value.
|
||||
player_throwing: u32,
|
||||
// The current phase the game is in, to determine allowed actions.
|
||||
game_phase: GamePhase,
|
||||
// The players at the start of the game.
|
||||
starting_players: Vec<Address>,
|
||||
// The current players active in the game.
|
||||
players: Vec<Address>,
|
||||
// The remaining lives of the players in the game.
|
||||
player_lives: SortedVecMap<Address, u8>,
|
||||
// The last throw's secret variable id.
|
||||
throw_result_id: Option<SecretVarId>,
|
||||
// The stated value of the current throw.
|
||||
stated_throw: Option<DiceThrow>,
|
||||
// The revealed value of a throw.
|
||||
throw_result: Option<DiceThrow>,
|
||||
// The announced throw value, where the next announced throw must be higher than, to be eligible.
|
||||
throw_to_beat: DiceThrow,
|
||||
// The winner of the game.
|
||||
winner: Option<Address>,
|
||||
}
|
||||
|
||||
impl MiaState {
|
||||
/// Get the current player in turn.
|
||||
fn current_player(&self) -> &Address {
|
||||
&self.players[self.player_throwing as usize]
|
||||
}
|
||||
/// Get the next player in turn.
|
||||
fn next_player(&self) -> &Address {
|
||||
&self.players[(self.player_throwing + 1) as usize % self.players.len()]
|
||||
}
|
||||
|
||||
/// Replace the current player in turn with the next player.
|
||||
fn go_to_next_player(&mut self) {
|
||||
self.player_throwing = (self.player_throwing + 1) % self.players.len() as u32;
|
||||
}
|
||||
|
||||
/// Check whether a player is dead i.e. have no lives left.
|
||||
fn is_player_dead(&self, player: Address) -> bool {
|
||||
self.player_lives[&player] == 0
|
||||
}
|
||||
|
||||
/// Remove a dead player from the list of players.
|
||||
fn remove_dead_player(&mut self, player: Address) {
|
||||
self.players.retain(|p| player != *p);
|
||||
}
|
||||
|
||||
/// Reduce a players lives by a given integer.
|
||||
fn reduce_players_life_by(&mut self, player: Address, lives_lost: u8) {
|
||||
if self.player_lives[&player] >= lives_lost {
|
||||
self.player_lives
|
||||
.insert(player, self.player_lives[&player] - lives_lost);
|
||||
} else {
|
||||
self.player_lives.insert(player, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/// Check whether the game if finished, i.e. whether only one player remains.
|
||||
fn is_the_game_finished(&self) -> bool {
|
||||
self.players.len() == 1
|
||||
}
|
||||
|
||||
/// Get the last remaining player, the winner.
|
||||
fn get_winner(&self) -> Address {
|
||||
*self.players.first().unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
/// A throw of two dice.
|
||||
#[derive(ReadWriteState, ReadWriteRPC, CreateTypeSpec, Debug, Copy, Clone)]
|
||||
pub struct DiceThrow {
|
||||
d1: u8,
|
||||
d2: u8,
|
||||
}
|
||||
|
||||
impl DiceThrow {
|
||||
/// The value of each die is reduced to be between 0 and 5.
|
||||
fn reduce(&self) -> DiceThrow {
|
||||
DiceThrow {
|
||||
d1: self.d1 % 6,
|
||||
d2: self.d2 % 6,
|
||||
}
|
||||
}
|
||||
|
||||
/// Checks whether a throw is better than the current dice throw to beat.
|
||||
/// The dice throws are compared based on their associated values.
|
||||
fn better_than_or_equal(self, actual: DiceThrow) -> bool {
|
||||
self.get_throw_score() >= actual.get_throw_score()
|
||||
}
|
||||
|
||||
/// Checks whether a dice throw is Mia, i.e. is (0,1) or (1,0).
|
||||
fn is_mia(self) -> bool {
|
||||
(self.d1 == 0 && self.d2 == 1) || (self.d2 == 0 && self.d1 == 1)
|
||||
}
|
||||
|
||||
/// Checks whether a dice throw is Little Mia, i.e. is (0,2) or (2,0).
|
||||
fn is_little_mia(self) -> bool {
|
||||
(self.d1 == 0 && self.d2 == 2) || (self.d2 == 0 && self.d1 == 2)
|
||||
}
|
||||
|
||||
/// Checks whether both dices in the dice throw have the same value.
|
||||
fn is_pair(self) -> bool {
|
||||
self.d1 == self.d2
|
||||
}
|
||||
|
||||
/// Get the score of a dice throw.
|
||||
/// The throw values are determined such that the highest roll is Mia, then Little Mia,
|
||||
/// followed by the doubles from (5,5) to (0,0), and then all other rolls from (5,4)
|
||||
/// down to (2,1).
|
||||
fn get_throw_score(self) -> u8 {
|
||||
let mut value = 0;
|
||||
if self.is_mia() {
|
||||
value += 128;
|
||||
};
|
||||
if self.is_little_mia() {
|
||||
value += 64;
|
||||
};
|
||||
if self.is_pair() {
|
||||
value += 32;
|
||||
};
|
||||
if (self.d1 == 5) || (self.d2 == 5) {
|
||||
value += 16;
|
||||
}
|
||||
if (self.d1 == 4) || (self.d2 == 4) {
|
||||
value += 8;
|
||||
}
|
||||
if (self.d1 == 3) || (self.d2 == 3) {
|
||||
value += 4;
|
||||
}
|
||||
if (self.d1 == 2) || (self.d2 == 2) {
|
||||
value += 2;
|
||||
}
|
||||
if (self.d1 == 1) || (self.d2 == 1) {
|
||||
value += 1;
|
||||
}
|
||||
value
|
||||
}
|
||||
}
|
||||
|
||||
/// The contribution each player must send to make a dice throw. The contributions should be in the
|
||||
/// interval \[ 0, 5 \] inclusive. If the contributions are outside this interval,
|
||||
/// they are normalized to the interval.
|
||||
#[derive(CreateTypeSpec, SecretBinary)]
|
||||
pub struct RandomContribution {
|
||||
d1: Sbi8,
|
||||
d2: Sbi8,
|
||||
}
|
||||
|
||||
/// The different phases the contract can be in before, during and after a game of Mia.
|
||||
#[derive(ReadWriteRPC, ReadWriteState, CreateTypeSpec, Debug, PartialEq, Copy, Clone)]
|
||||
pub enum GamePhase {
|
||||
#[discriminant(0)]
|
||||
/// The game has been initialized.
|
||||
Start {},
|
||||
#[discriminant(1)]
|
||||
/// Players can add randomness as secret inputs.
|
||||
AddRandomness {},
|
||||
#[discriminant(2)]
|
||||
/// The player in turn can throw the dice.
|
||||
Throw {},
|
||||
#[discriminant(3)]
|
||||
/// The player in turn can announce their throw.
|
||||
Announce {},
|
||||
#[discriminant(4)]
|
||||
/// The next player in turn can believe or call out the player's announced throw.
|
||||
Decide {},
|
||||
#[discriminant(5)]
|
||||
/// If a player was called out, they can reveal their actual throw.
|
||||
Reveal {},
|
||||
#[discriminant(6)]
|
||||
/// The game is finished.
|
||||
Done {},
|
||||
}
|
||||
|
||||
/// Initialize a new mia game.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `_ctx` - the contract context containing information about the sender and the blockchain.
|
||||
/// *
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// The initial state of the petition, with no signers.
|
||||
///
|
||||
#[init(zk = true)]
|
||||
pub fn initialize(
|
||||
context: ContractContext,
|
||||
zk_state: ZkState<SecretVarType>,
|
||||
addresses_to_play: Vec<Address>,
|
||||
) -> (MiaState, Vec<EventGroup>) {
|
||||
assert!(
|
||||
addresses_to_play.len() >= 3,
|
||||
"There must be at least 3 players to play Mia."
|
||||
);
|
||||
assert_eq!(
|
||||
SortedVecSet::from(addresses_to_play.clone()).len(),
|
||||
addresses_to_play.len(),
|
||||
"No duplicates in players."
|
||||
);
|
||||
|
||||
let mut state = MiaState {
|
||||
starting_players: addresses_to_play.clone(),
|
||||
players: addresses_to_play.clone(),
|
||||
nr_of_players_at_the_start: addresses_to_play.len() as u32,
|
||||
player_lives: SortedVecMap::new(),
|
||||
game_phase: GamePhase::Start {},
|
||||
player_throwing: 0,
|
||||
nr_of_randomness_contributions: 0,
|
||||
throw_result_id: None,
|
||||
stated_throw: None,
|
||||
throw_result: None,
|
||||
winner: None,
|
||||
throw_to_beat: DiceThrow { d1: 1, d2: 2 },
|
||||
};
|
||||
|
||||
for address in addresses_to_play {
|
||||
state.player_lives.insert(address, 6);
|
||||
}
|
||||
|
||||
(state, vec![])
|
||||
}
|
||||
|
||||
/// Start the game.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `ctx` - the contract context containing information about the sender and the blockchain.
|
||||
/// * `state` - the current state of the game.
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// The updated vote state reflecting the new signing.
|
||||
///
|
||||
#[action(shortname = 0x01, zk = true)]
|
||||
pub fn start_round(
|
||||
context: ContractContext,
|
||||
mut state: MiaState,
|
||||
zk_state: ZkState<SecretVarType>,
|
||||
) -> (MiaState, Vec<EventGroup>, Vec<ZkStateChange>) {
|
||||
assert_eq!(
|
||||
state.players[state.player_throwing as usize], context.sender,
|
||||
"Only the player whose turn it is can start the round."
|
||||
);
|
||||
state.game_phase = GamePhase::AddRandomness {};
|
||||
|
||||
(state, vec![], vec![])
|
||||
}
|
||||
|
||||
/// Add randomness for the next dice throw.
|
||||
/// The sender must be a player in the game to add randomness.
|
||||
#[zk_on_secret_input(shortname = 0x40, secret_type = "RandomContribution")]
|
||||
pub fn add_randomness_to_throw(
|
||||
context: ContractContext,
|
||||
state: MiaState,
|
||||
zk_state: ZkState<SecretVarType>,
|
||||
) -> (
|
||||
MiaState,
|
||||
Vec<EventGroup>,
|
||||
ZkInputDef<SecretVarType, RandomContribution>,
|
||||
) {
|
||||
assert_eq!(
|
||||
state.game_phase,
|
||||
GamePhase::AddRandomness {},
|
||||
"Must be in the AddRandomness phase to input secret randomness."
|
||||
);
|
||||
assert!(state.starting_players.contains(&context.sender));
|
||||
assert!(
|
||||
zk_state
|
||||
.secret_variables
|
||||
.iter()
|
||||
.chain(zk_state.pending_inputs.iter())
|
||||
.all(|(_, secret_variable)| secret_variable.owner != context.sender),
|
||||
"Each Player is only allowed to send one contribution to the randomness of the dice throw. Sender: {:?}",
|
||||
context.sender
|
||||
);
|
||||
|
||||
let input_def = ZkInputDef::with_metadata(
|
||||
Some(SHORTNAME_INPUTTED_VARIABLE),
|
||||
SecretVarType::Randomness {},
|
||||
);
|
||||
|
||||
(state, vec![], input_def)
|
||||
}
|
||||
|
||||
/// Automatically called when a variable is confirmed on chain.
|
||||
///
|
||||
/// Initializes opening.
|
||||
#[zk_on_variable_inputted(shortname = 0x01)]
|
||||
fn inputted_variable(
|
||||
context: ContractContext,
|
||||
mut state: MiaState,
|
||||
zk_state: ZkState<SecretVarType>,
|
||||
variable_id: SecretVarId,
|
||||
) -> MiaState {
|
||||
if state.nr_of_randomness_contributions == state.nr_of_players_at_the_start - 1 {
|
||||
state.nr_of_randomness_contributions = 0;
|
||||
state.game_phase = GamePhase::Throw {};
|
||||
} else {
|
||||
state.nr_of_randomness_contributions += 1;
|
||||
}
|
||||
state
|
||||
}
|
||||
|
||||
/// Start the computation to compute the dice throw.
|
||||
#[action(shortname = 0x02, zk = true)]
|
||||
pub fn throw_dice(
|
||||
context: ContractContext,
|
||||
state: MiaState,
|
||||
zk_state: ZkState<SecretVarType>,
|
||||
) -> (MiaState, Vec<EventGroup>, Vec<ZkStateChange>) {
|
||||
assert_eq!(
|
||||
state.game_phase,
|
||||
GamePhase::Throw {},
|
||||
"The dice can only be thrown in the Throw phase"
|
||||
);
|
||||
assert_eq!(
|
||||
*state.current_player(),
|
||||
context.sender,
|
||||
"Only the player in turn can throw the dice. It is currently {:?}s turn",
|
||||
state.current_player()
|
||||
);
|
||||
|
||||
(
|
||||
state,
|
||||
vec![],
|
||||
vec![zk_compute::compute_dice_throw_start(
|
||||
Some(SHORTNAME_SUM_COMPUTE_COMPLETE),
|
||||
&SecretVarType::ThrowResult {},
|
||||
)],
|
||||
)
|
||||
}
|
||||
|
||||
/// Automatically called when the sum of the random contributions are done.
|
||||
/// Transfers the resulting throw to the player throwing the dice.
|
||||
#[zk_on_compute_complete(shortname = 0x01)]
|
||||
fn sum_compute_complete(
|
||||
_context: ContractContext,
|
||||
mut state: MiaState,
|
||||
zk_state: ZkState<SecretVarType>,
|
||||
output_variables: Vec<SecretVarId>,
|
||||
) -> (MiaState, Vec<EventGroup>, Vec<ZkStateChange>) {
|
||||
let Some(result_id) = output_variables.first() else {
|
||||
panic!("No result")
|
||||
};
|
||||
|
||||
state.throw_result_id = Some(*result_id);
|
||||
state.game_phase = GamePhase::Announce {};
|
||||
let player_to_transfer_to = *state.current_player();
|
||||
|
||||
(
|
||||
state,
|
||||
vec![],
|
||||
vec![
|
||||
ZkStateChange::TransferVariable {
|
||||
variable: *result_id,
|
||||
new_owner: player_to_transfer_to,
|
||||
},
|
||||
ZkStateChange::DeleteVariables {
|
||||
variables_to_delete: zk_state
|
||||
.secret_variables
|
||||
.iter()
|
||||
.map(|(variable_id, _)| variable_id)
|
||||
.filter(|id| id != result_id)
|
||||
.collect(),
|
||||
},
|
||||
],
|
||||
)
|
||||
}
|
||||
|
||||
/// Announce a value such that the next player can decide if they believe it or not.
|
||||
/// The value must be higher than or equal to the throw to beat.
|
||||
#[action(shortname = 0x03, zk = true)]
|
||||
fn announce_throw(
|
||||
context: ContractContext,
|
||||
mut state: MiaState,
|
||||
zk_state: ZkState<SecretVarType>,
|
||||
dice_value: DiceThrow,
|
||||
) -> (MiaState, Vec<EventGroup>, Vec<ZkStateChange>) {
|
||||
assert_eq!(
|
||||
*state.current_player(),
|
||||
context.sender,
|
||||
"Only the current player can state the value of the dice throw."
|
||||
);
|
||||
|
||||
let reduced_dice_value = dice_value.reduce();
|
||||
|
||||
if !reduced_dice_value.better_than_or_equal(state.throw_to_beat) {
|
||||
panic!("Stated throw must be better than the last stated throw.")
|
||||
}
|
||||
|
||||
state.stated_throw = Some(dice_value);
|
||||
state.game_phase = GamePhase::Decide {};
|
||||
|
||||
(state, vec![], vec![])
|
||||
}
|
||||
|
||||
/// The next player believes the stated throw, and continues the round, where the throw to beat is
|
||||
/// the stated throw.
|
||||
#[action(shortname = 0x04, zk = true)]
|
||||
fn believe(
|
||||
context: ContractContext,
|
||||
mut state: MiaState,
|
||||
zk_state: ZkState<SecretVarType>,
|
||||
) -> (MiaState, Vec<EventGroup>, Vec<ZkStateChange>) {
|
||||
assert_eq!(
|
||||
context.sender,
|
||||
*state.next_player(),
|
||||
"Only the next player can say if they believe the stated throw."
|
||||
);
|
||||
assert_eq!(
|
||||
state.game_phase,
|
||||
GamePhase::Decide {},
|
||||
"Must be in the deciding phase to say believe."
|
||||
);
|
||||
|
||||
state.game_phase = GamePhase::AddRandomness {};
|
||||
state.throw_to_beat = state.stated_throw.unwrap();
|
||||
state.stated_throw = None;
|
||||
state.go_to_next_player();
|
||||
|
||||
(
|
||||
state,
|
||||
vec![],
|
||||
vec![ZkStateChange::DeleteVariables {
|
||||
variables_to_delete: zk_state
|
||||
.secret_variables
|
||||
.iter()
|
||||
.map(|(variable_id, _)| variable_id)
|
||||
.collect(),
|
||||
}],
|
||||
)
|
||||
}
|
||||
|
||||
/// The next player does not believe the stated throw, and starts a reveal of the dice.
|
||||
#[action(shortname = 0x05, zk = true)]
|
||||
fn call_out(
|
||||
context: ContractContext,
|
||||
mut state: MiaState,
|
||||
zk_state: ZkState<SecretVarType>,
|
||||
) -> (MiaState, Vec<EventGroup>, Vec<ZkStateChange>) {
|
||||
assert_eq!(
|
||||
context.sender,
|
||||
*state.next_player(),
|
||||
"Only the next player can say if the throwing player is lying."
|
||||
);
|
||||
assert_eq!(
|
||||
state.game_phase,
|
||||
GamePhase::Decide {},
|
||||
"Must be in the deciding phase say if the throwing player is lying."
|
||||
);
|
||||
let variable_to_open = state.throw_result_id.unwrap();
|
||||
state.game_phase = GamePhase::Reveal {};
|
||||
(
|
||||
state,
|
||||
vec![],
|
||||
vec![ZkStateChange::OpenVariables {
|
||||
variables: vec![variable_to_open],
|
||||
}],
|
||||
)
|
||||
}
|
||||
|
||||
/// Saves the opened variable in state and readies another computation.
|
||||
#[zk_on_variables_opened]
|
||||
fn save_opened_variable(
|
||||
context: ContractContext,
|
||||
mut state: MiaState,
|
||||
zk_state: ZkState<SecretVarType>,
|
||||
opened_variables: Vec<SecretVarId>,
|
||||
) -> (MiaState, Vec<EventGroup>, Vec<ZkStateChange>) {
|
||||
assert_eq!(
|
||||
opened_variables.len(),
|
||||
1,
|
||||
"Can only show one set of dice at a time."
|
||||
);
|
||||
|
||||
let variable_id = opened_variables.first().unwrap();
|
||||
let result: DiceThrow = read_opened_variable_data(&zk_state, variable_id).unwrap();
|
||||
|
||||
let result_reduced = result.reduce();
|
||||
|
||||
let Some(stated_throw) = state.stated_throw else {
|
||||
panic!("Could not find a stated throw in state.")
|
||||
};
|
||||
|
||||
let stated_throw_reduced = stated_throw.reduce();
|
||||
|
||||
let loser_of_round = if result.better_than_or_equal(stated_throw_reduced) {
|
||||
*state.next_player()
|
||||
} else {
|
||||
*state.current_player()
|
||||
};
|
||||
|
||||
if stated_throw.is_mia() {
|
||||
state.reduce_players_life_by(loser_of_round, 2);
|
||||
} else {
|
||||
state.reduce_players_life_by(loser_of_round, 1);
|
||||
}
|
||||
|
||||
if state.is_player_dead(loser_of_round) {
|
||||
state.remove_dead_player(loser_of_round);
|
||||
}
|
||||
|
||||
state.throw_result = Some(result_reduced);
|
||||
|
||||
if state.is_the_game_finished() {
|
||||
state.game_phase = GamePhase::Done {};
|
||||
state.winner = Some(state.get_winner());
|
||||
} else {
|
||||
state.go_to_next_player();
|
||||
state.game_phase = GamePhase::AddRandomness {};
|
||||
}
|
||||
|
||||
(
|
||||
state,
|
||||
vec![],
|
||||
vec![ZkStateChange::DeleteVariables {
|
||||
variables_to_delete: opened_variables,
|
||||
}],
|
||||
)
|
||||
}
|
||||
|
||||
/// Reads the data from a revealed secret variable
|
||||
fn read_opened_variable_data<T: ReadWriteState>(
|
||||
zk_state: &ZkState<SecretVarType>,
|
||||
variable_id: &SecretVarId,
|
||||
) -> Option<T> {
|
||||
let variable = zk_state.get_variable(*variable_id)?;
|
||||
variable.open_value()
|
||||
}
|
|
@ -1,44 +0,0 @@
|
|||
use pbc_zk::*;
|
||||
|
||||
/// Output variable type
|
||||
#[derive(pbc_zk::SecretBinary, Clone)]
|
||||
struct RandomnessInput {
|
||||
/// Token amount.
|
||||
d1: Sbi8,
|
||||
d2: Sbi8,
|
||||
}
|
||||
|
||||
/// Perform a zk computation on secret-shared randomness added to make a random dice throw.
|
||||
///
|
||||
/// ### Returns:
|
||||
///
|
||||
/// The sum of the randomness contributions variables.
|
||||
#[zk_compute(shortname = 0x61)]
|
||||
pub fn compute_dice_throw() -> RandomnessInput {
|
||||
let mut throw = RandomnessInput {
|
||||
d1: Sbi8::from(0),
|
||||
d2: Sbi8::from(0),
|
||||
};
|
||||
|
||||
for variable_id in secret_variable_ids() {
|
||||
let mut raw_contribution: RandomnessInput = load_sbi::<RandomnessInput>(variable_id);
|
||||
|
||||
let d1_reduced = reduce_contribution(raw_contribution.d1);
|
||||
let d2_reduced = reduce_contribution(raw_contribution.d2);
|
||||
|
||||
throw.d1 = throw.d1 + d1_reduced;
|
||||
throw.d2 = throw.d2 + d2_reduced;
|
||||
}
|
||||
|
||||
throw
|
||||
}
|
||||
|
||||
/// Reduce the contribution if it is not between 0 and 5.
|
||||
fn reduce_contribution(value: Sbi8) -> Sbi8 {
|
||||
let reduce = value & Sbi8::from(0b111);
|
||||
if reduce >= Sbi8::from(6) {
|
||||
reduce - Sbi8::from(6)
|
||||
} else {
|
||||
reduce
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user