1
\$\begingroup\$

I recently discovered to joys of rust programming and I have written a tic-tac-toe game. I was hoping for some feedback on how it is made. (The reason split and input are separate functions is because this is part of a larger collection of games)

fn input(prompt: &str) -> String {
    let mut out = String::new();
    print!("{}", prompt);
    std::io::Write::flush(&mut std::io::stdout()).expect("flush failed!");
    std::io::stdin().read_line(&mut out).expect("Err: no input");
    return out.trim().to_string();
}

fn split(string_in: String, delimiters: Vec<char>) -> Vec<String> {
    let mut out: Vec<String> = vec!();
    let mut start: usize = 0;
    for (i, c) in string_in.chars().enumerate() {
        if delimiters.contains(&c) {
            out.push(string_in[start..i].to_string());
            start = i + 1;
        }
        if  i == string_in.len() - 1 {
            out.push(string_in[start..i + 1].to_string());
        }
    }
    return out;
}

fn tic_tac_toe() {
    fn get_input(plr: &str) -> (usize, usize) {
        let mut x;
        let mut y;
        loop {
            let coords = tools::split(tools::input(&format!("{}'s move; Coordinates(x,y): ", plr)[..]), vec!(','));
            if coords.contains(&"exit".to_string()) {
                return (9usize, 9usize);
            }
            if coords.len() != 2 {
                println!("cannot parse coordinates. make sure it is formatted as: x,y\n(only comma, no space)\n");
                continue;
            }

            match coords[0].parse::<i32>() {
                Ok(n) => x = n - 1,
                Err(_) => {
                    println!("cannot parse coordinates. make sure it is formatted as: x,y");
                    continue;
                }
            }
            match coords[1].parse::<i32>() {
                Ok(n) => y = -n + 3,
                Err(_) => {
                    println!("cannot parse coordinates. make sure it is formatted as: x,y");
                    continue;
                }
            }
            if x > -1 && x < 3 && y > -1 && y < 3 {
                return (x as usize, y as usize);
            }
            println!("invalid coordinates. valid indices are from 1 to 3");
        }
    }
    fn vertical(brd: &[[&str; 3]; 3], ind: usize) -> String {
        let winner = brd[0][ind];
        for x in 1usize..3 {
            if brd[x][ind] != winner || winner == " ".to_string() {
                return String::new();
            }
        }
        return winner.to_string();
    }
    fn horizontal(brd: &[[&str; 3]; 3], ind: usize) -> String {
        let winner = brd[ind][0];
        for x in 1usize..3 {
            if brd[ind][x] != winner || winner == " ".to_string() {
                return String::new();
            }
        }
        return winner.to_string();
    }
    let mut board: [[&str; 3]; 3] = [[" "; 3]; 3];
    let plrs = ["X", "O"];
    let mut current: usize = 0;
    loop {
        let mut exit: bool = false;
        let mut tie: bool = true;
        for (i, row) in board.iter().enumerate() {
            print!("    |   |    \n ");
            for (j, elem) in row.iter().enumerate() {
                if j == row.len() - 1 {
                    print!(" {}", elem);
                }
                else {
                    print!(" {} |", elem);
                }
            }
            if i == board.len() - 1 {
                println!("\n    |   |");
            }
            else {
                println!("\n ___|___|___");
            }
        }
        for x in 0usize..3 {
            let win_v = vertical(&board, x);
            let win_h = horizontal(&board, x);
            let mut stop: bool = false;
            if win_v != "".to_string() {
                println!("{} wins!", win_v);
                stop = true;
            } 
            else if win_h != "".to_string() {
                println!("{} wins!", win_h);
                stop = true;
            }
            if stop {
                exit = true;
                break;
            }
        }
        let winner = board[2][2];
        if board[0][0] == winner && board[1][1] == winner && winner != " " {
            println!("{} wins!", winner);
            break;
        }
        let winner = board[2][0];
        if board[0][2] == winner && board[1][1] == winner && winner != " " {
            println!("{} wins!", winner);
            break;
        }
        for row in board.iter() {
            if row.contains(&" ") {
                tie = false;
            }
        }
        if tie && !exit {
            println!("Tie!");
            break;
        }
        if exit {
            break;
        }
        loop {
            let mov = get_input(plrs[current]);
            if mov == (9usize, 9usize) {
                return;
            }
            if board[mov.1][mov.0] == " " {
                board[mov.1][mov.0] = plrs[current];
                break;
            }
            else {
                println!("cant move there");
            }
        }
        current += 1;
        current %= 2;
    }
    let again = tools::input("Again(y/n)? ");
    if again == "y".to_string() {
        tic_tac_toe()
    }
}

fn main() {
    tic_tac_toe();
}
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.