Initial Commit

This commit is contained in:
Rekai Nyangadzayi Musuka 2021-02-08 22:33:35 -06:00
commit 4962ee3d79
9 changed files with 768 additions and 0 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/target

175
Cargo.lock generated Normal file
View File

@ -0,0 +1,175 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
[[package]]
name = "ba-gacha"
version = "0.1.0"
dependencies = [
"rand",
"serde",
"serde_json",
"serde_repr",
]
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "getrandom"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c9495705279e7140bf035dde1f6e750c162df8b625267cd52cc44e0b156732c8"
dependencies = [
"cfg-if",
"libc",
"wasi",
]
[[package]]
name = "itoa"
version = "0.4.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736"
[[package]]
name = "libc"
version = "0.2.86"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b7282d924be3275cec7f6756ff4121987bc6481325397dde6ba3e7802b1a8b1c"
[[package]]
name = "ppv-lite86"
version = "0.2.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857"
[[package]]
name = "proc-macro2"
version = "1.0.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71"
dependencies = [
"unicode-xid",
]
[[package]]
name = "quote"
version = "1.0.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "991431c3519a3f36861882da93630ce66b52918dcf1b8e2fd66b397fc96f28df"
dependencies = [
"proc-macro2",
]
[[package]]
name = "rand"
version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ef9e7e66b4468674bfcb0c81af8b7fa0bb154fa9f28eb840da5c447baeb8d7e"
dependencies = [
"libc",
"rand_chacha",
"rand_core",
"rand_hc",
]
[[package]]
name = "rand_chacha"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e12735cf05c9e10bf21534da50a147b924d555dc7a547c42e6bb2d5b6017ae0d"
dependencies = [
"ppv-lite86",
"rand_core",
]
[[package]]
name = "rand_core"
version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c026d7df8b298d90ccbbc5190bd04d85e159eaf5576caeacf8741da93ccbd2e5"
dependencies = [
"getrandom",
]
[[package]]
name = "rand_hc"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3190ef7066a446f2e7f42e239d161e905420ccab01eb967c9eb27d21b2322a73"
dependencies = [
"rand_core",
]
[[package]]
name = "ryu"
version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e"
[[package]]
name = "serde"
version = "1.0.123"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "92d5161132722baa40d802cc70b15262b98258453e85e5d1d365c757c73869ae"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.123"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9391c295d64fc0abb2c556bad848f33cb8296276b1ad2677d1ae1ace4f258f31"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "serde_json"
version = "1.0.62"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ea1c6153794552ea7cf7cf63b1231a25de00ec90db326ba6264440fa08e31486"
dependencies = [
"itoa",
"ryu",
"serde",
]
[[package]]
name = "serde_repr"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2dc6b7951b17b051f3210b063f12cc17320e2fe30ae05b0fe2a3abb068551c76"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "syn"
version = "1.0.60"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c700597eca8a5a762beb35753ef6b94df201c81cca676604f547495a0d7f0081"
dependencies = [
"proc-macro2",
"quote",
"unicode-xid",
]
[[package]]
name = "unicode-xid"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564"
[[package]]
name = "wasi"
version = "0.10.2+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6"

13
Cargo.toml Normal file
View File

@ -0,0 +1,13 @@
[package]
name = "ba-gacha"
version = "0.1.0"
authors = ["Rekai Musuka <rekai@musuka.dev>"]
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
rand = "^0.8"
serde = { version = "^1.0", features = ["derive"] }
serde_json = "^1.0"
serde_repr = "^0.1"

121
src/banner.rs Normal file
View File

@ -0,0 +1,121 @@
use std::convert::TryInto;
use rand::{prelude::SliceRandom, Rng};
use crate::{
gacha::Rarity,
student::{self, Student},
};
use crate::{
gacha::{Gacha, Recruitment},
i18n::{I18nString, Language},
};
#[derive(Debug, Default)]
pub struct BannerBuilder {
name: I18nString,
rates: Option<Gacha>,
sparkable: Option<Vec<Student>>,
}
impl BannerBuilder {
pub fn new(jpn_name: &str) -> Self {
Self {
name: I18nString::new(jpn_name),
..Default::default()
}
}
pub fn with_name_translation(mut self, language: Language, name: &str) -> Self {
self.name.update(language, name);
self
}
pub fn with_rates(self, rates: &Gacha) -> Self {
Self {
rates: Some(rates.to_owned()),
..self
}
}
pub fn with_sparkable_students(self, students: Vec<Student>) -> Self {
Self {
sparkable: Some(students),
..self
}
}
pub fn finish(self) -> Option<Banner> {
Some(Banner {
name: self.name,
rates: self.rates?,
sparkable: self.sparkable?,
})
}
}
pub struct Banner {
pub name: I18nString,
rates: Gacha,
sparkable: Vec<Student>, // FIXME: Can we safely assume this will only contain 2 studnets?
}
impl Banner {
fn get_random_student(&self, rarity: Rarity) -> Student {
let mut rng = rand::thread_rng();
let mut filtered_students: Vec<&Student> = self
.rates
.pool
.iter()
.filter(|student| student.rarity == rarity)
.collect();
filtered_students.shuffle(&mut rng);
let index: usize = rng.gen_range(0..filtered_students.len());
filtered_students[index].clone()
}
fn get_random_rarity(&self) -> Rarity {
let mut rng = rand::thread_rng();
let random_num: usize = rng.gen_range(0..1000);
let one_rate = self.rates.get_rate(Rarity::One);
let two_rate = self.rates.get_rate(Rarity::Two);
let three_rate = self.rates.get_rate(Rarity::Three);
if random_num < three_rate {
Rarity::Three
} else if random_num < three_rate + two_rate {
Rarity::Two
} else {
Rarity::One
}
}
}
impl Recruitment for Banner {
fn roll(&self) -> Student {
self.get_random_student(self.get_random_rarity())
}
fn roll10(&self) -> [Student; 10] {
let mut students: [Student; 10] = vec![Default::default(); 10].try_into().unwrap();
// Fill students with 10 random students
for student in students.iter_mut() {
*student = self.get_random_student(self.get_random_rarity());
}
let two_star_present = students.iter().any(|student| student.rarity == Rarity::Two);
if !two_star_present {
if students[students.len() - 1].rarity != Rarity::Three {
students[students.len() - 1] = self.get_random_student(Rarity::Two);
}
}
students
}
}

161
src/gacha.rs Normal file
View File

@ -0,0 +1,161 @@
use crate::student::Student;
use serde_repr::{Deserialize_repr, Serialize_repr};
#[derive(Debug, Clone, Copy, Serialize_repr, Deserialize_repr, PartialEq, Eq)]
#[repr(u8)]
/// The Available Rarities in Blue Archive's Gacha System
pub enum Rarity {
One = 1,
Two,
Three,
}
impl std::fmt::Display for Rarity {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match *self {
Rarity::One => f.write_str("1★"),
Rarity::Two => f.write_str("2★"),
Rarity::Three => f.write_str("3★"),
}
}
}
impl Default for Rarity {
fn default() -> Self {
Self::One
}
}
/// Recruitment is a trait that consists of two methods
/// Representing single and 10-rolls
///
/// Every Banner is expected to implement the Recruitment trait
pub trait Recruitment {
fn roll(&self) -> Student;
fn roll10(&self) -> [Student; 10];
}
/// Gacha Structs are built using this GachaBuilder Class
///
/// By Default, GachaBuilder assumes the rates:
/// * 1★: 79.0%
/// * 2★: 18.5%
/// * 3★: 2.5%
pub struct GachaBuilder {
rates: Option<(usize, usize, usize)>,
pool: Option<Vec<Student>>,
}
impl Default for GachaBuilder {
fn default() -> Self {
Self {
rates: Some((790, 185, 25)),
pool: Default::default(),
}
}
}
impl GachaBuilder {
/// Creates a new instance of a GachaBuilder.
///
///
/// # Arguments
/// * `one` - The percent chance of pulling a 1★ Student
/// * `two` - The percent chance of pulling a 2★ Student
/// * `three` - The percent chance of pulling a 3★ Student
///
/// # Examples
/// ```
/// # use ba_gacha::gacha::GachaBuilder;
/// let gacha_builder: GachaBuilder = GachaBuilder::new(79.0, 18.5, 2.5)
/// .with_pool(Vec::new());
/// ```
pub fn new(one: f32, two: f32, three: f32) -> Self {
let one = (one * 10.0) as usize;
let two = (two * 10.0) as usize;
let three = (three * 10.0) as usize;
assert_eq!(one + two + three, 1000);
Self {
rates: Some((one, two, three)),
pool: Default::default(),
}
}
/// Attaches a Student Gacha Pool to the GachaBuilder
///
/// # Arguments
/// * `students` - A Vector containing every single pullable student in the Gacha
///
/// # Examples
/// ```
/// # use ba_gacha::gacha::{GachaBuilder, Rarity};
/// # use ba_gacha::student::Student;
///
/// let aru = Student::new("アル", Rarity::Three);
/// let hina = Student::new("ヒナ", Rarity::Three);
/// let gacha_builder = GachaBuilder::default().with_pool(vec![aru, hina]);
/// ```
pub fn with_pool(self, students: Vec<Student>) -> Self {
Self {
pool: Some(students),
..self
}
}
/// Consumes a GachaBuilder and retuns a Gacha Struct.
///
/// Will return `None` if the `rates` or `pool` property of
/// GachaBuilder have not been set.
///
/// # Examples
/// ```
/// # use ba_gacha::gacha::{GachaBuilder, Gacha, Rarity};
/// # use ba_gacha::student::Student;
/// let aru = Student::new("アル", Rarity::Three);
/// let hina = Student::new("ヒナ", Rarity::Three);
/// let gacha = GachaBuilder::default()
/// .with_pool(vec![aru, hina])
/// .finish().unwrap();
/// ```
pub fn finish(self) -> Option<Gacha> {
Some(Gacha {
rates: self.rates?,
pool: self.pool?,
})
}
}
/// Provides the necessary information to facilitate a "pull", which is
/// to randomly select a Student from the gacha pool
#[derive(Debug, Default, Clone)]
pub struct Gacha {
pub rates: (usize, usize, usize), // One Star, Two Star, Three Star
pub pool: Vec<Student>,
}
impl Gacha {
/// Returns a usize representing the percent chance of pulling a specific rarity
/// (in terms of 1000)
///
/// # Arguments
/// * `rarity` - The Rarity who's gacha pull rate will be returned
///
/// # Examples
/// ```
/// # use ba_gacha::gacha::{GachaBuilder, Rarity};
/// let gacha = GachaBuilder::new(79.0, 18.5, 2.5)
/// .with_pool(Vec::new())
/// .finish()
/// .unwrap();
///
/// assert_eq!(gacha.get_rate(Rarity::One), 790);
/// ```
pub fn get_rate(&self, rarity: Rarity) -> usize {
match rarity {
Rarity::One => self.rates.0,
Rarity::Two => self.rates.1,
Rarity::Three => self.rates.2,
}
}
}

60
src/i18n.rs Normal file
View File

@ -0,0 +1,60 @@
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
/// A String-like Type which allows for easy Internationalization
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct I18nString {
translations: HashMap<Language, String>,
}
impl std::fmt::Display for I18nString {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(self.translations.get(&Language::Japanese).unwrap().as_str())
}
}
impl Default for I18nString {
fn default() -> Self {
let mut map: HashMap<Language, String> = Default::default();
let _ = map.insert(Language::Japanese, "".to_string());
Self { translations: map }
}
}
impl I18nString {
/// Blue Archive is a Japanese Game, therefore I18nString's constructor
/// expects Japanese text.
pub fn new(jpn_message: &str) -> Self {
let mut map: HashMap<Language, String> = Default::default();
let _ = map.insert(Language::Japanese, jpn_message.to_string());
Self { translations: map }
}
/// This method wraps HashMap's insert, which means that:
/// * If the Language doesn't already have a translation, one will be added
/// * If a translation for the Language already exists, it will be replaced.
pub fn update(&mut self, language: Language, message: &str) {
let _ = self.translations.insert(language, message.to_string());
}
/// Get a Language's translation as an Owned String
///
/// Will return None if there is no translation for the given language
pub fn get(&self, language: Language) -> Option<String> {
self.translations
.get(&language)
.map(|message| message.clone())
}
}
/// This enum represents all Languages this Gacha Simulator **must** support.
///
/// This enum follows ISO-639-2/T
#[derive(Debug, PartialEq, Eq, Hash, Clone, Serialize, Deserialize)]
pub enum Language {
#[serde(rename = "eng")]
English,
#[serde(rename = "jpn")]
Japanese,
}

4
src/lib.rs Normal file
View File

@ -0,0 +1,4 @@
pub mod banner;
pub mod gacha;
pub mod i18n;
pub mod student;

174
src/main.rs Normal file
View File

@ -0,0 +1,174 @@
use std::io::Write;
use ba_gacha::{
banner::BannerBuilder,
gacha::{GachaBuilder, Rarity, Recruitment},
i18n::Language,
student::Student,
};
fn main() {
// Create a Struct representing Shiroko
let mut shiroko = Student::new("シロコ", Rarity::Three);
shiroko.add_translation(Language::English, "Shiroko"); // Yes, this is a translation.
// Create a Struct representing Hoshino
let mut hoshino = Student::new("ホシノ", Rarity::Three);
hoshino.add_translation(Language::English, "Hoshino");
// Create a Vector Containing all the Sparkable Students
let sparkable_students = vec![shiroko, hoshino];
let rates = GachaBuilder::new(79.0, 18.5, 2.5)
.with_pool(pickup_banner_2021_02_11())
.finish()
.unwrap();
// Create the Banner Itself
let pickup_banner = BannerBuilder::new("ピックアップ募集")
.with_name_translation(Language::English, "Priority")
.with_sparkable_students(sparkable_students)
.with_rates(&rates)
.finish()
.unwrap();
// Roll Banner 1 Time
let student = pickup_banner.roll();
// Roll Banner 10 Times
let students = pickup_banner.roll10();
// Display Results
println!("{} Single: {}", pickup_banner.name, student);
println!();
println!("{} 10-roll:", pickup_banner.name);
for student in students.iter() {
println!("{}", student);
}
// let mut file = std::fs::File::create("students.json").unwrap();
// let students = all_students();
// let json = serde_json::to_string(&students).unwrap();
// file.write_all(json.as_bytes()).unwrap();
}
fn create_student(jpn_name: &str, eng_name: &str, rarity: Rarity) -> Student {
let mut student = Student::new(jpn_name, rarity);
student.add_translation(Language::English, eng_name);
student
}
fn pickup_banner_2021_02_11() -> Vec<Student> {
let mut test: Vec<Student> = vec![];
// 3 Star
test.push(create_student("ヒナ", "Hina", Rarity::Three));
test.push(create_student("イオリ", "Iori", Rarity::Three));
test.push(create_student("ハルナ", "Haruna", Rarity::Three));
test.push(create_student("イズミ", "Izumi", Rarity::Three));
test.push(create_student("アル", "Aru", Rarity::Three));
test.push(create_student("スミレ", "Sumire", Rarity::Three));
test.push(create_student("エイミ", "Iemi", Rarity::Three));
test.push(create_student("カリン", "Karin", Rarity::Three));
test.push(create_student("ネル", "Neru", Rarity::Three));
test.push(create_student("マキ", "Maki", Rarity::Three));
test.push(create_student("ヒビキ", "Hibiki", Rarity::Three));
test.push(create_student("サヤ", "Saya", Rarity::Three));
test.push(create_student("シュン", "Shun", Rarity::Three));
test.push(create_student("シロコ", "Shiroko", Rarity::Three));
test.push(create_student("ホシノ", "Hoshino", Rarity::Three));
test.push(create_student("ヒフミ", "Hifumi", Rarity::Three));
test.push(create_student("ツルギ", "Tsurugi", Rarity::Three));
// Two Star
test.push(create_student("アカリ", "Akari", Rarity::Two));
test.push(create_student("ジュンコ", "Junko", Rarity::Two));
test.push(create_student("ムツキ", "Mutsuki", Rarity::Two));
test.push(create_student("カヨコ", "Kayoko", Rarity::Two));
test.push(create_student("フウカ", "Fuuka", Rarity::Two));
test.push(create_student("ユウカ", "Yuuka", Rarity::Two));
test.push(create_student("アカネ", "Akane", Rarity::Two));
test.push(create_student("ハル", "Haru", Rarity::Two));
test.push(create_student("ウタハ", "Utaha", Rarity::Two));
test.push(create_student("チセ", "Chise", Rarity::Two));
test.push(create_student("ツバキ", "Tsubaki", Rarity::Two));
test.push(create_student("セリカ", "Serika", Rarity::Two));
test.push(create_student("アヤネ", "Ayane", Rarity::Two));
test.push(create_student("ハスミ", "Hasumi", Rarity::Two));
test.push(create_student("ハナエ", "Hanae", Rarity::Two));
test.push(create_student("アイリ", "Airi", Rarity::Two));
// 1 Star:
test.push(create_student("チナツ", "Chinatsu", Rarity::One));
test.push(create_student("ハルカ", "Haruka", Rarity::One));
test.push(create_student("ジュリ", "Juri", Rarity::One));
test.push(create_student("コタマ", "Kotama", Rarity::One));
test.push(create_student("アスナ", "Asuna", Rarity::One));
test.push(create_student("コトリ", "Kotori", Rarity::One));
test.push(create_student("フィーナ", "Pina", Rarity::One));
test.push(create_student("スズミ", "Suzumi", Rarity::One));
test.push(create_student("シミコ", "Shimiko", Rarity::One));
test.push(create_student("セリナ", "Serina", Rarity::One));
test.push(create_student("ヨシミ", "Yoshimi", Rarity::One));
test
}
fn all_students() -> Vec<Student> {
let mut students: Vec<Student> = Vec::with_capacity(45);
// 3 Star
students.push(create_student("ヒナ", "Hina", Rarity::Three));
students.push(create_student("イオリ", "Iori", Rarity::Three));
students.push(create_student("ハルナ", "Haruna", Rarity::Three));
students.push(create_student("イズミ", "Izumi", Rarity::Three));
students.push(create_student("アル", "Aru", Rarity::Three));
students.push(create_student("スミレ", "Sumire", Rarity::Three));
students.push(create_student("エイミ", "Iemi", Rarity::Three));
students.push(create_student("カリン", "Karin", Rarity::Three));
students.push(create_student("ネル", "Neru", Rarity::Three));
students.push(create_student("マキ", "Maki", Rarity::Three));
students.push(create_student("ヒビキ", "Hibiki", Rarity::Three));
students.push(create_student("サヤ", "Saya", Rarity::Three));
students.push(create_student("シュン", "Shun", Rarity::Three));
students.push(create_student("シロコ", "Shiroko", Rarity::Three));
students.push(create_student("ホシノ", "Hoshino", Rarity::Three));
students.push(create_student("ヒフミ", "Hifumi", Rarity::Three));
students.push(create_student("ツルギ", "Tsurugi", Rarity::Three));
// Two Star
students.push(create_student("アカリ", "Akari", Rarity::Two));
students.push(create_student("ジュンコ", "Junko", Rarity::Two));
students.push(create_student("ムツキ", "Mutsuki", Rarity::Two));
students.push(create_student("カヨコ", "Kayoko", Rarity::Two));
students.push(create_student("フウカ", "Fuuka", Rarity::Two));
students.push(create_student("ユウカ", "Yuuka", Rarity::Two));
students.push(create_student("アカネ", "Akane", Rarity::Two));
students.push(create_student("ハル", "Haru", Rarity::Two));
students.push(create_student("ウタハ", "Utaha", Rarity::Two));
students.push(create_student("チセ", "Chise", Rarity::Two));
students.push(create_student("ツバキ", "Tsubaki", Rarity::Two));
students.push(create_student("セリカ", "Serika", Rarity::Two));
students.push(create_student("アヤネ", "Ayane", Rarity::Two));
students.push(create_student("ハスミ", "Hasumi", Rarity::Two));
students.push(create_student("ハナエ", "Hanae", Rarity::Two));
students.push(create_student("アイリ", "Airi", Rarity::Two));
students.push(create_student("ノゾミ", "Nozomi", Rarity::Two)); // Not a part of Gacha
// 1 Star:
students.push(create_student("チナツ", "Chinatsu", Rarity::One));
students.push(create_student("ハルカ", "Haruka", Rarity::One));
students.push(create_student("ジュリ", "Juri", Rarity::One));
students.push(create_student("コタマ", "Kotama", Rarity::One));
students.push(create_student("アスナ", "Asuna", Rarity::One));
students.push(create_student("コトリ", "Kotori", Rarity::One));
students.push(create_student("フィーナ", "Pina", Rarity::One));
students.push(create_student("スズミ", "Suzumi", Rarity::One));
students.push(create_student("シミコ", "Shimiko", Rarity::One));
students.push(create_student("セリナ", "Serina", Rarity::One));
students.push(create_student("ヨシミ", "Yoshimi", Rarity::One));
students
}

59
src/student.rs Normal file
View File

@ -0,0 +1,59 @@
use crate::gacha::Rarity;
use crate::i18n::I18nString;
use crate::i18n::Language;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
/// A Student which has just the information necessary for gacha associated with it
pub struct Student {
/// There is guaranteed to be a Japanese Name available at all times
pub name: I18nString,
pub rarity: Rarity,
}
impl std::fmt::Display for Student {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}\t{}", self.name, self.rarity)
}
}
impl Student {
/// Creates a new Instance of a Student
///
/// # Arguments
/// * `jpn_name` - The name of the Student from the Japanese Version of Blue Archive
/// * `rarity` - The Rarity of the Student
///
/// # Examples
/// ```
/// # use ba_gacha::gacha::Rarity;
/// # use ba_gacha::student::Student;
///
/// let mutsuki = Student::new("ムツキ", Rarity::Two);
/// ```
pub fn new(jpn_name: &str, rarity: Rarity) -> Self {
Self {
name: I18nString::new(jpn_name),
rarity,
}
}
/// Adds a new Translation to the internal [`I18nString`].
///
/// # Arguments
/// * `language` - The Language of the translation to be added
/// * `name` - The Translated name, in the language of the previous argument.
///
/// # Examples
/// ```
/// # use ba_gacha::gacha::Rarity;
/// # use ba_gacha::student::Student;
/// # use ba_gacha::i18n::Language;
///
/// let mut mutsuki = Student::new("ムツキ", Rarity::Two);
/// mutsuki.add_translation(Language::English, "Mutsuki");
/// ```
pub fn add_translation(&mut self, language: Language, name: &str) {
self.name.update(language, name);
}
}