#![allow(clippy::print_stdout)]
use rlmesh::prelude::*;
use rlmesh::spaces::{self, SpaceValue};
struct CounterEnv {
observation_space: SpaceSpec,
action_space: SpaceSpec,
contract: EnvContract,
step: i64,
}
impl CounterEnv {
fn new() -> Self {
let observation_space = spaces::spaces::DiscreteBuilder::new(5)
.build()
.expect("discrete observation space spec is valid");
let action_space = spaces::spaces::DiscreteBuilder::new(2)
.build()
.expect("discrete action space spec is valid");
let contract = EnvContract {
id: "CounterEnv-v0".to_string(),
observation_space: Some(observation_space.clone()),
action_space: Some(action_space.clone()),
num_envs: 1,
..Default::default()
};
Self {
observation_space,
action_space,
contract,
step: 0,
}
}
}
#[rlmesh::async_trait]
impl Env for CounterEnv {
fn observation_space(&self) -> &SpaceSpec {
&self.observation_space
}
fn action_space(&self) -> &SpaceSpec {
&self.action_space
}
fn env_contract(&self) -> &EnvContract {
&self.contract
}
async fn reset(&mut self, _req: ResetRequest) -> Result<ResetResult, EnvRuntimeError> {
self.step = 0;
Ok(ResetResult {
observation: Some(SpaceValue::Discrete(self.step)),
info: None,
episode_id: None,
})
}
async fn step(&mut self, _req: StepRequest) -> Result<StepResult, EnvRuntimeError> {
self.step += 1;
Ok(StepResult {
observation: Some(SpaceValue::Discrete(self.step % 5)),
reward: 1.0,
terminated: self.step >= 3,
truncated: false,
info: None,
})
}
async fn render(
&mut self,
_req: spaces::RenderRequest,
) -> Result<spaces::RenderResult, EnvRuntimeError> {
Ok(spaces::RenderResult::default())
}
async fn close(&mut self, _req: spaces::CloseRequest) -> Result<CloseResult, EnvRuntimeError> {
Ok(CloseResult)
}
}
#[tokio::main]
async fn main() -> rlmesh::Result<()> {
let address = std::env::args()
.nth(1)
.unwrap_or_else(|| "127.0.0.1:5555".to_string());
let server = EnvServer::new(CounterEnv::new())
.bind(BindAddress::parse(&address)?)
.await?;
println!("serving CounterEnv on {}", server.local_addr());
server.serve().await
}