minesweeper 1.3.0

Simple minesweeper in Rust
extern crate piston_window;
#[macro_use]
extern crate clap;
extern crate chrono;
extern crate rand;
extern crate find_folder;

mod game;
mod field;
mod ui;
mod common;

use piston_window::*;
use clap::{Arg, App};

fn main() {
    let matches = App::new("Minesweeper")
        .author("Alexander Kuvaev <alexander@kuvaev.me>")
        .version(&*format!("v{}", crate_version!()))
        .about("Simple minesweeper in Rust ")
        .arg(Arg::from_usage("-s, --size [size] 'window size \"width\"x\"height\"'")
            .validator(|val| {
                let mut s = val.split("x");
                match s.next() {
                    Some(w) => {
                        match w.parse::<u32>() {
                            Ok(r) => {
                                if (r < 100) || (r > 4096) {
                                    return Err(format!("window width must be between 100 and 4096"))
                                }
                            },
                            Err(e) => return Err(format!("window width arg error: {}", e))
                        }
                    }
                    None => return Err(format!("window size expected \"width\"x\"height\", got {}", val))
                }
                match s.next() {
                    Some(h) => {
                        match h.parse::<u32>() {
                            Ok(r) => {
                                if (r < 100) || (r > 3072) {
                                    return Err(format!("window height must be between 100 and 3072"))
                                }
                            },
                            Err(e) => return Err(format!("window height arg error: {}", e))
                        }
                    }
                    None => return Err(format!("window size expected \"width\"x\"height\", got {}", val))
                }
                match s.next() {
                    Some(_r) => Err(format!("window size arg expected \"width\"x\"height\", got {}", val)),
                    None => Ok(())
                }
            }))
        .arg(Arg::from_usage("-f, --field [field] 'field size \"width\"x\"height\"'")
            .validator(|val| {
                let mut s = val.split("x");
                match s.next() {
                    Some(w) => {
                        match w.parse::<u32>() {
                            Ok(r) => {
                                if (r < 5) || (r > 100) {
                                    return Err(format!("field width must be between 5 and 100"))
                                }
                            },
                            Err(e) => return Err(format!("field width arg error: {}", e))
                        }
                    }
                    None => return Err(format!("field size expected \"width\"x\"height\", got {}", val))
                }
                match s.next() {
                    Some(h) => {
                        match h.parse::<u32>() {
                            Ok(r) => {
                                if (r < 5) || (r > 100) {
                                    return Err(format!("field height must be between 5 and 100"))
                                }
                            },
                            Err(e) => return Err(format!("field height arg error: {}", e))
                        }
                    }
                    None => return Err(format!("field size expected \"width\"x\"height\", got {}", val))
                }
                match s.next() {
                    Some(_r) => Err(format!("field size arg expected \"width\"x\"height\", got {}", val)),
                    None => Ok(())
                }
            }))
        .arg(Arg::from_usage("-m, --mines [mines] 'max mines'"))
        .arg(Arg::from_usage("--oldOGL 'set OpenGL version to 2.1'"))
        .arg(Arg::from_usage("--maxFPS [max_fps] 'set max fps'"))
        .get_matches();

    let mut width = 1024;
    let mut height = 768;
    let mut f_width = 20;
    let mut f_height = 20;
    let mut mines = 50;
    let mut max_fps = 60;
    let mut opengl = OpenGL::V3_2;
    if let Some(size) = matches.value_of("size") {
        let mut s = size.split("x");
        width = s.next().unwrap().parse().unwrap_or(width);
        height = s.next().unwrap().parse().unwrap_or(height);
    }
    if let Some(field) = matches.value_of("field") {
        let mut s = field.split("x");
        f_width = s.next().unwrap().parse().unwrap_or(f_width);
        f_height = s.next().unwrap().parse().unwrap_or(f_height);
    }
    if let Some(m) = matches.value_of("mines") {
        mines = m.parse().unwrap_or(mines);
    }
    if let Some(m) = matches.value_of("max_fps") {
        max_fps = m.parse().unwrap_or(max_fps);
    }
    if matches.is_present("oldOGL") {
        opengl = OpenGL::V2_1;
    }

    let mut window: PistonWindow = WindowSettings::new("Minesweeper", [width, height])
        .opengl(opengl)
        .exit_on_esc(true)
        .build()
        .expect("Try running with --oldOGL");

    let assets = find_folder::Search::ParentsThenKids(3, 3)
        .for_folder("assets")
        .unwrap();
    let ref font = assets.join("FiraSans-Regular.ttf");
    let factory = window.factory.clone();
    let glyphs = Glyphs::new(font, factory).unwrap();

    let mut game = game::Game::new(glyphs, f_width, f_height, mines);
    window.set_max_fps(max_fps);
    while let Some(e) = window.next() {
        game.update_state();

        if let Some(_) = e.render_args() {
            game.render(&mut window, &e);
        }

        if let Some(_) = e.resize_args() {
            game.resize()
        }

        if let Some(mouse_rel) = e.mouse_cursor_args() {
            game.mouse_move(mouse_rel);
        }

        if let Some(button) = e.press_args() {
            game.proc_key(button, &window);
        }

    }
}