commit 02bd016c8ff6976960dba6a80ff9b8bf35130ed6 Author: Alina Marquardt Date: Sat Mar 18 11:31:28 2023 +0000 initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7651006 --- /dev/null +++ b/.gitignore @@ -0,0 +1,56 @@ +# Created by https://www.toptal.com/developers/gitignore/api/nova,rust,macos +# Edit at https://www.toptal.com/developers/gitignore?templates=nova,rust,macos + +### macOS ### +# General +.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +### macOS Patch ### +# iCloud generated files +*.icloud + +### nova ### +.nova/* + +### Rust ### +# Generated by Cargo +# will have compiled files and executables +debug/ +target/ + +# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries +# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html +Cargo.lock + +# These are backup files generated by rustfmt +**/*.rs.bk + +# MSVC Windows builds of rustc generate these, which store debugging information +*.pdb + +# End of https://www.toptal.com/developers/gitignore/api/nova,rust,macos \ No newline at end of file diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..06ebe24 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "dice-roll" +authors = ["Alina Marquardt "] +version = "0.2.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +rand = "0.8.5" +regex = "1" +dialoguer = { version = "0.10.3", features = ["history"] } diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..ff3cc1d --- /dev/null +++ b/src/main.rs @@ -0,0 +1,133 @@ +use dialoguer::{theme::ColorfulTheme, Input, History}; +use std::collections::VecDeque; +use rand::prelude::*; +use regex::Regex; + +struct Die { + sides: u32, + roll: u32, +} + +/*impl Die { + fn crit(&self) -> bool { + self.sides == self.roll + } +}*/ + +fn parse_dice(dice_string: &str) -> (Vec, String) { + let mut dice: Vec = vec![]; + let re = Regex::new(r"(\d+)d(\d+)").unwrap(); + let mut parsed_string = String::new(); + for die in re.captures_iter(dice_string) { + let dice_num: u32 = die[1].parse().unwrap(); + let sides: u32 = die[2].parse().unwrap(); + if dice_num > 0 && sides > 0 { + parsed_string.push_str(&format!("{}d{} + ", dice_num, sides)); + for _ in 0..dice_num { + dice.push(Die { + sides, + roll: 0, + }) + } + } + } + let parsed_string = &parsed_string; + let mut parsed_string = parsed_string.chars(); + for _ in 0..3 { + parsed_string.next_back(); + } + let mut parsed_string = parsed_string.as_str(); + if dice.is_empty() { + parsed_string = "nothing"; + } + (dice, parsed_string.to_owned()) +} + +fn roll_dice(dice_to_roll: Vec) -> Vec { + let mut dice: Vec = vec![]; + for die in dice_to_roll { + dice.push(roll_die(die)); + } + dice +} + +fn roll_die(die_to_roll: Die) -> Die { + let mut rng = thread_rng(); + Die { + sides: die_to_roll.sides, + roll: rng.gen_range(1..=die_to_roll.sides), + } +} + +fn main() { + println!(); + println!("Use the Up/Down arrows to scroll through history"); + let mut history = MyHistory::default(); + loop { + println!(); + + let input: String = Input::::with_theme(&ColorfulTheme::default()) + .with_prompt("Roll dice (ex. \"2d8 3d4\") or \"q\"") + .history_with(&mut history) + .interact_text() + .unwrap(); + + let dice_string: &str = &input.trim().to_lowercase(); // trim and lowercase + + if dice_string.eq("q") { break; } + + let (mut dice, dice_string) = parse_dice(dice_string); + + print!("Rolling {}", dice_string); + dice = roll_dice(dice); + + let mut last = 0; + let mut sum = 0; + for die in dice { + if last != die.sides { + println!(); + print!("d{}: ", die.sides); + } else { + print!(" + "); + } + print!("{}", die.roll); + sum += die.roll; + last = die.sides; + } + + println!(); + println!("--==--"); + println!("SUM: {}", sum); + } + + println!("bye."); + + //println!("{} ({} sided die) was a {} {}", die.name, die.sides, die.roll, {if die.crit() {"and A CRIT!"} else {""}}); +} + +struct MyHistory { + max: usize, + history: VecDeque, +} + +impl Default for MyHistory { + fn default() -> Self { + MyHistory { + max: 20, + history: VecDeque::new(), + } + } +} + +impl History for MyHistory { + fn read(&self, pos: usize) -> Option { + self.history.get(pos).cloned() + } + + fn write(&mut self, val: &T) { + if self.history.len() == self.max { + self.history.pop_back(); + } + self.history.push_front(val.to_string()); + } +}