Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/werewolf cli night phase #68

Merged
merged 4 commits into from
Nov 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 40 additions & 26 deletions examples/werewolf_cli/game.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -232,71 +236,81 @@ impl Game {
}
}

pub fn werewolf_attack(&mut self, target_id: usize) -> Vec<String> {
pub fn werewolf_attack(&mut self, target_id: MFr) -> Vec<String> {
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());
}
}

events
}

pub fn seer_divination(&self, target_id: usize) -> Vec<String> {
pub fn seer_divination(&self, target_id: MFr) -> Vec<String> {
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
}

pub fn morning_phase(&mut self) -> Vec<String> {
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();
}
}

Expand Down
11 changes: 6 additions & 5 deletions examples/werewolf_cli/game/player.rs
Original file line number Diff line number Diff line change
@@ -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<Role>,
pub is_alive: bool,
pub death_day: Option<u32>,
pub marked_for_death: bool,
pub marked_for_death: MpcBooleanField<Fr, AdditiveFieldShare<Fr>>,
}

impl Player {
Expand All @@ -19,7 +20,7 @@ impl Player {
role,
is_alive: true,
death_day: None,
marked_for_death: false,
marked_for_death: MpcBooleanField::pub_false(),
}
}

Expand All @@ -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();
}
}

Expand Down
179 changes: 103 additions & 76 deletions examples/werewolf_cli/main.rs
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -99,34 +102,37 @@ fn register_players() -> Vec<String> {
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() {
Expand All @@ -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) {
Expand Down
Loading