card game stuff
This commit is contained in:
+58
-20
@@ -8,6 +8,25 @@ pub trait Game {
|
|||||||
fn process_instruction(&mut self, instruction: Self::Instruction);
|
fn process_instruction(&mut self, instruction: Self::Instruction);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
|
||||||
|
pub enum Suit {
|
||||||
|
Spades = 0b00,
|
||||||
|
Hearts = 0b01,
|
||||||
|
Clubs = 0b10,
|
||||||
|
Diamonds = 0b11,
|
||||||
|
}
|
||||||
|
impl Suit {
|
||||||
|
pub const SUITS: [Self; 4] = [Self::Spades, Self::Hearts, Self::Clubs, Self::Diamonds];
|
||||||
|
/// Is the suit red.
|
||||||
|
pub fn is_red(self) -> bool {
|
||||||
|
self as u8 & 0b01 != 0
|
||||||
|
}
|
||||||
|
/// Is the suit shape spikey. (Bouba/kiki)
|
||||||
|
pub fn is_kiki(self) -> bool {
|
||||||
|
self as u8 & 0b10 != 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub struct CardValue(u8);
|
||||||
/// An identifier which specifies the deck id, suit, and card value.
|
/// An identifier which specifies the deck id, suit, and card value.
|
||||||
/// 2 bits for deck ID
|
/// 2 bits for deck ID
|
||||||
/// 2 bits for suit ID
|
/// 2 bits for suit ID
|
||||||
@@ -15,15 +34,10 @@ pub trait Game {
|
|||||||
/// TODO: better encoding for slightly more decks
|
/// TODO: better encoding for slightly more decks
|
||||||
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
|
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
|
||||||
pub struct Card(u8);
|
pub struct Card(u8);
|
||||||
pub struct CardValue(u8);
|
|
||||||
#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
|
|
||||||
pub enum Suit {
|
|
||||||
Spades,
|
|
||||||
Hearts,
|
|
||||||
Clubs,
|
|
||||||
Diamonds,
|
|
||||||
}
|
|
||||||
impl Card {
|
impl Card {
|
||||||
|
pub fn new(deck: u8, suit: Suit, CardValue(value): CardValue) -> Self {
|
||||||
|
Self(deck << 6 | (suit as u8) << 4 | value)
|
||||||
|
}
|
||||||
pub fn value(&self) -> CardValue {
|
pub fn value(&self) -> CardValue {
|
||||||
let masked = self.0 & 0b1111;
|
let masked = self.0 & 0b1111;
|
||||||
CardValue(masked)
|
CardValue(masked)
|
||||||
@@ -53,28 +67,34 @@ impl Card {
|
|||||||
|
|
||||||
pub struct Stack(Vec<Card>);
|
pub struct Stack(Vec<Card>);
|
||||||
impl Stack {
|
impl Stack {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self(Vec::new())
|
||||||
|
}
|
||||||
/// Generate a full deck of cards with the specified deck id.
|
/// Generate a full deck of cards with the specified deck id.
|
||||||
pub fn full_deck(deck_id: u8) -> Stack {
|
pub fn full_deck(deck: u8) -> Stack {
|
||||||
let mut stack = Vec::with_capacity(52);
|
let mut stack = Vec::with_capacity(52);
|
||||||
for suit in 0..4 {
|
for suit in Suit::SUITS {
|
||||||
for value in 1..=13 {
|
for value in 1..=13 {
|
||||||
stack.push(Card(deck_id << 6 | suit << 4 | value));
|
stack.push(Card::new(deck, suit, CardValue(value)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Stack(stack)
|
Stack(stack)
|
||||||
}
|
}
|
||||||
pub fn shuffle<R: rand::Rng>(&mut self, rng: &mut R) {
|
|
||||||
use rand::seq::SliceRandom;
|
|
||||||
self.0.shuffle(rng);
|
|
||||||
}
|
}
|
||||||
pub fn push(&mut self, card: Card) {
|
impl From<Vec<Card>> for Stack {
|
||||||
self.0.push(card);
|
fn from(value: Vec<Card>) -> Self {
|
||||||
|
Self(value)
|
||||||
}
|
}
|
||||||
pub fn pop(&mut self) -> Option<Card> {
|
|
||||||
self.0.pop()
|
|
||||||
}
|
}
|
||||||
pub fn is_empty(&mut self) -> bool {
|
impl std::ops::Deref for Stack {
|
||||||
self.0.is_empty()
|
type Target = Vec<Card>;
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl std::ops::DerefMut for Stack {
|
||||||
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||||
|
&mut self.0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -83,6 +103,21 @@ pub struct Pile {
|
|||||||
face_up: Stack,
|
face_up: Stack,
|
||||||
}
|
}
|
||||||
impl Pile {
|
impl Pile {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
face_down: Stack::new(),
|
||||||
|
face_up: Stack::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn new_face_down(stack: Stack) -> Self {
|
||||||
|
Self {
|
||||||
|
face_down: stack,
|
||||||
|
face_up: Stack::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn make_face_down(&mut self) {
|
||||||
|
self.face_down.extend(self.face_up.drain(..));
|
||||||
|
}
|
||||||
pub fn pop(&mut self) -> Option<Card> {
|
pub fn pop(&mut self) -> Option<Card> {
|
||||||
let card = self.face_up.pop()?;
|
let card = self.face_up.pop()?;
|
||||||
if self.face_up.is_empty() {
|
if self.face_up.is_empty() {
|
||||||
@@ -110,6 +145,9 @@ impl<G: Game> Session<G> {
|
|||||||
history: Vec::new(),
|
history: Vec::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
pub fn history(&self) -> &[G::Instruction] {
|
||||||
|
&self.history
|
||||||
|
}
|
||||||
}
|
}
|
||||||
impl<G: Game> Game for Session<G>
|
impl<G: Game> Game for Session<G>
|
||||||
where
|
where
|
||||||
|
|||||||
+45
-10
@@ -1,17 +1,16 @@
|
|||||||
use crate::Rng;
|
use crate::Rng;
|
||||||
use crate::card_game::{Card, Game, Pile, Stack};
|
use crate::card_game::{Card, Game, Pile, Stack};
|
||||||
|
|
||||||
struct KlondikeConfig {}
|
pub struct KlondikeConfig {}
|
||||||
|
impl Default for KlondikeConfig {
|
||||||
|
fn default() -> Self {
|
||||||
|
KlondikeConfig {}
|
||||||
|
}
|
||||||
|
}
|
||||||
struct KlondikeState {
|
struct KlondikeState {
|
||||||
piles: [Pile; 14],
|
piles: [Pile; 13],
|
||||||
}
|
}
|
||||||
pub enum KlondikePileId {
|
pub enum KlondikePileId {
|
||||||
Stock,
|
|
||||||
Hand,
|
|
||||||
Foundation0,
|
|
||||||
Foundation1,
|
|
||||||
Foundation2,
|
|
||||||
Foundation3,
|
|
||||||
Tableau0,
|
Tableau0,
|
||||||
Tableau1,
|
Tableau1,
|
||||||
Tableau2,
|
Tableau2,
|
||||||
@@ -20,6 +19,11 @@ pub enum KlondikePileId {
|
|||||||
Tableau5,
|
Tableau5,
|
||||||
Tableau6,
|
Tableau6,
|
||||||
Tableau7,
|
Tableau7,
|
||||||
|
Stock,
|
||||||
|
Foundation0,
|
||||||
|
Foundation1,
|
||||||
|
Foundation2,
|
||||||
|
Foundation3,
|
||||||
}
|
}
|
||||||
impl std::ops::Index<KlondikePileId> for KlondikeState {
|
impl std::ops::Index<KlondikePileId> for KlondikeState {
|
||||||
type Output = Pile;
|
type Output = Pile;
|
||||||
@@ -42,10 +46,41 @@ pub struct Klondike {
|
|||||||
state: KlondikeState,
|
state: KlondikeState,
|
||||||
}
|
}
|
||||||
impl Klondike {
|
impl Klondike {
|
||||||
pub fn new(mut seed: Rng) -> Self {
|
pub fn new(mut seed: Rng, config: KlondikeConfig) -> Self {
|
||||||
|
// shuffle a new deck
|
||||||
let mut deck = Stack::full_deck(0);
|
let mut deck = Stack::full_deck(0);
|
||||||
|
use rand::seq::SliceRandom;
|
||||||
deck.shuffle(&mut seed);
|
deck.shuffle(&mut seed);
|
||||||
unimplemented!()
|
|
||||||
|
// generate tableaus
|
||||||
|
let [t0, t1, t2, t3, t4, t5, t6, t7] = core::array::from_fn(|i| {
|
||||||
|
let stack = deck.split_off(i).into();
|
||||||
|
let mut pile = Pile::new_face_down(stack);
|
||||||
|
pile.push(deck.pop().unwrap());
|
||||||
|
pile
|
||||||
|
});
|
||||||
|
|
||||||
|
// stock is remaining cards
|
||||||
|
let stock = Pile::new_face_down(deck);
|
||||||
|
|
||||||
|
let state = KlondikeState {
|
||||||
|
piles: [
|
||||||
|
t0,
|
||||||
|
t1,
|
||||||
|
t2,
|
||||||
|
t3,
|
||||||
|
t4,
|
||||||
|
t5,
|
||||||
|
t6,
|
||||||
|
t7,
|
||||||
|
stock,
|
||||||
|
Pile::new(),
|
||||||
|
Pile::new(),
|
||||||
|
Pile::new(),
|
||||||
|
Pile::new(),
|
||||||
|
],
|
||||||
|
};
|
||||||
|
Self { config, state }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl Game for Klondike {
|
impl Game for Klondike {
|
||||||
|
|||||||
Reference in New Issue
Block a user