package ws import "hakemsho/internal/game" // inboundMsg پیام دریافتی از کلاینت. type inboundMsg struct { Type string `json:"type"` // join_queue | choose_trump | play_card | leave | create_table | join_table | start_table | leave_table Mode string `json:"mode"` // برای join_queue Tier string `json:"tier"` // برای join_queue: نوع میز (beginner/pro/...) Suit string `json:"suit"` // برای choose_trump: hearts|spades|diamonds|clubs Card string `json:"card"` // برای play_card: مثل "AS" Code string `json:"code"` // برای join_table: شماره میز خصوصی Hands int `json:"hands"` // برای start_table: تعداد دستِ بازیِ خصوصی (۳/۵/۷) Dir int `json:"dir"` // برای rotate_table: جهتِ چرخشِ جایگاه‌ها (+۱/−۱) } // lobbyPlayer یک بازیکن در اتاق انتظارِ میز خصوصی. type lobbyPlayer struct { Name string `json:"name"` Host bool `json:"host"` Seat int `json:"seat"` // جایگاهِ مطلق (۰..۳) } // tableLobbyMsg وضعیت اتاق انتظارِ میز خصوصی (دورهمی). type tableLobbyMsg struct { Type string `json:"type"` // "table_lobby" Code string `json:"code"` Players []lobbyPlayer `json:"players"` Host bool `json:"host"` // آیا گیرنده میزبان است YouSeat int `json:"you_seat"` // جایگاهِ مطلقِ گیرنده (برای چیدمانِ صحنه) Remaining int `json:"remaining"` // باقیمانده‌ی میزهای رایگانِ گیرنده Unlimited bool `json:"unlimited"` } // countdownMsg شمارش معکوس پیش از شروع بازیِ خصوصی. type countdownMsg struct { Type string `json:"type"` // "countdown" Seconds int `json:"seconds"` } // tableClosedMsg انحلالِ میز خصوصی پیش از شروع (میزبان خارج شد). type tableClosedMsg struct { Type string `json:"type"` // "table_closed" Reason string `json:"reason"` } // PlayerInfo اطلاعات عمومی یک بازیکن سر میز. type PlayerInfo struct { Seat int `json:"seat"` Name string `json:"name"` Bot bool `json:"bot"` Connected bool `json:"connected"` } // matchedMsg به کلاینت پس از تشکیل میز. type matchedMsg struct { Type string `json:"type"` // "matched" Room string `json:"room"` Seat int `json:"seat"` Players []PlayerInfo `json:"players"` } // trickView یک کارت روی زمین. type trickView struct { Seat int `json:"seat"` Card string `json:"card"` } // stateMsg نمای مجاز بازی برای یک بازیکن خاص. type stateMsg struct { Type string `json:"type"` // "state" Room string `json:"room"` Phase string `json:"phase"` YourSeat int `json:"your_seat"` Hakem int `json:"hakem"` Turn int `json:"turn"` Trump string `json:"trump,omitempty"` // فقط پس از انتخاب حکم TrickDone bool `json:"trick_done"` // دستِ کامل در حال نمایش (بازی ممنوع) YourHand []string `json:"your_hand"` HandCounts [4]int `json:"hand_counts"` Trick []trickView `json:"trick"` LeadSuit string `json:"lead_suit,omitempty"` TricksWon [2]int `json:"tricks_won"` Scores [2]int `json:"scores"` TargetScore int `json:"target_score"` TurnTimeoutMs int `json:"turn_timeout_ms"` // مهلتِ نوبتِ انسان (برای شمارنده‌ی کلاینت) Players []PlayerInfo `json:"players"` } // handOverMsg نتیجه یک هَند. type handOverMsg struct { Type string `json:"type"` // "hand_over" WinnerTeam int `json:"winner_team"` Kot bool `json:"kot"` HakemKot bool `json:"hakem_kot"` Points int `json:"points"` Scores [2]int `json:"scores"` } // gameOverMsg پایان بازی. type gameOverMsg struct { Type string `json:"type"` // "game_over" WinnerTeam int `json:"winner_team"` Scores [2]int `json:"scores"` } // errorMsg خطا برای کلاینت. type errorMsg struct { Type string `json:"type"` // "error" Message string `json:"message"` } // playerLeftMsg خروج دائمی یک بازیکن (تبدیل به بات). type playerLeftMsg struct { Type string `json:"type"` // "player_left" Seat int `json:"seat"` } // playerStatusMsg تغییر وضعیت اتصال یک بازیکن (موقت). type playerStatusMsg struct { Type string `json:"type"` // "player_disconnected" | "player_reconnected" Seat int `json:"seat"` } // buildState نمای بازی را برای جایگاه seat می‌سازد (کارت بقیه مخفی می‌ماند). func buildState(g *game.Game, roomID string, seat int, players []PlayerInfo, turnTimeoutMs int) stateMsg { hand := g.Hand(seat) handStr := make([]string, len(hand)) for i, c := range hand { handStr[i] = c.String() } var counts [4]int for s := 0; s < 4; s++ { counts[s] = g.HandCount(s) } trick := make([]trickView, 0, len(g.Trick)) for _, tc := range g.Trick { trick = append(trick, trickView{Seat: tc.Seat, Card: tc.Card.String()}) } st := stateMsg{ Type: "state", Room: roomID, Phase: g.Phase.String(), TrickDone: g.TrickDone, YourSeat: seat, Hakem: g.Hakem, Turn: g.Turn, YourHand: handStr, HandCounts: counts, Trick: trick, TricksWon: g.TricksWon, Scores: g.Scores, TargetScore: g.TargetScore, Players: players, } if g.TrumpChosen { st.Trump = g.Trump.String() } if len(g.Trick) > 0 { st.LeadSuit = g.LeadSuit.String() } return st }