package rps import ( "context" "crypto/rand" "errors" "math/big" "strings" "velox-bot/internal/db/repos/rpsrepo" ) type Repo interface { GetScore(ctx context.Context, guildID int64, userID int64) (int, bool, error) SetScore(ctx context.Context, guildID int64, userID int64, score int) error TopScores(ctx context.Context, guildID int64, limit int) ([]rpsrepo.ScoreEntry, error) } type Service struct { repo Repo } func New(repo Repo) *Service { return &Service{repo: repo} } type Hand string const ( HandScissors Hand = "✌️" HandPaper Hand = "✋" HandRock Hand = "🤜" ) func (h Hand) String() string { return string(h) } func ParseHand(s string) (Hand, bool) { switch strings.TrimSpace(s) { case string(HandScissors): return HandScissors, true case string(HandPaper): return HandPaper, true case string(HandRock): return HandRock, true default: return "", false } } func RandomHand() (Hand, error) { n, err := rand.Int(rand.Reader, big.NewInt(3)) if err != nil { return "", err } switch n.Int64() { case 0: return HandScissors, nil case 1: return HandPaper, nil default: return HandRock, nil } } type GameResult string const ( ResultWin GameResult = "You won!" ResultLose GameResult = "You lost!" ResultTie GameResult = "It's a tie!" ) func DetermineResult(user Hand, bot Hand) GameResult { if user == bot { return ResultTie } switch user { case HandRock: if bot == HandScissors { return ResultWin } case HandPaper: if bot == HandRock { return ResultWin } case HandScissors: if bot == HandPaper { return ResultWin } } return ResultLose } type PlayOutput struct { UserHand Hand BotHand Hand Result GameResult Score int } func (s *Service) Play(ctx context.Context, guildID int64, userID int64, userHand Hand) (PlayOutput, error) { botHand, err := RandomHand() if err != nil { return PlayOutput{}, err } result := DetermineResult(userHand, botHand) score, _, err := s.repo.GetScore(ctx, guildID, userID) if err != nil { return PlayOutput{}, err } if result == ResultWin { score++ if err := s.repo.SetScore(ctx, guildID, userID, score); err != nil { return PlayOutput{}, err } } return PlayOutput{ UserHand: userHand, BotHand: botHand, Result: result, Score: score, }, nil } func (s *Service) GetScore(ctx context.Context, guildID int64, userID int64) (int, bool, error) { return s.repo.GetScore(ctx, guildID, userID) } func (s *Service) TopScores(ctx context.Context, guildID int64, limit int) ([]rpsrepo.ScoreEntry, error) { return s.repo.TopScores(ctx, guildID, limit) } var ErrGuildOnly = errors.New("guild only")