137 lines
2.6 KiB
Go
137 lines
2.6 KiB
Go
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")
|
|
|