diff options
| author | Andreas Grois <andi@grois.info> | 2023-04-02 21:38:17 +0200 |
|---|---|---|
| committer | Andreas Grois <andi@grois.info> | 2023-04-02 21:53:09 +0200 |
| commit | 418f514fc46f45ae2901753e3398adb33664bed9 (patch) | |
| tree | f8edc0df880a00d4964877d4b835c0eb9e481210 /examples/text-adventure | |
| parent | 02d01dd1b544a576caeb8da42912c5db904b94bd (diff) | |
I, for one, welcome our new clippy overlords
Diffstat (limited to 'examples/text-adventure')
| -rw-r--r-- | examples/text-adventure/data.rs | 25 | ||||
| -rw-r--r-- | examples/text-adventure/dsl.rs | 2 | ||||
| -rw-r--r-- | examples/text-adventure/logic.rs | 22 | ||||
| -rw-r--r-- | examples/text-adventure/main.rs | 16 | ||||
| -rw-r--r-- | examples/text-adventure/side_effects.rs | 10 |
5 files changed, 31 insertions, 44 deletions
diff --git a/examples/text-adventure/data.rs b/examples/text-adventure/data.rs index 2c12bb0..3e9c49e 100644 --- a/examples/text-adventure/data.rs +++ b/examples/text-adventure/data.rs @@ -83,19 +83,13 @@ pub enum Item{ impl Item { fn price(self) -> usize { match self { - Item::SausageRoll => 300, - Item::Pickles => 250, - Item::Milk => 125, - Item::Yoghurt => 125, + Item::SausageRoll | Item::FishSandwich | Item::Shots => 300, + Item::Pickles | Item::Pulp => 250, + Item::Milk | Item::Yoghurt | Item::Beer => 125, Item::Cheese => 750, Item::CatFood => 2500, - Item::Beer => 125, Item::ToiletPaper => 500, - Item::FishSandwich => 300, Item::ChewingGum => 100, - Item::Shots => 300, - Item::Pulp => 250, - } } pub fn description(self) -> &'static str { @@ -112,7 +106,6 @@ impl Item { Item::ChewingGum => "A pack of chewing gum, costing €1.00", Item::Shots => "A shot of a sad excuse for whisky, costing €3.00", Item::Pulp => "A pulp novel called \"Aliens ate my trashbin\", which should not cost the €2.50 it does", - } } } @@ -131,17 +124,11 @@ impl Location{ //In a real project I would probably aim to make this Copy as well, especially if it's as small as this. //I left it as Clone intentionally, to illustrate how one can work around the limitation of it not being Copy. -#[derive(Clone)] +#[derive(Clone, Default)] pub struct Inventory { pub items : Vec<Item>, } -impl Default for Inventory{ - fn default() -> Self { - Self { items: Default::default() } - } -} - impl Inventory{ pub fn has_item_from_room(&self, room : Location) -> bool { let items_from_room = room.items(); @@ -151,7 +138,7 @@ impl Inventory{ if self.items.len() < 3 { let mut items = self.items; items.push(item); //am I the only one that hates that push doesn't return the updated vec? - Ok(Inventory{items, ..self}) + Ok(Inventory{items}) } else { Err(self) } @@ -170,7 +157,7 @@ impl Inventory{ "€10.00" //It doesn't change. Can as well be a constant. } pub fn total_price(&self) -> usize { - self.items.iter().cloned().map(Item::price).sum::<usize>() + self.items.iter().copied().map(Item::price).sum::<usize>() } pub fn can_afford(&self) -> bool { self.total_price() <= 1000_usize diff --git a/examples/text-adventure/dsl.rs b/examples/text-adventure/dsl.rs index 44bc978..c448f04 100644 --- a/examples/text-adventure/dsl.rs +++ b/examples/text-adventure/dsl.rs @@ -5,7 +5,7 @@ use std::{rc::Rc, borrow::Cow}; use higher_free_macro::free; use std::convert::identity; use higher::Functor; -use super::data::*; +use super::data::{Location, Mood, Speaker}; #[derive(Clone)] pub enum SausageRoll<'a, 's,A>{ diff --git a/examples/text-adventure/logic.rs b/examples/text-adventure/logic.rs index dc3ff45..d884598 100644 --- a/examples/text-adventure/logic.rs +++ b/examples/text-adventure/logic.rs @@ -4,8 +4,8 @@ use std::borrow::Cow; use higher::{run, Functor, Pure, Bind}; -use super::data::*; -use super::dsl::*; +use super::data::{Inventory, Item, Location, Mood, Speaker}; +use super::dsl::{FreeSausageRoll, exposition, give_player_options, present_location, say_dialogue_line}; //Haskell has a when function, and it's nice. Sooo, copy that. macro_rules! when { @@ -24,7 +24,7 @@ pub fn game<'a,'s : 'a>() -> FreeSausageRoll<'a, 's, ()>{ c <= intro(); when!{c => { //handle_rooms is the main game loop: Go from room to room. - c <= handle_rooms(Location::Refrigerators, Default::default()); //can't destructure in assignment in higher-0.2. Maybe later. + c <= handle_rooms(Location::Refrigerators, Inventory::default()); //can't destructure in assignment in higher-0.2. Maybe later. //if we ended up here, we left the supermarket. ending(c.1) }} @@ -66,7 +66,7 @@ fn ending<'a,'s:'a>(inventory : Inventory) -> FreeSausageRoll<'a, 's, ()>{ } else { run!{ say_dialogue_line(Speaker::Partner, Cow::from("What did you do in there? I asked you to bring me a sausage roll..."), Mood::Annoyed); - when!{inventory.items.len() > 0 => { + when!{!inventory.items.is_empty() => { say_dialogue_line(Speaker::Partner, Cow::from("Also, why did you buy all that other stuff?"), Mood::Annoyed) }}; say_dialogue_line(Speaker::Partner, Cow::from("Well, let's move on, but don't complain if I get hangry on the way."), Mood::Annoyed) @@ -77,13 +77,11 @@ fn ending<'a,'s:'a>(inventory : Inventory) -> FreeSausageRoll<'a, 's, ()>{ fn handle_rooms<'a,'s:'a>(room: Location, inventory : Inventory) -> FreeSausageRoll<'a, 's, (Location, Inventory)>{ run!{ c <= handle_room(room, inventory); - if c.0 != Location::Entrance { + if c.0 == Location::Entrance { + FreeSausageRoll::pure(c) + } else { //If this were an actual game, we could put a save-point here. At this location the next room to handle is just determined by room and inventory. handle_rooms(c.0, c.1) - } else { - run!{ - yield c - } } } } @@ -185,7 +183,7 @@ fn handle_deli<'a,'s:'a>(inventory : Inventory) -> FreeSausageRoll<'a, 's, (Loca 3 => { run!{ i <= talk_to_deli_lady(inventory.clone()); - handle_deli(i.clone()) + handle_deli(i) } }, _ => unreachable!() @@ -215,7 +213,7 @@ fn handle_checkout<'a,'s:'a>(inventory : Inventory) -> FreeSausageRoll<'a, 's, ( FreeSausageRoll::pure((Location::Entrance, inventory.clone())) } }, - Err(inventory) => handle_checkout(inventory.clone()), + Err(inventory) => handle_checkout(inventory), } } }, @@ -275,7 +273,7 @@ fn return_item<'a,'s:'a>(inventory : Inventory, room : Location) -> FreeSausageR //similar to try_take_item here the inventory can't easily be captured. For illustration purposes, here we //don't pass it along as clones, but rather return from do-notation to capture it. let items_in_room = room.items(); - let carried_items_from_here = inventory.items.iter().filter(|i| items_in_room.contains(i)).cloned().collect::<Vec<_>>(); + let carried_items_from_here = inventory.items.iter().filter(|i| items_in_room.contains(i)).copied().collect::<Vec<_>>(); //ownership shmownership let carried_items_from_here2 = carried_items_from_here.clone(); let chosen = run! { diff --git a/examples/text-adventure/main.rs b/examples/text-adventure/main.rs index c98441b..1d538cc 100644 --- a/examples/text-adventure/main.rs +++ b/examples/text-adventure/main.rs @@ -1,3 +1,5 @@ +#![deny(clippy::pedantic)] +#![deny(clippy::all)] //! A small example text adventure, the logic of which is implemented as a Free Monad based eDSL. //! //! The goal of this game is to buy a sausage roll. With pickle. @@ -11,17 +13,17 @@ //! //! In a real project, I'd just make all game state (here: inventory) `Copy`, and use owned values wherever possible to make the code //! more concise. If `Copy` is not an option, I'd probably make a custom version of `run!{}` that allows to clone the -//! game state in a convenient way (see https://github.com/bodil/higher/issues/6). +//! game state in a convenient way (see [higher issue 6](https://github.com/bodil/higher/issues/6)). //! //! But on to the explanation what is going on: //! This project has 4 modules: -//! - "data" contains the data. Stuff like item types, item descriptions, rooms, etc. -//! - "dsl" contains the embedded domain specific language. In other words, a Functor and the corresponding Free Monad type (and some helpers) -//! - "logic" describes the game's main logic using the language defined in "dsl" -//! - "side_effects" actually runs the logic. +//! - `data` contains the data. Stuff like item types, item descriptions, rooms, etc. +//! - `dsl` contains the embedded domain specific language. In other words, a Functor and the corresponding Free Monad type (and some helpers) +//! - `logic` describes the game's main logic using the language defined in "dsl" +//! - `side_effects` actually runs the logic. //! -//! The important part here is that all the stuff that isn't in "side_effects" is independent of the concrete implementation of "side_effects". -//! The current "side_effects" runs a text-adventure, but it could just as well render as a visual-novel, without the need to touch any of the other modules. +//! The important part here is that all the stuff that isn't in `side_effects` is independent of the concrete implementation of `side_effects`. +//! The current `side_effects` runs a text-adventure, but it could just as well render as a visual-novel, without the need to touch any of the other modules. mod data; mod dsl; diff --git a/examples/text-adventure/side_effects.rs b/examples/text-adventure/side_effects.rs index ed0f9e1..dd911dd 100644 --- a/examples/text-adventure/side_effects.rs +++ b/examples/text-adventure/side_effects.rs @@ -11,23 +11,23 @@ pub fn run<'a, 's:'a>(mut game : FreeSausageRoll<'a, 's, ()>) -> std::io::Result while let FreeSausageRoll::Free(command) = game { game = match *command { crate::dsl::SausageRoll::SayDialogueLine { speaker, text, mood, next } => { - println!("{} says: \"{}\" with {} on their face.", speaker.text_description(), text, mood.text_description()); + println!("{} says: \"{text}\" with {} on their face.", speaker.text_description(), mood.text_description()); next }, crate::dsl::SausageRoll::GivePlayerOptions { options, next } => { println!("Your options are:"); for (id, option) in options.iter().enumerate().map(|(i,o)| (i+1,o)){ - println!("{}: {}", id, option); + println!("{id}: {option}"); } let mut input = String::new(); let mut chosen; - while let None = { + while { input.clear(); std::io::stdin().read_line(&mut input)?; chosen = input.trim().parse().ok().filter(|o : &usize| *o > 0 && *o <= options.len()); - chosen + chosen.is_none() } { println!("Invalid choice. Please select one of the options given above."); } @@ -39,7 +39,7 @@ pub fn run<'a, 's:'a>(mut game : FreeSausageRoll<'a, 's, ()>) -> std::io::Result next }, crate::dsl::SausageRoll::Exposition { text, next } => { - println!("{}", text); + println!("{text}"); next }, }; |
