This commit is contained in:
Tao Tien 2026-01-17 02:22:47 -08:00
parent 02b40ef344
commit 3182916832
7 changed files with 85 additions and 14 deletions

View file

@ -25,6 +25,9 @@ tracing = "0.1.44"
tracing-subscriber = "0.3.22"
tui-logger = { version = "0.18.0", features = ["tracing-support", "crossterm"] }
[dev-dependencies]
bevy = { version = "0.17.3", features = ["track_location"] }
[profile.dev]
opt-level = 1

View file

@ -47,6 +47,8 @@ impl Plugin for Riichi {
.add_systems(OnEnter(TurnState::Menzen), round::menzen)
.add_systems(Update, round::riichi_kan.run_if(in_state(TurnState::RiichiKan)))
.add_systems(Update, round::discard.run_if(in_state(TurnState::Discard)))
.add_systems(Update, round::ron_chi_pon_kan.run_if(in_state(TurnState::RonChiiPonKan)))
.add_systems(OnEnter(TurnState::End), round::end)
// .add_systems(Update, systems)
// semicolon stopper
;

View file

@ -1,3 +1,5 @@
use std::mem::discriminant;
use bevy::prelude::*;
use crate::{
@ -11,6 +13,9 @@ pub struct Hand;
#[derive(Component, Debug)]
pub struct DrawnTile(pub Entity);
#[derive(Component)]
pub struct DiscardedTile(pub Entity);
// #[derive(Component, Default)]
// enum SortHand {
// #[default]
@ -60,3 +65,20 @@ pub(crate) fn shuffle_deal(
next_gamestate.set(GameState::Play);
}
/// assumes hand is sorted
pub(crate) fn check_wincon(hand: &[Tile; 14], melds: &[&[Tile]]) -> bool {
// 4x3 + pair
// assume sorted
//
// let melds = hand.iter().array_chunks::<3>().all(|tiles| {
// let suit = discriminant(&tiles[0].suit);
// let starting_rank = tiles[0].suit
// // tiles.iter().all(|t| discriminant(&t.suit) == suit) && tiles.iter().zip(tiles[0].suit.rank())
// }) && melds.iter().all(|meld| todo!());
// let eyeball = todo!();
todo!();
// melds && eyeball
}

View file

@ -5,7 +5,7 @@ use crate::{
EnumNextCycle,
game::{
GameMessage, GameState,
hand::{DrawnTile, Hand},
hand::{DiscardedTile, DrawnTile, Hand},
player::Player,
wall::Wall,
},
@ -127,9 +127,10 @@ pub(crate) fn tsumo(
let drawn = walltiles.last().unwrap();
commands.entity(*wall_ent).remove_child(*drawn);
commands.entity(curr_player.0).insert(DrawnTile(*drawn));
let drawn_ent = commands.spawn(DrawnTile(*drawn)).id();
commands.entity(curr_player.0).add_child(drawn_ent);
debug!("drew: {:?}", drawn);
debug!("drew: ent: {drawn_ent:?} tile_ent: {:?}", drawn);
next_turnstate.set(curr_turnstate.next());
}
@ -138,6 +139,7 @@ pub(crate) fn menzen(
curr_turnstate: Res<State<TurnState>>,
mut next_turnstate: ResMut<NextState<TurnState>>,
) {
trace!("menzen check");
next_turnstate.set(curr_turnstate.next());
}
@ -145,14 +147,17 @@ pub(crate) fn riichi_kan(
curr_turnstate: Res<State<TurnState>>,
mut next_turnstate: ResMut<NextState<TurnState>>,
) {
trace!("riichi_kan");
next_turnstate.set(curr_turnstate.next());
}
#[allow(clippy::too_many_arguments, irrefutable_let_patterns)]
pub(crate) fn discard(
mut commands: Commands,
mut reader: MessageReader<GameMessage>,
currplayer: Res<CurrentPlayer>,
drawntile: Single<Entity, With<DrawnTile>>,
drawntile: Single<(&DrawnTile, Entity), With<DrawnTile>>,
player_hands: Populated<(&Player, &Children), With<Hand>>,
hands: Populated<&Children, (With<Hand>, Without<Player>)>,
@ -160,17 +165,42 @@ pub(crate) fn discard(
mut next_turnstate: ResMut<NextState<TurnState>>,
) {
let curr = currplayer.0;
let hand_ent = player_hands.get(curr).unwrap().1.iter().next().unwrap();
let hand = hands.get(hand_ent).unwrap();
let hand = player_hands.get(curr).unwrap().1.iter().next().unwrap();
let handtiles = hands.get(hand).unwrap();
let (drawntile, drawn_ent) = *drawntile;
// debug!("discard turn for: {curr:?}");
while let Some(message) = reader.read().next() {
if let GameMessage::Discarded(entity) = message {
if *entity == *drawntile {
} else if hand.contains(entity) {
debug!("{curr:?} discarded: {entity:?}");
// commands.entity(drawn_ent).despawn();
if *entity == drawntile.0 {
} else if handtiles.contains(entity) {
commands
.entity(hand)
.remove_child(*entity)
.add_child(drawntile.0);
} else {
panic!("discarded illegal player tile?")
}
commands.spawn(DiscardedTile(*entity));
next_turnstate.set(curr_turnstate.next());
break;
}
}
}
pub(crate) fn ron_chi_pon_kan(
curr_turnstate: Res<State<TurnState>>,
mut next_turnstate: ResMut<NextState<TurnState>>,
) {
next_turnstate.set(curr_turnstate.next());
}
pub(crate) fn end(
curr_turnstate: Res<State<TurnState>>,
mut next_turnstate: ResMut<NextState<TurnState>>,
) {
next_turnstate.set(curr_turnstate.next());
}

View file

@ -15,6 +15,18 @@ pub enum Suit {
Dragon(Dragon),
}
impl Suit {
pub fn rank(&self) -> Option<Rank> {
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(Deref, DerefMut, Debug, PartialEq, PartialOrd, Eq, Ord, Clone, Copy)]
pub struct Rank(pub u8);

View file

@ -54,7 +54,7 @@ pub(crate) fn keyboard(
}
_ => {}
},
TuiState::InGame => debug!("unhandled keyboard event"),
TuiState::InGame => { /* debug!("unhandled keyboard event") */ }
}
}
}

View file

@ -64,17 +64,19 @@ pub(crate) fn mouse(
_ => {}
},
ratatui::crossterm::event::MouseEventKind::Drag(mouse_button) => {
debug!("unhandled mouse event")
// debug!("unhandled mouse event")
}
ratatui::crossterm::event::MouseEventKind::ScrollDown => {
debug!("unhandled mouse event")
// debug!("unhandled mouse event")
}
ratatui::crossterm::event::MouseEventKind::ScrollUp => {
// debug!("unhandled mouse event")
}
ratatui::crossterm::event::MouseEventKind::ScrollUp => debug!("unhandled mouse event"),
ratatui::crossterm::event::MouseEventKind::ScrollLeft => {
debug!("unhandled mouse event")
// debug!("unhandled mouse event")
}
ratatui::crossterm::event::MouseEventKind::ScrollRight => {
debug!("unhandled mouse event")
// debug!("unhandled mouse event")
}
}
}