mirror of
https://github.com/coding-horror/basic-computer-games.git
synced 2025-12-22 07:10:42 -08:00
Merge pull request #728 from AnthonyMichaelTDM/rust-port-32_Diamond
Rust port 32_diamond
This commit is contained in:
8
32_Diamond/rust/Cargo.toml
Normal file
8
32_Diamond/rust/Cargo.toml
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
[package]
|
||||||
|
name = "rust"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
3
32_Diamond/rust/README.md
Normal file
3
32_Diamond/rust/README.md
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
|
||||||
|
|
||||||
|
Conversion to [Rust](https://www.rust-lang.org/) by Anthony Rubick [AnthonyMichaelTDM](https://github.com/AnthonyMichaelTDM)
|
||||||
182
32_Diamond/rust/src/lib.rs
Normal file
182
32_Diamond/rust/src/lib.rs
Normal file
@@ -0,0 +1,182 @@
|
|||||||
|
/*
|
||||||
|
lib.rs contains all the logic of the program
|
||||||
|
*/
|
||||||
|
|
||||||
|
use std::{error::Error, fmt::Display, str::FromStr, io::{self, Write}};
|
||||||
|
|
||||||
|
/// handles setup for the game
|
||||||
|
pub struct Config {
|
||||||
|
diamond_size: isize,
|
||||||
|
}
|
||||||
|
impl Config {
|
||||||
|
/// creates and returns a new Config from user input
|
||||||
|
pub fn new() -> Result<Config, Box<dyn Error>> {
|
||||||
|
//DATA
|
||||||
|
let mut config: Config = Config { diamond_size: 0 };
|
||||||
|
|
||||||
|
//get data from user input
|
||||||
|
|
||||||
|
//get num players
|
||||||
|
println!("FOR A PRETTY DIAMOND PATTERN,");
|
||||||
|
//input looop
|
||||||
|
config.diamond_size = loop {
|
||||||
|
match get_number_from_input("TYPE IN AN ODD NUMBER BETWEEN 5 AND 31 ", 5, 31) {
|
||||||
|
Ok(num) => {
|
||||||
|
//ensure num is odd
|
||||||
|
if num%2 == 0 {continue;}
|
||||||
|
else {break num;}
|
||||||
|
},
|
||||||
|
Err(e) => {
|
||||||
|
eprintln!("{}",e);
|
||||||
|
continue;
|
||||||
|
},
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//return new config
|
||||||
|
return Ok(config);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// run the program
|
||||||
|
pub fn run(config: &Config) -> Result<(), Box<dyn Error>> {
|
||||||
|
//DATA
|
||||||
|
let line_width: isize = 60;
|
||||||
|
let padding: char = 'C';
|
||||||
|
let pixel_width: isize = 1;
|
||||||
|
let filling: char = '!';
|
||||||
|
let border: char = '#';
|
||||||
|
|
||||||
|
let width_of_full_diamonds_in_line = (line_width/config.diamond_size) * config.diamond_size;
|
||||||
|
|
||||||
|
//print top border
|
||||||
|
println!("{}", n_chars(width_of_full_diamonds_in_line+2, border));
|
||||||
|
|
||||||
|
//print out diamonds
|
||||||
|
for row in 0..width_of_full_diamonds_in_line {
|
||||||
|
print_diamond_line(config.diamond_size, row, line_width, pixel_width, padding, filling, border);
|
||||||
|
}
|
||||||
|
|
||||||
|
//print bottom border
|
||||||
|
println!("{}", n_chars(width_of_full_diamonds_in_line+2, border));
|
||||||
|
|
||||||
|
//return to main
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// prints the next line of diamonds
|
||||||
|
fn print_diamond_line(diamond_width: isize,row: isize, line_width:isize, pixel_width:isize, padding:char, filling:char, border:char) {
|
||||||
|
//DATA
|
||||||
|
let diamonds_per_row = (line_width/pixel_width) / diamond_width;
|
||||||
|
//let row = row % (diamonds_per_row - 1);
|
||||||
|
let padding_amount; //total amount of padding before and after the filling of each diamond in this row
|
||||||
|
let filling_amount; //amount of "diamond" in each diamond in this row
|
||||||
|
|
||||||
|
//calculate padding
|
||||||
|
padding_amount = (2 * ( (row%(diamond_width-1)) - (diamond_width/2))).abs();
|
||||||
|
//calculate filling
|
||||||
|
filling_amount = -padding_amount + diamond_width;
|
||||||
|
|
||||||
|
//print border before every row
|
||||||
|
print!("{}", border);
|
||||||
|
|
||||||
|
//for every diamond in this row:
|
||||||
|
for _diamond in 0..diamonds_per_row {
|
||||||
|
//print leading padding
|
||||||
|
print!("{}", n_chars( pixel_width * padding_amount/2, padding ) );
|
||||||
|
//print filling
|
||||||
|
print!("{}", n_chars( pixel_width * filling_amount , filling ) );
|
||||||
|
//print trailing padding
|
||||||
|
print!("{}", n_chars( pixel_width * padding_amount/2, padding ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
//print border after every row
|
||||||
|
print!("{}", border);
|
||||||
|
//new line
|
||||||
|
println!("");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// returns n of the passed character, put into a string
|
||||||
|
fn n_chars(n:isize, character: char) -> String {
|
||||||
|
let mut output = String::new();
|
||||||
|
|
||||||
|
for _i in 0..n {
|
||||||
|
output.push(character);
|
||||||
|
}
|
||||||
|
|
||||||
|
output
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// gets a string from user input
|
||||||
|
fn get_string_from_user_input(prompt: &str) -> Result<String, Box<dyn Error>> {
|
||||||
|
//DATA
|
||||||
|
let mut raw_input = String::new();
|
||||||
|
|
||||||
|
//print prompt
|
||||||
|
print!("{}", prompt);
|
||||||
|
//make sure it's printed before getting input
|
||||||
|
io::stdout().flush().unwrap();
|
||||||
|
|
||||||
|
//read user input from standard input, and store it to raw_input, then return it or an error as needed
|
||||||
|
raw_input.clear(); //clear input
|
||||||
|
match io::stdin().read_line(&mut raw_input) {
|
||||||
|
Ok(_num_bytes_read) => return Ok(String::from(raw_input.trim())),
|
||||||
|
Err(err) => return Err(format!("ERROR: CANNOT READ INPUT!: {}", err).into()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// generic function to get a number from the passed string (user input)
|
||||||
|
/// pass a min lower than the max to have minimun and maximun bounds
|
||||||
|
/// pass a min higher than the max to only have a minumum bound
|
||||||
|
/// pass a min equal to the max to only have a maximun bound
|
||||||
|
///
|
||||||
|
/// Errors:
|
||||||
|
/// no number on user input
|
||||||
|
fn get_number_from_input<T:Display + PartialOrd + FromStr>(prompt: &str, min:T, max:T) -> Result<T, Box<dyn Error>> {
|
||||||
|
//DATA
|
||||||
|
let raw_input: String;
|
||||||
|
let processed_input: String;
|
||||||
|
|
||||||
|
|
||||||
|
//input looop
|
||||||
|
raw_input = loop {
|
||||||
|
match get_string_from_user_input(prompt) {
|
||||||
|
Ok(input) => break input,
|
||||||
|
Err(e) => {
|
||||||
|
eprintln!("{}",e);
|
||||||
|
continue;
|
||||||
|
},
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//filter out num-numeric characters from user input
|
||||||
|
processed_input = raw_input.chars().filter(|c| c.is_numeric()).collect();
|
||||||
|
|
||||||
|
//from input, try to read a number
|
||||||
|
match processed_input.trim().parse() {
|
||||||
|
Ok(i) => {
|
||||||
|
//what bounds must the input fall into
|
||||||
|
if min < max { //have a min and max bound: [min,max]
|
||||||
|
if i >= min && i <= max {//is input valid, within bounds
|
||||||
|
return Ok(i); //exit the loop with the value i, returning it
|
||||||
|
} else { //print error message specific to this case
|
||||||
|
return Err(format!("ONLY BETWEEN {} AND {}, PLEASE!", min, max).into());
|
||||||
|
}
|
||||||
|
} else if min > max { //only a min bound: [min, infinity)
|
||||||
|
if i >= min {
|
||||||
|
return Ok(i);
|
||||||
|
} else {
|
||||||
|
return Err(format!("NO LESS THAN {}, PLEASE!", min).into());
|
||||||
|
}
|
||||||
|
} else { //only a max bound: (-infinity, max]
|
||||||
|
if i <= max {
|
||||||
|
return Ok(i);
|
||||||
|
} else {
|
||||||
|
return Err(format!("NO MORE THAN {}, PLEASE!", max).into());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Err(_e) => return Err(format!("Error: couldn't find a valid number in {}",raw_input).into()),
|
||||||
|
}
|
||||||
|
}
|
||||||
40
32_Diamond/rust/src/main.rs
Normal file
40
32_Diamond/rust/src/main.rs
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
use std::process; //allows for some better error handling
|
||||||
|
|
||||||
|
mod lib;
|
||||||
|
use lib::Config;
|
||||||
|
|
||||||
|
/// main function
|
||||||
|
/// responsibilities:
|
||||||
|
/// - Calling the command line logic with the argument values
|
||||||
|
/// - Setting up any other configuration
|
||||||
|
/// - Calling a run function in lib.rs
|
||||||
|
/// - Handling the error if run returns an error
|
||||||
|
fn main() {
|
||||||
|
//greet user
|
||||||
|
welcome();
|
||||||
|
|
||||||
|
// set up other configuration
|
||||||
|
let config = Config::new().unwrap_or_else(|err| {
|
||||||
|
eprintln!("Problem configuring program: {}", err);
|
||||||
|
process::exit(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
// run the program
|
||||||
|
if let Err(e) = lib::run(&config) {
|
||||||
|
eprintln!("Application Error: {}", e); //use the eprintln! macro to output to standard error
|
||||||
|
process::exit(1); //exit the program with an error code
|
||||||
|
}
|
||||||
|
|
||||||
|
//end of program
|
||||||
|
println!("THANKS FOR PLAYING!");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// welcome message
|
||||||
|
fn welcome() {
|
||||||
|
print!("
|
||||||
|
DIAMOND
|
||||||
|
CREATIVE COMPUTING MORRISTOWN, NEW JERSEY
|
||||||
|
|
||||||
|
|
||||||
|
");
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user