initial commit
commit
02bd016c8f
|
@ -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
|
|
@ -0,0 +1,12 @@
|
|||
[package]
|
||||
name = "dice-roll"
|
||||
authors = ["Alina Marquardt <lastfuture@lastfuture.de>"]
|
||||
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"] }
|
|
@ -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<Die>, String) {
|
||||
let mut dice: Vec<Die> = 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<Die>) -> Vec<Die> {
|
||||
let mut dice: Vec<Die> = 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::<String>::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<String>,
|
||||
}
|
||||
|
||||
impl Default for MyHistory {
|
||||
fn default() -> Self {
|
||||
MyHistory {
|
||||
max: 20,
|
||||
history: VecDeque::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ToString> History<T> for MyHistory {
|
||||
fn read(&self, pos: usize) -> Option<String> {
|
||||
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());
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue