|  | #[macro_use] | 
|  | extern crate prettytable; | 
|  | extern crate term; | 
|  |  | 
|  | use prettytable::Table; | 
|  |  | 
|  | 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.printstd(); | 
|  | 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.printstd(); | 
|  | 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 | 
|  | } |