123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144 |
- use clap::{ArgAction, Parser};
- use crate::{MissingTilePolicy, TileSelectionPolicy, VacancyPolicy};
- /// Program to generate a larger image made up of different image tiles of the
- /// same size
- #[cfg_attr(test, derive(Clone, Debug))]
- #[derive(Parser)]
- #[command(author, version, about)]
- #[deny(missing_docs)]
- pub struct Arguments {
- /// Number of rows
- pub rows: u16,
- /// Number of columns
- pub cols: u16,
- /// Optional connector name that tiles must exhibit towards the border of
- /// the image; if this option is omitted, bordering tiles may have any
- /// connection towards the border.
- #[arg(short, long, value_name = "CONNECTOR_NAME")]
- pub border: Option<String>,
- /// Optional path to a tile configuration file; overrides any configuration
- /// file in the tile directory.
- #[arg(short, long, group = "config_arg_group", value_name = "PATH")]
- pub config: Option<String>,
- /// Optional path to a tile directory; if omitted, assume the current
- /// working directory.
- ///
- /// The directory may contain a tile configuration file named “config.yaml”.
- #[arg(short = 'd', long, value_name = "PATH")]
- pub tile_directory: Option<String>,
- #[rustfmt::skip]
- /// Optional policy name that specifies how to behave in case there is no
- /// tile with a required connectors list.
- ///
- /// MISSING_TILE_POLICY may have one of the following values:
- ///
- /// avoid:{n}
- /// Try to avoid leaving empty positions in the tile grid. This may
- /// take a considerable amount of time and memory to finish due to
- /// backtracking. The run may terminate unsuccessfully in case there
- /// is no solution.
- ///
- /// exit:{n}
- /// Exit immediately if there is no fitting tile; this may be useful
- /// for debugging tile configurations.
- #[arg(short, long, default_value_t = MissingTilePolicy::Avoid)]
- pub missing_tile_policy: MissingTilePolicy,
- /// Do not use any user defined tile configuration; Instead, assume all
- /// tiles have the connectors
- /// { north: “c”, east: “c”, south: “c”, west: “c” } and a weight of 1.
- // TODO: Implement error message when no configuration is passed and no_config is false.
- #[arg(short, long, group = "config_arg_group", action = ArgAction::SetTrue)]
- pub no_config: bool,
- /// Path to the output file.
- #[arg(short, long, value_name = "PATH", default_value = "output/tiled")]
- pub output: String,
- #[rustfmt::skip]
- /// Optional policy name that specifies how to handle vacant areas.
- ///
- /// VACANCY_POLICY may have one of the following values:
- ///
- /// avoid:{n}
- /// Try to avoid leaving vacant areas in the tile grid. This may take a
- /// considerable amount of time and memory to finish due to backtracking.
- /// The run may terminate unsuccessfully in case there is no solution.
- ///
- /// avoid-strict:{n}
- /// Same as avoid, but searches the entire problem space for a valid
- /// solution, if necessary, which might be much slower.
- ///
- /// ignore:{n}
- /// Ignore and vacant areas in the tile grid untouched.
- #[arg(short, long, default_value_t = VacancyPolicy::Avoid)]
- pub vacancy_policy: VacancyPolicy,
- #[rustfmt::skip]
- /// Optional policy name that specifies how to select tiles in case multiple
- /// fit into a slot.
- ///
- /// TILE_SELECTION_POLICY may have one of the following values:
- ///
- /// random:{n}
- /// Select a fitting tile at random using the provided weights. The tile
- /// weights need to be non-negative and their sum must not be zero.
- ///
- /// priority:{n}
- /// Select the tile with the greatest weight that fits.
- #[arg(short = 's', long, default_value_t = TileSelectionPolicy::Random)]
- pub tile_selection_policy: TileSelectionPolicy,
- }
- #[cfg(test)]
- mod tests {
- use super::*;
- use crate::test_utils::{
- RANDOM_BOOL,
- RANDOM_MISSING_TILE_POLICY,
- RANDOM_STRINGS,
- RANDOM_TILE_SELECTION_POLICY,
- RANDOM_USIZES,
- RANDOM_VACANCY_POLICY,
- };
- #[test]
- fn test_initialization() {
- let arguments = Arguments {
- rows: RANDOM_USIZES[0] as u16 + 1,
- cols: RANDOM_USIZES[1] as u16 + 1,
- config: Some(RANDOM_STRINGS[0].clone()),
- border: Some(RANDOM_STRINGS[1].clone()),
- missing_tile_policy: RANDOM_MISSING_TILE_POLICY.clone(),
- no_config: *RANDOM_BOOL,
- output: RANDOM_STRINGS[2].clone(),
- tile_directory: Some(RANDOM_STRINGS[3].clone()),
- vacancy_policy: RANDOM_VACANCY_POLICY.clone(),
- tile_selection_policy: RANDOM_TILE_SELECTION_POLICY.clone(),
- };
- assert_eq!(RANDOM_USIZES[0] as u16 + 1, arguments.rows);
- assert_eq!(RANDOM_USIZES[1] as u16 + 1, arguments.cols);
- assert_eq!(Some(RANDOM_STRINGS[0].clone()), arguments.config);
- assert_eq!(Some(RANDOM_STRINGS[1].clone()), arguments.border);
- assert_eq!(
- arguments.missing_tile_policy,
- RANDOM_MISSING_TILE_POLICY.clone()
- );
- assert_eq!(arguments.no_config, *RANDOM_BOOL);
- assert_eq!(arguments.output, RANDOM_STRINGS[2].clone());
- assert_eq!(arguments.tile_directory, Some(RANDOM_STRINGS[3].clone()));
- assert_eq!(arguments.vacancy_policy, RANDOM_VACANCY_POLICY.clone());
- assert_eq!(
- arguments.tile_selection_policy,
- RANDOM_TILE_SELECTION_POLICY.clone()
- );
- }
- }
|