use rand::Rng; use std::collections::HashMap; use std::net::SocketAddr; use std::vec; use tokio::sync::mpsc::UnboundedSender; use tokio_tungstenite::tungstenite::Message; #[derive(PartialEq, Clone)] pub enum Color { Red, Blue, None, } #[derive(Clone)] pub struct Client { pub username: String, pub connection: UnboundedSender, pub ready: bool, pub color: Color, pub current_match: Option, pub round_robin_id: u32, pub score: u32, pub addr: SocketAddr, } impl Client { pub fn new(username: String, connection: UnboundedSender, addr: SocketAddr) -> Client { Client { username, connection, ready: false, color: Color::None, current_match: None, round_robin_id: 0, score: 0, addr, } } } #[derive(Clone)] pub struct Tournament { pub players: HashMap, pub top_half: Vec, pub bottom_half: Vec, pub is_completed: bool, } impl Tournament { pub fn new(ready_players: &[SocketAddr]) -> Tournament { let mut result = Tournament { players: HashMap::new(), top_half: Vec::new(), bottom_half: Vec::new(), is_completed: false, }; let size = ready_players.len(); for (id, player) in ready_players.iter().enumerate() { result.players.insert(id as u32, *player); } for i in 0..size / 2 { result.top_half.push(i as u32); } for i in size / 2..size { result.bottom_half.push(i as u32); } result } pub fn next(&mut self) { if self.is_completed { return; } if self.top_half.len() <= 1 || self.bottom_half.is_empty() { self.is_completed = true; return; } let last_from_top = self.top_half.pop().unwrap(); let first_from_bottom = self.bottom_half.remove(0); self.top_half.insert(1, first_from_bottom); self.bottom_half.push(last_from_top); let expected_bottom_start = self.top_half.len() as u32; if self.top_half[1] == 1 && self.bottom_half[0] == expected_bottom_start { self.is_completed = true; } } } pub struct Match { pub id: u32, pub board: Vec>, pub viewers: Vec, pub ledger: Vec<(Color, usize)>, pub move_to_dispatch: (Color, usize), pub wait_thread: Option>, pub player1: SocketAddr, pub player2: SocketAddr, } impl Match { pub fn new(id: u32, player1: SocketAddr, player2: SocketAddr) -> Match { let first = if rand::rng().random_range(0..=1) == 0 { player1.to_string().parse().unwrap() } else { player2.to_string().parse().unwrap() }; Match { id, board: vec![vec![Color::None; 6]; 7], viewers: Vec::new(), ledger: Vec::new(), move_to_dispatch: (Color::None, 0), wait_thread: None, player1: if player1 == first {player1} else {player2}, player2: if player1 == first {player2} else {player1}, } } pub fn place_token(&mut self, color: Color, column: usize) { for i in 0..6 { if self.board[column][i] == Color::None { self.board[column][i] = color; break; } } } }