Project restructure
This commit is contained in:
1592
Cargo.lock
generated
1592
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
20
Cargo.toml
20
Cargo.toml
@@ -1,14 +1,6 @@
|
||||
[package]
|
||||
name = "pokemon_analysis"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
|
||||
[lib]
|
||||
name = "pokemon_lib"
|
||||
path = "src/lib.rs"
|
||||
|
||||
[[bin]]
|
||||
name = "demo"
|
||||
path = "src/main.rs"
|
||||
[workspace]
|
||||
resolver = "2"
|
||||
members = [
|
||||
"pokedex",
|
||||
"pokedex-viewer"
|
||||
]
|
||||
|
||||
69
docs/developer/pokemon_json_format.md
Normal file
69
docs/developer/pokemon_json_format.md
Normal file
@@ -0,0 +1,69 @@
|
||||
# The Pokemon.json File Format
|
||||
|
||||
The Pokemon.json file (and potential other future JSON files) serve as the actual initial data the pokedex uses when
|
||||
constructing all the data structures at startup. The layout of this file is described below. For the most part, the file
|
||||
is not hand-authored, and instead most of the data is either directly retrieved or derived from PokeAPI data. As
|
||||
explained in the [Rationale](#Rationale) section however, the data is by no means bound to only contain (or explicitly
|
||||
match) the data found in PokeAPI.
|
||||
|
||||
## Rationale
|
||||
|
||||
Although currently all application data for the pokedex comes courtesy of pokeapi, I've decided to make our own custom
|
||||
JSON format for the data used by the pokedex. The data in this file still primarily comes from PokeAPI, but undergoes
|
||||
a conversion process to match the expected format. Right now, this is done manually, but in the future there will be a
|
||||
conversion process that can do this automatically when changes to the PokeAPI data are detected. Using our own file and
|
||||
custom format accomplishes a number of goals:
|
||||
|
||||
1. Independence from changes to the PokeAPI JSON format. In case the format for PokeAPI ever changes, or even in the
|
||||
case that there may be an error in the format, we do not need to immediately change anything about our own data.
|
||||
2. More convenient data format layout. By using our own custom format, we are free to adapt it in the future to more
|
||||
closely match what the code actually works with, easing the development process for new features or working on bugs.
|
||||
3. No need to interface with pokeapi directly. By the very nature of this being a pokedex application, it will require
|
||||
almost all the data related to pokemon species that PokeAPI provides. While PokeAPI encourages cacheing on request, in
|
||||
the case of our application it will almost certainly be better if we just bundle all the data for the app rather than
|
||||
potentially make many requests to PokeAPI. Likewise, when the app checks for an update the data can come from the
|
||||
github repository or a separate server we manage, or even a separate data source the end user provides in the future.
|
||||
4. Ability to add our own data, or data from other sources, without having to explicitly add more application code. A
|
||||
format we control means that in the future, we can simply add any additional data we desire to the files, or even
|
||||
pull data from sources other than PokeAPI.
|
||||
|
||||
## Format
|
||||
|
||||
The file contains a top-level JSON object which contains a little metadata about all the pokemon it contains. This object
|
||||
primarily contains the array of PokemonSpecies objects.
|
||||
|
||||
|
||||
### Pokedex Root Object Layout
|
||||
The fields of the top-level object are as follows:
|
||||
|
||||
- version: A semver string denoting the current version of the data.
|
||||
- update: An additional integer that can be considered a part of the version. It denotes the specific build number for
|
||||
this version. This value is incremented anytime the data in the file is updated. The application will primarily use
|
||||
this and the version string to determine if this version of the file is newer or older than the version it currently
|
||||
uses.
|
||||
- pokemon_count: A non-zero integer value for the number of unique PokemonSpecies entries in the "pokemon" list.
|
||||
- pokemon: An array of PokemonSpecies objects.
|
||||
|
||||
### PokemonSpecies Object Layout
|
||||
|
||||
The following fields are defined for PokemonSpecies:
|
||||
- id - The national dex id number associated with this species.
|
||||
- name - The primary name used for the species.
|
||||
- generation - A list of generations this species is available in.
|
||||
- type1 - The primary Type associated with this species.
|
||||
- type2 - The secondary Type associated with this species.
|
||||
- height - A scaled integer representing the height of the pokemon in meters. The last two digits are the decimal
|
||||
fraction component of the height, so the height can be considered as being scaled by a factor of 100.
|
||||
- weight - A scaled integer representing the weight of the pokemon in kilograms. The last two digits are the decimal
|
||||
fraction component of the weight, so the weight can be considered as being scaled by a factor of 100.
|
||||
|
||||
|
||||
```json
|
||||
{
|
||||
id: number,
|
||||
name:
|
||||
}
|
||||
```
|
||||
|
||||
[
|
||||
]
|
||||
11
pokedex-viewer/Cargo.toml
Normal file
11
pokedex-viewer/Cargo.toml
Normal file
@@ -0,0 +1,11 @@
|
||||
[package]
|
||||
name = "pokedex-viewer"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
pokedex = { path = "../pokedex" }
|
||||
|
||||
[[bin]]
|
||||
name = "pokedex-viewer"
|
||||
path = "src/main.rs"
|
||||
3
pokedex-viewer/src/main.rs
Normal file
3
pokedex-viewer/src/main.rs
Normal file
@@ -0,0 +1,3 @@
|
||||
fn main() {
|
||||
println!("Hello, World!");
|
||||
}
|
||||
11
pokedex/Cargo.toml
Normal file
11
pokedex/Cargo.toml
Normal file
@@ -0,0 +1,11 @@
|
||||
[package]
|
||||
name = "pokedex"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[lib]
|
||||
name = "pokedex"
|
||||
path = "src/lib.rs"
|
||||
|
||||
[dependencies]
|
||||
reqwest = { version = "0.12.14", features = ["blocking"] }
|
||||
5
pokedex/src/lib.rs
Normal file
5
pokedex/src/lib.rs
Normal file
@@ -0,0 +1,5 @@
|
||||
#![allow(dead_code)]
|
||||
|
||||
pub mod types;
|
||||
pub mod resources;
|
||||
pub mod pokemon;
|
||||
49
pokedex/src/pokemon/evolution.rs
Normal file
49
pokedex/src/pokemon/evolution.rs
Normal file
@@ -0,0 +1,49 @@
|
||||
use super::{item::Item, moves::PokemonMove, PokemonGender, PokemonSpecies};
|
||||
|
||||
/// An enum for the various days/times/blocks that are relevant for various pokemon, items, etc.
|
||||
/// Date and Time in pokemon games can get complicated since every game has differences in how it
|
||||
/// handles date and time, how precisely date and time need to be represented, and how closely date
|
||||
/// and time map to the real world. This is an incomplete, but hopefully close enough,
|
||||
/// approximation.
|
||||
///
|
||||
/// As most events in pokemon don't tend to care about the precise minute, they can usually be
|
||||
/// broken down into "during the day", "during the night", "between 6pm and 9pm", "on a Friday",
|
||||
/// etc. This enum can be combined multiple times to get something more precise like "Between 6pm
|
||||
/// and 12pm on a Friday".
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub enum PokemonTime {
|
||||
Daytime,
|
||||
Nighttime,
|
||||
DayOfWeek(u8),
|
||||
BetweenHours(u8, u8),
|
||||
BetweenMinutes(u8, u8),
|
||||
}
|
||||
|
||||
/// Simple enum for the different restrictions on evolution
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum EvolutionRequirement {
|
||||
SpecificTime(PokemonTime),
|
||||
CurrentlyInArea(String),
|
||||
Friendship(u8),
|
||||
HoldItem(Item),
|
||||
KnowMove(PokemonMove),
|
||||
Gender(PokemonGender),
|
||||
Other(String),
|
||||
}
|
||||
|
||||
/// Simple enum for the different methods of evolution
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub enum EvolutionMethod {
|
||||
#[default]
|
||||
LevelUp,
|
||||
UseItem(Item),
|
||||
Trade,
|
||||
}
|
||||
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Evolution {
|
||||
from: PokemonSpecies,
|
||||
to: PokemonSpecies,
|
||||
method: EvolutionMethod,
|
||||
}
|
||||
3
pokedex/src/pokemon/item.rs
Normal file
3
pokedex/src/pokemon/item.rs
Normal file
@@ -0,0 +1,3 @@
|
||||
/// Stub newtype for Items.
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub struct Item(String);
|
||||
13
pokedex/src/pokemon/mod.rs
Normal file
13
pokedex/src/pokemon/mod.rs
Normal file
@@ -0,0 +1,13 @@
|
||||
mod species;
|
||||
pub mod evolution;
|
||||
pub mod item;
|
||||
pub mod moves;
|
||||
|
||||
pub use species::*;
|
||||
|
||||
/// Stub enum for gender
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub enum PokemonGender {
|
||||
Male,
|
||||
Female,
|
||||
}
|
||||
3
pokedex/src/pokemon/moves.rs
Normal file
3
pokedex/src/pokemon/moves.rs
Normal file
@@ -0,0 +1,3 @@
|
||||
/// Stub newtype for pokemon moves.
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub struct PokemonMove(String);
|
||||
86
pokedex/src/pokemon/species.rs
Normal file
86
pokedex/src/pokemon/species.rs
Normal file
@@ -0,0 +1,86 @@
|
||||
use crate::types::Type;
|
||||
|
||||
use super::evolution::Evolution;
|
||||
|
||||
const DEFAULT_CAPACITY: usize = 2048;
|
||||
|
||||
/// Simple newtype for Pokemon Species Index.
|
||||
#[derive(Debug, Copy, Clone, Default)]
|
||||
pub struct PokemonSpecies(u32);
|
||||
|
||||
/// Simple type for pokemon typing.
|
||||
#[derive(Debug, Copy, Clone, Default)]
|
||||
pub struct Typing {
|
||||
primary: Type,
|
||||
secondary: Option<Type>,
|
||||
}
|
||||
|
||||
/// Simple newtype for height and weight, which are scaled integers
|
||||
#[derive(Debug, Copy, Clone, Default)]
|
||||
pub struct ScaledInteger(u32);
|
||||
|
||||
/// Simple newtype for abilities. Temporary.
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub struct Ability(String);
|
||||
|
||||
#[derive(Debug, Copy, Clone, Default)]
|
||||
pub struct BaseStats {
|
||||
pub hp: u8,
|
||||
pub attack: u8,
|
||||
pub defense: u8,
|
||||
pub sp_attack: u8,
|
||||
pub sp_defense: u8,
|
||||
pub speed: u8,
|
||||
}
|
||||
|
||||
impl BaseStats {
|
||||
pub fn total(&self) -> u16 {
|
||||
(self.hp as u16)
|
||||
+ (self.attack as u16)
|
||||
+ (self.defense as u16)
|
||||
+ (self.sp_attack as u16)
|
||||
+ (self.sp_defense as u16)
|
||||
+ (self.speed as u16)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct MiscSpeciesData {
|
||||
species_descriptor: String,
|
||||
height: ScaledInteger,
|
||||
weight: ScaledInteger,
|
||||
}
|
||||
|
||||
/// This structure contains all the data necessary for the context of the application as it relates to the pokemon the
|
||||
/// application uses. It acts as a "context" which contains all the data for pokemon in an arbitrary pokedex. Usually
|
||||
/// this is used for the "national dex" which contains data for all pokemon of all generations, but it can be
|
||||
/// arbitrarily built as well.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Pokedex {
|
||||
/*
|
||||
* Implementation Details:
|
||||
*
|
||||
* This struct is a "Struct of Arrays (SoA)" as a manner of speaking. In theory, we could have
|
||||
* an Array of Structs (AoS) of Pokemon Species, but it is not generally common that a user of
|
||||
* the pokedex is interested in ALL the data for a given species. Usually, they want to do
|
||||
* something like iterate over base stats, abilities, egg groups, or evolution lines. Therefore,
|
||||
* it makes more sense for a "Species" to simply be an index that can be used to lookup the
|
||||
* relevant data, instead of stuffing all the data into a single Species struct.
|
||||
*/
|
||||
species: Vec<PokemonSpecies>,
|
||||
base_stats: Vec<BaseStats>,
|
||||
types: Vec<(Type, Option<Type>)>,
|
||||
abilities: Vec<(Ability, Option<Ability>, Option<Ability>)>,
|
||||
evolutions: Vec<Option<Evolution>>,
|
||||
}
|
||||
|
||||
impl Default for Pokedex {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
species: Vec::with_capacity(DEFAULT_CAPACITY),
|
||||
base_stats: Vec::with_capacity(DEFAULT_CAPACITY),
|
||||
types: Vec::with_capacity(DEFAULT_CAPACITY),
|
||||
abilities: Vec::with_capacity(DEFAULT_CAPACITY),
|
||||
evolutions: Vec::with_capacity(DEFAULT_CAPACITY),
|
||||
}
|
||||
}
|
||||
}
|
||||
4
pokedex/src/resources/mod.rs
Normal file
4
pokedex/src/resources/mod.rs
Normal file
@@ -0,0 +1,4 @@
|
||||
mod pokeapi;
|
||||
pub mod pokemon;
|
||||
|
||||
pub use pokeapi::*;
|
||||
18
pokedex/src/resources/pokeapi/mod.rs
Normal file
18
pokedex/src/resources/pokeapi/mod.rs
Normal file
@@ -0,0 +1,18 @@
|
||||
/// A struct for interfacing with the PokeAPI REST API.
|
||||
pub struct PokeAPIClient {
|
||||
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||
pub enum APIError {
|
||||
ResourceNotFound
|
||||
}
|
||||
|
||||
impl PokeAPIClient {
|
||||
pub fn init() -> Self {
|
||||
Self {}
|
||||
}
|
||||
|
||||
pub fn retrieve_pokemon_by_id(_id: usize) {
|
||||
}
|
||||
}
|
||||
2
pokedex/src/resources/pokeapi/pokemon_json.rs
Normal file
2
pokedex/src/resources/pokeapi/pokemon_json.rs
Normal file
@@ -0,0 +1,2 @@
|
||||
struct PokemonJSON {
|
||||
}
|
||||
6
pokedex/src/resources/pokemon.rs
Normal file
6
pokedex/src/resources/pokemon.rs
Normal file
@@ -0,0 +1,6 @@
|
||||
use crate::pokemon::PokemonSpecies;
|
||||
|
||||
/// Retrieves info about a given pokemon species given its national dex id
|
||||
pub fn get_species_by_id(_id: usize) -> PokemonSpecies {
|
||||
todo!()
|
||||
}
|
||||
@@ -1,11 +1,12 @@
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
||||
#[derive(Debug, Copy, Clone, Default, PartialEq, Eq, Hash)]
|
||||
pub enum SpecialType {
|
||||
Bird, // Only present in gens 1 and 2 as an unused type value.
|
||||
#[default]
|
||||
Unknown, // Only present in older generations
|
||||
Bird, // Only present in gens 1 and 2 as an unused type value.
|
||||
Stellar, // Only present in gen 9 for the tera stellar type.
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Hash)]
|
||||
#[derive(Debug, Copy, Clone, Default, PartialEq, Hash)]
|
||||
pub enum Type {
|
||||
Bug,
|
||||
Dark,
|
||||
@@ -19,7 +20,10 @@ pub enum Type {
|
||||
Grass,
|
||||
Ground,
|
||||
Ice,
|
||||
|
||||
#[default]
|
||||
Normal,
|
||||
|
||||
Poison,
|
||||
Psychic,
|
||||
Rock,
|
||||
@@ -1,2 +0,0 @@
|
||||
mod types;
|
||||
pub use types::*;
|
||||
47
src/main.rs
47
src/main.rs
@@ -1,47 +0,0 @@
|
||||
use pokemon_lib::*;
|
||||
|
||||
fn main() {
|
||||
let mut total = 0u32;
|
||||
let mut neutral = 0u32;
|
||||
let mut immune = 0u32;
|
||||
let mut effective = 0u32;
|
||||
let mut resisted = 0u32;
|
||||
let mut double_effective = 0u32;
|
||||
let mut double_resisted = 0u32;
|
||||
|
||||
for t1 in TYPES {
|
||||
for t2 in TYPES {
|
||||
for t3 in TYPES {
|
||||
total += 1;
|
||||
|
||||
let effectiveness = Type::double_effectiveness(&t1, &t2, &t3);
|
||||
|
||||
match effectiveness {
|
||||
DoubleEffectiveness::Immune => immune += 1,
|
||||
DoubleEffectiveness::Neutral => neutral += 1,
|
||||
DoubleEffectiveness::Effective => effective += 1,
|
||||
DoubleEffectiveness::Resisted => resisted += 1,
|
||||
DoubleEffectiveness::DoubleEffective => double_effective += 1,
|
||||
DoubleEffectiveness::DoubleResisted => double_resisted += 1,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mut percent: f64;
|
||||
|
||||
println!("TOTALS: ");
|
||||
println!("TOTAL: {total}");
|
||||
percent = 100.0 * neutral as f64 / total as f64;
|
||||
println!("NEUTRAL: {neutral} ({percent:.2}%)");
|
||||
percent = 100.0 * immune as f64 / total as f64;
|
||||
println!("IMMUNE: {immune} ({percent:.2}%)");
|
||||
percent = 100.0 * effective as f64 / total as f64;
|
||||
println!("EFFECTIVE: {effective} ({percent:.2}%)");
|
||||
percent = 100.0 * resisted as f64 / total as f64;
|
||||
println!("RESISTED: {resisted} ({percent:.2}%)");
|
||||
percent = 100.0 * double_effective as f64 / total as f64;
|
||||
println!("DOUBLE_EFFECTIVE: {double_effective} ({percent:.2}%)");
|
||||
percent = 100.0 * double_resisted as f64 / total as f64;
|
||||
println!("DOUBLE_RESISTED: {double_resisted} ({percent:.2}%)");
|
||||
}
|
||||
Reference in New Issue
Block a user