pub type CardId = u32;
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum CardType {
Attack,
Skill,
Power,
}
#[derive(Debug, Clone)]
pub struct Card {
pub id: CardId,
pub name: String,
pub description: String,
pub cost: u32,
pub card_type: CardType,
}
impl Card {
pub fn new(
id: CardId,
name: impl Into<String>,
description: impl Into<String>,
cost: u32,
card_type: CardType,
) -> Self {
Self {
id,
name: name.into(),
description: description.into(),
cost,
card_type,
}
}
}
pub struct Deck {
pub draw_pile: Vec<Card>,
pub discard_pile: Vec<Card>,
}
impl Deck {
pub fn new(cards: Vec<Card>) -> Self {
Self {
draw_pile: cards,
discard_pile: Vec::new(),
}
}
pub fn shuffle(&mut self) {
self.draw_pile.append(&mut self.discard_pile);
self.draw_pile.reverse();
}
pub fn draw(&mut self) -> Option<Card> {
if let Some(card) = self.draw_pile.pop() {
Some(card)
} else {
self.shuffle();
self.draw_pile.pop()
}
}
pub fn discard(&mut self, card: Card) {
self.discard_pile.push(card);
}
pub fn draw_multiple(&mut self, count: usize) -> Vec<Card> {
let mut drawn = Vec::with_capacity(count);
for _ in 0..count {
if let Some(c) = self.draw() {
drawn.push(c);
} else {
break;
}
}
drawn
}
pub fn peek(&self, count: usize) -> Vec<&Card> {
self.draw_pile.iter().rev().take(count).collect()
}
pub fn mill(&mut self, count: usize) -> Vec<Card> {
let mut milled = Vec::with_capacity(count);
for _ in 0..count {
if let Some(card) = self.draw_pile.pop() {
milled.push(card.clone());
self.discard_pile.push(card);
} else {
break;
}
}
milled
}
pub fn search<F>(&mut self, predicate: F) -> Option<Card>
where
F: Fn(&Card) -> bool,
{
if let Some(pos) = self.draw_pile.iter().position(|c| predicate(c)) {
Some(self.draw_pile.remove(pos))
} else {
None
}
}
pub fn move_to_bottom(&mut self, card: Card) {
self.draw_pile.insert(0, card);
}
}
pub struct GameContext {
pub player_health: i32,
pub enemy_health: i32,
pub energy: u32,
pub turn: u32, }
impl GameContext {
pub fn new(player_health: i32, enemy_health: i32) -> Self {
Self {
player_health,
enemy_health,
energy: 0,
turn: 1,
}
}
pub fn deal_damage(&mut self, amount: i32) {
self.enemy_health -= amount;
}
pub fn heal(&mut self, amount: i32) {
self.player_health += amount;
}
pub fn spend_energy(&mut self, amount: u32) -> bool {
if self.energy >= amount {
self.energy -= amount;
true
} else {
false
}
}
pub fn is_game_over(&self) -> bool {
self.player_health <= 0 || self.enemy_health <= 0
}
pub fn new_turn(&mut self, max_energy: u32) {
self.turn += 1;
self.energy = max_energy;
}
}
pub trait Playable {
fn play(&self, ctx: &mut GameContext);
}
pub struct AttackCard {
pub card: Card,
pub damage: i32,
}
impl Playable for AttackCard {
fn play(&self, ctx: &mut GameContext) {
ctx.deal_damage(self.damage);
}
}
pub struct HealCard {
pub card: Card,
pub heal_amount: i32,
}
impl Playable for HealCard {
fn play(&self, ctx: &mut GameContext) {
ctx.heal(self.heal_amount);
}
}
pub struct CompoundCard {
pub card: Card,
pub effects: Vec<Box<dyn Playable>>,
}
impl Playable for CompoundCard {
fn play(&self, ctx: &mut GameContext) {
for effect in &self.effects {
effect.play(ctx);
}
}
}