Add more command-line options for generating caves
Add all the necessary params to the CLI options for generating caves
This commit is contained in:
		
							parent
							
								
									d001b0a017
								
							
						
					
					
						commit
						68e8ad8a0e
					
				
					 4 changed files with 106 additions and 25 deletions
				
			
		
							
								
								
									
										26
									
								
								src/cli.yml
									
										
									
									
									
								
							
							
						
						
									
										26
									
								
								src/cli.yml
									
										
									
									
									
								
							| 
						 | 
					@ -10,7 +10,7 @@ args:
 | 
				
			||||||
      help: Sets a custom config file
 | 
					      help: Sets a custom config file
 | 
				
			||||||
      takes_value: true
 | 
					      takes_value: true
 | 
				
			||||||
subcommands:
 | 
					subcommands:
 | 
				
			||||||
  - debug:
 | 
					  - info:
 | 
				
			||||||
      about: Writes debug information to the terminal and exits
 | 
					      about: Writes debug information to the terminal and exits
 | 
				
			||||||
  - generate-level:
 | 
					  - generate-level:
 | 
				
			||||||
      about: Generate a level and print it to the screen
 | 
					      about: Generate a level and print it to the screen
 | 
				
			||||||
| 
						 | 
					@ -20,3 +20,27 @@ subcommands:
 | 
				
			||||||
          value_name: GEN
 | 
					          value_name: GEN
 | 
				
			||||||
          help: Select which generator to use
 | 
					          help: Select which generator to use
 | 
				
			||||||
          takes_value: true
 | 
					          takes_value: true
 | 
				
			||||||
 | 
					      - width:
 | 
				
			||||||
 | 
					          long: width
 | 
				
			||||||
 | 
					          short: w
 | 
				
			||||||
 | 
					          value_name: WIDTH
 | 
				
			||||||
 | 
					          takes_value: true
 | 
				
			||||||
 | 
					      - height:
 | 
				
			||||||
 | 
					          long: height
 | 
				
			||||||
 | 
					          short: h
 | 
				
			||||||
 | 
					          value_name: HEIGHT
 | 
				
			||||||
 | 
					          takes_value: true
 | 
				
			||||||
 | 
					      - start-alive-chance:
 | 
				
			||||||
 | 
					          long: start-alive-chance
 | 
				
			||||||
 | 
					          takes_value: true
 | 
				
			||||||
 | 
					      - birth_limit:
 | 
				
			||||||
 | 
					          long: birth-limit
 | 
				
			||||||
 | 
					          takes_value: true
 | 
				
			||||||
 | 
					      - death_limit:
 | 
				
			||||||
 | 
					          long: death-limit
 | 
				
			||||||
 | 
					          takes_value: true
 | 
				
			||||||
 | 
					      - steps:
 | 
				
			||||||
 | 
					          long: steps
 | 
				
			||||||
 | 
					          short: s
 | 
				
			||||||
 | 
					          value_name: STEPS
 | 
				
			||||||
 | 
					          takes_value: true
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -4,17 +4,46 @@ use rand::Rng;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub struct Params {
 | 
					pub struct Params {
 | 
				
			||||||
    chance_to_start_alive: f64,
 | 
					    chance_to_start_alive: f64,
 | 
				
			||||||
    dimensions: Dimensions,
 | 
					 | 
				
			||||||
    birth_limit: i32,
 | 
					    birth_limit: i32,
 | 
				
			||||||
    death_limit: i32,
 | 
					    death_limit: i32,
 | 
				
			||||||
    steps: usize,
 | 
					    steps: usize,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					macro_rules! parse_optional {
 | 
				
			||||||
 | 
					    ($out: ident . $attr: ident, $matches: expr, $arg: expr) => {
 | 
				
			||||||
 | 
					        if let Some(val_s) = $matches.value_of($arg) {
 | 
				
			||||||
 | 
					            $out.$attr = val_s.parse().unwrap();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					macro_rules! parse_optional_matches {
 | 
				
			||||||
 | 
					    ($matches: expr) => {};
 | 
				
			||||||
 | 
					    ($matches: expr , { $ret: ident . $attr: ident = $arg: expr }) => {
 | 
				
			||||||
 | 
					        parse_optional!($ret.$attr, $matches, $arg);
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    ($matches: expr, { $($ret: ident . $attr: ident = $arg: expr ,)* }) => {
 | 
				
			||||||
 | 
					        $(parse_optional!($ret.$attr, $matches, $arg);)*
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl Params {
 | 
				
			||||||
 | 
					    pub fn from_matches<'a>(matches: &clap::ArgMatches<'a>) -> Self {
 | 
				
			||||||
 | 
					        let mut ret: Self = Default::default();
 | 
				
			||||||
 | 
					        parse_optional_matches!(matches, {
 | 
				
			||||||
 | 
					            ret.chance_to_start_alive = "start-alive-chance",
 | 
				
			||||||
 | 
					            ret.birth_limit = "birth-limit",
 | 
				
			||||||
 | 
					            ret.death_limit = "death-limit",
 | 
				
			||||||
 | 
					            ret.steps = "steps",
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					        ret
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl Default for Params {
 | 
					impl Default for Params {
 | 
				
			||||||
    fn default() -> Self {
 | 
					    fn default() -> Self {
 | 
				
			||||||
        Params {
 | 
					        Params {
 | 
				
			||||||
            chance_to_start_alive: 0.45,
 | 
					            chance_to_start_alive: 0.45,
 | 
				
			||||||
            dimensions: Dimensions { w: 80, h: 20 },
 | 
					 | 
				
			||||||
            birth_limit: 4,
 | 
					            birth_limit: 4,
 | 
				
			||||||
            death_limit: 3,
 | 
					            death_limit: 3,
 | 
				
			||||||
            steps: 2,
 | 
					            steps: 2,
 | 
				
			||||||
| 
						 | 
					@ -23,21 +52,26 @@ impl Default for Params {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub fn generate<R: Rng + ?Sized>(
 | 
					pub fn generate<R: Rng + ?Sized>(
 | 
				
			||||||
 | 
					    dimensions: &Dimensions,
 | 
				
			||||||
    params: &Params,
 | 
					    params: &Params,
 | 
				
			||||||
    rand: &mut R,
 | 
					    rand: &mut R,
 | 
				
			||||||
) -> Vec<Vec<bool>> {
 | 
					) -> Vec<Vec<bool>> {
 | 
				
			||||||
    let mut cells =
 | 
					    let mut cells =
 | 
				
			||||||
        rand_initialize(¶ms.dimensions, rand, params.chance_to_start_alive);
 | 
					        rand_initialize(&dimensions, rand, params.chance_to_start_alive);
 | 
				
			||||||
    for _ in 0..params.steps {
 | 
					    for _ in 0..params.steps {
 | 
				
			||||||
        step_automata(&mut cells, params);
 | 
					        step_automata(&mut cells, dimensions, params);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    cells
 | 
					    cells
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fn step_automata(cells: &mut Vec<Vec<bool>>, params: &Params) {
 | 
					fn step_automata(
 | 
				
			||||||
 | 
					    cells: &mut Vec<Vec<bool>>,
 | 
				
			||||||
 | 
					    dimensions: &Dimensions,
 | 
				
			||||||
 | 
					    params: &Params,
 | 
				
			||||||
 | 
					) {
 | 
				
			||||||
    let orig_cells = (*cells).clone();
 | 
					    let orig_cells = (*cells).clone();
 | 
				
			||||||
    for x in 0..(params.dimensions.h as usize) {
 | 
					    for x in 0..(dimensions.h as usize) {
 | 
				
			||||||
        for y in 0..(params.dimensions.w as usize) {
 | 
					        for y in 0..(dimensions.w as usize) {
 | 
				
			||||||
            let nbs = num_alive_neighbors(&orig_cells, x as i32, y as i32);
 | 
					            let nbs = num_alive_neighbors(&orig_cells, x as i32, y as i32);
 | 
				
			||||||
            if orig_cells[x][y] {
 | 
					            if orig_cells[x][y] {
 | 
				
			||||||
                if nbs < params.death_limit {
 | 
					                if nbs < params.death_limit {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										51
									
								
								src/main.rs
									
										
									
									
									
								
							
							
						
						
									
										51
									
								
								src/main.rs
									
										
									
									
									
								
							| 
						 | 
					@ -39,6 +39,7 @@ mod level_gen;
 | 
				
			||||||
mod messages;
 | 
					mod messages;
 | 
				
			||||||
mod settings;
 | 
					mod settings;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use crate::types::Dimensions;
 | 
				
			||||||
use clap::App;
 | 
					use clap::App;
 | 
				
			||||||
use game::Game;
 | 
					use game::Game;
 | 
				
			||||||
use prettytable::format::consts::FORMAT_BOX_CHARS;
 | 
					use prettytable::format::consts::FORMAT_BOX_CHARS;
 | 
				
			||||||
| 
						 | 
					@ -59,7 +60,7 @@ fn init(
 | 
				
			||||||
    stdin: StdinLock<'_>,
 | 
					    stdin: StdinLock<'_>,
 | 
				
			||||||
    w: u16,
 | 
					    w: u16,
 | 
				
			||||||
    h: u16,
 | 
					    h: u16,
 | 
				
			||||||
) {
 | 
					) -> io::Result<()> {
 | 
				
			||||||
    panic::set_hook(if settings.logging.print_backtrace {
 | 
					    panic::set_hook(if settings.logging.print_backtrace {
 | 
				
			||||||
        Box::new(|info| (error!("{}\n{:#?}", info, Backtrace::new())))
 | 
					        Box::new(|info| (error!("{}\n{:#?}", info, Backtrace::new())))
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
| 
						 | 
					@ -67,10 +68,36 @@ fn init(
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let game = Game::new(settings, stdout, stdin, w, h);
 | 
					    let game = Game::new(settings, stdout, stdin, w, h);
 | 
				
			||||||
    game.run().unwrap()
 | 
					    game.run()
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fn main() {
 | 
					fn generate_level<'a, W: io::Write>(
 | 
				
			||||||
 | 
					    stdout: &mut W,
 | 
				
			||||||
 | 
					    params: &clap::ArgMatches<'a>,
 | 
				
			||||||
 | 
					) -> io::Result<()> {
 | 
				
			||||||
 | 
					    let mut rand = SmallRng::from_entropy();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let mut dimensions: Dimensions = Default::default();
 | 
				
			||||||
 | 
					    if let Some(h_s) = params.value_of("height") {
 | 
				
			||||||
 | 
					        dimensions.h = h_s.parse().unwrap();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if let Some(w_s) = params.value_of("width") {
 | 
				
			||||||
 | 
					        dimensions.w = w_s.parse().unwrap();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let level = match params.value_of("generator") {
 | 
				
			||||||
 | 
					        None => panic!("Must supply a generator with --generator"),
 | 
				
			||||||
 | 
					        Some("cave_automata") => level_gen::cave_automata::generate(
 | 
				
			||||||
 | 
					            &dimensions,
 | 
				
			||||||
 | 
					            &level_gen::cave_automata::Params::from_matches(params),
 | 
				
			||||||
 | 
					            &mut rand,
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					        Some(gen) => panic!("Unrecognized generator: {}", gen),
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    level_gen::display::print_generated_level(&level, stdout)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn main() -> io::Result<()> {
 | 
				
			||||||
    let yaml = load_yaml!("cli.yml");
 | 
					    let yaml = load_yaml!("cli.yml");
 | 
				
			||||||
    let matches = App::from_yaml(yaml).get_matches();
 | 
					    let matches = App::from_yaml(yaml).get_matches();
 | 
				
			||||||
    let settings = Settings::load().unwrap();
 | 
					    let settings = Settings::load().unwrap();
 | 
				
			||||||
| 
						 | 
					@ -85,7 +112,7 @@ fn main() {
 | 
				
			||||||
    let (termwidth, termheight) = termsize.unwrap_or((70, 40));
 | 
					    let (termwidth, termheight) = termsize.unwrap_or((70, 40));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    match matches.subcommand() {
 | 
					    match matches.subcommand() {
 | 
				
			||||||
        ("debug", _) => {
 | 
					        ("info", _) => {
 | 
				
			||||||
            let mut table = table!(
 | 
					            let mut table = table!(
 | 
				
			||||||
                [br->"termwidth", termwidth],
 | 
					                [br->"termwidth", termwidth],
 | 
				
			||||||
                [br->"termheight", termheight],
 | 
					                [br->"termheight", termheight],
 | 
				
			||||||
| 
						 | 
					@ -94,24 +121,14 @@ fn main() {
 | 
				
			||||||
            );
 | 
					            );
 | 
				
			||||||
            table.set_format(*FORMAT_BOX_CHARS);
 | 
					            table.set_format(*FORMAT_BOX_CHARS);
 | 
				
			||||||
            table.printstd();
 | 
					            table.printstd();
 | 
				
			||||||
 | 
					            Ok(())
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        ("generate-level", params) => {
 | 
					        ("generate-level", params) => {
 | 
				
			||||||
            let params = params.unwrap();
 | 
					            generate_level(&mut stdout, params.unwrap())
 | 
				
			||||||
            let mut rand = SmallRng::from_entropy();
 | 
					 | 
				
			||||||
            let level = match params.value_of("generator") {
 | 
					 | 
				
			||||||
                None => panic!("Must supply a generator with --generator"),
 | 
					 | 
				
			||||||
                Some("cave_automata") => level_gen::cave_automata::generate(
 | 
					 | 
				
			||||||
                    &Default::default(),
 | 
					 | 
				
			||||||
                    &mut rand,
 | 
					 | 
				
			||||||
                ),
 | 
					 | 
				
			||||||
                Some(gen) => panic!("Unrecognized generator: {}", gen),
 | 
					 | 
				
			||||||
            };
 | 
					 | 
				
			||||||
            level_gen::display::print_generated_level(&level, &mut stdout)
 | 
					 | 
				
			||||||
                .unwrap();
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        _ => {
 | 
					        _ => {
 | 
				
			||||||
            let stdout = stdout.into_raw_mode().unwrap();
 | 
					            let stdout = stdout.into_raw_mode().unwrap();
 | 
				
			||||||
            init(settings, stdout, stdin, termwidth, termheight);
 | 
					            init(settings, stdout, stdin, termwidth, termheight)
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -24,6 +24,12 @@ pub struct Dimensions {
 | 
				
			||||||
pub const ZERO_DIMENSIONS: Dimensions = Dimensions { w: 0, h: 0 };
 | 
					pub const ZERO_DIMENSIONS: Dimensions = Dimensions { w: 0, h: 0 };
 | 
				
			||||||
pub const UNIT_DIMENSIONS: Dimensions = Dimensions { w: 1, h: 1 };
 | 
					pub const UNIT_DIMENSIONS: Dimensions = Dimensions { w: 1, h: 1 };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl Default for Dimensions {
 | 
				
			||||||
 | 
					    fn default() -> Self {
 | 
				
			||||||
 | 
					        Dimensions { w: 80, h: 20 }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl ops::Sub<Dimensions> for Dimensions {
 | 
					impl ops::Sub<Dimensions> for Dimensions {
 | 
				
			||||||
    type Output = Dimensions;
 | 
					    type Output = Dimensions;
 | 
				
			||||||
    fn sub(self, dims: Dimensions) -> Dimensions {
 | 
					    fn sub(self, dims: Dimensions) -> Dimensions {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue