diff --git a/Cargo.lock b/Cargo.lock index 125842b..8c66fed 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -33,6 +33,7 @@ name = "balatro-cli" version = "0.0.1" dependencies = [ "balatro-rs", + "colored", "text_io", ] @@ -40,6 +41,7 @@ dependencies = [ name = "balatro-rs" version = "0.0.1" dependencies = [ + "colored", "criterion", "indexmap", "itertools 0.13.0", @@ -94,6 +96,16 @@ dependencies = [ "unicode-width", ] +[[package]] +name = "colored" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "117725a109d387c937a1533ce01b450cbde6b88abceea8473c4d7a85853cda3c" +dependencies = [ + "lazy_static", + "windows-sys", +] + [[package]] name = "criterion" version = "0.3.6" diff --git a/cli/Cargo.toml b/cli/Cargo.toml index 10225ce..3f5ffba 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -8,4 +8,5 @@ repository ="https://github.com/evanofslack/balatro-rs" [dependencies] text_io = "0.1.9" -balatro-rs = {path = "../core/", version = "0.0.1"} +colored = "2.2.0" +balatro-rs = {path = "../core/", version = "0.0.1", features = ["colored"]} diff --git a/core/Cargo.toml b/core/Cargo.toml index 2213077..0853c17 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -18,6 +18,7 @@ itertools = "0.13.0" indexmap = "2.6.0" strum = { version = "0.26", features = ["derive"] } pyo3 = {version = "0.23.1", optional = true} +colored = {version = "2.2.0", optional = true} [dev-dependencies] criterion = "0.3" @@ -26,6 +27,7 @@ criterion = "0.3" default = ["serde", "python"] python = ["dep:pyo3"] serde = ["dep:serde", "dep:serde_json", "uuid?/serde"] +colored = ["dep:colored"] [[bench]] name = "benchmark" diff --git a/core/src/action.rs b/core/src/action.rs index 7d51370..ec31d22 100644 --- a/core/src/action.rs +++ b/core/src/action.rs @@ -44,7 +44,7 @@ impl fmt::Display for Action { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { Self::SelectCard(card) => { - write!(f, "SelectCard: {:?}", card) + write!(f, "SelectCard: {}", card) } Self::Play() => { write!(f, "Play") @@ -53,10 +53,10 @@ impl fmt::Display for Action { write!(f, "Discard") } Self::MoveCard(dir, card) => { - write!(f, "MoveCard: {:?} - {:}", card, dir) + write!(f, "MoveCard: {} - {}", card, dir) } Self::CashOut(reward) => { - write!(f, "CashOut: {:}", reward) + write!(f, "CashOut: {}", reward) } Self::BuyJoker(joker) => { write!(f, "BuyJoker: {:?}", joker) @@ -65,7 +65,7 @@ impl fmt::Display for Action { write!(f, "NextRound") } Self::SelectBlind(blind) => { - write!(f, "SelectBlind: {:?}", blind) + write!(f, "SelectBlind: {}", blind) } } } diff --git a/core/src/card.rs b/core/src/card.rs index 9c1948b..6d8a58a 100644 --- a/core/src/card.rs +++ b/core/src/card.rs @@ -1,3 +1,5 @@ +#[cfg(feature = "colored")] +use colored::Colorize; use pyo3::pyclass; use std::{ fmt, @@ -88,6 +90,14 @@ impl Suit { pub const fn suits() -> [Self; 4] { SUITS } + pub fn unicode(&self) -> &str { + match self { + Self::Spade => "♤", + Self::Club => "♧", + Self::Heart => "♡", + Self::Diamond => "♢", + } + } } impl From for char { @@ -205,18 +215,31 @@ impl Card { impl fmt::Debug for Card { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!( - f, - "Card({}{})", - char::from(self.value), - char::from(self.suit) - ) + #[cfg(feature = "colored")] + let suit = match self.suit { + Suit::Spade => self.suit.unicode().black(), + Suit::Club => self.suit.unicode().green(), + Suit::Heart => self.suit.unicode().red(), + Suit::Diamond => self.suit.unicode().blue(), + }; + #[cfg(not(feature = "colored"))] + let suit = self.suit.unicode(); + write!(f, "Card({}{})", char::from(self.value), suit) } } impl fmt::Display for Card { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{}{}", char::from(self.value), char::from(self.suit)) + #[cfg(feature = "colored")] + let suit = match self.suit { + Suit::Spade => self.suit.unicode().black(), + Suit::Club => self.suit.unicode().green(), + Suit::Heart => self.suit.unicode().red(), + Suit::Diamond => self.suit.unicode().blue(), + }; + #[cfg(not(feature = "colored"))] + let suit = self.suit.unicode(); + write!(f, "{}{}", char::from(self.value), suit) } } diff --git a/core/src/joker.rs b/core/src/joker.rs index 9318930..0010269 100644 --- a/core/src/joker.rs +++ b/core/src/joker.rs @@ -3,6 +3,7 @@ use crate::effect::Effects; use crate::game::Game; use crate::hand::MadeHand; use pyo3::pyclass; +use std::fmt; use std::sync::{Arc, Mutex}; use strum::{EnumIter, IntoEnumIterator}; @@ -33,6 +34,25 @@ pub enum Rarity { Legendary, } +impl fmt::Display for Rarity { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Self::Common => { + write!(f, "Common") + } + Self::Uncommon => { + write!(f, "Uncommon") + } + Self::Rare => { + write!(f, "Rare") + } + Self::Legendary => { + write!(f, "Legendary") + } + } + } +} + // We could pass around `Box` but it doesn't work so nice with pyo3 and serde. // Since we know all variants (one for each joker), we define an enum that implements // our `Joker` trait. This macro just reduces the amount of boilerplate we have to copy @@ -122,6 +142,19 @@ impl Jokers { } } +impl fmt::Display for Jokers { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!( + f, + "{} [${}, {}] - {}", + self.name(), + self.cost(), + self.rarity(), + self.desc() + ) + } +} + #[derive(Debug, Clone, Default, Eq, PartialEq, Hash, serde::Serialize, serde::Deserialize)] #[cfg_attr(feature = "python", pyclass(eq))] pub struct TheJoker {} diff --git a/core/src/stage.rs b/core/src/stage.rs index 165aa0c..f9154b8 100644 --- a/core/src/stage.rs +++ b/core/src/stage.rs @@ -1,4 +1,5 @@ use pyo3::pyclass; +use std::fmt; /// Types of blinds #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] @@ -29,6 +30,16 @@ impl Blind { } } +impl fmt::Display for Blind { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Self::Small => write!(f, "Small Blind"), + Self::Big => write!(f, "Big Blind"), + Self::Boss => write!(f, "Boss Blind"), + } + } +} + /// Game ending #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "python", pyclass(eq))]