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

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)
}
}