From aaf0332117636e8a962607e92013c90b537d579f Mon Sep 17 00:00:00 2001 From: Lukas Kalbertodt Date: Thu, 16 Feb 2017 15:08:25 +0100 Subject: [PATCH] Add forgotten solutions --- aufgaben/sheet10/sol1/magic.s | 39 +++++++++ aufgaben/sheet10/sol2/Cargo.lock | 109 ++++++++++++++++++++++++ aufgaben/sheet10/sol2/Cargo.toml | 8 ++ aufgaben/sheet10/sol2/src/cmd/choose.rs | 63 ++++++++++++++ aufgaben/sheet10/sol2/src/cmd/coin.rs | 23 +++++ aufgaben/sheet10/sol2/src/cmd/dice.rs | 36 ++++++++ aufgaben/sheet10/sol2/src/cmd/mod.rs | 10 +++ aufgaben/sheet10/sol2/src/main.rs | 90 +++++++++++++++++++ 8 files changed, 378 insertions(+) create mode 100755 aufgaben/sheet10/sol1/magic.s create mode 100755 aufgaben/sheet10/sol2/Cargo.lock create mode 100755 aufgaben/sheet10/sol2/Cargo.toml create mode 100755 aufgaben/sheet10/sol2/src/cmd/choose.rs create mode 100755 aufgaben/sheet10/sol2/src/cmd/coin.rs create mode 100755 aufgaben/sheet10/sol2/src/cmd/dice.rs create mode 100755 aufgaben/sheet10/sol2/src/cmd/mod.rs create mode 100755 aufgaben/sheet10/sol2/src/main.rs diff --git a/aufgaben/sheet10/sol1/magic.s b/aufgaben/sheet10/sol1/magic.s new file mode 100755 index 0000000..f59094d --- /dev/null +++ b/aufgaben/sheet10/sol1/magic.s @@ -0,0 +1,39 @@ +; This is the assembly of: +; +; fn is_prime(n: u64) -> bool { +; (2..n).all(|d| n % d != 0) +; } +; +; Of course, it was compiled in release mode. Thus, this is a primality test +; which works for numbers >= 2. + +magic: + push rbp ; standard function prologue: + mov rbp, rsp ; storing old rbp and setting new one + + mov rcx, rdi ; copy function argument to rcx + mov esi, 2 ; rsi = 2 (this will be our counter) + +.LBB0_1: + mov al, 1 ; out = true (rax contains the return value) + + cmp rsi, rcx ; if our counter is equal to our function argument + jae .LBB0_4 ; (rsi == rcx) we will jump to the end (return) + + xor edx, edx ; set rdx to 0 (just for the upcoming div instruction) + mov rax, rcx ; copy the function argument into rax temporarily + ; (this is just for the next instruction) + + div rsi ; divide rdx:rax by rsi (counter). The result is stored + ; in rax and more importantly: the remainder is stored + ; in rdx! + + inc rsi ; increment our counter + + test rdx, rdx ; if the remainder is NOT 0, we will jump up + jne .LBB0_1 ; again (keep going). Else we will just continue... + + xor eax, eax ; out = false +.LBB0_4: + pop rbp ; standard function epilogue + ret diff --git a/aufgaben/sheet10/sol2/Cargo.lock b/aufgaben/sheet10/sol2/Cargo.lock new file mode 100755 index 0000000..d3630f8 --- /dev/null +++ b/aufgaben/sheet10/sol2/Cargo.lock @@ -0,0 +1,109 @@ +[root] +name = "flip" +version = "0.1.0" +dependencies = [ + "clap 2.20.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "ansi_term" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "bitflags" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "clap" +version = "2.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "ansi_term 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)", + "strsim 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "term_size 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-segmentation 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "vec_map 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "kernel32-sys" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "libc" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "rand" +version = "0.3.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "strsim" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "term_size" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "unicode-segmentation" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "unicode-width" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "vec_map" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "winapi" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "winapi-build" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[metadata] +"checksum ansi_term 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "23ac7c30002a5accbf7e8987d0632fa6de155b7c3d39d0067317a391e00a2ef6" +"checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d" +"checksum clap 2.20.0 (registry+https://github.com/rust-lang/crates.io-index)" = "dd1cb22651881e6379f4492d0d572ecb8022faef8c8aaae285bb18cb307bfa30" +"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" +"checksum libc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)" = "a51822fc847e7a8101514d1d44e354ba2ffa7d4c194dcab48870740e327cac70" +"checksum rand 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "022e0636ec2519ddae48154b028864bdce4eaf7d35226ab8e65c611be97b189d" +"checksum strsim 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b4d15c810519a91cf877e7e36e63fe068815c678181439f2f29e2562147c3694" +"checksum term_size 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3f7f5f3f71b0040cecc71af239414c23fd3c73570f5ff54cf50e03cef637f2a0" +"checksum unicode-segmentation 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7baebdc1df1363fa66161fca2fe047e4f4209011cc7e045948298996afdf85df" +"checksum unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "bf3a113775714a22dcb774d8ea3655c53a32debae63a063acc00a91cc586245f" +"checksum vec_map 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cac5efe5cb0fa14ec2f84f83c701c562ee63f6dcc680861b21d65c682adfb05f" +"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" +"checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" diff --git a/aufgaben/sheet10/sol2/Cargo.toml b/aufgaben/sheet10/sol2/Cargo.toml new file mode 100755 index 0000000..48dfd8d --- /dev/null +++ b/aufgaben/sheet10/sol2/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "flip" +version = "0.1.0" +authors = ["Lukas Kalbertodt "] + +[dependencies] +clap = "~2.20" +rand = "0.3.15" diff --git a/aufgaben/sheet10/sol2/src/cmd/choose.rs b/aufgaben/sheet10/sol2/src/cmd/choose.rs new file mode 100755 index 0000000..a1aca65 --- /dev/null +++ b/aufgaben/sheet10/sol2/src/cmd/choose.rs @@ -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::() + .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> { + // 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)) + } +} diff --git a/aufgaben/sheet10/sol2/src/cmd/coin.rs b/aufgaben/sheet10/sol2/src/cmd/coin.rs new file mode 100755 index 0000000..62e5aa8 --- /dev/null +++ b/aufgaben/sheet10/sol2/src/cmd/coin.rs @@ -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> { + let out = if rand::thread_rng().gen() { + "heads" + } else { + "tails" + }; + + Ok(out.into()) +} diff --git a/aufgaben/sheet10/sol2/src/cmd/dice.rs b/aufgaben/sheet10/sol2/src/cmd/dice.rs new file mode 100755 index 0000000..17450aa --- /dev/null +++ b/aufgaben/sheet10/sol2/src/cmd/dice.rs @@ -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::() + .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> { + let sides = value_t!(matches, "sides", u64).unwrap_or(6); + + let num = rand::thread_rng().gen_range(1, sides); + Ok(num.to_string()) +} diff --git a/aufgaben/sheet10/sol2/src/cmd/mod.rs b/aufgaben/sheet10/sol2/src/cmd/mod.rs new file mode 100755 index 0000000..bdae59b --- /dev/null +++ b/aufgaben/sheet10/sol2/src/cmd/mod.rs @@ -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; diff --git a/aufgaben/sheet10/sol2/src/main.rs b/aufgaben/sheet10/sol2/src/main.rs new file mode 100755 index 0000000..3e69ecb --- /dev/null +++ b/aufgaben/sheet10/sol2/src/main.rs @@ -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> { + 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::) + .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(s: String) -> Result<(), String> + where T: FromStr, + T::Err: ToString, +{ + s.parse::() + .map(|_| ()) + .map_err(|e| e.to_string()) +}