use std::time::Duration;
use maiko::*;
#[derive(Clone, Debug, Copy, PartialEq, Eq)]
enum PlayerId {
Player1,
Player2,
}
#[derive(Clone, Debug, Event)]
enum GuesserEvent {
Guess { player: PlayerId, number: u8 },
Result { player1: u8, player2: u8 },
Message(String),
}
#[derive(Debug, Hash, Eq, PartialEq, Clone)]
enum GuesserTopic {
Game,
Output,
}
impl Topic<GuesserEvent> for GuesserTopic {
fn from_event(event: &GuesserEvent) -> Self {
use GuesserEvent::*;
use GuesserTopic::*;
match event {
Message(..) => Output,
Result { .. } => Output,
Guess { .. } => Game,
}
}
}
struct Guesser {
ctx: Context<GuesserEvent>,
player_id: PlayerId,
cycle_time: Duration,
}
impl Guesser {
fn new(ctx: Context<GuesserEvent>, player_id: PlayerId, interval_ms: u64) -> Self {
Self {
ctx,
player_id,
cycle_time: Duration::from_millis(interval_ms),
}
}
}
impl Actor for Guesser {
type Event = GuesserEvent;
async fn step(&mut self) -> maiko::Result<StepAction> {
let rand = getrandom::u32().map_err(Error::external)?;
let number = (rand % 10) as u8;
self.ctx
.send(GuesserEvent::Guess {
player: self.player_id,
number,
})
.await?;
Ok(StepAction::Backoff(self.cycle_time))
}
}
struct Game {
ctx: Context<GuesserEvent>,
player1_guess: Option<u8>,
player2_guess: Option<u8>,
round: u64,
}
impl Game {
fn new(ctx: Context<GuesserEvent>) -> Self {
Self {
ctx,
player1_guess: None,
player2_guess: None,
round: 0,
}
}
}
impl Actor for Game {
type Event = GuesserEvent;
async fn on_start(&mut self) -> maiko::Result {
self.ctx
.send(GuesserEvent::Message(
"Welcome to the Guessing Game!\n(the game will stop after 10 rounds)".to_string(),
))
.await
}
async fn handle_event(&mut self, envelope: &Envelope<Self::Event>) -> maiko::Result {
if let GuesserEvent::Guess { player, number } = envelope.event() {
match player {
PlayerId::Player1 => self.player1_guess = Some(*number),
PlayerId::Player2 => self.player2_guess = Some(*number),
}
if let (Some(n1), Some(n2)) = (self.player1_guess, self.player2_guess) {
self.round += 1;
self.player1_guess = None;
self.player2_guess = None;
self.ctx
.send_child_event(
GuesserEvent::Result {
player1: n1,
player2: n2,
},
envelope.id(),
)
.await?;
}
}
Ok(())
}
async fn step(&mut self) -> maiko::Result<StepAction> {
if self.round >= 10 {
self.ctx.stop_runtime()?;
}
Ok(StepAction::AwaitEvent)
}
}
struct Printer;
impl Actor for Printer {
type Event = GuesserEvent;
async fn handle_event(&mut self, envelope: &Envelope<Self::Event>) -> maiko::Result {
match envelope.event() {
GuesserEvent::Message(msg) => {
println!("{}", msg);
}
GuesserEvent::Result { player1, player2 } if player1 == player2 => {
println!("Match! Both players guessed {}", player1);
}
GuesserEvent::Result { player1, player2 } => {
println!("No match. Player1: {}, Player2: {}", player1, player2);
}
_ => {}
}
Ok(())
}
}
#[tokio::main]
async fn main() -> Result {
let mut supervisor = Supervisor::<GuesserEvent, GuesserTopic>::default();
supervisor.add_actor(
"Player1",
|ctx| Guesser::new(ctx, PlayerId::Player1, 500),
Subscribe::none(),
)?;
supervisor.add_actor(
"Player2",
|ctx| Guesser::new(ctx, PlayerId::Player2, 350),
Subscribe::none(),
)?;
supervisor.add_actor("Game", Game::new, [GuesserTopic::Game])?;
supervisor.add_actor("Printer", |_| Printer, [GuesserTopic::Output])?;
supervisor.run().await?;
println!("\nGame over!");
Ok(())
}