about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/cli.yml26
-rw-r--r--src/level_gen/cave_automata.rs48
-rw-r--r--src/main.rs51
-rw-r--r--src/types/mod.rs6
4 files changed, 106 insertions, 25 deletions
diff --git a/src/cli.yml b/src/cli.yml
index 937b44c9c6f9..4b2e94e57b0e 100644
--- a/src/cli.yml
+++ b/src/cli.yml
@@ -10,7 +10,7 @@ args:
       help: Sets a custom config file
       takes_value: true
 subcommands:
-  - debug:
+  - info:
       about: Writes debug information to the terminal and exits
   - generate-level:
       about: Generate a level and print it to the screen
@@ -20,3 +20,27 @@ subcommands:
           value_name: GEN
           help: Select which generator to use
           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
diff --git a/src/level_gen/cave_automata.rs b/src/level_gen/cave_automata.rs
index e46d542e6955..6a237c0303df 100644
--- a/src/level_gen/cave_automata.rs
+++ b/src/level_gen/cave_automata.rs
@@ -4,17 +4,46 @@ use rand::Rng;
 
 pub struct Params {
     chance_to_start_alive: f64,
-    dimensions: Dimensions,
     birth_limit: i32,
     death_limit: i32,
     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 {
     fn default() -> Self {
         Params {
             chance_to_start_alive: 0.45,
-            dimensions: Dimensions { w: 80, h: 20 },
             birth_limit: 4,
             death_limit: 3,
             steps: 2,
@@ -23,21 +52,26 @@ impl Default for Params {
 }
 
 pub fn generate<R: Rng + ?Sized>(
+    dimensions: &Dimensions,
     params: &Params,
     rand: &mut R,
 ) -> Vec<Vec<bool>> {
     let mut cells =
-        rand_initialize(&params.dimensions, rand, params.chance_to_start_alive);
+        rand_initialize(&dimensions, rand, params.chance_to_start_alive);
     for _ in 0..params.steps {
-        step_automata(&mut cells, params);
+        step_automata(&mut cells, dimensions, params);
     }
     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();
-    for x in 0..(params.dimensions.h as usize) {
-        for y in 0..(params.dimensions.w as usize) {
+    for x in 0..(dimensions.h as usize) {
+        for y in 0..(dimensions.w as usize) {
             let nbs = num_alive_neighbors(&orig_cells, x as i32, y as i32);
             if orig_cells[x][y] {
                 if nbs < params.death_limit {
diff --git a/src/main.rs b/src/main.rs
index 8479b5fa437c..dc958ca1a16d 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -39,6 +39,7 @@ mod level_gen;
 mod messages;
 mod settings;
 
+use crate::types::Dimensions;
 use clap::App;
 use game::Game;
 use prettytable::format::consts::FORMAT_BOX_CHARS;
@@ -59,7 +60,7 @@ fn init(
     stdin: StdinLock<'_>,
     w: u16,
     h: u16,
-) {
+) -> io::Result<()> {
     panic::set_hook(if settings.logging.print_backtrace {
         Box::new(|info| (error!("{}\n{:#?}", info, Backtrace::new())))
     } else {
@@ -67,10 +68,36 @@ fn init(
     });
 
     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 matches = App::from_yaml(yaml).get_matches();
     let settings = Settings::load().unwrap();
@@ -85,7 +112,7 @@ fn main() {
     let (termwidth, termheight) = termsize.unwrap_or((70, 40));
 
     match matches.subcommand() {
-        ("debug", _) => {
+        ("info", _) => {
             let mut table = table!(
                 [br->"termwidth", termwidth],
                 [br->"termheight", termheight],
@@ -94,24 +121,14 @@ fn main() {
             );
             table.set_format(*FORMAT_BOX_CHARS);
             table.printstd();
+            Ok(())
         }
         ("generate-level", params) => {
-            let params = 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();
+            generate_level(&mut stdout, params.unwrap())
         }
         _ => {
             let stdout = stdout.into_raw_mode().unwrap();
-            init(settings, stdout, stdin, termwidth, termheight);
+            init(settings, stdout, stdin, termwidth, termheight)
         }
     }
 }
diff --git a/src/types/mod.rs b/src/types/mod.rs
index 1e86fb369e86..e656048e873c 100644
--- a/src/types/mod.rs
+++ b/src/types/mod.rs
@@ -24,6 +24,12 @@ pub struct Dimensions {
 pub const ZERO_DIMENSIONS: Dimensions = Dimensions { w: 0, h: 0 };
 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 {
     type Output = Dimensions;
     fn sub(self, dims: Dimensions) -> Dimensions {