diff --git a/Cargo.lock b/Cargo.lock index fa24bf0..8df40c7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3337,6 +3337,12 @@ dependencies = [ "byteorder", ] +[[package]] +name = "hashbag" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7040a10f52cba493ddb09926e15d10a9d8a28043708a405931fe4c6f19fac064" + [[package]] name = "hashbrown" version = "0.12.3" @@ -3710,6 +3716,14 @@ version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2" +[[package]] +name = "jiang" +version = "0.1.0" +dependencies = [ + "hashbag", + "jong-types", +] + [[package]] name = "jni" version = "0.21.1" diff --git a/Cargo.toml b/Cargo.toml index eb2e720..753b960 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [workspace] resolver = "3" -members = ["jong", "jong-types", "spacetimedb"] +members = ["jiang","jong", "jong-types", "spacetimedb"] [workspace.dependencies] jong = { version = "0.1.0", path = "jong" } diff --git a/jiang/Cargo.toml b/jiang/Cargo.toml new file mode 100644 index 0000000..eeb2ed3 --- /dev/null +++ b/jiang/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "jiang" +version = "0.1.0" +edition = "2024" + +[dependencies] +hashbag = "0.1.13" +jong-types.workspace = true diff --git a/jiang/src/lib.rs b/jiang/src/lib.rs new file mode 100644 index 0000000..2a698f7 --- /dev/null +++ b/jiang/src/lib.rs @@ -0,0 +1,62 @@ +use std::collections::HashMap; + +use hashbag::HashBag; +use jong_types::*; + +// pub fn check_valid() {} + +pub enum Meldable { + Chii(Tile, Tile), + Pon, + Kan, +} + +pub fn find_meldables(hand: &[Tile], dealt: Tile) -> Vec { + let counts = hand.iter().fold(HashMap::new(), |mut m, t| { + let e = m.entry(t).or_insert(0); + *e += 1; + m + }); + + let mut calls = vec![]; + + // find pon & kan + if let Some(&count) = counts.get(&dealt) { + if count == 3 { + calls.push(Meldable::Kan) + } else if count == 2 { + calls.push(Meldable::Pon) + } + } + + // find chii + if let Some(next_outer) = dealt.next_rank() { + if let Some(next_inner) = next_outer.next_rank() + && counts.contains_key(&next_outer) + && counts.contains_key(&next_inner) + { + calls.push(Meldable::Chii(next_outer, next_inner)); + } + if let Some(prev_inner) = next_outer.prev_rank() + && counts.contains_key(&next_outer) + && counts.contains_key(&prev_inner) + { + calls.push(Meldable::Chii(next_outer, prev_inner)); + } + } + if let Some(prev_outer) = dealt.prev_rank() + && let Some(prev_inner) = prev_outer.prev_rank() + && counts.contains_key(&prev_outer) + && counts.contains_key(&prev_inner) + { + calls.push(Meldable::Chii(prev_outer, prev_inner)); + } + + calls +} + +pub fn check_ron(hand: &[Tile], melds: &[&[Tile]]) { + let bag: HashBag = HashBag::from_iter(hand.iter().cloned()); + + +} diff --git a/jong-types/src/lib.rs b/jong-types/src/lib.rs index 535a9cd..5b2ad19 100644 --- a/jong-types/src/lib.rs +++ b/jong-types/src/lib.rs @@ -4,7 +4,7 @@ mod derive_alias { Eq = ::core::cmp::PartialEq, ::core::cmp::Eq; Ord = ..Eq, ::core::cmp::PartialOrd, ::core::cmp::PartialEq, ::core::cmp::Ord; - Base = ::core::fmt::Debug, ..Copy, ..Ord; + Base = ::core::fmt::Debug, ..Copy, ..Ord, ::core::hash::Hash; } } use derive_aliases::derive; @@ -13,7 +13,7 @@ use bevy::prelude::*; use spacetimedb::SpacetimeType; use strum::{EnumCount, FromRepr}; -#[derive(..Base, Hash, Default, FromRepr)] +#[derive(..Base, Default, FromRepr)] #[derive(States, SpacetimeType)] pub enum GameState { #[default] @@ -41,18 +41,6 @@ pub enum Suit { Dragon(Dragon), } -impl Suit { - pub fn rank(&self) -> Option { - match self { - Suit::Man(rank) => Some(*rank), - Suit::Pin(rank) => Some(*rank), - Suit::Sou(rank) => Some(*rank), - // Suit::Wind(wind) | Suit::Dragon(dragon) => None, - _ => None, - } - } -} - #[derive( ..Base, Deref, @@ -63,6 +51,49 @@ pub struct Rank { pub number: u8, } +impl Tile { + pub fn next_rank(self) -> Option { + match self.suit { + Suit::Man(rank) if rank.number < 9 => Some(Tile { + suit: Suit::Man(Rank { + number: rank.number + 1, + }), + }), + Suit::Pin(rank) if rank.number < 9 => Some(Tile { + suit: Suit::Pin(Rank { + number: rank.number + 1, + }), + }), + Suit::Sou(rank) if rank.number < 9 => Some(Tile { + suit: Suit::Sou(Rank { + number: rank.number + 1, + }), + }), + _ => None, + } + } + pub fn prev_rank(self) -> Option { + match self.suit { + Suit::Man(rank) if rank.number > 1 => Some(Tile { + suit: Suit::Man(Rank { + number: rank.number - 1, + }), + }), + Suit::Pin(rank) if rank.number > 1 => Some(Tile { + suit: Suit::Pin(Rank { + number: rank.number - 1, + }), + }), + Suit::Sou(rank) if rank.number > 1 => Some(Tile { + suit: Suit::Sou(Rank { + number: rank.number - 1, + }), + }), + _ => None, + } + } +} + #[derive( ..Base, FromRepr, diff --git a/jong/src/game.rs b/jong/src/game.rs index 4f947ba..ded0db7 100644 --- a/jong/src/game.rs +++ b/jong/src/game.rs @@ -227,7 +227,9 @@ fn on_lobby_insert_update( } stdb::TurnState::Menzen => todo!(), stdb::TurnState::RiichiKan => todo!(), - stdb::TurnState::Discard => todo!(), + stdb::TurnState::Discard => { + // TODO check if can call reducer here maybe? + } stdb::TurnState::RonChiiPonKan => todo!(), stdb::TurnState::End => todo!(), } diff --git a/spacetimedb/src/tables/player.rs b/spacetimedb/src/tables/player.rs index f0b2f8a..6b873a0 100644 --- a/spacetimedb/src/tables/player.rs +++ b/spacetimedb/src/tables/player.rs @@ -4,6 +4,7 @@ use spacetimedb::{SpacetimeType, table}; use super::DbTile; // FIXME this shant be public, use views +// TODO split up tables so we aren't sending this over the wire every update, or is differencial handled already #[table(name = player, public)] #[derive(Debug)] pub struct Player { @@ -26,6 +27,7 @@ pub struct Player { pub pond: Vec, pub drawn_tile: Option, + pub actionable: Option<()>, } #[table(name = bot)]