mirror of
https://github.com/LukasKalbertodt/programmieren-in-rust.git
synced 2025-07-13 22:47:32 +02:00
Add forgotten solutions
This commit is contained in:
63
aufgaben/sheet10/sol2/src/cmd/choose.rs
Executable file
63
aufgaben/sheet10/sol2/src/cmd/choose.rs
Executable file
@ -0,0 +1,63 @@
|
||||
//! This subcommand chooses items from a list.
|
||||
//!
|
||||
|
||||
use clap::{Arg, ArgMatches, App, SubCommand};
|
||||
use rand::{self, Rng};
|
||||
use std::error::Error;
|
||||
|
||||
pub fn clap() -> App<'static, 'static> {
|
||||
SubCommand::with_name("choose")
|
||||
.about("Chooses one or more values from a list")
|
||||
.arg(
|
||||
Arg::with_name("count")
|
||||
.long("count")
|
||||
.short("c")
|
||||
.help("How many elements to choose")
|
||||
.takes_value(true)
|
||||
.validator(|s| {
|
||||
s.parse::<u64>()
|
||||
.map_err(|e| e.to_string())
|
||||
.and_then(|n| {
|
||||
if n == 1 {
|
||||
Err("number is smaller than 2".into())
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
})
|
||||
})
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("ELEMENTS")
|
||||
.help("The list to choose one item from (comma separated)")
|
||||
.required(true)
|
||||
.multiple(true)
|
||||
)
|
||||
}
|
||||
|
||||
pub fn exec(matches: &ArgMatches) -> Result<String, Box<Error>> {
|
||||
// Retrieve arguments
|
||||
let count = value_t!(matches, "count", u64).unwrap_or(1);
|
||||
let mut elements = values_t!(matches, "ELEMENTS", String).unwrap();
|
||||
|
||||
// Sanity check arguments
|
||||
if count > elements.len() as u64 {
|
||||
return Err("'count' argument is greater than the number of given elements".into());
|
||||
}
|
||||
|
||||
let mut rng = rand::thread_rng();
|
||||
|
||||
// Choose a random valid index, remove the respective element from the
|
||||
// input vector and insert it into the out vector. Repeat specified number
|
||||
// of times.
|
||||
let mut out = Vec::with_capacity(count as usize);
|
||||
for _ in 0..count {
|
||||
let idx = rng.gen_range(0, elements.len());
|
||||
out.push(elements.swap_remove(idx));
|
||||
}
|
||||
|
||||
if count == 1 {
|
||||
Ok(out[0].to_string())
|
||||
} else {
|
||||
Ok(format!("{:?}", out))
|
||||
}
|
||||
}
|
23
aufgaben/sheet10/sol2/src/cmd/coin.rs
Executable file
23
aufgaben/sheet10/sol2/src/cmd/coin.rs
Executable file
@ -0,0 +1,23 @@
|
||||
//! This subcommand flips a coin, returning either 'heads' or 'tails'
|
||||
//!
|
||||
|
||||
use clap::{ArgMatches, App, SubCommand};
|
||||
use rand::{self, Rng};
|
||||
use std::error::Error;
|
||||
|
||||
|
||||
pub fn clap() -> App<'static, 'static> {
|
||||
SubCommand::with_name("coin")
|
||||
.about("Flips a coin, returning either 'heads' or 'tails'")
|
||||
|
||||
}
|
||||
|
||||
pub fn exec(_: &ArgMatches) -> Result<String, Box<Error>> {
|
||||
let out = if rand::thread_rng().gen() {
|
||||
"heads"
|
||||
} else {
|
||||
"tails"
|
||||
};
|
||||
|
||||
Ok(out.into())
|
||||
}
|
36
aufgaben/sheet10/sol2/src/cmd/dice.rs
Executable file
36
aufgaben/sheet10/sol2/src/cmd/dice.rs
Executable file
@ -0,0 +1,36 @@
|
||||
//! This subcommand rolls a dice with a configurable number of sides, returning
|
||||
//! the number of the rolled dice.
|
||||
//!
|
||||
|
||||
use clap::{Arg, ArgMatches, App, SubCommand};
|
||||
use rand::{self, Rng};
|
||||
use std::error::Error;
|
||||
|
||||
pub fn clap() -> App<'static, 'static> {
|
||||
SubCommand::with_name("dice")
|
||||
.about("Rolls a dice")
|
||||
.arg(
|
||||
Arg::with_name("sides")
|
||||
.long("sides")
|
||||
.help("The number of sides of the dice")
|
||||
.takes_value(true)
|
||||
.validator(|s| {
|
||||
s.parse::<u64>()
|
||||
.map_err(|e| e.to_string())
|
||||
.and_then(|n| {
|
||||
if n <= 1 {
|
||||
Err("number is smaller than 2".into())
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
})
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
pub fn exec(matches: &ArgMatches) -> Result<String, Box<Error>> {
|
||||
let sides = value_t!(matches, "sides", u64).unwrap_or(6);
|
||||
|
||||
let num = rand::thread_rng().gen_range(1, sides);
|
||||
Ok(num.to_string())
|
||||
}
|
10
aufgaben/sheet10/sol2/src/cmd/mod.rs
Executable file
10
aufgaben/sheet10/sol2/src/cmd/mod.rs
Executable file
@ -0,0 +1,10 @@
|
||||
//! Contains all subcommands.
|
||||
//!
|
||||
//! Each subcommand's module has a `clap()` function which returns the clap
|
||||
//! structure describing the subcommand's command line use. The `exec()`
|
||||
//! function of each module executes the actual algorithm.
|
||||
//!
|
||||
|
||||
pub mod dice;
|
||||
pub mod coin;
|
||||
pub mod choose;
|
90
aufgaben/sheet10/sol2/src/main.rs
Executable file
90
aufgaben/sheet10/sol2/src/main.rs
Executable file
@ -0,0 +1,90 @@
|
||||
//! Flip -- command line utility for randomness tools
|
||||
//!
|
||||
//! This is a simple application which offers several small tools related to
|
||||
//! randomness. It uses the crates `clap` and `rand` for argument parsing and
|
||||
//! random number generation, respectively. Example usage:
|
||||
//!
|
||||
//! ```
|
||||
//! $ flip coin
|
||||
//! heads
|
||||
//! $ flip dice --sides=10
|
||||
//! 7
|
||||
//! $ flip choose --count=2 Peter Ursula Jürgen
|
||||
//! ["Peter", "Jürgen"]
|
||||
//! $ flip --times=3 coin
|
||||
//! heads
|
||||
//! heads
|
||||
//! tails
|
||||
//! ```
|
||||
|
||||
#[macro_use]
|
||||
extern crate clap;
|
||||
extern crate rand;
|
||||
|
||||
mod cmd;
|
||||
|
||||
use clap::{Arg, App, AppSettings};
|
||||
use std::str::FromStr;
|
||||
use std::error::Error;
|
||||
|
||||
|
||||
/// Does most of the work: parses the command line args and executes the
|
||||
/// subcommand.
|
||||
fn parse_and_exec() -> Result<(), Box<Error>> {
|
||||
let matches = App::new("Flip")
|
||||
.version(crate_version!())
|
||||
.author(crate_authors!())
|
||||
.about("Offers several tools related to randomness")
|
||||
.setting(AppSettings::SubcommandRequired)
|
||||
.arg(
|
||||
Arg::with_name("times")
|
||||
.short("t")
|
||||
.long("times")
|
||||
.takes_value(true)
|
||||
.validator(validate_parse::<u64>)
|
||||
.help("Executes the specified subcommand the given number of times")
|
||||
)
|
||||
.subcommand(cmd::coin::clap())
|
||||
.subcommand(cmd::dice::clap())
|
||||
.subcommand(cmd::choose::clap())
|
||||
.get_matches();
|
||||
|
||||
// Check what subcommand has been executed and fetch the matching
|
||||
// function and sub-matches.
|
||||
let (cmd_fn, sub_matches): (fn(_) -> _, _) = match matches.subcommand() {
|
||||
("coin", sub_matches) => (cmd::coin::exec, sub_matches.unwrap()),
|
||||
("dice", sub_matches) => (cmd::dice::exec, sub_matches.unwrap()),
|
||||
("choose", sub_matches) => (cmd::choose::exec, sub_matches.unwrap()),
|
||||
_ => unreachable!("We enabled 'SubcommandRequired' for clap!"),
|
||||
};
|
||||
|
||||
// We validate the string above. Thus, this will be an `Err` iff the
|
||||
// argument wasn't specified. In this case it defaults to 1.
|
||||
let times = value_t!(matches, "times", u64).unwrap_or(1);
|
||||
|
||||
// Execute the sub command the specified number of times, printing
|
||||
// every result
|
||||
for _ in 0..times {
|
||||
let s = cmd_fn(sub_matches)?;
|
||||
println!("{}", s);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let res = parse_and_exec();
|
||||
if let Err(e) = res {
|
||||
println!("{}", e);
|
||||
}
|
||||
}
|
||||
|
||||
/// Validator shorthand to check if a string is parsable as given type.
|
||||
fn validate_parse<T>(s: String) -> Result<(), String>
|
||||
where T: FromStr,
|
||||
T::Err: ToString,
|
||||
{
|
||||
s.parse::<T>()
|
||||
.map(|_| ())
|
||||
.map_err(|e| e.to_string())
|
||||
}
|
Reference in New Issue
Block a user