hyperchess 0.1.1

A fast, terminal-based multiplayer chess game built with Rust.
Documentation
use tokio::net::TcpListener;
use tokio::io::{AsyncReadExt, AsyncWriteExt};
use tokio::sync::broadcast;
use serde_json;
use hyperchess::protocol::GameMessage; // Adjust crate name if different

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let listener = TcpListener::bind("0.0.0.0:8080").await?;
    println!("Chess Server running on port 8080...");
    println!("Waiting for players...");

    // Channel to broadcast moves to all connected players
    let (tx, _rx) = broadcast::channel(100);
    let mut player_count = 0;

    loop {
        let (mut socket, addr) = listener.accept().await?;
        player_count += 1;
        println!("Player {} connected: {}", player_count, addr);

        let tx = tx.clone();
        let mut rx = tx.subscribe();

        // Assign color based on arrival order (Odd=White, Even=Black)
        let my_color = if player_count % 2 != 0 { "white" } else { "black" };
        
        tokio::spawn(async move {
            let (mut reader, mut writer) = socket.split();
            
            // 1. Send GameStart to this player
            let start_msg = GameMessage::GameStart(my_color.to_string());
            let start_json = serde_json::to_string(&start_msg).unwrap();
            let _ = writer.write_all(start_json.as_bytes()).await;

            let mut buffer = [0; 1024];

            loop {
                tokio::select! {
                    // A. Receive from Client
                    result = reader.read(&mut buffer) => {
                        match result {
                            Ok(0) => break, // Connection closed
                            Ok(n) => {
                                if let Ok(msg) = serde_json::from_slice::<GameMessage>(&buffer[..n]) {
                                    match msg {
                                        GameMessage::MakeMove { from, to } => {
                                            println!("Move received from {}: {} -> {}", my_color, from, to);
                                            // Broadcast as OpponentMove
                                            let broadcast_msg = GameMessage::OpponentMove { from, to };
                                            let _ = tx.send((broadcast_msg, my_color.to_string()));
                                        }
                                        _ => {}
                                    }
                                }
                            }
                            Err(_) => break,
                        }
                    }
                    // B. Send Broadcast to Client
                    Ok((msg, sender_color)) = rx.recv() => {
                        // Don't send my own move back to me
                        if sender_color != my_color {
                            let json = serde_json::to_string(&msg).unwrap();
                            let _ = writer.write_all(json.as_bytes()).await;
                        }
                    }
                }
            }
            println!("Player disconnected");
        });
    }
}