diff --git a/examples/werewolf_cli/game.rs b/examples/werewolf_cli/game.rs index 7154746..3b9dfb1 100644 --- a/examples/werewolf_cli/game.rs +++ b/examples/werewolf_cli/game.rs @@ -4,9 +4,13 @@ use ark_ff::BigInteger; use ark_ff::PrimeField; use ark_ff::UniformRand; use ark_marlin::IndexProverKey; +use ark_std::One; use mpc_algebra::commitment::CommitmentScheme; +use mpc_algebra::BooleanWire; use mpc_algebra::FromLocal; +use mpc_algebra::MpcBooleanField; use mpc_algebra::Reveal; +use mpc_net::{MpcMultiNet as Net, MpcNet}; use nalgebra::DMatrix; use player::Player; use rand::Rng; @@ -232,24 +236,27 @@ impl Game { } } - pub fn werewolf_attack(&mut self, target_id: usize) -> Vec { + pub fn werewolf_attack(&mut self, target_id: MFr) -> Vec { let mut events = Vec::new(); - if let Some(_werewolf) = self + let am_werewolf = self .state .players .iter() - .find(|p| p.is_werewolf() && p.is_alive) + .any(|p| p.id == Net::party_id() && p.role == Some(Role::Werewolf) && p.is_alive); + + // calc + if let Some(target) = + self.state.players.iter_mut().find(|p| { + Fr::from(p.id as i32) == target_id.reveal() && p.is_alive && !p.is_werewolf() + }) { - if let Some(target) = self - .state - .players - .iter_mut() - .find(|p| p.id == target_id && p.is_alive && !p.is_werewolf()) - { - target.mark_for_death(); + target.mark_for_death(); + if am_werewolf { events.push(format!("人狼が{}を襲撃対象に選びました。", target.name)); - } else { + } + } else { + if am_werewolf { events.push("無効な襲撃対象が選択されました。".to_string()); } } @@ -257,35 +264,42 @@ impl Game { events } - pub fn seer_divination(&self, target_id: usize) -> Vec { + pub fn seer_divination(&self, target_id: MFr) -> Vec { let mut events = Vec::new(); + // get FortuneTeller + let am_fortune_teller = + self.state.players.iter().any(|p| { + p.id == Net::party_id() && p.role == Some(Role::FortuneTeller) && p.is_alive + }); + + // calc if let Some(seer) = self .state .players .iter() .find(|p| p.role == Some(Role::FortuneTeller) && p.is_alive) { - if let Some(target) = self - .state - .players - .iter() - .find(|p| p.id == target_id && p.is_alive && p.id != seer.id) - { + if let Some(target) = self.state.players.iter().find(|p| { + Fr::from(p.id as i32) == target_id.reveal() && p.is_alive && p.id != seer.id + }) { let role_name = if target.is_werewolf() { "人狼" } else { "人狼ではない" }; - events.push(format!( - "占い師が{}を占いました。結果:{}", - target.name, role_name - )); + if am_fortune_teller { + events.push(format!( + "占い師が{}を占いました。結果:{}", + target.name, role_name + )); + } } else { - events.push("無効な占い対象が選択されました。".to_string()); + if am_fortune_teller { + events.push("無効な占い対象が選択されました。".to_string()); + } } } - events } @@ -293,10 +307,10 @@ impl Game { let mut events = Vec::new(); for player in &mut self.state.players { - if player.marked_for_death && player.is_alive { + if player.marked_for_death.reveal().is_one() && player.is_alive { player.kill(self.state.day); events.push(format!("{}が無残な姿で発見されました。", player.name)); - player.marked_for_death = false; + player.marked_for_death = MpcBooleanField::pub_false(); } } diff --git a/examples/werewolf_cli/game/player.rs b/examples/werewolf_cli/game/player.rs index c7eb9c6..0abb385 100644 --- a/examples/werewolf_cli/game/player.rs +++ b/examples/werewolf_cli/game/player.rs @@ -1,14 +1,15 @@ -use serde::{Deserialize, Serialize}; +use ark_bls12_377::Fr; +use mpc_algebra::{AdditiveFieldShare, BooleanWire, MpcBooleanField}; use zk_mpc::werewolf::types::Role; -#[derive(Debug, Clone, Serialize, Deserialize)] +#[derive(Debug, Clone)] pub struct Player { pub id: usize, pub name: String, pub role: Option, pub is_alive: bool, pub death_day: Option, - pub marked_for_death: bool, + pub marked_for_death: MpcBooleanField>, } impl Player { @@ -19,7 +20,7 @@ impl Player { role, is_alive: true, death_day: None, - marked_for_death: false, + marked_for_death: MpcBooleanField::pub_false(), } } @@ -33,7 +34,7 @@ impl Player { } pub fn mark_for_death(&mut self) { - self.marked_for_death = true; + self.marked_for_death = MpcBooleanField::pub_true(); } } diff --git a/examples/werewolf_cli/main.rs b/examples/werewolf_cli/main.rs index f21889e..8999b16 100644 --- a/examples/werewolf_cli/main.rs +++ b/examples/werewolf_cli/main.rs @@ -1,9 +1,12 @@ +use ark_bls12_377::Fr; use game::{player::Player, Game, GameRules}; use mpc_algebra::channel::MpcSerNet; +use mpc_algebra::Reveal; use mpc_net::{MpcMultiNet as Net, MpcNet}; use std::io::{self, Write}; use std::path::PathBuf; use structopt::StructOpt; +use zk_mpc::marlin::MFr; use zk_mpc::werewolf::types::{GroupingParameter, Role}; pub mod game; @@ -99,34 +102,37 @@ fn register_players() -> Vec { fn night_phase(game: &mut Game) { println!("\n--- 夜のフェーズ ---"); let players = game.state.players.clone(); - for player in &players { - if player.is_alive { - let mut events = Vec::new(); - match player.role { - Some(Role::Werewolf) => { - let werewolf_target = get_werewolf_target(game, player); - events.extend(game.werewolf_attack(werewolf_target)); - } - Some(Role::FortuneTeller) => { - let seer_target = get_seer_target(game, player); - events.extend(game.seer_divination(seer_target)); - } - Some(Role::Villager) => { - println!( - "{}さん、あなたは村人です。次の人に渡してください。", - player.name - ); - } - None => unreachable!(), - } - for event in events { - println!("{}", event); - } - wait_for_enter(); - // 各プレイヤーのフェーズ後にCLIをフラッシュ - clear_screen(); + + let player = players.iter().find(|p| p.id == Net::party_id()).unwrap(); + + let mut events = Vec::new(); + + match player.role { + Some(Role::Villager) => { + println!("You are a villager. Please wait until everyone has finished their actions."); + } + Some(Role::Werewolf) => { + println!("You are a werewolf."); } + Some(Role::FortuneTeller) => { + println!("You are a fortune Teller. Please wait until other roles actions."); + } + None => todo!(), + } + + let attack_target = get_werewolf_target(game, player); + events.extend(game.werewolf_attack(attack_target)); + + let seer_target = get_seer_target(game, player); + events.extend(game.seer_divination(seer_target)); + + for event in events { + println!("{}", event); } + wait_for_enter(); + println!("Waiting for all players to finish their actions."); + wait_for_everyone(); + clear_screen(); } fn wait_for_enter() { @@ -135,73 +141,94 @@ fn wait_for_enter() { io::stdin().read_line(&mut input).unwrap(); } +fn wait_for_everyone() { + let dummy = 0_u32; + Net::broadcast(&dummy); +} + fn clear_screen() { print!("\x1B[2J\x1B[1;1H"); // ANSI escape code for clearing the screen io::stdout().flush().unwrap(); } -fn get_werewolf_target(game: &Game, werewolf: &Player) -> usize { - println!( - "{}さん、あなたは人狼です。襲撃する対象を選んでください:", - werewolf.name - ); - game.state - .players - .iter() - .filter(|p| p.is_alive && !p.is_werewolf()) - .for_each(|p| println!("{}: {}", p.id, p.name)); +fn get_werewolf_target(game: &Game, player: &Player) -> MFr { + let mut target_id = Fr::default(); - loop { - print!("対象のIDを入力してください: "); - io::stdout().flush().unwrap(); - - let mut input = String::new(); - io::stdin().read_line(&mut input).unwrap(); - let target_id: usize = input.trim().parse().unwrap_or(0); - - if game - .state + if player.role.unwrap().is_werewolf() { + println!( + "{}さん、あなたは人狼です。襲撃する対象を選んでください:", + player.name + ); + game.state .players .iter() - .any(|p| p.id == target_id && p.is_alive && !p.is_werewolf()) - { - return target_id; - } else { - println!("無効な選択です。もう一度選んでください。"); + .filter(|p| p.is_alive && !p.is_werewolf()) + .for_each(|p| println!("{}: {}", p.id, p.name)); + + loop { + print!("対象のIDを入力してください: "); + io::stdout().flush().unwrap(); + + let mut input = String::new(); + io::stdin().read_line(&mut input).unwrap(); + target_id = Fr::from(input.trim().parse().unwrap_or(0) as i32); + + if game + .state + .players + .iter() + .any(|p| Fr::from(p.id as i32) == target_id && p.is_alive && !p.is_werewolf()) + { + break; + } else { + println!("無効な選択です。もう一度選んでください。"); + } } + } else { + target_id = Fr::default(); } -} -fn get_seer_target(game: &Game, seer: &Player) -> usize { - println!( - "{}さん、あなたは占い師です。占う対象を選んでください:", - seer.name - ); - game.state - .players - .iter() - .filter(|p| p.is_alive && p.id != seer.id) - .for_each(|p| println!("{}: {}", p.id, p.name)); + return MFr::from_add_shared(target_id); +} - loop { - print!("対象のIDを入力してください: "); - io::stdout().flush().unwrap(); +fn get_seer_target(game: &Game, player: &Player) -> MFr { + let mut target_id = Fr::default(); - let mut input = String::new(); - io::stdin().read_line(&mut input).unwrap(); - let target_id: usize = input.trim().parse().unwrap_or(0); - - if game - .state + if player.role.unwrap() == Role::FortuneTeller { + println!( + "{}さん、あなたは占い師です。占う対象を選んでください:", + player.name + ); + game.state .players .iter() - .any(|p| p.id == target_id && p.is_alive && p.id != seer.id) - { - return target_id; - } else { - println!("無効な選択です。もう一度選んでください。"); + .filter(|p| p.is_alive && p.id != player.id) + .for_each(|p| println!("{}: {}", p.id, p.name)); + + loop { + print!("対象のIDを入力してください: "); + io::stdout().flush().unwrap(); + + let mut input = String::new(); + io::stdin().read_line(&mut input).unwrap(); + target_id = Fr::from(input.trim().parse().unwrap_or(0) as i32); + + if game + .state + .players + .iter() + .any(|p| Fr::from(p.id as i32) == target_id && p.is_alive && p.id != player.id) + { + break; + } else { + println!("無効な選択です。もう一度選んでください。"); + } } + } else { + target_id = Fr::default(); } + + return MFr::from_add_shared(target_id); } fn morning_phase(game: &mut Game) {