chess_game 0.2.0

Simple Chess game
Documentation
pub mod game_settings;
pub mod ui_settings;

use std::{str::FromStr, io::stdin, thread::sleep, time::Duration, process::Command};
use chess::{Board, BoardStatus, Color};

use game_settings::*;
use method_shorthands::methods::*;
use ui_settings::*;
use crate::{turn::handle_turn, gui::display_board, player::Player, color::Opposite};

#[derive(Debug, Copy, Clone, PartialEq, Default)]
pub struct Game<'a, W, B> {
    pub board: Board,
    pub game_settings: GameSettings<'a, W, B>,
    pub ui_settings: UISettings,
    pub num_moves: usize
}

impl<W: Player, B: Player> Game<'_, W, B> {
    pub fn new(game_settings: GameSettings<W, B>, ui_settings: UISettings) -> Game<W, B> {
        let mut game = Game { 
            board: Board::from_str("k1K5/8/8/8/8/8/8/8 w - 0 1").uw(), 
            game_settings: game_settings, 
            ui_settings: ui_settings, 
            num_moves: 0 
        };

        game.set_board_state();

        game
    }

    fn set_board_state(&mut self) {
        self.board = Board::from_str(self.game_settings.initial_state).uw();
    }

    pub fn start(&mut self) {
        loop {    
            self.set_board_state();
            self.num_moves = 0;

            if self.ui_settings.cls { Command::new("clear").spawn().uw(); sleep(Duration::from_millis(10)); }
            if self.ui_settings.view_board_display { display_board(self.board, self.ui_settings); }

            self.game_loop();
        }
    }

    fn game_loop(&mut self) {
        loop {
            let m = match self.board.side_to_move() {
                Color::White => W::get_move(self.board, self.num_moves, self.ui_settings.bot_wait_ms),
                Color::Black => B::get_move(self.board, self.num_moves, self.ui_settings.bot_wait_ms),
            };
            if m.is_err() {
                println!("Invalid input.");
                continue;
            }
            let m = m.uw();

            let res = handle_turn(self.board, m, self.ui_settings);
            if res.is_err() { 
                if res.unwrap_err() == "insuff mat" {
                    println!("Insufficient material.");
                    Game::<W, B>::stalemate();
                    break;
                }
                else if res.unwrap_err() == "Illegal move." && self.game_settings.disqualification {
                    println!("Illegal move.");
                    Game::<W, B>::checkmate(self.board.side_to_move());
                    break;
                }
                println!("{:?}", res.unwrap_err().ts());
                continue; 
            }
            else { self.board = res.uw(); }

            if self.board.status() == BoardStatus::Checkmate {
                Game::<W, B>::checkmate(self.board.side_to_move());
                break;
            }
            else if self.board.status() == BoardStatus::Stalemate {
                Game::<W, B>::stalemate();
                break;
            }

            self.num_moves += 1;
            if self.num_moves == self.game_settings.move_limit {
                println!("{} move limit has been reached.", self.game_settings.move_limit);
                Game::<W, B>::stalemate();
                break;
            }
        }
    }

    fn checkmate(side_to_move: Color) {
        let color = side_to_move.opposite();

        println!("Game over: {:?} won!", color);
        stdin().read_line(&mut String::new()).uw();
    }

    fn stalemate() {
        println!("Game over: Stalemate.");
        stdin().read_line(&mut String::new()).uw();
    }
}