mk_ext_prettytable 0.11.0

A library for printing pretty formatted tables in terminal
Documentation
use prettytable::{
  cell,
  table,
  Table,
};

use std::io;
use std::io::Write;
use std::str::FromStr;

const CROSS: &str = "X";
const EMPTY: &str = " ";
const ROUND: &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 !(1..=9).contains(&i) {
      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
}