diff --git a/Cargo.lock b/Cargo.lock index 647c206..18fc858 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -246,12 +246,6 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" -[[package]] -name = "cfg_aliases" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e" - [[package]] name = "cipher" version = "0.4.4" @@ -399,16 +393,6 @@ dependencies = [ "typenum", ] -[[package]] -name = "ctrlc" -version = "3.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "672465ae37dc1bc6380a6547a8883d5dd397b0f1faaad4f265726cc7042a5345" -dependencies = [ - "nix", - "windows-sys 0.52.0", -] - [[package]] name = "deranged" version = "0.3.11" @@ -1060,18 +1044,6 @@ version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" -[[package]] -name = "nix" -version = "0.28.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab2156c4fce2f8df6c499cc1c763e4394b7482525bf2a9701c9d79d215f519e4" -dependencies = [ - "bitflags 2.5.0", - "cfg-if", - "cfg_aliases", - "libc", -] - [[package]] name = "nom" version = "7.1.3" @@ -1607,7 +1579,6 @@ version = "0.1.0" dependencies = [ "clap", "crossterm", - "ctrlc", "dirs", "image", "once_cell", diff --git a/Cargo.toml b/Cargo.toml index 45e35f3..703f2c9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,7 +6,6 @@ edition = "2021" [dependencies] clap = { version = "3.2.22", features = ["cargo"] } crossterm = "0.27.0" -ctrlc = "3.4.4" dirs = "5.0.1" image = "0.25.1" once_cell = "1.19.0" diff --git a/src/bin/clap.rs b/src/bin/clap.rs deleted file mode 100644 index bacea23..0000000 --- a/src/bin/clap.rs +++ /dev/null @@ -1,60 +0,0 @@ -use std::path::PathBuf; - -use clap::{arg, value_parser, ArgAction, Command}; - -fn main() { - let matches = clap::command!() // requires `cargo` feature - .arg(arg!([name] "Optional name to operate on")) - .arg( - arg!( - -c --config "Sets a custom config file" - ) - // We don't have syntax yet for optional options, so manually calling `required` - .required(false) - .value_parser(value_parser!(PathBuf)), - ) - .arg(arg!( - -d --debug ... "Turn debugging information on" - )) - .subcommand( - Command::new("test") - .about("does testing things") - .arg(arg!(-l --list "lists test values").action(ArgAction::SetTrue)), - ) - .get_matches(); - - // You can check the value provided by positional arguments, or option arguments - if let Some(name) = matches.get_one::("name") { - println!("Value for name: {name}"); - } - - if let Some(config_path) = matches.get_one::("config") { - println!("Value for config: {}", config_path.display()); - } - - // You can see how many times a particular flag or argument occurred - // Note, only flags can have multiple occurrences - match matches - .get_one::("debug") - .expect("Count's are defaulted") - { - 0 => println!("Debug mode is off"), - 1 => println!("Debug mode is kind of on"), - 2 => println!("Debug mode is on"), - _ => println!("Don't be crazy"), - } - - // You can check for the existence of subcommands, and if found use their - // matches just as you would the top level cmd - if let Some(matches) = matches.subcommand_matches("test") { - // "$ myapp test" was run - if matches.get_flag("list") { - // "$ myapp test -l" was run - println!("Printing testing lists..."); - } else { - println!("Not printing testing lists..."); - } - } - - // Continued program logic goes here... -} diff --git a/src/bin/serde.rs b/src/bin/serde.rs deleted file mode 100644 index 989ba2b..0000000 --- a/src/bin/serde.rs +++ /dev/null @@ -1,68 +0,0 @@ -use serde::{Deserialize, Serialize}; -use serde_json::{Result, Value}; -use std::collections::HashMap; -use std::fs; - -#[derive(Deserialize)] -struct Input { - #[serde(flatten)] - other: HashMap, // Capturing the rest of the data - gen_8: Option, // Making gen_8 optional -} - -#[derive(Deserialize)] -struct Generation8 { - forms: HashMap, -} - -#[derive(Serialize)] -struct Pokemon { - name: String, - id: String, - forms: Vec, -} - -fn main() -> Result<()> { - let data = fs::read_to_string("pokemon.json").expect("Unable to read file"); - let input_pokemons: HashMap = serde_json::from_str(&data)?; - - let mut output_pokemons: Vec = Vec::new(); - - for (id, pokemon) in input_pokemons { - // Check if gen_8 data exists - let forms: Vec = if let Some(gen_8) = pokemon.gen_8 { - gen_8 - .forms - .keys() - .map(|key| { - if key == "$" { - "regular".to_string() - } else { - key.clone() - } - }) - .collect() - } else { - // If there's no gen_8 data, you might want to handle it differently - // For now, let's just use an empty Vec - Vec::new() - }; - - // Proceed as before - output_pokemons.push(Pokemon { - name: pokemon.other["name"]["eng"] - .as_str() - .unwrap_or_default() - .to_string(), - id, - forms, - }); - } - - let output_json = serde_json::to_string_pretty(&output_pokemons)?; - println!("{}", output_json); - - fs::write("output_pokemon.json", output_json).expect("Unable to write file"); - - Ok(()) -} diff --git a/src/bin/testing.rs b/src/bin/testing.rs deleted file mode 100644 index a96a036..0000000 --- a/src/bin/testing.rs +++ /dev/null @@ -1,323 +0,0 @@ -fn main() { - let _bruh = "bruh"; -} - -// use std::fs; - -// fn main() { -// let contents = fs::read_to_string("testing/testing.fuck").unwrap(); -// let mut found: bool = false; - -// for line in contents.lines() { -// match line { -// "1" | "2" => { -// found = true; -// break; -// } - -// // if not found -// _ => found = false, -// } -// } - -// if found == true { -// println!("Gotcha bitch"); -// } else { -// println!("Never mind") -// } -// } - -// use rand::{thread_rng, Rng}; -// use std::io::{self, stdout, Write}; -// use std::num::ParseIntError; - -// #[derive(Debug)] -// enum Error { -// InvalidNumber(ParseIntError), -// OutOfRange, -// } - -// fn main() { -// loop { -// let random_number: u8 = generate_random_number(); -// loop { -// match get_user_number() { -// Ok(user_number) => { -// if user_number < random_number { -// println!("Too low!"); -// } else if user_number > random_number { -// println!("Too high!"); -// } else { -// println!("You guessed the correct number!"); -// break; -// } -// } -// Err(e) => println!("{:?}", e), -// } -// } -// let user_choice = get_user_choice(); -// if user_choice != "y" { -// break; -// } -// } -// } - -// fn generate_random_number() -> u8 { -// let mut rng = thread_rng(); -// rng.gen_range(1..101) -// } - -// fn get_user_number() -> Result { -// let string_input = read_user_input("Guess an integer between 1 and 100: ").unwrap(); -// match string_input.trim().parse::() { -// Ok(value) if value >= 1 && value <= 100 => Ok(value), -// Ok(_) => Err(Error::OutOfRange), -// Err(e) => Err(Error::InvalidNumber(e)), -// } -// } - -// fn get_user_choice() -> String { -// loop { -// let choice = read_user_input("Would you like to play again? (y/n): ").unwrap(); -// if choice == "y" || choice == "n" { -// return choice; -// } else { -// println!("Invalid input. Please enter 'y' or 'n'."); -// } -// } -// } - -// fn read_user_input(prompt: &str) -> io::Result { -// let mut string_input = String::new(); -// print!("{}", prompt); -// stdout().flush()?; -// io::stdin().read_line(&mut string_input)?; -// Ok(string_input.trim().to_string()) -// } - -// use rand::{thread_rng, Rng}; -// use std::io::stdin; -// use std::io::{stdout, Write}; - -// fn main() { -// loop { -// // generate a random number -// let random_number: u8 = generate_random_number(); - -// // loop until they get it correct -// loop { -// // get the user input -// match get_user_number() { -// Ok(user_number) => { -// if user_number < random_number { -// println!("Too low!"); -// } else if user_number > random_number { -// println!("Too high!"); -// } else { -// println!("You guessed the correct number!"); -// break; -// } -// } -// Err(e) => println!("{}", e), -// } -// } -// let user_choice = get_user_choice(); -// if user_choice != "y" { -// break; -// } -// } -// } - -// fn generate_random_number() -> u8 { -// let mut rng = thread_rng(); -// return rng.gen_range(1..101); -// } - -// fn get_user_number() -> Result { -// let mut string_input = String::new(); -// print!("Guess an integer between 1 and 100: "); -// stdout().flush().unwrap(); -// std::io::stdin().read_line(&mut string_input).unwrap(); -// let parsed_input = string_input.trim().parse::(); -// // check if the input is a valid number -// // this is validation -// match parsed_input { -// Ok(value) => { -// if value < 1 || value > 100 { -// return Err("Please enter an integer between 1 and 100.".to_string()); -// } else { -// return Ok(value); -// } -// } -// Err(_) => { -// return Err("Please enter an integer between 1 and 100.".to_string()); -// } -// } -// } - -// fn get_user_choice() -> String { -// loop { -// let mut string_input = String::new(); -// print!("Would you like to play again? (y/n): "); -// stdout().flush().unwrap(); -// stdin().read_line(&mut string_input).unwrap(); -// let choice = string_input.trim().to_string(); -// if choice == "y" || choice == "n" { -// return choice; -// } else { -// println!("Invalid input. Please enter 'y' or 'n'."); -// } -// } -// } - -// use ctrlc; -// use rand::{thread_rng, Rng}; -// use std::io::stdin; -// use std::io::{stdout, Write}; -// use std::sync::atomic::{AtomicBool, Ordering}; -// use std::sync::Arc; - -// fn main() { -// let running = Arc::new(AtomicBool::new(true)); -// let r = running.clone(); -// ctrlc::set_handler(move || { -// r.store(false, Ordering::SeqCst); -// println!("You cannot escape. Play the fucking game."); // Print message when Ctrl-C is pressed -// }) -// .expect("Error setting Ctrl-C handler"); - -// while running.load(Ordering::SeqCst) { -// // generate a random number -// let random_number: u8 = generate_random_number(); - -// // loop until they get it correct -// loop { -// // get the user input -// match get_user_number() { -// Ok(user_number) => { -// if user_number < random_number { -// println!("Too low!"); -// } else if user_number > random_number { -// println!("Too high!"); -// } else { -// println!("You guessed the correct number!"); -// break; -// } -// } -// Err(e) => println!("{}", e), -// } -// } -// let user_choice = get_user_choice(); -// if user_choice != "y" { -// break; -// } -// } -// } - -// fn generate_random_number() -> u8 { -// let mut rng = thread_rng(); -// return rng.gen_range(1..101); -// } - -// fn get_user_number() -> Result { -// let mut string_input = String::new(); -// print!("Guess an integer between 1 and 100: "); -// stdout().flush().unwrap(); -// std::io::stdin().read_line(&mut string_input).unwrap(); -// let parsed_input = string_input.trim().parse::(); -// // check if the input is a valid number -// // this is validation -// match parsed_input { -// Ok(value) => { -// if value < 1 || value > 100 { -// return Err("Please enter an integer between 1 and 100.".to_string()); -// } else { -// return Ok(value); -// } -// } -// Err(_) => { -// return Err("Please enter an integer between 1 and 100.".to_string()); -// } -// } -// } - -// fn get_user_choice() -> String { -// loop { -// let mut string_input = String::new(); -// print!("Would you like to play again? (y/n): "); -// stdout().flush().unwrap(); -// stdin().read_line(&mut string_input).unwrap(); -// let choice = string_input.trim().to_string(); -// if choice == "y" || choice == "n" { -// return choice; -// } else { -// println!("Invalid input. Please enter 'y' or 'n'."); -// } -// } -// } - -// use std::io::Write; - -// fn main() { -// let mut string_input = String::new(); -// print!("Enter a string: "); -// std::io::stdout().flush().unwrap(); -// std::io::stdin().read_line(&mut string_input).unwrap(); -// let mut trimmed_string = string_input.trim().to_string().push_str("hello"); -// println!("You entered: {}", trimmed_string); -// } - -// fn main() { -// let numbers = [1, 9, -2, 0, 23, 20, -7, 13, 37, 20, 56, -18, 20, 3]; - -// let max = *numbers.iter().max().unwrap(); -// let min = *numbers.iter().min().unwrap(); - -// let sum: i32 = numbers.iter().sum(); -// let mean = sum as f64 / numbers.len() as f64; - -// assert_eq!(max, 56); -// assert_eq!(min, -18); -// assert_eq!(mean, 12.5); -// } - -// fn main() { -// let numbers = [1, 9, -2, 0, 23, 20, -7, 13, 37, 20, 56, -18, 20, 3]; -// let mut max: i32; -// let mut min: i32; -// let mean: f64; - -// max = numbers[0]; -// for n in numbers { -// if n > max { -// max = n; -// }; -// } - -// min = numbers[0]; -// for n in numbers { -// if n < min { -// min = n; -// }; -// } - -// let mut sum = 0; -// for n in numbers { -// sum += n; -// } - -// mean = sum as f64 / numbers.len() as f64; - -// assert_eq!(max, 56); -// assert_eq!(min, -18); -// assert_eq!(mean, 12.5); -// } - -// fn main() { -// let mut numbers = [1, 2, 3, 4, 5]; - -// for i in numbers.iter_mut() { -// *i += 1; -// println!("{}", &*i + 1); -// } -// } diff --git a/src/constants.rs b/src/constants.rs index 08bf06c..f0a4330 100644 --- a/src/constants.rs +++ b/src/constants.rs @@ -1,16 +1,27 @@ -pub static TARGET_URL: &str = +pub const TARGET_URL: &str = "https://github.com/Vomitblood/pokesprite/archive/refs/heads/master.zip"; -pub static DATA_DIRECTORY: once_cell::sync::Lazy = +pub const DATA_DIRECTORY: once_cell::sync::Lazy = once_cell::sync::Lazy::new(|| { dirs::data_dir() .map(|dir| dir.join("rustmon")) .expect("Data directory not found") }); -pub static CACHE_DIRECTORY: once_cell::sync::Lazy = +pub const CACHE_DIRECTORY: once_cell::sync::Lazy = once_cell::sync::Lazy::new(|| { dirs::cache_dir() .map(|dir| dir.join("rustmon")) .expect("Cache directory not found") }); + +// pub const GENERATIONS: [(&str, (u16, u16)); 8] = [ +// ("1", (1, 151)), +// ("2", (152, 251)), +// ("3", (252, 386)), +// ("4", (387, 493)), +// ("5", (494, 649)), +// ("6", (650, 721)), +// ("7", (722, 809)), +// ("8", (810, 905)), +// ]; diff --git a/src/main.rs b/src/main.rs index 2a79970..48540d5 100644 --- a/src/main.rs +++ b/src/main.rs @@ -9,11 +9,12 @@ ## `print` - Print a Pokemon colorscript - `big` - Print a bigger version of the colorscript -- `name` - Print Pokemon by name -- `no-title` - Do not print Pokemon name -- `pokedex` - Print Pokemon by Pokedex number -- `random` - Print a random Pokemon colorscript +- `form` - Print Pokemon by list of space-separated forms. Follows the order of the names/Pokedex number specified. If not specified, it will print the regular form. +- `hide-name` - Do not print Pokemon name +- `name` - Print Pokemon by list of space-separated names. Use `random` to print a random Pokemon. +- `pokedex` - Print Pokemon by list of space-separated Pokedex numbers. Use `0` to print a random Pokemon. - `shiny` - Rate of printing the shiny version of the colorscript +- `spacing` - Number of spaces between colorscripts */ /// Pokemon Colorscripts written in Rust @@ -67,13 +68,15 @@ fn main() { // declare and define variables from arguments let big = print_args.get_flag("big"); - let pokedex: u16 = *print_args.get_one::("pokedex").unwrap(); - let name: &String = print_args.get_one::("name").unwrap(); - let no_title: bool = print_args.get_flag("no-title"); - let random: bool = print_args.get_flag("random"); - let shiny: f32 = *print_args.get_one::("shiny").unwrap(); + let forms: Vec<&String> = print_args.get_many("form").unwrap().collect(); + let hide_name: bool = print_args.get_flag("hide-name"); + let names: Vec<&String> = print_args.get_many("name").unwrap().collect(); + let pokedexes: Vec = print_args.get_many("pokedex").unwrap().copied().collect(); + let shiny_rate: f32 = *print_args.get_one::("shiny").unwrap(); + let spacing: u8 = *print_args.get_one::("spacing").unwrap(); - rustmon::print::print(big, pokedex, name, no_title, random, shiny); + // print + rustmon::print::print(big, forms, hide_name, names, pokedexes, shiny_rate, spacing); } } @@ -126,6 +129,7 @@ For more advanced usage, use `less` or `more` to scroll through the list!", .subcommand( clap::Command::new("print") .about("Print a Pokemon colorscript") + .arg_required_else_help(true) // print/big .arg( clap::Arg::new("big") @@ -134,43 +138,47 @@ For more advanced usage, use `less` or `more` to scroll through the list!", .long("big") .action(clap::ArgAction::SetTrue), ) + // print/form + .arg( + clap::Arg::new("form") + .help("Print Pokemon by list of space-separated forms. Follows the order of the names/Pokedex number specified. If not specified, it will print the regular form. Has no effect on random Pokemon.") + .short('f') + .long("form") + .default_value("regular") + .multiple_values(true) + .requires("name_or_pokedex"), + ) + // print/hide-name + .arg( + clap::Arg::new("hide-name") + .help("Do not print Pokemon name") + .long("hide-name") + .action(clap::ArgAction::SetTrue), + ) // print/name .arg( clap::Arg::new("name") - .help("Print Pokemon by name") + .help("Print Pokemon by list of space-separated names. Use `random` to print a random Pokemon.") .short('n') .long("name") .default_value("") .hide_default_value(true) + .multiple_values(true) .conflicts_with("pokedex") - .conflicts_with("random"), - ) - // print/no-title - .arg( - clap::Arg::new("no-title") - .help("Do not print Pokemon name") - .long("no-title") - .action(clap::ArgAction::SetTrue), - ) - // print/random - .arg( - clap::Arg::new("random") - .help("Print a random Pokemon colorscript") - .short('r') - .long("random") - .action(clap::ArgAction::SetTrue), ) // print/pokedex .arg( clap::Arg::new("pokedex") - .help("Print Pokemon by Pokedex number") + .help("Print Pokemon by list of space-separated Pokedex numbers. Use `0` to print a random Pokemon.") .short('p') .long("pokedex") - .value_parser(clap::value_parser!(u16).range(0..)) + // TODO: use a dynamic range instead of 0..906 + // try not to hardcode? + .value_parser(clap::value_parser!(u16).range(0..906)) .default_value("0") .hide_default_value(true) + .multiple_values(true) .conflicts_with("name") - .conflicts_with("random"), ) // print/shiny .arg( @@ -181,9 +189,25 @@ For more advanced usage, use `less` or `more` to scroll through the list!", .short('s') .long("shiny") .value_parser(clap::value_parser!(f32)) - .default_value("0.10"), - ), + .default_value("0.00"), + ) + // print/spacing + .arg( + clap::Arg::new("spacing") + .help( + "Number of spaces between colorscripts", + ) + .long("spacing") + .value_parser(clap::value_parser!(u8).range(0..21)) + .default_value("4"), + ) + .group( + clap::ArgGroup::new("name_or_pokedex") + .args(&["name", "pokedex"]) + .required(false), + ) ) + .subcommand_required(true) // finalize .get_matches(); } diff --git a/src/print.rs b/src/print.rs index 3234fb6..b94fb5e 100644 --- a/src/print.rs +++ b/src/print.rs @@ -1,49 +1,293 @@ +use rand::prelude::SliceRandom; +use rand::SeedableRng; +use std::io::BufRead; use std::io::Read; -pub fn print(big: bool, pokedex: u16, name: &String, no_title: bool, random: bool, shiny: f32) { - println!("Big: {}", big); - println!("pokedex: {}", pokedex); - println!("Name: {}", name); - println!("No title: {}", no_title); - println!("Random: {}", random); - println!("Shiny: {}", shiny); - +pub fn print( + big: bool, + forms: Vec<&String>, + hide_name: bool, + names: Vec<&String>, + pokedexes: Vec, + shiny_rate: f32, + spacing: u8, +) { // decide which function to call - // random, by pokedex or by name - if random { - // random - println!("Random"); - } else if pokedex > 0 { - // by pokedex - println!("By pokedex"); + if big == false + // uber fast random + && forms.len() == 1 + && hide_name == false + && (names.len() == 1 && pokedexes.len() == 1) + && shiny_rate == 0.0 + && forms[0] == "regular" + && (names[0] == "random" && pokedexes[0] == 0) + { + random_lite().unwrap(); } else { - // by name - println!("By name"); - } + // convert list of names to list of pokedex numbers + let pokedexes = if !names[0].is_empty() { + let mut pokedexes: Vec = Vec::new(); + for name in names { + match find_pokedex_by_pokemon(name) { + Ok(pokedex) => pokedexes.push(pokedex.parse().unwrap()), + Err(e) => { + println!("Error: {}", e); + std::process::exit(1); + } + } + } + pokedexes + } else { + pokedexes.clone() + }; - match find_pokemon_by_pokedex(&pokedex.to_string()) { - Ok(pokemon_name) => println!("Found Pokémon: {}", pokemon_name), - Err(e) => eprintln!("Error: {}", e), + // process the forms list + // the length of the forms list should be the same as the pokedexes list, resize with `regular` if different length + // if the form is not available for the pokemon then print the available forms and exit + let forms = process_forms_list(&pokedexes, forms); + + // generate a list of slugs + let slugs = generate_slug_list(big, forms, &pokedexes, shiny_rate); + + println!("{:?}", slugs); + + print_name(&slugs); + + print_ascii_side_by_side(&slugs, spacing).unwrap(); } } -fn find_pokemon_by_pokedex(pokedex_number: &str) -> Result> { +fn random_lite() -> std::io::Result<()> { + let path = crate::constants::DATA_DIRECTORY.join("colorscripts/small/regular/"); + let mut files: Vec = Vec::new(); + + for entry in std::fs::read_dir(&path)? { + let dir_entry = entry?; + files.push(dir_entry.path()); + } + + let mut rng = rand::rngs::SmallRng::from_entropy(); + if let Some(random_file) = files.choose(&mut rng) { + if let Some(file_name) = random_file.file_name() { + match file_name.to_str() { + Some(name) => println!("{}", name), + None => println!("Invalid UTF-8 sequence in file name"), + } + } + + match std::fs::read_to_string(random_file) { + Ok(file_data) => { + println!("{}", file_data); + Ok(()) + } + Err(e) => { + println!("Failed to read file contents: {}", e); + Err(e) + } + } + } else { + println!("No files found in the directory"); + Err(std::io::Error::new( + std::io::ErrorKind::NotFound, + "No files available", + )) + } +} + +fn get_pokemon_data(pokedex_number: u16) -> crate::structs::Pokemon { // read the file - let mut file = std::fs::File::open(crate::constants::DATA_DIRECTORY.join("pokemon.json"))?; + let mut file = + std::fs::File::open(crate::constants::DATA_DIRECTORY.join("pokemon.json")).unwrap(); let mut contents = String::new(); - file.read_to_string(&mut contents)?; + file.read_to_string(&mut contents).unwrap(); // deserialize into the struct - let pokemons: Vec = serde_json::from_str(&contents)?; + let pokemons: Vec = serde_json::from_str(&contents).unwrap(); - // iterate through the list to find the specified pokemon - for pokemon in pokemons { - if pokemon.pokedex == pokedex_number { - // if found then return the name - return Ok(pokemon.name); + // get the pokemon data + // remember that the pokedex number is 1-indexed + // gawdamn it + let pokemon_data: crate::structs::Pokemon = + pokemons.get(pokedex_number as usize - 1).unwrap().clone(); + + // return the data + return pokemon_data; +} + +fn find_pokemon_by_pokedex( + pokedex_number_string: &str, +) -> Result> { + // handle random + if pokedex_number_string == "0" { + return Ok("random".to_string()); + } else { + // read the file + let mut file = std::fs::File::open(crate::constants::DATA_DIRECTORY.join("pokemon.json"))?; + let mut contents = String::new(); + file.read_to_string(&mut contents)?; + + // deserialize into the struct + let pokemons: Vec = serde_json::from_str(&contents)?; + + let pokedex_number = pokedex_number_string.parse::().unwrap(); + + let pokemon_data = pokemons.get(pokedex_number).unwrap(); + + return Ok(pokemon_data.name.clone()); + } +} + +fn find_pokedex_by_pokemon(pokemon_name: &str) -> Result> { + // handle random + if pokemon_name == "random" { + return Ok("0".to_string()); + } else { + // read the file + let mut file = std::fs::File::open(crate::constants::DATA_DIRECTORY.join("pokemon.json"))?; + let mut contents = String::new(); + file.read_to_string(&mut contents)?; + + // deserialize into the struct + let pokemons: Vec = serde_json::from_str(&contents)?; + + // iterate through the list to find the specified pokemon + for pokemon in pokemons { + if pokemon.name == pokemon_name { + // if found then return the pokedex number + return Ok(pokemon.pokedex); + } + } + + // if not found the return an error + return Err(format!("Pokemon {} not found", pokemon_name).into()); + } +} + +fn is_shiny(shiny_rate: f32) -> bool { + // generate a random number between 0 and 1 + let random_number = rand::random::(); + + // if the random number is less than the shiny rate then return true + return random_number < shiny_rate; +} + +fn process_forms_list(pokedexes: &Vec, forms: Vec<&String>) -> Vec { + let mut forms_processed: Vec = forms.iter().map(|s| s.to_string()).collect(); + + // ensure forms_processed has the same length as pokedexes + forms_processed.resize_with(pokedexes.len(), || "regular".to_string()); + + for i in 0..pokedexes.len() { + let pokemon = get_pokemon_data(pokedexes[i]); + let form = &forms_processed[i]; + + if !pokemon.forms.contains(&form.to_string()) { + // iterate and print out the available forms + // consider using crate::list::print_pokemon_forms(pokemon_name) + println!("Available forms for {}:", pokemon.name); + for available_form in &pokemon.forms { + println!(" - {}", available_form); + } + std::process::exit(1); } } - // if not found the return an error - return Err("Pokemon not found".into()); + return forms_processed; +} + +fn slug_generator(big: bool, form: String, name: String, shiny_rate: f32) -> std::path::PathBuf { + // big is just a boolean, convert it to big or small + // form is a string, if `regular` then replace with empty string. else keep it as is. + // name is a string, should be cleaned up already. there should be no `random` as a name should be generated before this. + // shiny_rate is a float, let it be + + // if big is true then use big, else use small + let big: String = if big { + "big".to_string() + } else { + "small".to_string() + }; + + // if form is regular then replace with empty string + let form: String = if form == "regular" { + "".to_string() + } else { + format!("-{}", form) + }; + + // determine if shiny directory is to be used + let shiny_directory: String = if is_shiny(shiny_rate) { + "shiny".to_string() + } else { + "regular".to_string() + }; + + // construct the path using PathBuf + let mut path = std::path::PathBuf::new(); + path.push(crate::constants::DATA_DIRECTORY.join("colorscripts")); + path.push(format!("{}", big)); + path.push(shiny_directory); + path.push(format!("{}{}", name, form)); + + return path; +} + +fn generate_slug_list( + big: bool, + forms: Vec, + pokedexes: &Vec, + shiny_rate: f32, +) -> Vec { + let mut slugs: Vec = Vec::new(); + + // iterate through the pokedexes to generate the slugs with the complementing form + for i in 0..pokedexes.len() { + let pokemon = get_pokemon_data(pokedexes[i]); + let form = &forms[i]; + + let slug = slug_generator(big, form.to_string(), pokemon.name, shiny_rate); + slugs.push(slug); + } + + return slugs; +} + +fn print_name(paths: &Vec) { + let last_parts: Vec<&str> = paths + .iter() + .filter_map(|path| path.file_name()) + .filter_map(|os_str| os_str.to_str()) + .collect(); + + let output = last_parts.join(", "); + println!("{}", output); +} + +fn print_ascii_side_by_side(paths: &Vec, spacing: u8) -> std::io::Result<()> { + // open all files and create BufReaders + let mut readers: Vec<_> = paths + .iter() + .map(|path| std::fs::File::open(path)) + .filter_map(|result| result.ok()) + .map(|file| std::io::BufReader::new(file)) + .collect(); + + // create a string for spacing + let separator = " ".repeat(spacing as usize); + + // one line by one line + let mut lines: Vec = vec![]; + loop { + lines.clear(); + for reader in &mut readers { + let mut line = String::new(); + if reader.read_line(&mut line)? > 0 { + lines.push(line.trim_end().to_string()); + } else { + // End of file reached + return Ok(()); + } + } + println!("{}", lines.join(&separator)); + } } diff --git a/src/structs.rs b/src/structs.rs index b2cb7c5..250f699 100644 --- a/src/structs.rs +++ b/src/structs.rs @@ -27,7 +27,7 @@ pub struct PokemonRawCollection { pub entries: std::collections::HashMap, } -#[derive(serde::Serialize, serde::Deserialize, Debug)] +#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] pub struct Pokemon { pub pokedex: String, pub name: String, diff --git a/testing/testing.fuck b/testing/testing.fuck deleted file mode 100644 index 6e2517e..0000000 --- a/testing/testing.fuck +++ /dev/null @@ -1,8 +0,0 @@ -asdf -3 -4 -5 -6 -1 -7 -69 \ No newline at end of file diff --git a/testing/testing.py b/testing/testing.py deleted file mode 100644 index 89a7c8a..0000000 --- a/testing/testing.py +++ /dev/null @@ -1,22 +0,0 @@ -import random - -# generate a random integer between 1 and 100 -random_number = random.randint(1, 100) - -user_input = input("Guess an integer between 1 and 100: ") - -# convert the user input to an integer -try: - user_input = int(user_input) -except ValueError: - print("Please enter a valid number") - exit() - -if user_input < 1 or user_input > 100: - print("Please enter a number between 1 and 100") - exit() -elif random_number == user_input: - print("You guessed correctly!") -else: - # use f strings to format the string - print(f"Sorry, the number was {random_number}. Try again next time!") diff --git a/testing/testing.ts b/testing/testing.ts deleted file mode 100644 index e69de29..0000000