protohack

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs

commit 4957e77896554ffc0b8e0a5657015e4f76f6bfd4
parent 979362c646144a14ec8b98b308668f0a943f7efc
Author: minerva-jupiter <ryouturn@gmail.com>
Date:   Thu,  2 Apr 2026 14:32:11 +0900

feat(mean-server): Implement a TCP server for mean calculation

Diffstat:
Asrc/bin/mean.rs | 80+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 80 insertions(+), 0 deletions(-)

diff --git a/src/bin/mean.rs b/src/bin/mean.rs @@ -0,0 +1,80 @@ +use std::collections::BTreeMap; +use tokio::io::{AsyncReadExt, AsyncWriteExt, stdin}; +use tokio::sync::oneshot; + +#[tokio::main] +async fn main() -> std::io::Result<()> { + let (tx, rx) = oneshot::channel(); + + tokio::spawn(async move { + let mut reader = stdin(); + let mut buffer = [0u8; 1]; + loop { + if reader.read_exact(&mut buffer).await.is_ok() { + if buffer[0] == b'q' { + let _ = tx.send(()); + break; + } + } + } + }); + + let listener = tokio::net::TcpListener::bind("0.0.0.0:8080").await?; + println!("Server started. Press 'q' then Enter to stop."); + + tokio::select! { + res = async { + loop { + let (mut socket, _) = listener.accept().await?; + tokio::spawn(async move { + let (mut rd, mut wr) = socket.split(); + let mut buf = [0u8; 9]; + let mut history = BTreeMap::new(); + loop { + if rd.read_exact(&mut buf).await.is_err() { + break; + } + match buf[0] { + b'I' => { + let t = i32::from_be_bytes(buf[1..5].try_into().unwrap()); + let p = i32::from_be_bytes(buf[5..9].try_into().unwrap()); + history.insert(t, p); + } + b'Q' => { + let min = i32::from_be_bytes(buf[1..5].try_into().unwrap()); + let max = i32::from_be_bytes(buf[5..9].try_into().unwrap()); + let avg = calculate_average(&history, min, max); + if wr.write_all(&avg.to_be_bytes()).await.is_err() { + break; + } + } + _ => break, + } + } + }); + } + #[allow(unreachable_code)] + Ok::<(), std::io::Error>(()) + } => { + if let Err(e) = res { + eprintln!("Accept error: {}", e); + } + }, + _ = rx => { + println!("Shutdown signal received. Exiting..."); + } + } + + Ok(()) +} + +fn calculate_average(history: &BTreeMap<i32, i32>, min: i32, max: i32) -> i32 { + if min > max { + return 0; + } + let subset: Vec<_> = history.range(min..=max).map(|(_, &v)| v as i64).collect(); + if subset.is_empty() { + return 0; + } + (subset.iter().sum::<i64>() / subset.len() as i64) as i32 +}