Compare commits
3 Commits
6bec93765a
...
3838052cf5
Author | SHA1 | Date |
---|---|---|
Nat | 3838052cf5 | |
Nat | d48a021f85 | |
Nat | db7df4da37 |
|
@ -0,0 +1,131 @@
|
|||
use std::collections::{BTreeMap};
|
||||
|
||||
pub enum ArgumentFormat {
|
||||
Flag,
|
||||
Store
|
||||
}
|
||||
|
||||
pub struct FlagArgument {
|
||||
pub short_name: char,
|
||||
pub long_name: &'static str,
|
||||
pub description: &'static str,
|
||||
pub format: ArgumentFormat,
|
||||
pub required: bool,
|
||||
pub default: Option<&'static str>
|
||||
}
|
||||
|
||||
pub struct PositionalArgument {
|
||||
pub long_name: &'static str,
|
||||
pub description: &'static str,
|
||||
pub default: Option<&'static str>,
|
||||
pub required: bool,
|
||||
}
|
||||
|
||||
pub struct ArgumentCollection {
|
||||
storage_map: BTreeMap<&'static str, String>
|
||||
}
|
||||
|
||||
pub fn parse_arguments(
|
||||
accepted_flag_arguments: Vec<FlagArgument>,
|
||||
mut accepted_positional_arguments: Vec<PositionalArgument>,
|
||||
arguments: Vec<String>
|
||||
) -> Result<ArgumentCollection, String> {
|
||||
let mut accepted_long_arguments: BTreeMap<&'static str, FlagArgument> = BTreeMap::new();
|
||||
let mut accepted_short_arguments: BTreeMap<char, &'static str> = BTreeMap::new();
|
||||
let mut storage_map: BTreeMap<&'static str, String> = BTreeMap::new();
|
||||
|
||||
// Re-map the flag arguments for ease of access when parsing
|
||||
for argument in accepted_flag_arguments {
|
||||
let long_name = argument.long_name;
|
||||
let short_name = argument.short_name;
|
||||
|
||||
if argument.default.is_some() {
|
||||
storage_map.insert(long_name, argument.default.unwrap().to_string());
|
||||
}
|
||||
|
||||
accepted_long_arguments.insert(long_name, argument);
|
||||
accepted_short_arguments.insert(
|
||||
short_name,
|
||||
long_name
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
let positional_argument_count = accepted_positional_arguments.len();
|
||||
|
||||
// `.pop()` takes from the back of the vector, so we need to reverse it
|
||||
let mut reversed_arguments = arguments.clone();
|
||||
reversed_arguments.reverse();
|
||||
|
||||
// The first argument is always the binary name
|
||||
let _ = reversed_arguments.pop();
|
||||
|
||||
while let Some(arg) = reversed_arguments.pop() {
|
||||
if arg.starts_with("-") {
|
||||
let argument_struct = if arg.starts_with("--") {
|
||||
match accepted_long_arguments.get(&arg[2..]) {
|
||||
Some(a) => a,
|
||||
None => return Err(format!("Unknown argument: {arg}"))
|
||||
}
|
||||
} else {
|
||||
let long_name = match accepted_short_arguments.get(&arg[1..].chars().next().unwrap()) {
|
||||
Some(a) => a,
|
||||
None => return Err(format!("Unknown argument: {arg}"))
|
||||
};
|
||||
|
||||
accepted_long_arguments.get(long_name).unwrap()
|
||||
};
|
||||
|
||||
let value_to_store = match argument_struct.format {
|
||||
ArgumentFormat::Flag => "".to_string(),
|
||||
ArgumentFormat::Store => match reversed_arguments.pop() {
|
||||
Some(v) => v,
|
||||
None => return Err(format!("Missing value for argument {arg}"))
|
||||
}
|
||||
};
|
||||
|
||||
storage_map.insert(argument_struct.long_name, value_to_store);
|
||||
} else {
|
||||
let positional_argument = accepted_positional_arguments.pop()
|
||||
.expect(format!("Too many positional arguments given. Limit: {positional_argument_count}").as_str());
|
||||
|
||||
storage_map.insert(positional_argument.long_name, arg);
|
||||
}
|
||||
}
|
||||
|
||||
for argument in accepted_long_arguments.values() {
|
||||
if !storage_map.contains_key(argument.long_name) {
|
||||
if argument.required {
|
||||
panic!("Missing required flag: --{}", argument.long_name);
|
||||
}
|
||||
|
||||
if argument.default.is_some() {
|
||||
storage_map.insert(argument.long_name, argument.default.unwrap().to_string());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for argument in accepted_positional_arguments {
|
||||
if storage_map.get(argument.long_name).is_none() {
|
||||
if argument.required {
|
||||
panic!("Missing required positional argument: {}", argument.long_name);
|
||||
}
|
||||
|
||||
if argument.default.is_some() {
|
||||
storage_map.insert(argument.long_name, argument.default.unwrap().to_string());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(ArgumentCollection { storage_map: storage_map })
|
||||
}
|
||||
|
||||
impl ArgumentCollection {
|
||||
pub fn get(&self, arg: &str) -> &String {
|
||||
self.storage_map.get(arg).expect(format!("Unknown argument: {arg}").as_str())
|
||||
}
|
||||
|
||||
pub fn flag(&self, arg: &str) -> bool {
|
||||
self.storage_map.contains_key(arg)
|
||||
}
|
||||
}
|
|
@ -5,6 +5,7 @@ use std::io::Read;
|
|||
use std::collections::{VecDeque, HashMap, BTreeSet, BTreeMap};
|
||||
|
||||
use ponderosa::{math, stack, state, control, forestry};
|
||||
use ponderosa::arguments::{parse_arguments, PositionalArgument, FlagArgument, ArgumentFormat};
|
||||
|
||||
fn parse_rom(path: &String) -> io::Result<(state::Land, Vec<state::Rule>, HashMap<u16, state::Tree>)> {
|
||||
let mut rom_file = File::open(path)?;
|
||||
|
@ -66,13 +67,7 @@ fn parse_rom(path: &String) -> io::Result<(state::Land, Vec<state::Rule>, HashMa
|
|||
}
|
||||
|
||||
println!("World\n=====");
|
||||
|
||||
for y in (0..land.height).rev() {
|
||||
for x in 0..land.width {
|
||||
print!("{}\t", land.map.get(&(x, y)).unwrap_or(&0u16));
|
||||
}
|
||||
println!();
|
||||
}
|
||||
dbg!(&land);
|
||||
|
||||
rom_words.pop_front().unwrap(); // null-word delimiter
|
||||
|
||||
|
@ -106,15 +101,41 @@ fn parse_rom(path: &String) -> io::Result<(state::Land, Vec<state::Rule>, HashMa
|
|||
}
|
||||
|
||||
fn main() -> io::Result<()> {
|
||||
let args: Vec<String> = env::args().collect();
|
||||
let rom_path = &args[1];
|
||||
let unparsed_args: Vec<String> = env::args().collect();
|
||||
|
||||
let positional_arguments = vec![
|
||||
PositionalArgument {
|
||||
long_name: "path",
|
||||
description: "Path to the compiled ROM file",
|
||||
required: true,
|
||||
default: None
|
||||
},
|
||||
];
|
||||
|
||||
let flag_arguments = vec![
|
||||
FlagArgument {
|
||||
long_name: "generations",
|
||||
short_name: 'g',
|
||||
description: "Number of generations before halting. If 0, the program will run until all trees have been composted",
|
||||
format: ArgumentFormat::Store,
|
||||
required: false,
|
||||
default: Some("1")
|
||||
},
|
||||
];
|
||||
|
||||
let arguments = match parse_arguments(flag_arguments, positional_arguments, unparsed_args) {
|
||||
Ok(map) => map,
|
||||
Err(e) => panic!("{}", e),
|
||||
};
|
||||
|
||||
let rom_path = &arguments.get("path");
|
||||
|
||||
let (mut land, mut rules, mut trees) = parse_rom(rom_path).unwrap();
|
||||
let mut scheduled_trees = vec![0u16];
|
||||
|
||||
let mut next_tree_id = 1u16;
|
||||
|
||||
let generation_count = 1;
|
||||
let generation_count = arguments.get("generations").parse::<u16>().unwrap();
|
||||
|
||||
for _ in 0..generation_count {
|
||||
let mut trees_to_plant: Vec<state::Tree> = Vec::new();
|
||||
|
@ -227,13 +248,7 @@ fn main() -> io::Result<()> {
|
|||
}
|
||||
|
||||
println!("Resulting World\n=====");
|
||||
|
||||
for y in (0..land.height).rev() {
|
||||
for x in 0..land.width {
|
||||
print!("{}\t", land.map.get(&(x, y)).unwrap_or(&0u16));
|
||||
}
|
||||
println!();
|
||||
}
|
||||
dbg!(land);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -3,3 +3,4 @@ pub mod stack;
|
|||
pub mod state;
|
||||
pub mod control;
|
||||
pub mod forestry;
|
||||
pub mod arguments;
|
||||
|
|
|
@ -12,7 +12,7 @@ macro_rules! define_binary_op {
|
|||
let $left = tree.pull_by_stack_code((stack_code & 0b100) >> 2);
|
||||
let $right = tree.pull_by_stack_code((stack_code & 0b010) >> 1);
|
||||
|
||||
let $right = if !use_literal { $left } else { literal };
|
||||
let $right = if !use_literal { $right } else { literal };
|
||||
|
||||
if is_signed {
|
||||
let $left = $left as i16;
|
||||
|
|
15
src/state.rs
15
src/state.rs
|
@ -92,6 +92,21 @@ impl Land {
|
|||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for Land {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
let mut built_string = "\n".to_owned();
|
||||
|
||||
for y in (0..self.height).rev() {
|
||||
for x in 0..self.width {
|
||||
built_string.push_str(&format!("{}\t", self.map.get(&(x, y)).unwrap_or(&0u16)));
|
||||
}
|
||||
built_string.push_str("\n");
|
||||
}
|
||||
|
||||
write!(f, "{}", built_string)
|
||||
}
|
||||
}
|
||||
|
||||
pub type Rule = VecDeque<u16>;
|
||||
|
||||
pub struct Tree {
|
||||
|
|
Loading…
Reference in New Issue