mirror of https://github.com/Paoda/blue-gacha.git
feat: implement rate-up
This commit is contained in:
parent
4962ee3d79
commit
aa68942d84
|
@ -7,7 +7,7 @@ edition = "2018"
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
rand = "^0.8"
|
rand = { version = "^0.8", features = ["alloc"] }
|
||||||
serde = { version = "^1.0", features = ["derive"] }
|
serde = { version = "^1.0", features = ["derive"] }
|
||||||
serde_json = "^1.0"
|
serde_json = "^1.0"
|
||||||
serde_repr = "^0.1"
|
serde_repr = "^0.1"
|
||||||
|
|
183
src/banner.rs
183
src/banner.rs
|
@ -1,24 +1,29 @@
|
||||||
use std::convert::TryInto;
|
use crate::gacha::{Gacha, Rarity, Recruitment};
|
||||||
|
use crate::i18n::{I18nString, Language};
|
||||||
use rand::{prelude::SliceRandom, Rng};
|
use crate::student::Student;
|
||||||
|
use rand::distributions::{Distribution, WeightedIndex};
|
||||||
use crate::{
|
use rand::Rng;
|
||||||
gacha::Rarity,
|
use std::convert::{TryFrom, TryInto};
|
||||||
student::{self, Student},
|
|
||||||
};
|
|
||||||
use crate::{
|
|
||||||
gacha::{Gacha, Recruitment},
|
|
||||||
i18n::{I18nString, Language},
|
|
||||||
};
|
|
||||||
|
|
||||||
|
/// Used to Construct a Banner
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
pub struct BannerBuilder {
|
pub struct BannerBuilder {
|
||||||
name: I18nString,
|
name: I18nString,
|
||||||
rates: Option<Gacha>,
|
gacha: Option<Gacha>,
|
||||||
sparkable: Option<Vec<Student>>,
|
sparkable: Option<Vec<Student>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BannerBuilder {
|
impl BannerBuilder {
|
||||||
|
/// Creates a new instance of a BannerBuilder
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
/// * `jpn_name` - The name of the Banner as seen in Blue Archive
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
/// ```
|
||||||
|
/// # use ba_gacha::banner::BannerBuilder;
|
||||||
|
/// let banner_builder = BannerBuilder::new("ピックアップ募集");
|
||||||
|
/// ```
|
||||||
pub fn new(jpn_name: &str) -> Self {
|
pub fn new(jpn_name: &str) -> Self {
|
||||||
Self {
|
Self {
|
||||||
name: I18nString::new(jpn_name),
|
name: I18nString::new(jpn_name),
|
||||||
|
@ -26,21 +31,58 @@ impl BannerBuilder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Adds a Translation to the internal I18nString
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
/// * `language` - The target language.
|
||||||
|
/// * `name` - The name of the Banner in the target language.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
/// ```
|
||||||
|
/// # use ba_gacha::banner::BannerBuilder;
|
||||||
|
/// # use ba_gacha::i18n::Language;
|
||||||
|
/// let banner_builder = BannerBuilder::new("ピックアップ募集")
|
||||||
|
/// .with_name_translation(Language::English, "Focus Recruitment");
|
||||||
|
/// ```
|
||||||
pub fn with_name_translation(mut self, language: Language, name: &str) -> Self {
|
pub fn with_name_translation(mut self, language: Language, name: &str) -> Self {
|
||||||
self.name.update(language, name);
|
self.name.update(language, name);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn with_rates(self, rates: &Gacha) -> Self {
|
/// Adds an instance of a Gacha struct
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
/// * `gacha` - An instance of a Gacha struct
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
/// ```
|
||||||
|
/// # use ba_gacha::gacha::GachaBuilder;
|
||||||
|
/// # use ba_gacha::banner::BannerBuilder;
|
||||||
|
/// let gacha = GachaBuilder::default()
|
||||||
|
/// .with_pool(Vec::new())
|
||||||
|
/// .finish().unwrap();
|
||||||
|
///
|
||||||
|
/// let banner_builder = BannerBuilder::new("ピックアップ募集")
|
||||||
|
/// .with_gacha(&gacha);
|
||||||
|
/// ```
|
||||||
|
pub fn with_gacha(self, gacha: &Gacha) -> Self {
|
||||||
Self {
|
Self {
|
||||||
rates: Some(rates.to_owned()),
|
gacha: Some(gacha.to_owned()),
|
||||||
..self
|
..self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn with_sparkable_students(self, students: Vec<Student>) -> Self {
|
/// Adds a vector containing all sparkable students in the current Banner
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
/// * `students` - A Vector of Students which are sparkable
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
/// ```
|
||||||
|
/// # use ba_gacha::banner::BannerBuilder;
|
||||||
|
pub fn with_sparkable_students(self, students: &[Student]) -> Self {
|
||||||
Self {
|
Self {
|
||||||
sparkable: Some(students),
|
sparkable: Some(students.to_vec()),
|
||||||
..self
|
..self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -48,56 +90,99 @@ impl BannerBuilder {
|
||||||
pub fn finish(self) -> Option<Banner> {
|
pub fn finish(self) -> Option<Banner> {
|
||||||
Some(Banner {
|
Some(Banner {
|
||||||
name: self.name,
|
name: self.name,
|
||||||
rates: self.rates?,
|
gacha: self.gacha?,
|
||||||
sparkable: self.sparkable?,
|
sparkable: self.sparkable,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
enum StudentType {
|
||||||
|
One = 1, // One Star
|
||||||
|
Two, // Two Stars
|
||||||
|
Three, // Three Stars
|
||||||
|
Priority, // Rate-up Student (Presumably 3*)
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Rarity> for StudentType {
|
||||||
|
fn from(rarity: Rarity) -> Self {
|
||||||
|
match rarity {
|
||||||
|
Rarity::One => Self::One,
|
||||||
|
Rarity::Two => Self::Two,
|
||||||
|
Rarity::Three => Self::Three,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryFrom<StudentType> for Rarity {
|
||||||
|
type Error = &'static str;
|
||||||
|
|
||||||
|
fn try_from(value: StudentType) -> Result<Self, Self::Error> {
|
||||||
|
Ok(match value {
|
||||||
|
StudentType::One => Self::One,
|
||||||
|
StudentType::Two => Self::Two,
|
||||||
|
StudentType::Three => Self::Three,
|
||||||
|
StudentType::Priority => return Err("Can not convert from Priority to Rarity"),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Banner {
|
pub struct Banner {
|
||||||
pub name: I18nString,
|
pub name: I18nString,
|
||||||
rates: Gacha,
|
gacha: Gacha,
|
||||||
sparkable: Vec<Student>, // FIXME: Can we safely assume this will only contain 2 studnets?
|
sparkable: Option<Vec<Student>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Banner {
|
impl Banner {
|
||||||
fn get_random_student(&self, rarity: Rarity) -> Student {
|
fn get_random_student(&self) -> Student {
|
||||||
let mut rng = rand::thread_rng();
|
let mut rng = rand::thread_rng();
|
||||||
|
let priority_rate = self.gacha.priority.as_ref().map_or(0, |tuple| tuple.1);
|
||||||
|
let three_star_rate = self.gacha.get_rate(Rarity::Three) - priority_rate;
|
||||||
|
|
||||||
let mut filtered_students: Vec<&Student> = self
|
let items: [(StudentType, usize); 4] = [
|
||||||
.rates
|
(StudentType::One, self.gacha.get_rate(Rarity::One)),
|
||||||
.pool
|
(StudentType::Two, self.gacha.get_rate(Rarity::Two)),
|
||||||
|
(StudentType::Three, three_star_rate),
|
||||||
|
(StudentType::Priority, priority_rate),
|
||||||
|
];
|
||||||
|
|
||||||
|
let dist = WeightedIndex::new(items.iter().map(|item| item.1)).unwrap();
|
||||||
|
let students = &self.gacha.pool;
|
||||||
|
|
||||||
|
match items[dist.sample(&mut rng)] {
|
||||||
|
(StudentType::Priority, _) => {
|
||||||
|
let priority_students = &self.gacha.priority.as_ref().unwrap().0;
|
||||||
|
|
||||||
|
let index: usize = rng.gen_range(0..priority_students.len());
|
||||||
|
priority_students[index].clone()
|
||||||
|
}
|
||||||
|
(rarity, _) => {
|
||||||
|
let students: Vec<&Student> = students
|
||||||
|
.iter()
|
||||||
|
.filter(|student| student.rarity == rarity.try_into().unwrap())
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let index: usize = rng.gen_range(0..students.len());
|
||||||
|
students[index].clone()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_random_student_of_rarity(&self, rarity: Rarity) -> Student {
|
||||||
|
let students = &self.gacha.pool;
|
||||||
|
let two_star_students: Vec<&Student> = students
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|student| student.rarity == rarity)
|
.filter(|student| student.rarity == rarity)
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
filtered_students.shuffle(&mut rng);
|
let index = rand::thread_rng().gen_range(0..two_star_students.len());
|
||||||
let index: usize = rng.gen_range(0..filtered_students.len());
|
two_star_students[index].clone()
|
||||||
|
|
||||||
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 {
|
impl Recruitment for Banner {
|
||||||
fn roll(&self) -> Student {
|
fn roll(&self) -> Student {
|
||||||
self.get_random_student(self.get_random_rarity())
|
self.get_random_student()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn roll10(&self) -> [Student; 10] {
|
fn roll10(&self) -> [Student; 10] {
|
||||||
|
@ -105,14 +190,14 @@ impl Recruitment for Banner {
|
||||||
|
|
||||||
// Fill students with 10 random students
|
// Fill students with 10 random students
|
||||||
for student in students.iter_mut() {
|
for student in students.iter_mut() {
|
||||||
*student = self.get_random_student(self.get_random_rarity());
|
*student = self.get_random_student()
|
||||||
}
|
}
|
||||||
|
|
||||||
let two_star_present = students.iter().any(|student| student.rarity == Rarity::Two);
|
let two_star_present = students.iter().any(|student| student.rarity == Rarity::Two);
|
||||||
|
|
||||||
if !two_star_present {
|
if !two_star_present {
|
||||||
if students[students.len() - 1].rarity != Rarity::Three {
|
if students[students.len() - 1].rarity != Rarity::Three {
|
||||||
students[students.len() - 1] = self.get_random_student(Rarity::Two);
|
students[students.len() - 1] = self.get_random_student_of_rarity(Rarity::Two);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
32
src/gacha.rs
32
src/gacha.rs
|
@ -43,6 +43,7 @@ pub trait Recruitment {
|
||||||
pub struct GachaBuilder {
|
pub struct GachaBuilder {
|
||||||
rates: Option<(usize, usize, usize)>,
|
rates: Option<(usize, usize, usize)>,
|
||||||
pool: Option<Vec<Student>>,
|
pool: Option<Vec<Student>>,
|
||||||
|
priority: Option<(Vec<Student>, usize)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for GachaBuilder {
|
impl Default for GachaBuilder {
|
||||||
|
@ -50,6 +51,7 @@ impl Default for GachaBuilder {
|
||||||
Self {
|
Self {
|
||||||
rates: Some((790, 185, 25)),
|
rates: Some((790, 185, 25)),
|
||||||
pool: Default::default(),
|
pool: Default::default(),
|
||||||
|
priority: Default::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -78,7 +80,7 @@ impl GachaBuilder {
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
rates: Some((one, two, three)),
|
rates: Some((one, two, three)),
|
||||||
pool: Default::default(),
|
..Default::default()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -103,6 +105,29 @@ impl GachaBuilder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Attaches a pool of Students who have increased rates
|
||||||
|
///
|
||||||
|
/// # Arugments
|
||||||
|
/// * `students` - A Vector of Students who have increased rates
|
||||||
|
/// * `rate` - The rate of the students in the previous argument
|
||||||
|
///
|
||||||
|
/// # 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::new(79.0, 18.5, 2.5)
|
||||||
|
/// .with_pool(vec![aru, hina.clone()])
|
||||||
|
/// .with_priority(vec![hina], 3.5);
|
||||||
|
/// ```
|
||||||
|
pub fn with_priority(self, students: &[Student], total_rate: f32) -> Self {
|
||||||
|
Self {
|
||||||
|
priority: Some((students.to_vec(), (total_rate * 10.0) as usize)),
|
||||||
|
..self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Consumes a GachaBuilder and retuns a Gacha Struct.
|
/// Consumes a GachaBuilder and retuns a Gacha Struct.
|
||||||
///
|
///
|
||||||
/// Will return `None` if the `rates` or `pool` property of
|
/// Will return `None` if the `rates` or `pool` property of
|
||||||
|
@ -122,6 +147,7 @@ impl GachaBuilder {
|
||||||
Some(Gacha {
|
Some(Gacha {
|
||||||
rates: self.rates?,
|
rates: self.rates?,
|
||||||
pool: self.pool?,
|
pool: self.pool?,
|
||||||
|
priority: self.priority,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -130,8 +156,10 @@ impl GachaBuilder {
|
||||||
/// to randomly select a Student from the gacha pool
|
/// to randomly select a Student from the gacha pool
|
||||||
#[derive(Debug, Default, Clone)]
|
#[derive(Debug, Default, Clone)]
|
||||||
pub struct Gacha {
|
pub struct Gacha {
|
||||||
pub rates: (usize, usize, usize), // One Star, Two Star, Three Star
|
/// (1★, 2★, 3★)
|
||||||
|
pub rates: (usize, usize, usize),
|
||||||
pub pool: Vec<Student>,
|
pub pool: Vec<Student>,
|
||||||
|
pub priority: Option<(Vec<Student>, usize)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Gacha {
|
impl Gacha {
|
||||||
|
|
18
src/i18n.rs
18
src/i18n.rs
|
@ -7,6 +7,24 @@ pub struct I18nString {
|
||||||
translations: HashMap<Language, String>,
|
translations: HashMap<Language, String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl PartialEq for I18nString {
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
self.get(Language::Japanese).unwrap() == other.get(Language::Japanese).unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialEq<String> for I18nString {
|
||||||
|
fn eq(&self, other: &String) -> bool {
|
||||||
|
self.get(Language::Japanese).unwrap() == *other
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialEq<&str> for I18nString {
|
||||||
|
fn eq(&self, other: &&str) -> bool {
|
||||||
|
self.get(Language::Japanese).unwrap() == *other
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl std::fmt::Display for I18nString {
|
impl std::fmt::Display for I18nString {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
f.write_str(self.translations.get(&Language::Japanese).unwrap().as_str())
|
f.write_str(self.translations.get(&Language::Japanese).unwrap().as_str())
|
||||||
|
|
188
src/main.rs
188
src/main.rs
|
@ -1,174 +1,46 @@
|
||||||
use std::io::Write;
|
use ba_gacha::banner::BannerBuilder;
|
||||||
|
use ba_gacha::gacha::{GachaBuilder, Recruitment};
|
||||||
use ba_gacha::{
|
use ba_gacha::i18n::Language;
|
||||||
banner::BannerBuilder,
|
use ba_gacha::student::Student;
|
||||||
gacha::{GachaBuilder, Rarity, Recruitment},
|
use std::{fs::File, io::Read};
|
||||||
i18n::Language,
|
|
||||||
student::Student,
|
|
||||||
};
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
// Create a Struct representing Shiroko
|
let mut file = File::open("students.json").unwrap();
|
||||||
let mut shiroko = Student::new("シロコ", Rarity::Three);
|
let mut json = String::new();
|
||||||
shiroko.add_translation(Language::English, "Shiroko"); // Yes, this is a translation.
|
file.read_to_string(&mut json).unwrap();
|
||||||
|
|
||||||
// Create a Struct representing Hoshino
|
let students: Vec<Student> = serde_json::from_str(&json).unwrap();
|
||||||
let mut hoshino = Student::new("ホシノ", Rarity::Three);
|
|
||||||
hoshino.add_translation(Language::English, "Hoshino");
|
|
||||||
|
|
||||||
// Create a Vector Containing all the Sparkable Students
|
let banner_students: Vec<Student> = students
|
||||||
let sparkable_students = vec![shiroko, hoshino];
|
.iter()
|
||||||
|
.filter(|student| student.name != "ノゾミ")
|
||||||
|
.map(|student| student.clone())
|
||||||
|
.collect();
|
||||||
|
|
||||||
let rates = GachaBuilder::new(79.0, 18.5, 2.5)
|
let hoshino = find_student(&students, "ホシノ").unwrap();
|
||||||
.with_pool(pickup_banner_2021_02_11())
|
let shiroko = find_student(&students, "シロコ").unwrap();
|
||||||
|
let rate_up_students = vec![shiroko, hoshino];
|
||||||
|
|
||||||
|
let gacha = GachaBuilder::new(79.0, 18.5, 2.5)
|
||||||
|
.with_pool(banner_students)
|
||||||
|
.with_priority(&rate_up_students, 0.7)
|
||||||
.finish()
|
.finish()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
// Create the Banner Itself
|
|
||||||
let pickup_banner = BannerBuilder::new("ピックアップ募集")
|
let pickup_banner = BannerBuilder::new("ピックアップ募集")
|
||||||
.with_name_translation(Language::English, "Priority")
|
.with_name_translation(Language::English, "Rate-Up Registration")
|
||||||
.with_sparkable_students(sparkable_students)
|
.with_sparkable_students(&rate_up_students)
|
||||||
.with_rates(&rates)
|
.with_gacha(&gacha)
|
||||||
.finish()
|
.finish()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
// Roll Banner 1 Time
|
// let student = pickup_banner.roll();
|
||||||
let student = pickup_banner.roll();
|
// let students = pickup_banner.roll10();
|
||||||
|
|
||||||
// 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();
|
pub fn find_student(students: &[Student], jpn_name: &str) -> Option<Student> {
|
||||||
// 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
|
students
|
||||||
|
.iter()
|
||||||
|
.find(|student| student.name == jpn_name)
|
||||||
|
.map(|student| student.clone())
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
use crate::gacha::Rarity;
|
use crate::gacha::Rarity;
|
||||||
use crate::i18n::I18nString;
|
use crate::i18n::{I18nString, Language};
|
||||||
use crate::i18n::Language;
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
|
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
|
||||||
|
|
|
@ -0,0 +1,407 @@
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"name": {
|
||||||
|
"translations": {
|
||||||
|
"jpn": "ヒナ",
|
||||||
|
"eng": "Hina"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"rarity": 3
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": {
|
||||||
|
"translations": {
|
||||||
|
"jpn": "イオリ",
|
||||||
|
"eng": "Iori"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"rarity": 3
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": {
|
||||||
|
"translations": {
|
||||||
|
"jpn": "ハルナ",
|
||||||
|
"eng": "Haruna"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"rarity": 3
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": {
|
||||||
|
"translations": {
|
||||||
|
"jpn": "イズミ",
|
||||||
|
"eng": "Izumi"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"rarity": 3
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": {
|
||||||
|
"translations": {
|
||||||
|
"eng": "Aru",
|
||||||
|
"jpn": "アル"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"rarity": 3
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": {
|
||||||
|
"translations": {
|
||||||
|
"jpn": "スミレ",
|
||||||
|
"eng": "Sumire"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"rarity": 3
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": {
|
||||||
|
"translations": {
|
||||||
|
"jpn": "エイミ",
|
||||||
|
"eng": "Iemi"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"rarity": 3
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": {
|
||||||
|
"translations": {
|
||||||
|
"eng": "Karin",
|
||||||
|
"jpn": "カリン"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"rarity": 3
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": {
|
||||||
|
"translations": {
|
||||||
|
"jpn": "ネル",
|
||||||
|
"eng": "Neru"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"rarity": 3
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": {
|
||||||
|
"translations": {
|
||||||
|
"eng": "Maki",
|
||||||
|
"jpn": "マキ"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"rarity": 3
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": {
|
||||||
|
"translations": {
|
||||||
|
"eng": "Hibiki",
|
||||||
|
"jpn": "ヒビキ"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"rarity": 3
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": {
|
||||||
|
"translations": {
|
||||||
|
"eng": "Saya",
|
||||||
|
"jpn": "サヤ"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"rarity": 3
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": {
|
||||||
|
"translations": {
|
||||||
|
"eng": "Shun",
|
||||||
|
"jpn": "シュン"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"rarity": 3
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": {
|
||||||
|
"translations": {
|
||||||
|
"eng": "Shiroko",
|
||||||
|
"jpn": "シロコ"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"rarity": 3
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": {
|
||||||
|
"translations": {
|
||||||
|
"eng": "Hoshino",
|
||||||
|
"jpn": "ホシノ"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"rarity": 3
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": {
|
||||||
|
"translations": {
|
||||||
|
"jpn": "ヒフミ",
|
||||||
|
"eng": "Hifumi"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"rarity": 3
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": {
|
||||||
|
"translations": {
|
||||||
|
"eng": "Tsurugi",
|
||||||
|
"jpn": "ツルギ"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"rarity": 3
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": {
|
||||||
|
"translations": {
|
||||||
|
"jpn": "アカリ",
|
||||||
|
"eng": "Akari"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"rarity": 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": {
|
||||||
|
"translations": {
|
||||||
|
"jpn": "ジュンコ",
|
||||||
|
"eng": "Junko"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"rarity": 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": {
|
||||||
|
"translations": {
|
||||||
|
"jpn": "ムツキ",
|
||||||
|
"eng": "Mutsuki"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"rarity": 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": {
|
||||||
|
"translations": {
|
||||||
|
"eng": "Kayoko",
|
||||||
|
"jpn": "カヨコ"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"rarity": 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": {
|
||||||
|
"translations": {
|
||||||
|
"jpn": "フウカ",
|
||||||
|
"eng": "Fuuka"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"rarity": 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": {
|
||||||
|
"translations": {
|
||||||
|
"jpn": "ユウカ",
|
||||||
|
"eng": "Yuuka"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"rarity": 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": {
|
||||||
|
"translations": {
|
||||||
|
"eng": "Akane",
|
||||||
|
"jpn": "アカネ"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"rarity": 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": {
|
||||||
|
"translations": {
|
||||||
|
"jpn": "ハル",
|
||||||
|
"eng": "Haru"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"rarity": 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": {
|
||||||
|
"translations": {
|
||||||
|
"eng": "Utaha",
|
||||||
|
"jpn": "ウタハ"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"rarity": 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": {
|
||||||
|
"translations": {
|
||||||
|
"jpn": "チセ",
|
||||||
|
"eng": "Chise"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"rarity": 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": {
|
||||||
|
"translations": {
|
||||||
|
"eng": "Tsubaki",
|
||||||
|
"jpn": "ツバキ"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"rarity": 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": {
|
||||||
|
"translations": {
|
||||||
|
"jpn": "セリカ",
|
||||||
|
"eng": "Serika"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"rarity": 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": {
|
||||||
|
"translations": {
|
||||||
|
"jpn": "アヤネ",
|
||||||
|
"eng": "Ayane"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"rarity": 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": {
|
||||||
|
"translations": {
|
||||||
|
"eng": "Hasumi",
|
||||||
|
"jpn": "ハスミ"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"rarity": 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": {
|
||||||
|
"translations": {
|
||||||
|
"eng": "Hanae",
|
||||||
|
"jpn": "ハナエ"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"rarity": 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": {
|
||||||
|
"translations": {
|
||||||
|
"eng": "Airi",
|
||||||
|
"jpn": "アイリ"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"rarity": 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": {
|
||||||
|
"translations": {
|
||||||
|
"jpn": "ノゾミ",
|
||||||
|
"eng": "Nozomi"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"rarity": 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": {
|
||||||
|
"translations": {
|
||||||
|
"eng": "Chinatsu",
|
||||||
|
"jpn": "チナツ"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"rarity": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": {
|
||||||
|
"translations": {
|
||||||
|
"eng": "Haruka",
|
||||||
|
"jpn": "ハルカ"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"rarity": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": {
|
||||||
|
"translations": {
|
||||||
|
"jpn": "ジュリ",
|
||||||
|
"eng": "Juri"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"rarity": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": {
|
||||||
|
"translations": {
|
||||||
|
"jpn": "コタマ",
|
||||||
|
"eng": "Kotama"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"rarity": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": {
|
||||||
|
"translations": {
|
||||||
|
"jpn": "アスナ",
|
||||||
|
"eng": "Asuna"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"rarity": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": {
|
||||||
|
"translations": {
|
||||||
|
"jpn": "コトリ",
|
||||||
|
"eng": "Kotori"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"rarity": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": {
|
||||||
|
"translations": {
|
||||||
|
"jpn": "フィーナ",
|
||||||
|
"eng": "Pina"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"rarity": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": {
|
||||||
|
"translations": {
|
||||||
|
"jpn": "スズミ",
|
||||||
|
"eng": "Suzumi"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"rarity": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": {
|
||||||
|
"translations": {
|
||||||
|
"eng": "Shimiko",
|
||||||
|
"jpn": "シミコ"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"rarity": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": {
|
||||||
|
"translations": {
|
||||||
|
"eng": "Serina",
|
||||||
|
"jpn": "セリナ"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"rarity": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": {
|
||||||
|
"translations": {
|
||||||
|
"eng": "Yoshimi",
|
||||||
|
"jpn": "ヨシミ"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"rarity": 1
|
||||||
|
}
|
||||||
|
]
|
Loading…
Reference in New Issue