You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
231 lines
6.6 KiB
Rust
231 lines
6.6 KiB
Rust
use bevy::{prelude::*, utils::HashMap};
|
|
|
|
/// Deck and Cards
|
|
pub struct DeckPlugin;
|
|
|
|
impl Plugin for DeckPlugin {
|
|
fn build(&self, _app: &mut App) {
|
|
// Nothing yet!
|
|
}
|
|
}
|
|
|
|
/// We expect 81 cards total
|
|
#[derive(Resource)]
|
|
pub(crate) struct Deck {
|
|
pub cards: HashMap<Card, Sprite>,
|
|
}
|
|
|
|
impl Deck {
|
|
pub(crate) fn cards() -> Vec<Card> {
|
|
let mut v = Vec::new();
|
|
|
|
[ItemColor::Red, ItemColor::Green, ItemColor::Purple]
|
|
.iter()
|
|
.for_each(|&color| {
|
|
[ItemShape::Oval, ItemShape::Diamond, ItemShape::Squiggle]
|
|
.iter()
|
|
.for_each(|&shape| {
|
|
[ItemPattern::Open, ItemPattern::Solid, ItemPattern::Striped]
|
|
.iter()
|
|
.for_each(|&pattern| {
|
|
[ItemNumber::One, ItemNumber::Two, ItemNumber::Three]
|
|
.iter()
|
|
.for_each(|&number| {
|
|
v.push(Card {
|
|
color,
|
|
shape,
|
|
pattern,
|
|
number,
|
|
})
|
|
});
|
|
});
|
|
});
|
|
});
|
|
v
|
|
}
|
|
|
|
pub(crate) fn iter_cards() -> impl Iterator<Item = Card> {
|
|
Self::cards().into_iter()
|
|
}
|
|
|
|
pub(crate) fn shuffled() -> Vec<Card> {
|
|
let mut base = Self::cards();
|
|
|
|
{
|
|
use rand::seq::SliceRandom;
|
|
use rand::thread_rng;
|
|
|
|
let mut rng = thread_rng();
|
|
|
|
base.as_mut_slice().shuffle(&mut rng);
|
|
}
|
|
base
|
|
}
|
|
|
|
pub(crate) fn iter_shuffled() -> impl Iterator<Item = Card> {
|
|
Deck::shuffled().into_iter()
|
|
}
|
|
}
|
|
|
|
/// A card describes abstractly the contents of a card
|
|
/// including color of items, number of items, pattern, and shape
|
|
#[derive(PartialEq, Eq, Hash, Clone, Copy, Component, Debug)]
|
|
pub(crate) struct Card {
|
|
pub color: ItemColor,
|
|
pub number: ItemNumber,
|
|
pub pattern: ItemPattern,
|
|
pub shape: ItemShape,
|
|
}
|
|
|
|
impl Card {
|
|
pub(crate) fn sprite(&self) -> (String, TextureAtlasLayout, u8) {
|
|
// Spritesheet contains all cards ordered like so:
|
|
// | squiggle | diamond | oval |
|
|
// | 1 | 2 | 3 | 1 | 2 | 3 | 1 | 2 | 3 |
|
|
// | open green
|
|
// | open blue
|
|
// | open red
|
|
// | shaded green
|
|
// | shaded blue
|
|
// | shaded red
|
|
// | filled green
|
|
// | filled blue
|
|
// | filled red
|
|
// with all sprites being 20x32
|
|
// we have 12 rows and 9 columns total
|
|
// so the col + row for 1+open+red+squiggle is col 0 + row 3
|
|
// and the col + row for 3 filled blue oval is col 8 + row 11
|
|
|
|
let num = {
|
|
let row = {
|
|
let pattern_row = match self.pattern {
|
|
ItemPattern::Open => 0,
|
|
ItemPattern::Striped => 1,
|
|
ItemPattern::Solid => 2,
|
|
};
|
|
let color_row = match self.color {
|
|
ItemColor::Green => 0,
|
|
ItemColor::Purple => 1,
|
|
ItemColor::Red => 2,
|
|
};
|
|
(3 * pattern_row) + color_row + 3
|
|
};
|
|
|
|
let col = {
|
|
let shape_col = match self.shape {
|
|
ItemShape::Squiggle => 0,
|
|
ItemShape::Diamond => 1,
|
|
ItemShape::Oval => 2,
|
|
};
|
|
let number_col = match self.number {
|
|
ItemNumber::One => 0,
|
|
ItemNumber::Two => 1,
|
|
ItemNumber::Three => 2,
|
|
};
|
|
(3 * shape_col) + number_col
|
|
};
|
|
assert!(row < 12, "Sprite row should be less than 12");
|
|
assert!(row > 2, "sprite row should be greater than 2");
|
|
assert!(col < 9, "Sprite column should be less than 9");
|
|
|
|
// Figure out the sprite number based on row + col
|
|
(9 * row) + col
|
|
};
|
|
assert!(num < 108, "Sprite index should be less than 108");
|
|
|
|
let size = UVec2 { x: 20, y: 32 };
|
|
let layout = TextureAtlasLayout::from_grid(size, 9, 12, None, None);
|
|
|
|
("cards.png".into(), layout, num)
|
|
}
|
|
}
|
|
|
|
impl std::fmt::Display for Card {
|
|
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
|
write!(
|
|
f,
|
|
"{} {} {} {}",
|
|
self.number, self.pattern, self.color, self.shape
|
|
)
|
|
}
|
|
}
|
|
|
|
/// Item colors for the card may be red, green or purple
|
|
/// All items must be the same color
|
|
#[derive(PartialEq, Eq, Hash, Clone, Copy, Debug)]
|
|
pub(crate) enum ItemColor {
|
|
Red,
|
|
Green,
|
|
Purple,
|
|
}
|
|
|
|
impl std::fmt::Display for ItemColor {
|
|
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
|
let color = match self {
|
|
ItemColor::Red => "red",
|
|
ItemColor::Green => "green",
|
|
ItemColor::Purple => "purple",
|
|
};
|
|
write!(f, "{}", color)
|
|
}
|
|
}
|
|
|
|
/// A card may have 1 to 3 items
|
|
#[derive(PartialEq, Eq, Hash, Clone, Copy, Debug)]
|
|
pub(crate) enum ItemNumber {
|
|
One,
|
|
Two,
|
|
Three,
|
|
}
|
|
|
|
impl std::fmt::Display for ItemNumber {
|
|
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
|
let num = match self {
|
|
ItemNumber::One => 1,
|
|
ItemNumber::Two => 2,
|
|
ItemNumber::Three => 3,
|
|
};
|
|
write!(f, "{}", num)
|
|
}
|
|
}
|
|
|
|
/// Each item can be solid, striped, or open
|
|
/// a card has all of it's item as one pattern
|
|
#[derive(PartialEq, Eq, Hash, Clone, Copy, Debug)]
|
|
pub(crate) enum ItemPattern {
|
|
Solid,
|
|
Striped,
|
|
Open,
|
|
}
|
|
|
|
impl std::fmt::Display for ItemPattern {
|
|
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
|
let fill = match self {
|
|
ItemPattern::Open => "empty",
|
|
ItemPattern::Striped => "shaded",
|
|
ItemPattern::Solid => "solid",
|
|
};
|
|
write!(f, "{}", fill)
|
|
}
|
|
}
|
|
|
|
/// Each item can be an oval, diamond, or squiggle
|
|
/// All items on a card are one shape
|
|
#[derive(PartialEq, Eq, Hash, Clone, Copy, Debug)]
|
|
pub(crate) enum ItemShape {
|
|
Oval,
|
|
Diamond,
|
|
Squiggle,
|
|
}
|
|
|
|
impl std::fmt::Display for ItemShape {
|
|
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
|
let shape = match self {
|
|
ItemShape::Oval => "oval",
|
|
ItemShape::Diamond => "diamond",
|
|
ItemShape::Squiggle => "squiggle",
|
|
};
|
|
write!(f, "{}", shape)
|
|
}
|
|
}
|