use prettytable::{Table, table, cell}; use std::io; use std::io::Write; use std::str::FromStr; const CROSS: &'static str = "X"; const EMPTY: &'static str = " "; const ROUND: &'static str = "O"; fn main() { let mut table = table![ [EMPTY, EMPTY, EMPTY], [EMPTY, EMPTY, EMPTY], [EMPTY, EMPTY, EMPTY] ]; let mut height = table.print_tty(false).unwrap(); let stdin = io::stdin(); let mut stdout = io::stdout(); let mut current = CROSS; let mut terminal = term::stdout().unwrap(); loop { let mut line = String::new(); print!("{} plays > ", current); height += 1; stdout.flush().unwrap(); stdin.read_line(&mut line).expect("Cannot read input"); let i = match usize::from_str(line.trim()) { Ok(i) => i, _ => { println!("Bad input"); height += 1; continue; } }; if i < 1 || i > 9 { println!("Bad input, should be between 1 and 9"); height += 1; continue; } let x = (i - 1) % 3; let y = (i - 1) / 3; { let row = table.get_mut_row(y).unwrap(); if row.get_cell(x).unwrap().to_string() != EMPTY { println!("There's already someone there"); height += 1; continue; } row.set_cell(cell!(current), x).unwrap(); } for _ in 0..height { terminal.cursor_up().unwrap(); terminal.delete_line().unwrap(); } height = table.print_tty(false).unwrap(); if check(&table) { return; } if current == CROSS { current = ROUND; } else { current = CROSS; } } } fn get(table: &Table, x: usize, y: usize) -> String { match table.get_row(y) { Some(r) => match r.get_cell(x) { Some(c) => c.to_string(), _ => EMPTY.to_string(), }, _ => EMPTY.to_string(), } } fn is(table: &Table, s: &str, x: usize, y: usize) -> bool { get(table, x, y).as_str() == s } fn check(table: &Table) -> bool { let mut full = true; for y in 0..3 { for x in 0..3 { if is(table, EMPTY, x, y) { full = false; continue; } let current = get(table, x, y); let c = current.as_str(); if is(table, c, x + 1, y) && is(table, c, x + 2, y) || is(table, c, x + 1, y + 1) && is(table, c, x + 2, y + 2) || x >= 2 && is(table, c, x - 1, y + 1) && is(table, c, x - 2, y + 2) || is(table, c, x, y + 1) && is(table, c, x, y + 2) { println!("Game is over. {} is the winner", current); return true; } } } if full { println!("Game is over. It's a draw"); } full }