use rand::RngExt; use std::net::SocketAddr; use std::time::Instant; use std::{ops, vec}; use tokio::sync::mpsc::UnboundedSender; use tokio_tungstenite::tungstenite::Message; #[derive(PartialEq, Clone, Copy)] pub enum Color { Red, Yellow, None, } impl ops::Not for Color { type Output = Color; fn not(self) -> Color { match self { Color::Red => Color::Yellow, Color::Yellow => Color::Red, Color::None => Color::None, } } } impl From for bool { fn from(color: Color) -> bool { match color { Color::Red => true, Color::Yellow => false, Color::None => panic!("Cannot convert Color::None to bool"), } } } #[derive(Clone)] pub struct Client { pub username: String, pub connection: UnboundedSender, pub ready: bool, pub color: Color, pub current_match: Option, 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, addr, } } } pub struct Match { pub id: u32, pub demo_mode: bool, pub board: Vec>, pub ledger: Vec<(Color, usize, Instant)>, pub wait_thread: Option>, pub timeout_thread: Option>, pub player1: String, pub player2: String, } impl Match { pub fn new(id: u32, player1: String, player2: String, demo_mode: bool) -> Match { let (first_player, second_player) = if rand::rng().random_range(0..=1) == 0 { (player1, player2) } else { (player2, player1) }; Match { id, demo_mode, board: vec![vec![Color::None; 6]; 7], ledger: Vec::new(), wait_thread: None, timeout_thread: None, player1: first_player, player2: second_player, } } pub fn new_with_order(id: u32, player1: String, player2: String, demo_mode: bool) -> Match { Match { id, demo_mode, board: vec![vec![Color::None; 6]; 7], ledger: Vec::new(), wait_thread: None, timeout_thread: None, player1, player2, } } 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; } } } pub fn end_game_check(&self) -> (Color, bool) { let mut result = (Color::None, false); let mut any_empty = true; for x in 0..7 { for y in 0..6 { let color = self.board[x][y].clone(); let mut horizontal_end = true; let mut vertical_end = true; let mut diagonal_end_up = true; let mut diagonal_end_down = true; if any_empty && color == Color::None { any_empty = false; } for i in 0..4 { if x + i >= 7 || self.board[x + i][y] != color && horizontal_end { horizontal_end = false; } if y + i >= 6 || self.board[x][y + i] != color && vertical_end { vertical_end = false; } if x + i >= 7 || y + i >= 6 || self.board[x + i][y + i] != color && diagonal_end_up { diagonal_end_up = false; } if x + i >= 7 || (y as i32 - i as i32) < 0 || self.board[x + i][y - i] != color && diagonal_end_down { diagonal_end_down = false; } } if horizontal_end || vertical_end || diagonal_end_up || diagonal_end_down { result = (color.clone(), false); break; } } if result.0 != Color::None { break; } } if any_empty && result.0 == Color::None { result.1 = true; } result } }