// موجودیت‌های وضعیت بازی (نگاشت از پیام‌های WebSocket سرور). class GamePlayer { final int seat; final String name; final bool bot; final bool connected; GamePlayer.fromJson(Map j) : seat = (j['seat'] ?? 0) as int, name = (j['name'] ?? '') as String, bot = (j['bot'] ?? false) as bool, connected = (j['connected'] ?? false) as bool; } class TrickCard { final int seat; final String card; TrickCard(this.seat, this.card); factory TrickCard.fromJson(Map j) => TrickCard((j['seat'] ?? 0) as int, (j['card'] ?? '') as String); } /// نمای وضعیت بازی برای بازیکن جاری (پیام type=state). class GameState { final String room; final String phase; // choose_trump | playing | hand_over | game_over final int yourSeat; final int hakem; final int turn; final String? trump; final bool trickDone; final List yourHand; final List handCounts; final List trick; final String? leadSuit; final List tricksWon; final List scores; final int targetScore; final List players; GameState({ required this.room, required this.phase, required this.yourSeat, required this.hakem, required this.turn, required this.trump, required this.trickDone, required this.yourHand, required this.handCounts, required this.trick, required this.leadSuit, required this.tricksWon, required this.scores, required this.targetScore, required this.players, }); factory GameState.fromJson(Map j) { List ints(dynamic v) => ((v as List?) ?? []).map((e) => (e as num).toInt()).toList(); return GameState( room: (j['room'] ?? '') as String, phase: (j['phase'] ?? '') as String, yourSeat: (j['your_seat'] ?? 0) as int, hakem: (j['hakem'] ?? 0) as int, turn: (j['turn'] ?? 0) as int, trump: j['trump'] as String?, trickDone: (j['trick_done'] ?? false) as bool, yourHand: ((j['your_hand'] as List?) ?? []).map((e) => e as String).toList(), handCounts: ints(j['hand_counts']), trick: ((j['trick'] as List?) ?? []) .map((e) => TrickCard.fromJson(Map.from(e as Map))) .toList(), leadSuit: j['lead_suit'] as String?, tricksWon: ints(j['tricks_won']), scores: ints(j['scores']), targetScore: (j['target_score'] ?? 7) as int, players: ((j['players'] as List?) ?? []) .map((e) => GamePlayer.fromJson(Map.from(e as Map))) .toList(), ); } bool get isMyTurn => turn == yourSeat; bool get amHakem => hakem == yourSeat; GamePlayer? playerAt(int seat) => players.where((p) => p.seat == seat).cast().firstOrNull; } /// نتیجه‌ی یک هَند (پیام type=hand_over). class HandResult { final int winnerTeam; final bool kot; final bool hakemKot; final int points; final List scores; HandResult.fromJson(Map j) : winnerTeam = (j['winner_team'] ?? 0) as int, kot = (j['kot'] ?? false) as bool, hakemKot = (j['hakem_kot'] ?? false) as bool, points = (j['points'] ?? 0) as int, scores = ((j['scores'] as List?) ?? []).map((e) => (e as num).toInt()).toList(); } /// نتیجه‌ی پایان بازی (پیام type=game_over). class GameOver { final int winnerTeam; final List scores; GameOver.fromJson(Map j) : winnerTeam = (j['winner_team'] ?? 0) as int, scores = ((j['scores'] as List?) ?? []).map((e) => (e as num).toInt()).toList(); } extension FirstOrNullExt on Iterable { E? get firstOrNull { final it = iterator; return it.moveNext() ? it.current : null; } }