initiative_core/world/place/location/geographical/
canyon.rs

1use crate::world::place::PlaceData;
2use crate::world::Demographics;
3use rand::prelude::*;
4
5pub fn generate(place: &mut PlaceData, rng: &mut impl Rng, _demographics: &Demographics) {
6    place.name.replace_with(|_| name(rng));
7}
8
9fn name(rng: &mut impl Rng) -> String {
10    match rng.gen_range(0..=7) {
11        0 => format!("The {} {}", placement(rng), canyon_synonym(rng)),
12        1 => format!("{} {}", cardinal_direction(rng), canyon_synonym(rng)),
13        2 => format!("{} {}", adjective(rng), canyon_synonym(rng)),
14        3 => format!("{} {} {}", adjective(rng), thing(rng), canyon_synonym(rng)),
15        4..=5 => format!("{} {}", thing(rng), canyon_synonym(rng)),
16        6..=7 => format!("{}'s {}", profession(rng), canyon_synonym(rng)),
17        _ => unreachable!(),
18    }
19}
20
21fn thing(rng: &mut impl Rng) -> &'static str {
22    match rng.gen_range(0..=9) {
23        0 => other_animal(rng),
24        1..=4 => canyon_animal(rng),
25        5 => enemy(rng),
26        6 => food(rng),
27        7 => profession(rng),
28        8 => symbol(rng),
29        9 => gem(rng),
30        _ => unreachable!(),
31    }
32}
33
34fn adjective(rng: &mut impl Rng) -> &'static str {
35    #[rustfmt::skip]
36    const ADJECTIVES: &[&str] = &[
37        "Angry", "Awkward", "Bloated", "Driven", "Elegant", "Engorged",
38        "Enchanted", "Gold", "Green", "Grey", "Grouchy", "Hallowed", "Happy",
39        "Hidden", "Hungry", "Jovial", "Lone", "Lost", "Lucky", "Merry", "Moody",
40        "Morose", "Quiet", "Red", "Sickly", "Silent", "Silver", "Slim",
41        "Slender", "Solemn", "Starved", "Stoic", "Thirsty", "Wasted", "Wild",
42        "White", "Yellow"
43    ];
44    ADJECTIVES[rng.gen_range(0..ADJECTIVES.len())]
45}
46
47fn canyon_synonym(rng: &mut impl Rng) -> &'static str {
48    #[rustfmt::skip]
49    const CANYON_SYNONYMS: &[&str] = &[
50        // Doubling-up on some options to increase odds as per this discussion
51        // `github.com/initiative-sh/initiative.sh/pull/313/files/2b3195490641b537abbaab23aa38e279a4fb1216#r1331670310`
52        // Could use rand::distributions::WeightedIndex in future if desired.
53        "Canyon", "Canyon", "Ravine", "Ravine", "Gorge", "Gorge", "Crevice",
54        "Gap", "Abyss", "Flume", "Fissure", "Trench"
55    ];
56    CANYON_SYNONYMS[rng.gen_range(0..CANYON_SYNONYMS.len())]
57}
58
59fn other_animal(rng: &mut impl Rng) -> &'static str {
60    #[rustfmt::skip]
61    const LAND_ANIMALS: &[&str] = &[
62        "Antelope", "Ape", "Baboon", "Bat", "Bear", "Beaver", "Bee", "Beetle",
63        "Boar", "Cow", "Deer", "Dove", "Dragonfly", "Duck", "Elephant", "Elk",
64        "Ermine", "Frog", "Goose", "Hart", "Hedgehog", "Heron", "Herring",
65        "Horse", "Hound", "Lamb", "Leopard", "Lion", "Magpie", "Mole",
66        "Panther", "Peacock", "Phoenix", "Porcupine", "Rat", "Raven",
67        "Salamander", "Sheep", "Squid", "Squirrel", "Stag", "Stoat", "Stork",
68        "Swan", "Tiger", "Toad", "Turkey", "Turtle", "Unicorn", "Weasel"
69    ];
70    LAND_ANIMALS[rng.gen_range(0..LAND_ANIMALS.len())]
71}
72
73fn canyon_animal(rng: &mut impl Rng) -> &'static str {
74    #[rustfmt::skip]
75    const CANYON_ANIMALS: &[&str] = &[
76        "Camel", "Badger", "Scorpion", "Beetle", "Fox", "Gecko", "Viper",
77        "Snake", "Vulture", "Condor", "Dog", "Donkey", "Mule", "Owl", "Hyena",
78        "Coyote", "Lizard", "Cat", "Eagle", "Goat", "Ram", "Hawk", "Tortoise",
79        "Hare", "Ram", "Pony", "Rabbit", "Wolf"
80    ];
81    CANYON_ANIMALS[rng.gen_range(0..CANYON_ANIMALS.len())]
82}
83
84fn enemy(rng: &mut impl Rng) -> &'static str {
85    #[rustfmt::skip]
86    const ENEMIES: &[&str] = &[
87        "Angel", "Bandit", "Brigand", "Centaur", "Chimera", "Demon", "Devil",
88        "Dragon", "Fairy", "Ghost", "Giant", "Goblin", "Gorgon", "Gremlin",
89        "Hag","Harpy", "Hydra", "Imp", "Kappa", "Lich", "Manticore", "Minotaur",
90        "Necromancer", "Oni", "Orc", "Peryton", "Pirate", "Roc", "Satyr",
91        "Seraph", "Siren", "Sorcerer", "Sphinx", "Thief", "Trickster", "Troll",
92        "Unicorn", "Vampire", "Werewolf", "Witch", "Wyvern", "Zombie",
93    ];
94    ENEMIES[rng.gen_range(0..ENEMIES.len())]
95}
96
97fn food(rng: &mut impl Rng) -> &'static str {
98    #[rustfmt::skip]
99    const FOODS: &[&str] = &[
100        "Barley", "Barrel", "Beef", "Beer", "Bread", "Cask", "Cheese", "Hop",
101        "Keg", "Malt", "Mead", "Meat", "Mutton", "Pint", "Pork", "Potatoes",
102        "Rye", "Tun", "Veal", "Venison", "Vine",
103    ];
104    FOODS[rng.gen_range(0..FOODS.len())]
105}
106
107fn gem(rng: &mut impl Rng) -> &'static str {
108    #[rustfmt::skip]
109    const GEMS: &[&str] = &[
110        "Amber", "Agate", "Amethyst", "Aquamarine", "Beryl", "Citrine",
111        "Diamond", "Emerald", "Opal", "Quartz", "Sapphire", "Topaz"
112    ];
113    GEMS[rng.gen_range(0..GEMS.len())]
114}
115
116fn placement(rng: &mut impl Rng) -> &'static str {
117    #[rustfmt::skip]
118    const PLACEMENT: &[&str] = &["First", "Last"];
119    PLACEMENT[rng.gen_range(0..PLACEMENT.len())]
120}
121
122fn cardinal_direction(rng: &mut impl Rng) -> &'static str {
123    const CARDINAL_DIRS: &[&str] = &["North", "South", "East", "West"];
124    CARDINAL_DIRS[rng.gen_range(0..CARDINAL_DIRS.len())]
125}
126
127fn profession(rng: &mut impl Rng) -> &'static str {
128    #[rustfmt::skip]
129    const PROFESSIONS: &[&str] = &[
130        "Adventurer", "Baker", "Beggar", "Blacksmith", "Brewer", "Bricklayer",
131        "Builder", "Butcher", "Carpenter", "Conjurer", "Cooper", "Diviner",
132        "Enchanter", "Evoker", "Farrier", "Ferryman", "Fisherman", "Glazier",
133        "Illusionist", "Knight", "Mage", "Magician", "Mason", "Miller",
134        "Plumber", "Porter", "Printer", "Roper", "Sailor", "Shipwright",
135        "Smith", "Soldier", "Waterman", "Warrior", "Wizard",
136    ];
137    PROFESSIONS[rng.gen_range(0..PROFESSIONS.len())]
138}
139
140fn symbol(rng: &mut impl Rng) -> &'static str {
141    #[rustfmt::skip]
142    const SYMBOLS: &[&str] = &[
143        "Abbey", "Anchor", "Anvil", "Arrow", "Axe", "Belfry", "Bell", "Book",
144        "Buckle", "Cap", "Castle", "Column", "Crescent", "Crown", "Drum",
145        "Feather", "Foil", "Hammer", "Harp", "Harrow", "Helmet", "Horseshoe",
146        "Key", "Lance", "Lance", "Locket", "Mace", "Mill", "Mitre", "Moon",
147        "Nail", "Oar", "Phalactary", "Rake", "Rook", "Scale", "Sceptre",
148        "Scythe", "Ship", "Shovel", "Spear", "Spur", "Star", "Steeple", "Sun",
149        "Sword", "Thunderbolt", "Tower", "Trumpet", "Wand", "Wheel",
150    ];
151    SYMBOLS[rng.gen_range(0..SYMBOLS.len())]
152}
153
154#[cfg(test)]
155mod test {
156    use super::*;
157
158    #[test]
159    fn name_test() {
160        let mut rng = SmallRng::seed_from_u64(4);
161
162        #[rustfmt::skip]
163        assert_eq!(
164            ["Printer Gorge", "Viper Gorge", "The Last Flume", "West Fissure",
165             "Mage Canyon", "The First Crevice", "Tortoise Fissure",
166             "Badger Fissure", "Rye Ravine", "Porter's Fissure", "Ram Gorge",
167             "Cooper's Fissure", "Evoker's Abyss", "Porter's Ravine",
168             "Keg Flume", "Smith's Ravine", "Rabbit Trench", "Grey Pork Flume",
169             "Plumber Canyon", "Gorgon Canyon"]
170            .iter()
171            .map(|s| s.to_string())
172            .collect::<Vec<_>>(),
173            (0..20).map(|_| name(&mut rng)).collect::<Vec<String>>(),
174        );
175    }
176}