Add some types to be serialized over IO
This commit is contained in:
parent
d30f413949
commit
370a0329b9
|
@ -33,6 +33,7 @@ dependencies = [
|
|||
"ahash",
|
||||
"hashbrown",
|
||||
"mino",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
|
@ -5,10 +5,12 @@ version = "0.1.0"
|
|||
edition = "2021"
|
||||
|
||||
[features]
|
||||
default = []
|
||||
default = ["io"]
|
||||
io = ["serde"]
|
||||
|
||||
[dependencies]
|
||||
mino = { path = "../mino" }
|
||||
|
||||
ahash = "0.8"
|
||||
hashbrown = "0.13"
|
||||
serde = { version = "1.0", features = ["derive"], optional = true }
|
||||
|
|
|
@ -0,0 +1,194 @@
|
|||
use alloc::boxed::Box;
|
||||
use alloc::string::String;
|
||||
use alloc::vec::Vec;
|
||||
use mino::srs::PieceType;
|
||||
use mino::MatBuf;
|
||||
use mino::{srs::Piece, Loc};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
/// Deserializable description of an initial game state. This is intentionally similar to
|
||||
/// the TBP "start" message.
|
||||
#[derive(Clone, Debug, Deserialize)]
|
||||
pub struct InputState {
|
||||
#[serde(flatten)]
|
||||
pub queue: InputQueue,
|
||||
#[allow(dead_code)]
|
||||
#[serde(flatten)]
|
||||
_attack: AttackState,
|
||||
// XXX(iitalics): TBP uses the terminology "board" but we use "matrix".
|
||||
#[serde(rename = "board")]
|
||||
pub matrix: InputMatrix,
|
||||
}
|
||||
|
||||
/// Deserializable description of the queue.
|
||||
#[derive(Clone, Debug, Deserialize)]
|
||||
pub struct InputQueue {
|
||||
#[serde(deserialize_with = "deserialize_hold")]
|
||||
pub hold: Option<PieceType>,
|
||||
#[serde(deserialize_with = "deserialize_previews")]
|
||||
#[serde(rename = "queue")]
|
||||
pub previews: Vec<PieceType>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize)]
|
||||
#[allow(dead_code)]
|
||||
struct AttackState {
|
||||
combo: u32,
|
||||
back_to_back: u32,
|
||||
// TODO: use this?
|
||||
}
|
||||
|
||||
// use FromStr to deserialize a PieceType
|
||||
|
||||
fn deserialize_hold<'de, D>(de: D) -> Result<Option<PieceType>, D::Error>
|
||||
where
|
||||
D: serde::Deserializer<'de>,
|
||||
{
|
||||
Option::<String>::deserialize(de)?
|
||||
.map(|s| s.parse())
|
||||
.transpose()
|
||||
.map_err(serde::de::Error::custom)
|
||||
}
|
||||
|
||||
fn deserialize_previews<'de, D>(de: D) -> Result<Vec<PieceType>, D::Error>
|
||||
where
|
||||
D: serde::Deserializer<'de>,
|
||||
{
|
||||
Vec::<String>::deserialize(de)?
|
||||
.iter()
|
||||
.map(|s| s.parse())
|
||||
.collect::<Result<Vec<_>, _>>()
|
||||
.map_err(serde::de::Error::custom)
|
||||
}
|
||||
|
||||
/// Deserializable description of the game matrix.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct InputMatrix {
|
||||
pub cells: Box<[[Option<Color>; 10]; 40]>,
|
||||
}
|
||||
|
||||
impl InputMatrix {
|
||||
/// Converts this matrix to a [`MatBuf`], which discards color information but is
|
||||
/// stored more efficiently.
|
||||
pub fn to_mat(&self) -> MatBuf {
|
||||
let mut mat = MatBuf::new();
|
||||
for (y, row) in self.cells.iter().enumerate() {
|
||||
for (x, cell) in row.iter().enumerate() {
|
||||
if cell.is_some() {
|
||||
mat.set(x as i16, y as i16);
|
||||
}
|
||||
}
|
||||
}
|
||||
mat
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Eq, PartialEq, Debug, Deserialize)]
|
||||
#[repr(u8)]
|
||||
pub enum Color {
|
||||
I = 1,
|
||||
J = 2,
|
||||
L = 3,
|
||||
O = 4,
|
||||
S = 5,
|
||||
T = 6,
|
||||
Z = 7,
|
||||
G = 8,
|
||||
}
|
||||
|
||||
impl<'de> serde::de::Deserialize<'de> for InputMatrix {
|
||||
fn deserialize<D>(de: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: serde::Deserializer<'de>,
|
||||
{
|
||||
// XXX(iitalics): serde doesn't let you deserialize a [T; 40] so we have to go
|
||||
// through Vec first and then check the length :|
|
||||
let cells: Vec<_> = serde::de::Deserialize::deserialize(de)?;
|
||||
let cells: [_; 40] = cells
|
||||
.try_into()
|
||||
.map_err(|_| serde::de::Error::custom("board must contain 40 rows"))?;
|
||||
Ok(Self {
|
||||
cells: Box::new(cells),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Default)]
|
||||
pub struct OutputMoves {
|
||||
pub moves: Vec<OutputMove>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize)]
|
||||
pub struct OutputMove {
|
||||
pub location: OutputLocation,
|
||||
pub spin: Spin,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize)]
|
||||
pub struct OutputLocation {
|
||||
#[serde(serialize_with = "serialize_piece_type")]
|
||||
#[serde(rename = "type")]
|
||||
pub ty: PieceType,
|
||||
#[serde(serialize_with = "serialize_loc")]
|
||||
#[serde(flatten)]
|
||||
pub location: Loc,
|
||||
}
|
||||
|
||||
impl From<Piece> for OutputLocation {
|
||||
fn from(pc: Piece) -> Self {
|
||||
Self {
|
||||
ty: pc.ty,
|
||||
location: pc.loc,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq, Default, Serialize)]
|
||||
#[serde(rename_all = "lowercase")]
|
||||
pub enum Spin {
|
||||
#[default]
|
||||
None,
|
||||
Mini,
|
||||
Full,
|
||||
}
|
||||
|
||||
fn serialize_piece_type<S>(ty: &PieceType, ser: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: serde::Serializer,
|
||||
{
|
||||
ty.as_char().serialize(ser)
|
||||
}
|
||||
|
||||
fn serialize_loc<S>(loc: &Loc, ser: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: serde::Serializer,
|
||||
{
|
||||
use serde::ser::SerializeStruct;
|
||||
let mut ser = ser.serialize_struct("Location", 3)?;
|
||||
ser.serialize_field("x", &loc.x)?;
|
||||
ser.serialize_field("y", &loc.y)?;
|
||||
let r = ["north", "east", "south", "west"][loc.r as usize];
|
||||
ser.serialize_field("orientation", r)?;
|
||||
ser.end()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_color_repr() {
|
||||
assert_eq!(
|
||||
core::mem::size_of::<Option<Color>>(),
|
||||
core::mem::size_of::<u8>()
|
||||
);
|
||||
assert_eq!(
|
||||
core::mem::size_of::<[Option<Color>; 10]>(),
|
||||
core::mem::size_of::<[u8; 10]>()
|
||||
);
|
||||
assert_eq!(
|
||||
unsafe { core::mem::transmute::<Option<Color>, u8>(None) },
|
||||
0u8
|
||||
);
|
||||
}
|
||||
}
|
|
@ -4,4 +4,7 @@ extern crate alloc;
|
|||
|
||||
pub mod find;
|
||||
|
||||
#[cfg(feature = "io")]
|
||||
pub mod io;
|
||||
|
||||
pub use find::find_locations;
|
||||
|
|
Loading…
Reference in New Issue