1use prettytable::{
2 cell,
3 table,
4 Table,
5};
6
7use std::io;
8use std::io::Write;
9use std::str::FromStr;
10
11const CROSS: &str = "X";
12const EMPTY: &str = " ";
13const ROUND: &str = "O";
14
15fn main() {
16 let mut table = table![
17 [EMPTY, EMPTY, EMPTY],
18 [EMPTY, EMPTY, EMPTY],
19 [EMPTY, EMPTY, EMPTY]
20 ];
21 let mut height = table.print_tty(false).unwrap();
22 let stdin = io::stdin();
23 let mut stdout = io::stdout();
24 let mut current = CROSS;
25 let mut terminal = term::stdout().unwrap();
26 loop {
27 let mut line = String::new();
28 print!("{} plays > ", current);
29 height += 1;
30 stdout.flush().unwrap();
31 stdin.read_line(&mut line).expect("Cannot read input");
32 let i = match usize::from_str(line.trim()) {
33 Ok(i) => i,
34 _ => {
35 println!("Bad input");
36 height += 1;
37 continue;
38 },
39 };
40 if !(1..=9).contains(&i) {
41 println!("Bad input, should be between 1 and 9");
42 height += 1;
43 continue;
44 }
45 let x = (i - 1) % 3;
46 let y = (i - 1) / 3;
47 {
48 let row = table.get_mut_row(y).unwrap();
49 if row.get_cell(x).unwrap().to_string() != EMPTY {
50 println!("There's already someone there");
51 height += 1;
52 continue;
53 }
54 row.set_cell(cell!(current), x).unwrap();
55 }
56 for _ in 0..height {
57 terminal.cursor_up().unwrap();
58 terminal.delete_line().unwrap();
59 }
60 height = table.print_tty(false).unwrap();
61 if check(&table) {
62 return;
63 }
64 if current == CROSS {
65 current = ROUND;
66 } else {
67 current = CROSS;
68 }
69 }
70}
71
72fn get(table: &Table, x: usize, y: usize) -> String {
73 match table.get_row(y) {
74 Some(r) => match r.get_cell(x) {
75 Some(c) => c.to_string(),
76 _ => EMPTY.to_string(),
77 },
78 _ => EMPTY.to_string(),
79 }
80}
81
82fn is(table: &Table, s: &str, x: usize, y: usize) -> bool {
83 get(table, x, y).as_str() == s
84}
85
86fn check(table: &Table) -> bool {
87 let mut full = true;
88 for y in 0..3 {
89 for x in 0..3 {
90 if is(table, EMPTY, x, y) {
91 full = false;
92 continue;
93 }
94 let current = get(table, x, y);
95 let c = current.as_str();
96 if is(table, c, x + 1, y) && is(table, c, x + 2, y)
97 || is(table, c, x + 1, y + 1) && is(table, c, x + 2, y + 2)
98 || x >= 2 && is(table, c, x - 1, y + 1) && is(table, c, x - 2, y + 2)
99 || is(table, c, x, y + 1) && is(table, c, x, y + 2)
100 {
101 println!("Game is over. {} is the winner", current);
102 return true;
103 }
104 }
105 }
106 if full {
107 println!("Game is over. It's a draw");
108 }
109 full
110}