OA2SY6VNE4QSCQJ5PUNJ42RB7BK5PE26CWBAOYNGDVGIBWPHCGOAC
pub struct Support;
pub struct Supports;
pub struct Summon;
pub struct Summons;
use enum_dispatch::enum_dispatch;
#[enum_dispatch(StatusTrait)]
pub enum Status {}
#[enum_dispatch]
pub trait StatusTrait {}
pub struct Statuses;
pub struct EquipmentStatuses;
pub enum Preprocessables {
Swap,
Skill,
Card,
DmgElement,
DmgReaction,
DmgAmountPlus,
DmgAmountMinus,
DmgAmountMul,
RollChances,
}
pub enum Informables {
DmgDelt,
SkillUsage,
CharacterDeath,
}
use enumset::EnumSetType;
use Reaction::*;
#[repr(u8)]
#[derive(EnumSetType, Debug)]
pub enum Reaction {
BLOOM,
BURNING,
CRYSTALLIZE,
ELECTROCHARGED,
FROZEN,
MELT,
OVERLOADED,
QUICKEN,
SUPERCONDUCT,
SWIRL,
VAPORIZE,
}
use crate::element::Element::{self, *};
use crate::element::ElementSet;
use crate::element::{elem_set, ElementalAura};
macro_rules! test {
($fst:expr, $snd:expr; $value:path, $($rest:path),* $(,)*) => {
if $value.test_reaction($fst, $snd) { return Some($value) };
$(if $rest.test_reaction($fst, $snd) { return Some($value) });*
}
}
macro_rules! test_detail {
($fst:expr, $snd:expr; $value:path, $($rest:path),* $(,)*) => {
if $value.test_reaction($fst, $snd) { return Some(ReactionDetail::new($value, $fst, $snd)) };
$(if $rest.test_reaction($fst, $snd) { return Some(ReactionDetail::new($value, $fst, $snd)) });*
}
}
impl Reaction {
pub const fn reaction_elems(self) -> (ElementSet, ElementSet) {
use elem_set as S;
match self {
BLOOM => (S!(DENDRO), S!(HYDRO)),
BURNING => (S!(DENDRO), S!(PYRO)),
CRYSTALLIZE => (S!(PYRO, HYDRO, CRYO, ELECTRO), S!(GEO)),
ELECTROCHARGED => (S!(HYDRO), S!(ELECTRO)),
FROZEN => (S!(HYDRO), S!(CRYO)),
MELT => (S!(PYRO), S!(CRYO)),
OVERLOADED => (S!(PYRO), S!(ELECTRO)),
QUICKEN => (S!(DENDRO), S!(ELECTRO)),
SUPERCONDUCT => (S!(CRYO), S!(ELECTRO)),
SWIRL => (S!(PYRO, HYDRO, CRYO, ELECTRO), S!(ANEMO)),
VAPORIZE => (S!(HYDRO), S!(PYRO)),
}
}
pub const fn damage_boost(self) -> usize {
match self {
BLOOM => 1,
BURNING => 1,
CRYSTALLIZE => 1,
ELECTROCHARGED => 1,
FROZEN => 1,
MELT => 2,
OVERLOADED => 2,
QUICKEN => 1,
SUPERCONDUCT => 1,
SWIRL => 0,
VAPORIZE => 2,
}
}
fn test_reaction(self, fst: Element, snd: Element) -> bool {
let (x, y) = self.reaction_elems();
x.contains(fst) && y.contains(snd) || y.contains(fst) && x.contains(snd)
}
pub fn consult_reaction(fst: Element, snd: Element) -> Option<Reaction> {
test!(fst, snd;
BURNING,
CRYSTALLIZE,
ELECTROCHARGED,
FROZEN,
MELT,
OVERLOADED,
QUICKEN,
SUPERCONDUCT,
SWIRL,
VAPORIZE,
);
None
}
pub fn consult_reaction_detail(fst: Element, snd: Element) -> Option<ReactionDetail> {
test_detail!(fst, snd;
BURNING,
CRYSTALLIZE,
ELECTROCHARGED,
FROZEN,
MELT,
OVERLOADED,
QUICKEN,
SUPERCONDUCT,
SWIRL,
VAPORIZE,
);
None
}
pub fn consult_reaction_with_aura(aura: ElementalAura, snd: Element) -> Option<ReactionDetail> {
aura.consult_reaction(snd)
}
}
pub struct ReactionDetail {
reaction: Reaction,
fst: Element,
snd: Element,
}
impl ReactionDetail {
pub const fn new(reaction: Reaction, fst: Element, snd: Element) -> Self {
Self { reaction, fst, snd }
}
pub fn elem_reaction(self, elem: Element) -> bool {
self.fst == elem || self.snd == elem
}
}
use crate::{
act::Act, card::Cards, character::Characters, dice::ActualDices, status::Statuses,
summon::Summons, support::Supports,
};
pub struct PlayerState {
pub phase: Act,
pub conset_action: bool,
pub charcters: Characters,
pub hidden_statuses: Statuses,
pub combat_statuses: Statuses,
pub summons: Summons,
pub supports: Supports,
pub card_redraw_chances: usize,
pub dice_reroll_chances: usize,
pub dices: ActualDices,
pub hand_cards: Cards,
pub deck_cards: Cards,
pub publicly_used_cards: Cards,
pub publicly_gained_cards: Cards,
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum Pid {
Player1,
Player2,
}
impl std::ops::Not for Pid {
type Output = Pid;
fn not(self) -> Self::Output {
match self {
Pid::Player1 => Pid::Player2,
Pid::Player2 => Pid::Player1,
}
}
}
use enum_dispatch::enum_dispatch;
use crate::{game_state::GameState, pid::Pid, act::Act, action_generator::ActionGenerator};
#[enum_dispatch(PhaseTrait)]
pub enum Phase {
CardsSelectPhase,
}
#[enum_dispatch]
trait PhaseTrait {
fn step(&self, state: &GameState) -> GameState;
fn step_action(&self, state: &GameState, pid: Pid) -> GameState;
fn waiting_for(&self, state: &GameState) -> Option<Pid>;
fn action_generator(&self, state: &GameState, pid: Pid) -> ActionGenerator;
}
struct CardsSelectPhase;
impl PhaseTrait for CardsSelectPhase {
fn step(&self, state: &GameState) -> GameState {
let ref p1 = state.player1;
let ref p2 = state.player2;
todo!()
}
fn step_action(&self, state: &GameState, pid: Pid) -> GameState {
todo!()
}
fn waiting_for(&self, state: &GameState) -> Option<Pid> {
todo!()
}
fn action_generator(&self, state: &GameState, pid: Pid) -> ActionGenerator {
todo!()
}
}
use crate::{
dice::{AbstractDices, Dices},
element::Element,
event::EventSpeed,
};
use once_cell::sync::Lazy;
const CARD_REDRAW_CHANCES: usize = 1;
const DECK_CARDS_REQUIREMENT: usize = 30;
const DECK_CARD_LIMIT_PER_KIND: usize = 2;
const DECK_CHARS_REQUIREMENT: usize = 3;
const DECK_CHAR_LIMIT_PER_KIND: usize = 1;
const DICE_LIMIT: usize = 16;
const DICE_REROLL_CHANCES: usize = 1;
const HAND_CARD_LIMIT: usize = 10;
const MAX_CARDS_PER_KIND: usize = 2;
const ROUND_LIMIT: usize = 15;
const SUMMONS_LIMIT: usize = 4;
const SUPPORTS_LIMIT: usize = 4;
const SWAP_COST: Lazy<AbstractDices> = Lazy::new(|| AbstractDices::new_from_element_iter([Element::ANY; 1].into_iter()));
const SWAP_SPEED: EventSpeed = EventSpeed::Combat;
pub struct Mode {
card_redraw_chances: usize,
deck_cards_requirement: usize,
deck_card_limit_per_kind: usize,
deck_chars_requirement: usize,
deck_char_limit_per_kind: usize,
dice_limit: usize,
dice_reroll_chances: usize,
hand_card_limit: usize,
max_cards_per_kind: usize,
round_limit: usize,
summons_limit: usize,
supports_limit: usize,
swap_cost: AbstractDices,
swap_speed: EventSpeed,
}
impl Default for Mode {
fn default() -> Self {
Self {
card_redraw_chances: CARD_REDRAW_CHANCES,
deck_cards_requirement: DECK_CARDS_REQUIREMENT,
deck_card_limit_per_kind: DECK_CARD_LIMIT_PER_KIND,
deck_chars_requirement: DECK_CHARS_REQUIREMENT,
deck_char_limit_per_kind: DECK_CHAR_LIMIT_PER_KIND,
dice_limit: DICE_LIMIT,
dice_reroll_chances: DICE_REROLL_CHANCES,
hand_card_limit: HAND_CARD_LIMIT,
max_cards_per_kind: MAX_CARDS_PER_KIND,
round_limit: ROUND_LIMIT,
summons_limit: SUMMONS_LIMIT,
supports_limit: SUPPORTS_LIMIT,
swap_cost: SWAP_COST.clone(),
swap_speed: SWAP_SPEED,
}
}
}
fn main() {
println!("Hello, world!");
}
#![allow(dead_code)]
mod act;
mod action;
mod action_generator;
mod agent;
mod card;
mod character;
mod deck;
mod dice;
mod effect;
mod element;
mod event;
mod game_state_machine;
mod game_state;
mod mode;
mod phase;
mod pid;
mod player_state;
mod reaction;
mod status;
mod summon;
mod support;
use typed_arena::Arena;
use crate::{game_state::GameState, action::PlayerAction, agent::PlayerAgent};
pub struct GameStateMachine<'a> {
pub state_arena: Arena<GameState>,
pub action_arena: Arena<PlayerAction>,
pub history: Vec<&'a GameState>,
pub action_history: Vec<&'a PlayerAction>,
pub current_state: &'a GameState,
pub player_agent1: PlayerAgent,
pub player_agent2: PlayerAgent,
}
use crate::{effect::EffectStack, mode::Mode, phase::Phase, pid::Pid, player_state::PlayerState};
pub struct GameState {
pub mode: Mode,
pub phase: Phase,
pub round: usize,
pub active_player: Pid,
pub player1: PlayerState,
pub player2: PlayerState,
pub effect_stack: EffectStack,
}
use enum_map::Enum;
use enumset::EnumSetType;
#[derive(Enum, EnumSetType, Debug)]
pub enum EventSpeed {
Fast,
Combat,
}
#[derive(Enum, EnumSetType, Debug)]
pub enum EventType {
Normal,
ElementalSkill1,
ElementalSkill2,
ElementalBurst,
Swap,
}
use crate::reaction::{Reaction, ReactionDetail};
use enum_map::Enum;
use enumset::{enum_set, EnumSet, EnumSetType};
use Element::*;
#[repr(u8)]
#[derive(Enum, EnumSetType, Debug)]
pub enum Element {
OMNI,
PYRO,
HYDRO,
ANEMO,
ELECTRO,
DENDRO,
CRYO,
GEO,
PHYSICAL,
PIERCING,
ANY,
}
impl Element {
pub fn is_pure(self) -> bool {
!matches!(self, OMNI | PHYSICAL | PIERCING | ANY)
}
}
pub const PURE_ELEMENTS: ElementSet = elem_set!(PYRO, HYDRO, ANEMO, ELECTRO, DENDRO, CRYO, GEO);
pub const ORDERED_AURA_ELEMENTS: [Element; 5] = [PYRO, HYDRO, ELECTRO, CRYO, DENDRO];
pub const AURA_ELEMENTS: ElementSet = elem_set!(PYRO, HYDRO, ELECTRO, CRYO, DENDRO);
pub const ORDERED_LEGAL_ACTUAL_DICE_ELEMENTS: [Element; 8] =
[OMNI, CRYO, HYDRO, PYRO, ELECTRO, GEO, DENDRO, ANEMO];
pub const LEGAL_ACTUAL_DICE_ELEMENTS: ElementSet =
elem_set!(OMNI, PYRO, HYDRO, ANEMO, ELECTRO, DENDRO, CRYO, GEO);
pub const LEGAL_ABSTRACT_DICE_ELEMENTS: ElementSet =
elem_set!(OMNI, PYRO, HYDRO, ANEMO, ELECTRO, DENDRO, CRYO, GEO, ANY);
#[derive(Clone, Copy, PartialEq, Debug)]
pub struct ElementalAura(ElementSet);
impl ElementalAura {
pub fn aurable(elem: Element) -> bool {
AURA_ELEMENTS.contains(elem)
}
pub fn peek(self) -> Option<Element> {
for elem in ORDERED_AURA_ELEMENTS.iter() {
if self.0.contains(*elem) {
return Some(*elem);
}
}
None
}
pub fn remove(self, elem: Element) -> ElementalAura {
assert!(Self::aurable(elem));
ElementalAura(self.0 - elem)
}
pub fn add(self, elem: Element) -> ElementalAura {
assert!(Self::aurable(elem));
ElementalAura(self.0 | elem)
}
pub fn contains(self, elem: Element) -> bool {
assert!(Self::aurable(elem));
self.0.contains(elem)
}
pub fn has_aura(self) -> bool {
!self.0.is_empty()
}
pub fn elem_auras(self) -> ElementSet {
self.0
}
pub fn consult_reaction(self, income: Element) -> Option<ReactionDetail> {
for elem in ORDERED_AURA_ELEMENTS.into_iter() {
if self.contains(elem) {
if let Some(detail) = Reaction::consult_reaction_detail(elem, income) {
return Some(detail);
}
}
}
None
}
}
pub type ElementSet = EnumSet<Element>;
#[macro_export]
macro_rules! _elem_set {
($(|)*) => { { use enumset::enum_set; enum_set!() } };
($value:path $(,)*) => { { use enumset::enum_set; enum_set!($value) } };
($value:path , $($rest:path),* $(,)*) => { { use enumset::enum_set; enum_set!($value $(| $rest)*) } };
}
pub(crate) use _elem_set as elem_set;
pub enum Zone {
Characters,
Summons,
Supports,
HiddenStatuses,
CombatStatuses,
}
use enum_dispatch::enum_dispatch;
#[enum_dispatch(TriggerrableEffectTrait)]
pub enum TriggerrableEffect {
AllStatusTriggererEffect,
PlayerStatusTriggererEffect,
PersonalStatusTriggerEffect,
TriggerStatusEffect,
TriggerHiddenStatusEffect,
TriggerCombatStatusEffect,
TriggerSummonEffect,
TriggerSupportEffect,
}
#[enum_dispatch]
pub trait TriggerrableEffectTrait {}
pub struct AllStatusTriggererEffect;
pub struct PlayerStatusTriggererEffect;
pub struct PersonalStatusTriggerEffect;
pub struct TriggerStatusEffect;
pub struct TriggerHiddenStatusEffect;
pub struct TriggerCombatStatusEffect;
pub struct TriggerSummonEffect;
pub struct TriggerSupportEffect;
pub enum TriggeringSignal {
FastAction,
CombatAction,
DeathEvent,
TriggerRevival,
SwapEvent1,
SwapEvent2,
PostReaction,
PostDmg,
GameStart,
RoundStart,
PreAction,
ActPreSkill,
SelfDeclareEndRound,
OppoDeclareEndRound,
EndRoundCheckOut,
RoundEnd,
}
use crate::pid::Pid;
use super::zone::Zone;
pub enum DynamicCharacterTarget {
SelfSelf,
SelfActive,
SelfOffField,
SelfAll,
SelfAbs,
OppoActive,
OppoOffField,
}
pub struct StaticTarget {
pid: Pid,
zone: Zone,
id: usize,
}
use enum_dispatch::enum_dispatch;
#[enum_dispatch(PhaseEffectTrait)]
pub enum PhaseEffect {
DeathSwapPhaseStartEffect,
DeathSwapPhaseEndEffect,
EndPhaseCheckoutEffect,
EndRoundEffect,
RollPhaseStartEffect,
SetBothPlayerPhaseEffect,
TurnEndEffect,
}
#[enum_dispatch]
pub trait PhaseEffectTrait {}
pub struct DeathSwapPhaseStartEffect;
pub struct DeathSwapPhaseEndEffect;
pub struct EndPhaseCheckoutEffect;
pub struct EndRoundEffect;
pub struct RollPhaseStartEffect;
pub struct SetBothPlayerPhaseEffect;
pub struct TurnEndEffect;
use enum_dispatch::enum_dispatch;
pub mod damage_type;
pub mod target;
pub mod triggering_signal;
pub mod zone;
pub mod triggerrable_effect;
pub mod phase_effect;
pub mod checker_effect;
pub mod direct_effect;
#[enum_dispatch(EffectTrait)]
pub enum Effect {
TriggerrableEffect,
PhaseEffect,
CheckerEffect,
DirectEffect,
}
#[enum_dispatch]
pub trait EffectTrait {}
type TriggerrableEffect = triggerrable_effect::TriggerrableEffect;
type PhaseEffect = phase_effect::PhaseEffect;
type CheckerEffect = checker_effect::CheckerEffect;
type DirectEffect = direct_effect::DirectEffect;
pub struct EffectStack {
pub effects: Vec<Effect>,
}
use enum_dispatch::enum_dispatch;
#[enum_dispatch(DirectEffectTrait)]
pub enum DirectEffect {
ConsecutiveActionEffect,
SwapCharacterEffect,
BackwardSwapCharacterEffect,
ForwardSwapCharacterEffect,
ForwardSwapCharacterCheckEffect,
ApplyElementalAuraEffect,
SpecificDamageEffect,
ReferredDamageEffect,
EnergyRechargeEffect,
EnergyDrainEffect,
RecoverHPEffect,
ReviveRecoverHPEffect,
PublicAddCardEffect,
PublicRemoveCardEffect,
PublicRemoveAllCardEffect,
AddDiceEffect,
RemoveDiceEffect,
AddCharacterStatusEffect,
RemoveCharacterStatusEffect,
UpdateCharacterStatusEffect,
OverrideCharacterStatusEffect,
AddHiddenStatusEffect,
RemoveHiddenStatusEffect,
UpdateHiddenStatusEffect,
OverrideHiddenStatusEffect,
AddCombatStatusEffect,
RemoveCombatStatusEffect,
UpdateCombatStatusEffect,
OverrideCombatStatusEffect,
AddSummonEffect,
RemoveSummonEffect,
UpdateSummonEffect,
OverrideSummonEffect,
AllSummonIncreaseUsage,
OneSummonDecreaseUsage,
OneSummonIncreaseUsage,
AddSupportEffect,
RemoveSupportEffect,
UpdateSupportEffect,
OverrideSupportEffect,
CastSkillEffect,
BroadCastSkillInfoEffect,
}
#[enum_dispatch]
pub trait DirectEffectTrait {}
pub struct ConsecutiveActionEffect;
pub struct SwapCharacterEffect;
pub struct BackwardSwapCharacterEffect;
pub struct ForwardSwapCharacterEffect;
pub struct ForwardSwapCharacterCheckEffect;
pub struct ApplyElementalAuraEffect;
pub struct SpecificDamageEffect;
pub struct ReferredDamageEffect;
pub struct EnergyRechargeEffect;
pub struct EnergyDrainEffect;
pub struct RecoverHPEffect;
pub struct ReviveRecoverHPEffect;
pub struct PublicAddCardEffect;
pub struct PublicRemoveCardEffect;
pub struct PublicRemoveAllCardEffect;
pub struct AddDiceEffect;
pub struct RemoveDiceEffect;
pub struct AddCharacterStatusEffect;
pub struct RemoveCharacterStatusEffect;
pub struct UpdateCharacterStatusEffect;
pub struct OverrideCharacterStatusEffect;
pub struct AddHiddenStatusEffect;
pub struct RemoveHiddenStatusEffect;
pub struct UpdateHiddenStatusEffect;
pub struct OverrideHiddenStatusEffect;
pub struct AddCombatStatusEffect;
pub struct RemoveCombatStatusEffect;
pub struct UpdateCombatStatusEffect;
pub struct OverrideCombatStatusEffect;
pub struct AddSummonEffect;
pub struct RemoveSummonEffect;
pub struct UpdateSummonEffect;
pub struct OverrideSummonEffect;
pub struct AllSummonIncreaseUsage;
pub struct OneSummonDecreaseUsage;
pub struct OneSummonIncreaseUsage;
pub struct AddSupportEffect;
pub struct RemoveSupportEffect;
pub struct UpdateSupportEffect;
pub struct OverrideSupportEffect;
pub struct CastSkillEffect;
pub struct BroadCastSkillInfoEffect;
use enumset::{EnumSetType, EnumSet};
#[derive(EnumSetType, Debug)]
pub enum DamageKind {
NormalAttack,
ChargedAttack,
PlungeAttack,
ElementalSkill,
ElementalBurst,
Status,
Summon,
Reaction,
NoBoost,
}
pub type DamageType = EnumSet<DamageKind>;
use enum_dispatch::enum_dispatch;
#[enum_dispatch(CheckerEffectTrait)]
pub enum CheckerEffect {
AliveMarkCheckerEffect,
SwapCharacterCheckerEffect,
DeathCheckCheckerEffect,
DefeatedCheckerEffect,
}
#[enum_dispatch]
pub trait CheckerEffectTrait {}
pub struct AliveMarkCheckerEffect;
pub struct SwapCharacterCheckerEffect;
pub struct DeathCheckCheckerEffect;
pub struct DefeatedCheckerEffect;
use std::ops::Index;
use crate::element::{
Element::{*, self}, ElementSet, LEGAL_ABSTRACT_DICE_ELEMENTS, LEGAL_ACTUAL_DICE_ELEMENTS, PURE_ELEMENTS,
};
use enum_map::EnumMap;
use rand::{seq::IteratorRandom, thread_rng};
pub trait Dices<Rhs = Self> {
type Output;
fn empty() -> Self;
fn new_from_counter_iter<T>(dices: T) -> Self
where
T: Iterator<Item = (Element, i8)>;
fn new_from_element_iter<T>(dices: T) -> Self
where
T: Iterator<Item = Element>;
fn add_mut(&mut self, other: &Rhs);
fn add(&self, other: &Rhs) -> Self::Output;
fn sub_mut(&mut self, other: &Rhs);
fn sub(&self, other: &Rhs) -> Self::Output;
fn add_elements_mut<T>(&mut self, other: T)
where
T: Iterator<Item = Element>;
fn add_elements<T>(&self, other: T) -> Self::Output
where
T: Iterator<Item = Element>;
fn sub_elements_mut<T>(&mut self, other: T)
where
T: Iterator<Item = Element>;
fn sub_elements<T>(&self, other: T) -> Self::Output
where
T: Iterator<Item = Element>;
fn num_dices(&self) -> usize;
fn is_even(&self) -> bool;
fn is_odd(&self) -> bool;
fn is_empty(&self) -> bool;
fn is_legal(&self) -> bool;
fn elem_set(&self) -> ElementSet;
fn elems(&self) -> impl Iterator<Item = Element>;
fn values(&self) -> impl Iterator<Item = i8>;
fn elem_values(&self) -> impl Iterator<Item = (Element, i8)>;
fn legal_elems() -> ElementSet;
fn extract_with(&self, eset: ElementSet) -> Self::Output;
fn pick_random(&self, x: usize) -> (Self, Self)
where
Self: Sized;
fn contains(&self, elem: Element) -> bool;
}
fn check_is_legal(dices: &impl Dices, legal_elements: ElementSet) -> bool {
dices
.elem_values()
.all(|(elem, count)| count > 0 && legal_elements.contains(elem) || count == 0)
}
impl ActualDices {
fn satisfy(&self, requirement: &AbstractDices) -> bool {
assert!(self.is_legal() && requirement.is_legal());
let upgraded: AbstractDices = self.clone().into();
let pure_deducted = upgraded.sub(requirement).extract_with(PURE_ELEMENTS);
let omni_required = pure_deducted.values().filter(|x| *x < 0).sum::<i8>();
if self[OMNI] < omni_required {
return false;
}
let omni_remained = self[OMNI] - omni_required;
let most_pure = pure_deducted.values().max().unwrap();
if omni_remained + most_pure < requirement[OMNI] {
return false;
}
true
}
fn loosely_satify(&self, requirement: &AbstractDices) -> bool {
self.num_dices() >= requirement.num_dices() && self.satisfy(requirement)
}
fn just_satisfy(&self, requirement: &AbstractDices) -> bool {
self.num_dices() == requirement.num_dices() && self.satisfy(requirement)
}
}
impl ActualDices {
pub const fn new_from_raw(x: EnumMap<Element, i8>) -> Self {
ActualDices(x)
}
}
impl AbstractDices {
pub const fn new_from_raw(x: EnumMap<Element, i8>) -> Self {
AbstractDices(x)
}
}
impl Dices for EnumMap<Element, i8> {
type Output = Self;
fn empty() -> Self {
EnumMap::default()
}
fn new_from_counter_iter<T>(dices: T) -> Self
where
T: Iterator<Item = (Element, i8)>,
{
let mut dices = dices;
let mut map = EnumMap::default();
while let Some((elem, count)) = dices.next() {
map[elem] += count;
}
map
}
fn new_from_element_iter<T>(dices: T) -> Self
where
T: Iterator<Item = Element>,
{
let mut dices = dices;
let mut map = EnumMap::default();
while let Some(elem) = dices.next() {
map[elem] += 1;
}
map
}
fn add_mut(&mut self, other: &Self) {
for (elem, count) in other {
self[elem] += count;
}
}
fn add(&self, other: &Self) -> Self::Output {
let mut new = self.clone();
new.add_mut(other);
new
}
fn sub_mut(&mut self, other: &Self) {
for (elem, count) in other {
self[elem] -= count;
}
}
fn sub(&self, other: &Self) -> Self::Output {
let mut new = self.clone();
new.sub_mut(other);
new
}
fn add_elements_mut<T>(&mut self, other: T)
where
T: Iterator<Item = Element>,
{
for elem in other {
self[elem] += 1;
}
}
fn add_elements<T>(&self, other: T) -> Self::Output
where
T: Iterator<Item = Element>,
{
let mut new = self.clone();
new.add_elements_mut(other);
new
}
fn sub_elements_mut<T>(&mut self, other: T)
where
T: Iterator<Item = Element>,
{
for elem in other {
self[elem] -= 1;
}
}
fn sub_elements<T>(&self, other: T) -> Self::Output
where
T: Iterator<Item = Element>,
{
let mut new = self.clone();
new.sub_elements_mut(other);
new
}
fn num_dices(&self) -> usize {
assert!(self.is_legal());
self.values().sum::<i8>() as usize
}
fn is_even(&self) -> bool {
self.num_dices() % 2 == 0
}
fn is_odd(&self) -> bool {
!self.is_even()
}
fn is_empty(&self) -> bool {
self.num_dices() == 0
}
fn is_legal(&self) -> bool {
unreachable!("EnumMap is always legal")
}
fn elem_set(&self) -> ElementSet {
let mut es = ElementSet::empty();
for (elem, count) in self {
if *count > 0 {
es.insert(elem);
}
}
es
}
fn elems(&self) -> impl Iterator<Item = Element> {
let mut es = Vec::new();
for (elem, count) in self {
let mut n = *count as usize;
while n > 0 {
es.push(elem);
n -= 1;
}
}
es.into_iter()
}
fn values(&self) -> impl Iterator<Item = i8> {
let mut vs = Vec::new();
for (_, count) in self {
vs.push(*count);
}
vs.into_iter()
}
fn elem_values(&self) -> impl Iterator<Item = (Element, i8)> {
self.into_iter().map(|(elem, count)| (elem, *count))
}
fn legal_elems() -> ElementSet {
ElementSet::all()
}
fn extract_with(&self, eset: ElementSet) -> Self::Output {
Self::new_from_counter_iter(self.elem_values().filter(|x| eset.contains(x.0)))
}
fn pick_random(&self, n: usize) -> (Self, Self) {
let m = n.min(self.num_dices());
if m == 0 {
(self.clone(), Self::empty())
} else {
let mut trng = thread_rng();
let dices = self.elems();
let choosen = dices.into_iter().choose_multiple(&mut trng, m);
let picked = Self::new_from_element_iter(choosen.into_iter());
let new_dices = self.sub(&picked);
(new_dices, picked)
}
}
fn contains(&self, elem: Element) -> bool {
self[elem] > 0
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct ActualDices(EnumMap<Element, i8>);
impl From<EnumMap<Element, i8>> for ActualDices {
fn from(map: EnumMap<Element, i8>) -> Self {
Self(map)
}
}
impl Dices for ActualDices {
type Output = Self;
fn empty() -> Self {
Self(EnumMap::empty())
}
fn new_from_counter_iter<T>(dices: T) -> Self
where
T: Iterator<Item = (Element, i8)>,
{
EnumMap::new_from_counter_iter(dices).into()
}
fn new_from_element_iter<T>(dices: T) -> Self
where
T: Iterator<Item = Element>,
{
EnumMap::new_from_element_iter(dices).into()
}
fn add_mut(&mut self, other: &Self) {
self.0.add_mut(&other.0)
}
fn add(&self, other: &Self) -> Self {
self.0.add(&other.0).into()
}
fn sub_mut(&mut self, other: &Self) {
self.0.sub_mut(&other.0)
}
fn sub(&self, other: &Self) -> Self {
self.0.sub(&other.0).into()
}
fn add_elements_mut<T>(&mut self, other: T)
where
T: Iterator<Item = Element>,
{
self.0.add_elements_mut(other);
}
fn add_elements<T>(&self, other: T) -> Self
where
T: Iterator<Item = Element>,
{
self.0.add_elements(other).into()
}
fn sub_elements_mut<T>(&mut self, other: T)
where
T: Iterator<Item = Element>,
{
self.0.sub_elements_mut(other);
}
fn sub_elements<T>(&self, other: T) -> Self
where
T: Iterator<Item = Element>,
{
self.0.sub_elements(other).into()
}
fn num_dices(&self) -> usize {
assert!(self.is_legal());
self.0.num_dices()
}
fn is_even(&self) -> bool {
self.0.is_even()
}
fn is_odd(&self) -> bool {
self.0.is_odd()
}
fn is_empty(&self) -> bool {
self.0.is_empty()
}
fn is_legal(&self) -> bool {
check_is_legal(self, Self::legal_elems())
}
fn elem_set(&self) -> ElementSet {
self.0.elem_set()
}
fn elems(&self) -> impl Iterator<Item = Element> {
Dices::elems(&self.0)
}
fn values(&self) -> impl Iterator<Item = i8> {
Dices::values(&self.0)
}
fn elem_values(&self) -> impl Iterator<Item = (Element, i8)> {
Dices::elem_values(&self.0)
}
fn legal_elems() -> ElementSet {
LEGAL_ACTUAL_DICE_ELEMENTS
}
fn extract_with(&self, eset: ElementSet) -> Self::Output {
self.0.extract_with(eset).into()
}
fn pick_random(&self, x: usize) -> (Self, Self)
where
Self: Sized,
{
let (a, b) = self.0.pick_random(x);
(a.into(), b.into())
}
fn contains(&self, elem: Element) -> bool {
self.0.contains(elem)
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct AbstractDices(EnumMap<Element, i8>);
impl From<EnumMap<Element, i8>> for AbstractDices {
fn from(map: EnumMap<Element, i8>) -> Self {
Self(map)
}
}
impl From<ActualDices> for AbstractDices {
fn from(dices: ActualDices) -> Self {
AbstractDices::new_from_counter_iter(dices.elem_values())
}
}
impl Dices for AbstractDices {
type Output = Self;
fn empty() -> Self {
Self(EnumMap::empty())
}
fn new_from_counter_iter<T>(dices: T) -> Self
where
T: Iterator<Item = (Element, i8)>,
{
EnumMap::new_from_counter_iter(dices).into()
}
fn new_from_element_iter<T>(dices: T) -> Self
where
T: Iterator<Item = Element>,
{
EnumMap::new_from_element_iter(dices).into()
}
fn add_mut(&mut self, other: &Self) {
self.0.add_mut(&other.0)
}
fn add(&self, other: &Self) -> Self {
self.0.add(&other.0).into()
}
fn sub_mut(&mut self, other: &Self) {
self.0.sub_mut(&other.0)
}
fn sub(&self, other: &Self) -> Self::Output {
self.0.sub(&other.0).into()
}
fn add_elements_mut<T>(&mut self, other: T)
where
T: Iterator<Item = Element>,
{
self.0.add_elements_mut(other);
}
fn add_elements<T>(&self, other: T) -> Self::Output
where
T: Iterator<Item = Element>,
{
self.0.add_elements(other).into()
}
fn sub_elements_mut<T>(&mut self, other: T)
where
T: Iterator<Item = Element>,
{
self.0.sub_elements_mut(other);
}
fn sub_elements<T>(&self, other: T) -> Self::Output
where
T: Iterator<Item = Element>,
{
self.0.sub_elements(other).into()
}
fn num_dices(&self) -> usize {
assert!(self.is_legal());
self.0.num_dices()
}
fn is_even(&self) -> bool {
self.0.is_even()
}
fn is_odd(&self) -> bool {
self.0.is_odd()
}
fn is_empty(&self) -> bool {
self.0.is_empty()
}
fn is_legal(&self) -> bool {
check_is_legal(self, Self::legal_elems())
}
fn elem_set(&self) -> ElementSet {
self.0.elem_set()
}
fn elems(&self) -> impl Iterator<Item = Element> {
Dices::elems(&self.0)
}
fn values(&self) -> impl Iterator<Item = i8> {
Dices::values(&self.0)
}
fn elem_values(&self) -> impl Iterator<Item = (Element, i8)> {
Dices::elem_values(&self.0)
}
fn legal_elems() -> ElementSet {
LEGAL_ABSTRACT_DICE_ELEMENTS
}
fn extract_with(&self, eset: ElementSet) -> Self::Output {
self.0.extract_with(eset).into()
}
fn pick_random(&self, x: usize) -> (Self, Self)
where
Self: Sized,
{
let (a, b) = self.0.pick_random(x);
(a.into(), b.into())
}
fn contains(&self, elem: Element) -> bool {
self.0.contains(elem)
}
}
impl Index<Element> for ActualDices {
type Output = i8;
fn index(&self, elem: Element) -> &Self::Output {
&self.0[elem]
}
}
impl Index<Element> for AbstractDices {
type Output = i8;
fn index(&self, elem: Element) -> &Self::Output {
&self.0[elem]
}
}
use enum_map::EnumMap;
use crate::{card::Cards, character::Character};
pub struct Deck {
characters: Vec<Character>,
cards: Cards,
}
use enum_dispatch::enum_dispatch;
use crate::{element::{ElementalAura, Element}, event::EventType, status::{Statuses, EquipmentStatuses}, dice::AbstractDices};
#[derive(Hash, Eq, PartialEq, Debug)]
#[enum_dispatch(CharacterTrait)]
pub enum Character {
Klee,
}
#[enum_dispatch]
pub trait CharacterTrait {
fn status(&self) -> &CharacterStatus;
}
struct Klee(CharacterInfo, CharacterStatus);
impl CharacterTrait for Klee {
fn status(&self) -> &CharacterStatus {
&self.1
}
}
pub struct CharacterInfo {
element: Element,
weapon: WeaponType,
normal_attack_cost: AbstractDices,
elemental_skill1_cost: AbstractDices,
elemental_skill2_cost: AbstractDices,
elemental_burst_cost: AbstractDices,
}
pub struct CharacterStatus {
id: u8,
alive: bool,
hp: u8,
max_hp: u8,
energy: u8,
max_energy: u8,
hiddens: Statuses,
equipments: EquipmentStatuses,
statuses: Statuses,
elemental_aura: ElementalAura,
}
pub struct Characters {
pub inner: Vec<Character>,
pub active: Option<u32>,
}
impl Characters {
fn characters(&self) -> &[Character] {
&self.inner
}
fn characters_in_activity_order(&self) -> Vec<Character> {
todo!()
}
}
pub enum CharacterSkill {
Normal,
ElementalSkill1,
ElementalSkill2,
ElementalBurst,
}
impl From<CharacterSkill> for EventType {
fn from(skill: CharacterSkill) -> Self {
match skill {
CharacterSkill::Normal => EventType::Normal,
CharacterSkill::ElementalSkill1 => EventType::ElementalSkill1,
CharacterSkill::ElementalSkill2 => EventType::ElementalSkill2,
CharacterSkill::ElementalBurst => EventType::ElementalBurst,
}
}
}
pub enum WeaponType {
Bow,
Catalyst,
Claymore,
Polearm,
Sword,
None,
}
use std::collections::HashMap;
use enum_dispatch::enum_dispatch;
#[enum_dispatch]
#[derive(Hash, Eq, PartialEq, Debug)]
pub enum Card {}
#[enum_dispatch(Card)]
pub trait CardTrait {}
struct OmniCard;
pub struct Cards {
pub inner: HashMap<Card, u8>,
}
use enum_dispatch::enum_dispatch;
#[enum_dispatch(PlayerAgentTrait)]
pub enum PlayerAgent {
CustomChoiceAgent,
LazyAgent,
NoneAgent,
PuppetAgent,
RandomAgent,
}
#[enum_dispatch]
pub trait PlayerAgentTrait {
}
pub struct CustomChoiceAgent;
pub struct LazyAgent;
pub struct NoneAgent;
pub struct PuppetAgent;
pub struct RandomAgent;
pub struct ActionGenerator {
}
use enum_dispatch::enum_dispatch;
use crate::{
card::{Card, Cards},
character::CharacterSkill,
dice::ActualDices,
effect::target::StaticTarget,
element::Element,
};
pub enum ActionType {
SelectCards,
SelectActiveCharacter,
SelectDices,
PlayCard,
CastSkill,
SwapCharacter,
ElementalTuning,
EndRound,
}
#[enum_dispatch(PlayerActionTrait)]
pub enum PlayerAction {
CardsSelectAction,
DicesSelectAction,
CharacterSelectAction,
EndRoundAction,
}
#[enum_dispatch]
pub trait PlayerActionTrait {}
pub struct CardsSelectAction {
pub cards: Cards,
}
pub struct DicesSelectAction {
pub dices: ActualDices,
}
pub struct CharacterSelectAction {
pub character: usize,
}
pub struct EndRoundAction;
#[enum_dispatch(GameActionTrait)]
pub enum GameAction {
ElementalTuningAction,
CardAction,
SkillAction,
SwapAction,
DeathSwapAction,
}
#[enum_dispatch]
pub trait GameActionTrait {}
pub struct ElementalTuningAction {
pub card: Card,
pub elem: Element,
}
pub struct CardAction {
pub card: Card,
pub instruction: Instruction,
}
pub struct SkillAction {
pub character_skill: CharacterSkill,
pub instruction: DiceOnlyInstruction,
}
pub struct SwapAction {
pub character: usize,
pub instruction: Instruction,
}
pub struct DeathSwapAction {
pub character: usize,
}
#[enum_dispatch(InstructionTrait)]
pub enum Instruction {
DiceOnlyInstruction,
StaticTargetInstruction,
SourceTargetInstruction,
}
#[enum_dispatch]
pub trait InstructionTrait {}
pub struct DiceOnlyInstruction {}
pub struct StaticTargetInstruction {
pub target: StaticTarget,
}
pub struct SourceTargetInstruction {
pub source: StaticTarget,
pub target: StaticTarget,
}
pub enum Act {
ActionPhase,
PassiveWaitPhase,
ActiveWaitPhase,
EndPhase,
}
tab_spaces = 2
[package]
name = "tcg"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
enum-map = "2.7.3"
enum_dispatch = "0.3.12"
enumset = "1.1.3"
once_cell = "1.19.0"
rand = "0.8.5"
typed-arena = "2.0.2"
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "darling"
version = "0.20.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0209d94da627ab5605dcccf08bb18afa5009cfbef48d8a8b7d7bdbc79be25c5e"
dependencies = [
"darling_core",
"darling_macro",
]
[[package]]
name = "darling_core"
version = "0.20.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "177e3443818124b357d8e76f53be906d60937f0d3a90773a664fa63fa253e621"
dependencies = [
"fnv",
"ident_case",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "darling_macro"
version = "0.20.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "836a9bbc7ad63342d6d6e7b815ccab164bc77a2d95d84bc3117a8c0d5c98e2d5"
dependencies = [
"darling_core",
"quote",
"syn",
]
[[package]]
name = "enum-map"
version = "2.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6866f3bfdf8207509a033af1a75a7b08abda06bbaaeae6669323fd5a097df2e9"
dependencies = [
"enum-map-derive",
]
[[package]]
name = "enum-map-derive"
version = "0.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f282cfdfe92516eb26c2af8589c274c7c17681f5ecc03c18255fe741c6aa64eb"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "enum_dispatch"
version = "0.3.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f33313078bb8d4d05a2733a94ac4c2d8a0df9a2b84424ebf4f33bfc224a890e"
dependencies = [
"once_cell",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "enumset"
version = "1.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "226c0da7462c13fb57e5cc9e0dc8f0635e7d27f276a3a7fd30054647f669007d"
dependencies = [
"enumset_derive",
]
[[package]]
name = "enumset_derive"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e08b6c6ab82d70f08844964ba10c7babb716de2ecaeab9be5717918a5177d3af"
dependencies = [
"darling",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "fnv"
version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
[[package]]
name = "getrandom"
version = "0.2.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fe9006bed769170c11f845cf00c7c1e9092aeb3f268e007c3e760ac68008070f"
dependencies = [
"cfg-if",
"libc",
"wasi",
]
[[package]]
name = "ident_case"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
[[package]]
name = "libc"
version = "0.2.151"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "302d7ab3130588088d277783b1e2d2e10c9e9e4a16dd9050e6ec93fb3e7048f4"
[[package]]
name = "once_cell"
version = "1.19.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
[[package]]
name = "ppv-lite86"
version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
[[package]]
name = "proc-macro2"
version = "1.0.75"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "907a61bd0f64c2f29cd1cf1dc34d05176426a3f504a78010f08416ddb7b13708"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef"
dependencies = [
"proc-macro2",
]
[[package]]
name = "rand"
version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
dependencies = [
"libc",
"rand_chacha",
"rand_core",
]
[[package]]
name = "rand_chacha"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
dependencies = [
"ppv-lite86",
"rand_core",
]
[[package]]
name = "rand_core"
version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
dependencies = [
"getrandom",
]
[[package]]
name = "syn"
version = "2.0.48"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "tcg"
version = "0.1.0"
dependencies = [
"enum-map",
"enum_dispatch",
"enumset",
"once_cell",
"rand",
"typed-arena",
]
[[package]]
name = "typed-arena"
version = "2.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6af6ae20167a9ece4bcb41af5b80f8a1f1df981f6391189ce00fd257af04126a"
[[package]]
name = "unicode-ident"
version = "1.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
[[package]]
name = "wasi"
version = "0.11.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
.git
.DS_Store
.vscode
# Added by cargo
/target