serde impl #16
Generated
+145
@@ -14,6 +14,12 @@ version = "0.7.6"
|
||||
source = "sparse+https://git.aleshym.co/api/packages/Quaternions/cargo/"
|
||||
checksum = "813440870d646c57c222c1d713dc4e3ddcb2919c3801564d767d85d7bf2afee4"
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "2.11.1"
|
||||
@@ -25,6 +31,8 @@ name = "card_game"
|
||||
version = "0.4.0"
|
||||
dependencies = [
|
||||
"arrayvec",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -44,6 +52,17 @@ dependencies = [
|
||||
"rand_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "console"
|
||||
version = "0.16.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d64e8af5551369d19cf50138de61f1c42074ab970f74e99be916646777f8fc87"
|
||||
dependencies = [
|
||||
"encode_unicode",
|
||||
"libc",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cpufeatures"
|
||||
version = "0.3.0"
|
||||
@@ -53,12 +72,34 @@ dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "encode_unicode"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0"
|
||||
|
||||
[[package]]
|
||||
name = "equivalent"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
|
||||
|
||||
[[package]]
|
||||
name = "errno"
|
||||
version = "0.3.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fastrand"
|
||||
version = "2.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9f1f227452a390804cdb637b74a86990f2a7d7ba4b7d5693aac9b4dd6defd8d6"
|
||||
|
||||
[[package]]
|
||||
name = "foldhash"
|
||||
version = "0.1.5"
|
||||
@@ -118,6 +159,18 @@ dependencies = [
|
||||
"serde_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "insta"
|
||||
version = "1.47.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7b4a6248eb93a4401ed2f37dfe8ea592d3cf05b7cf4f8efa867b6895af7e094e"
|
||||
dependencies = [
|
||||
"console",
|
||||
"once_cell",
|
||||
"similar",
|
||||
"tempfile",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "1.0.18"
|
||||
@@ -129,7 +182,12 @@ name = "klondike"
|
||||
version = "0.3.0"
|
||||
dependencies = [
|
||||
"card_game",
|
||||
"insta",
|
||||
"rand",
|
||||
"rmp-serde",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -162,6 +220,12 @@ version = "0.2.186"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66"
|
||||
|
||||
[[package]]
|
||||
name = "linux-raw-sys"
|
||||
version = "0.12.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53"
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.29"
|
||||
@@ -174,6 +238,21 @@ version = "2.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79"
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.2.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.21.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50"
|
||||
|
||||
[[package]]
|
||||
name = "prettyplease"
|
||||
version = "0.2.37"
|
||||
@@ -225,6 +304,38 @@ version = "0.10.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "63b8176103e19a2643978565ca18b50549f6101881c443590420e4dc998a3c69"
|
||||
|
||||
[[package]]
|
||||
name = "rmp"
|
||||
version = "0.8.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4ba8be72d372b2c9b35542551678538b562e7cf86c3315773cae48dfbfe7790c"
|
||||
dependencies = [
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rmp-serde"
|
||||
version = "1.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "72f81bee8c8ef9b577d1681a70ebbc962c232461e397b22c208c43c04b67a155"
|
||||
dependencies = [
|
||||
"rmp",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustix"
|
||||
version = "1.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"errno",
|
||||
"libc",
|
||||
"linux-raw-sys",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "semver"
|
||||
version = "1.0.28"
|
||||
@@ -273,6 +384,12 @@ dependencies = [
|
||||
"zmij",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "similar"
|
||||
version = "2.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bbbb5d9659141646ae647b42fe094daf6c6192d1620870b449d9557f748b2daa"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.117"
|
||||
@@ -284,6 +401,19 @@ dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tempfile"
|
||||
version = "3.27.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd"
|
||||
dependencies = [
|
||||
"fastrand",
|
||||
"getrandom",
|
||||
"once_cell",
|
||||
"rustix",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.24"
|
||||
@@ -348,6 +478,21 @@ dependencies = [
|
||||
"semver",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-link"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.61.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc"
|
||||
dependencies = [
|
||||
"windows-link",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wit-bindgen"
|
||||
version = "0.51.0"
|
||||
|
||||
@@ -10,6 +10,12 @@ keywords = ["card", "cards", "solitaire", "klondike"]
|
||||
|
||||
[dependencies]
|
||||
arrayvec = { version = "0.7.6", registry = "Quaternions", features = ["len_u8"], default-features = false }
|
||||
serde = { version = "1.0.228", default-features = false, optional = true }
|
||||
serde_derive = { version = "1.0.228", default-features = false, optional = true }
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
||||
[features]
|
||||
default = ["serde"]
|
||||
serde = ["dep:serde", "dep:serde_derive"]
|
||||
|
||||
@@ -146,6 +146,11 @@ impl Rank {
|
||||
/// 2 bits for suit ID
|
||||
/// 4 bits for card Value
|
||||
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
|
||||
#[cfg_attr(
|
||||
feature = "serde",
|
||||
derive(serde_derive::Deserialize, serde_derive::Serialize),
|
||||
serde(transparent)
|
||||
)]
|
||||
pub struct Card(core::num::NonZeroU8);
|
||||
impl Card {
|
||||
pub const fn new(deck: Deck, suit: Suit, rank: Rank) -> Self {
|
||||
@@ -230,8 +235,54 @@ impl<const CAP: usize> IntoIterator for Stack<CAP> {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "serde")]
|
||||
impl<'de, const CAP: usize> serde::Deserialize<'de> for Stack<CAP> {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: serde::Deserializer<'de>,
|
||||
{
|
||||
struct StackVisitor<const CAP: usize>;
|
||||
impl<'de, const CAP: usize> serde::de::Visitor<'de> for StackVisitor<CAP> {
|
||||
type Value = Stack<CAP>;
|
||||
fn expecting(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
write!(f, "Card Stack")
|
||||
}
|
||||
fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
|
||||
where
|
||||
A: serde::de::SeqAccess<'de>,
|
||||
{
|
||||
use serde::de::Error;
|
||||
let mut stack = Stack::new();
|
||||
while let Some(card) = seq.next_element()? {
|
||||
|
Quaternions marked this conversation as resolved
Quaternions
commented
Review
- [x] Do this
|
||||
stack.try_push(card).map_err(A::Error::custom)?;
|
||||
}
|
||||
Ok(stack)
|
||||
}
|
||||
}
|
||||
deserializer.deserialize_seq(StackVisitor)
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "serde")]
|
||||
impl<const CAP: usize> serde::Serialize for Stack<CAP> {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: serde::Serializer,
|
||||
{
|
||||
use serde::ser::SerializeSeq;
|
||||
let mut seq = serializer.serialize_seq(Some(self.len()))?;
|
||||
for card in self.as_slice() {
|
||||
seq.serialize_element(card)?;
|
||||
}
|
||||
seq.end()
|
||||
}
|
||||
}
|
||||
|
||||
/// A pile is a stack of face down cards and a stack of face up cards.
|
||||
#[derive(Clone, Debug, Default, Eq, Hash, PartialEq)]
|
||||
#[cfg_attr(
|
||||
feature = "serde",
|
||||
derive(serde_derive::Deserialize, serde_derive::Serialize)
|
||||
)]
|
||||
pub struct Pile<const DN: usize, const UP: usize> {
|
||||
face_down: Stack<DN>,
|
||||
face_up: Stack<UP>,
|
||||
@@ -372,6 +423,10 @@ pub enum SessionInstruction<I> {
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default)]
|
||||
#[cfg_attr(
|
||||
feature = "serde",
|
||||
derive(serde_derive::Deserialize, serde_derive::Serialize)
|
||||
)]
|
||||
pub struct SessionStats<S> {
|
||||
inner: S,
|
||||
undos: u32,
|
||||
@@ -388,6 +443,10 @@ impl<S> SessionStats<S> {
|
||||
}
|
||||
}
|
||||
#[derive(Clone, Debug)]
|
||||
#[cfg_attr(
|
||||
feature = "serde",
|
||||
derive(serde_derive::Deserialize, serde_derive::Serialize)
|
||||
)]
|
||||
pub struct SessionConfig<C> {
|
||||
pub inner: C,
|
||||
pub undo_penalty: i32,
|
||||
@@ -417,6 +476,10 @@ pub struct Session<G: Game> {
|
||||
state: SessionState<G>,
|
||||
}
|
||||
#[derive(Clone, Debug)]
|
||||
#[cfg_attr(
|
||||
feature = "serde",
|
||||
derive(serde_derive::Deserialize, serde_derive::Serialize)
|
||||
)]
|
||||
pub struct StateSnapshot<G: Game> {
|
||||
state: G,
|
||||
instruction: G::Instruction,
|
||||
@@ -590,3 +653,95 @@ where
|
||||
self.state.is_win()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "serde")]
|
||||
impl<'de, G: Game<Score = i32>> serde::de::Deserialize<'de> for Session<G>
|
||||
where
|
||||
G: serde::Deserialize<'de> + Clone + Eq + core::hash::Hash,
|
||||
G::Stats: Default,
|
||||
G::Instruction: serde::Deserialize<'de> + Eq + core::hash::Hash,
|
||||
SessionConfig<G::Config>: serde::Deserialize<'de>,
|
||||
Vec<G::Instruction>: serde::Deserialize<'de>,
|
||||
{
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: serde::Deserializer<'de>,
|
||||
{
|
||||
#[derive(serde_derive::Deserialize)]
|
||||
#[serde(bound(deserialize = "
|
||||
G: serde::Deserialize<'de>,
|
||||
SessionConfig<G::Config>: serde::Deserialize<'de>,
|
||||
Vec<G::Instruction>: serde::Deserialize<'de>,
|
||||
"))]
|
||||
struct SerializedSession<G: Game> {
|
||||
config: SessionConfig<G::Config>,
|
||||
initial_state: G,
|
||||
instructions: Vec<G::Instruction>,
|
||||
}
|
||||
let serialized = SerializedSession::deserialize(deserializer)?;
|
||||
let mut session = Session::new(serialized.initial_state, serialized.config);
|
||||
for instruction in serialized.instructions {
|
||||
session.process_instruction(instruction);
|
||||
}
|
||||
Ok(session)
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "serde")]
|
||||
impl<G: Game> serde::Serialize for Session<G>
|
||||
where
|
||||
G: serde::Serialize,
|
||||
G::Config: serde::Serialize,
|
||||
G::Instruction: serde::Serialize,
|
||||
{
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: serde::Serializer,
|
||||
{
|
||||
struct History<'a, G: Game>(&'a [StateSnapshot<G>]);
|
||||
impl<G: Game> serde::Serialize for History<'_, G>
|
||||
where
|
||||
G: serde::Serialize,
|
||||
G::Instruction: serde::Serialize,
|
||||
{
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: serde::Serializer,
|
||||
{
|
||||
let &History(history) = self;
|
||||
use serde::ser::SerializeSeq;
|
||||
let mut seq = serializer.serialize_seq(Some(history.len()))?;
|
||||
for snapshot in history {
|
||||
seq.serialize_element(&snapshot.instruction)?;
|
||||
}
|
||||
seq.end()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(serde_derive::Serialize)]
|
||||
#[serde(bound(serialize = "
|
||||
G: serde::Serialize,
|
||||
SessionConfig<G::Config>: serde::Serialize,
|
||||
G::Instruction: serde::Serialize,
|
||||
"))]
|
||||
struct SerializedSession<'a, G: Game> {
|
||||
config: &'a SessionConfig<G::Config>,
|
||||
initial_state: &'a G,
|
||||
instructions: History<'a, G>,
|
||||
}
|
||||
|
||||
// serialize the initial state of the game.
|
||||
// if there is history, it is the first snapshot's state,
|
||||
// otherwise it is the current game state since there are no moves.
|
||||
|
Quaternions marked this conversation as resolved
Outdated
Quaternions
commented
- [x] use a real struct
|
||||
let initial_state = if let Some(snapshot) = self.state.history.first() {
|
||||
snapshot.state()
|
||||
} else {
|
||||
&self.state.state
|
||||
};
|
||||
let session = SerializedSession {
|
||||
config: &self.config,
|
||||
initial_state,
|
||||
instructions: History(&self.state.history),
|
||||
};
|
||||
session.serialize(serializer)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,9 +4,6 @@ use klondike::{
|
||||
KlondikePile, KlondikePileStack, SkipCards, Tableau, TableauStack,
|
||||
};
|
||||
|
||||
#[cfg(test)]
|
||||
mod test;
|
||||
|
||||
use std::fmt::Display;
|
||||
struct Displayed<T>(T);
|
||||
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
use card_game::Session;
|
||||
use klondike::Klondike;
|
||||
#[test]
|
||||
fn test_is_winnable() {
|
||||
// is winnable
|
||||
let solution_result = Session::new_default(Klondike::with_seed(124)).solve();
|
||||
if let Ok(Some(solution)) = solution_result {
|
||||
let win_moves = solution.clean_solution();
|
||||
// for (i, ins) in win_moves.into_iter().enumerate() {
|
||||
// println!("{i} = {:?}", ins.instruction());
|
||||
// }
|
||||
println!("Game is winnable with {} moves", win_moves.len());
|
||||
} else {
|
||||
println!("Game is not winnable");
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,18 @@ edition = "2024"
|
||||
[dependencies]
|
||||
card_game.workspace = true
|
||||
rand = { version = "0.10.1", default-features = false, features = ["std_rng"] }
|
||||
serde = { version = "1.0.228", default-features = false, optional = true }
|
||||
serde_derive = { version = "1.0.228", default-features = false, optional = true }
|
||||
|
||||
[dev-dependencies]
|
||||
insta = "1.47.2"
|
||||
rmp-serde = "1.3.1"
|
||||
serde = { version = "1.0.228", default-features = false }
|
||||
serde_json = "1.0.149"
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
||||
[features]
|
||||
default = ["serde"]
|
||||
serde = ["dep:serde", "dep:serde_derive", "card_game/serde"]
|
||||
|
||||
@@ -2,11 +2,18 @@ pub type Rng = rand::rngs::StdRng;
|
||||
|
||||
use card_game::{Card, Game, Pile, Rank, Stack};
|
||||
|
||||
#[cfg(test)]
|
||||
mod test;
|
||||
|
||||
// test readme
|
||||
#[doc = include_str!("../README.md")]
|
||||
#[cfg(doctest)]
|
||||
struct ReadmeDoctests;
|
||||
|
||||
#[cfg_attr(
|
||||
feature = "serde",
|
||||
derive(serde_derive::Deserialize, serde_derive::Serialize)
|
||||
)]
|
||||
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
|
||||
pub enum DrawStockConfig {
|
||||
#[default]
|
||||
@@ -14,6 +21,10 @@ pub enum DrawStockConfig {
|
||||
DrawThree = 3,
|
||||
}
|
||||
|
||||
#[cfg_attr(
|
||||
feature = "serde",
|
||||
derive(serde_derive::Deserialize, serde_derive::Serialize)
|
||||
)]
|
||||
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
|
||||
pub enum MoveFromFoundationConfig {
|
||||
#[default]
|
||||
@@ -21,6 +32,10 @@ pub enum MoveFromFoundationConfig {
|
||||
Disallowed,
|
||||
}
|
||||
|
||||
#[cfg_attr(
|
||||
feature = "serde",
|
||||
derive(serde_derive::Deserialize, serde_derive::Serialize)
|
||||
)]
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct ScoringConfig {
|
||||
pub move_to_foundation: i32,
|
||||
@@ -44,6 +59,10 @@ impl Default for ScoringConfig {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(
|
||||
feature = "serde",
|
||||
derive(serde_derive::Deserialize, serde_derive::Serialize)
|
||||
)]
|
||||
#[derive(Clone, Debug, Default)]
|
||||
pub struct KlondikeConfig {
|
||||
pub draw_stock: DrawStockConfig,
|
||||
@@ -379,6 +398,10 @@ const fn sum(n: usize) -> usize {
|
||||
const STOCK: usize = 52 - sum(TABLEAUS);
|
||||
const NUM_RANKS: usize = Rank::RANKS.len();
|
||||
|
||||
#[cfg_attr(
|
||||
feature = "serde",
|
||||
derive(serde_derive::Deserialize, serde_derive::Serialize)
|
||||
)]
|
||||
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
|
||||
pub struct KlondikeState {
|
||||
stock: Pile<STOCK, STOCK>,
|
||||
@@ -613,6 +636,11 @@ fn test_klondike_iter() {
|
||||
assert_eq!(KlondikeIter::new().count(), 721);
|
||||
}
|
||||
|
||||
#[cfg_attr(
|
||||
feature = "serde",
|
||||
derive(serde_derive::Deserialize, serde_derive::Serialize),
|
||||
serde(transparent)
|
||||
)]
|
||||
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
|
||||
pub struct Klondike {
|
||||
state: KlondikeState,
|
||||
@@ -797,3 +825,28 @@ impl Game for Klondike {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "serde")]
|
||||
impl serde::Serialize for KlondikeInstruction {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: serde::Serializer,
|
||||
{
|
||||
// There is 721 klondike instructions
|
||||
let instruction_id = KlondikeIter::new()
|
||||
.position(|instruction| &instruction == self)
|
||||
.unwrap();
|
||||
serializer.serialize_u16(instruction_id as u16)
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "serde")]
|
||||
impl<'de> serde::Deserialize<'de> for KlondikeInstruction {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: serde::Deserializer<'de>,
|
||||
{
|
||||
let instruction_id = u16::deserialize(deserializer)?;
|
||||
let instruction = KlondikeIter::new().nth(instruction_id as usize).unwrap();
|
||||
Ok(instruction)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
source: klondike/src/test.rs
|
||||
expression: serialized
|
||||
---
|
||||
{"config":{"inner":{"draw_stock":"DrawOne","move_from_foundation":"Allowed","scoring":{"move_to_foundation":10,"flip_up_bonus":5,"move_to_tableau":5,"move_from_foundation":-15,"recycle":0}},"undo_penalty":-15,"solve_moves_budget":100000,"solve_states_budget":100000},"initial_state":{"stock":{"face_down":[52,51,21,59,36,45,49,50,22,3,58,39,41,61,13,57,34,56,28,1,19,12,17,5],"face_up":[]},"foundations":[[],[],[],[]],"tableau1":{"face_down":[],"face_up":[40]},"tableau2":{"face_down":[9],"face_up":[4]},"tableau3":{"face_down":[35,8],"face_up":[60]},"tableau4":{"face_down":[11,27,44],"face_up":[25]},"tableau5":{"face_down":[6,7,23,18],"face_up":[29]},"tableau6":{"face_down":[2,55,10,42,24],"face_up":[54]},"tableau7":{"face_down":[26,43,38,53,37,33],"face_up":[20]}},"instructions":[336,100,720,619,606,6,720,19,16,388,497,580,388,720,139,720,19,720,17,31,720,720,720,7,720,720,523,458,720,720,720,720,720,720,720,720,43,43,720,720,720,139,720,19,720,43,720,43,720,720,720,720,720,720,720,720,720,623,619,720,720,720,720,720,720,720,720,720,720,693,281,333,253,209,113,87,720,720,720,720,720,720,720,720,75,223,619,533,74,2,720,116,331,279,279,305,305,29,25,24,12,37,25,222,24,42,126,471,720,720,720,362,292,331,253,720,19,720,183,151,12,67,336,61,93,235,720,7,2,0,7,38,26,14,27,15,26,36,0,7,3,6,18,43,36,24,12,0,1,19,38,26,39,27,15,38,26,36]}
|
||||
@@ -0,0 +1,6 @@
|
||||
---
|
||||
source: klondike/src/test.rs
|
||||
expression: serialized
|
||||
extension: bin
|
||||
snapshot_kind: binary
|
||||
---
|
||||
Binary file not shown.
@@ -0,0 +1,55 @@
|
||||
use crate::Klondike;
|
||||
use card_game::Session;
|
||||
|
||||
#[test]
|
||||
fn test_is_winnable() {
|
||||
// is winnable
|
||||
let solution_result = Session::new_default(Klondike::with_seed(124)).solve();
|
||||
if let Ok(Some(solution)) = solution_result {
|
||||
let win_moves = solution.clean_solution();
|
||||
// for (i, ins) in win_moves.into_iter().enumerate() {
|
||||
// println!("{i} = {:?}", ins.instruction());
|
||||
// }
|
||||
println!("Game is winnable with {} moves", win_moves.len());
|
||||
} else {
|
||||
println!("Game is not winnable");
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "serde")]
|
||||
#[test]
|
||||
fn test_json() {
|
||||
let mut session = Session::new_default(Klondike::with_seed(124));
|
||||
let solution_result = session.solve();
|
||||
if let Ok(Some(solution)) = solution_result {
|
||||
for snapshot in solution.clean_solution() {
|
||||
session.process_instruction(snapshot.instruction().clone());
|
||||
}
|
||||
}
|
||||
let serialized = serde_json::to_string(&session).unwrap();
|
||||
println!("serialized = {serialized}");
|
||||
let round_trip_session: Session<Klondike> = serde_json::from_str(&serialized).unwrap();
|
||||
let serialized2 = serde_json::to_string(&round_trip_session).unwrap();
|
||||
assert_eq!(serialized, serialized2);
|
||||
|
||||
insta::assert_snapshot!(serialized);
|
||||
}
|
||||
|
||||
#[cfg(feature = "serde")]
|
||||
#[test]
|
||||
fn test_rmp() {
|
||||
let mut session = Session::new_default(Klondike::with_seed(124));
|
||||
let solution_result = session.solve();
|
||||
if let Ok(Some(solution)) = solution_result {
|
||||
for snapshot in solution.clean_solution() {
|
||||
session.process_instruction(snapshot.instruction().clone());
|
||||
}
|
||||
}
|
||||
let serialized = rmp_serde::to_vec(&session).unwrap();
|
||||
println!("serialized.len() = {}", serialized.len());
|
||||
let round_trip_session: Session<Klondike> = rmp_serde::from_slice(&serialized).unwrap();
|
||||
let serialized2 = rmp_serde::to_vec(&round_trip_session).unwrap();
|
||||
assert_eq!(serialized, serialized2);
|
||||
|
||||
insta::assert_binary_snapshot!("save_rmp.bin", serialized);
|
||||
}
|
||||
Reference in New Issue
Block a user