package main import ( "bytes" "fmt" "image" _ "image/jpeg" "image/png" "log" "math/rand" "net/http" "slices" "time" "git.niplace.ru/XoxJlopeZi4BB/imageutils" "git.niplace.ru/XoxJlopeZi4BB/paxpamir/token" tg "github.com/go-telegram-bot-api/telegram-bot-api/v5" ) const ( CardNum = 116 DominanceCheck = 4 EventCards = 12 SpecialCards = DominanceCheck + EventCards ) func shuffle[S ~[]E, E any](a S) { rand.Seed(time.Now().UnixNano()) for i := len(a) - 1; i > 0; i-- { j := rand.Intn(i + 1) a[i], a[j] = a[j], a[i] } } func takeOne[S ~[]T, T any](s *S) T { var new = slices.Clone(*s) v := new[0] *s = new[1:] return v } var ShuffledCardPool []int = func(n int) []int { arr := make([]int, n, n) for i := 0; i < n; i++ { arr[i] = i + 1 } shuffle(arr) return arr }(CardNum) var RupeesOnCards []int = func() (ns []int) { rand.Seed(time.Now().UnixNano()) for i := 0; i < 2; i++ { ns = append(ns, rand.Intn(4)) } return }() var LinkFormat string = "https://rally-the-troops.com" + "/pax-pamir/cards/card_%d.jpg" type Button struct { Text string `json:"text"` Data string `json:"data"` } type ListEntry struct { Images []string Buttons []Button } var Commands = map[string](func(tg.Update, *tg.BotAPI)){ "market": func(update tg.Update, bot *tg.BotAPI) { maxCost := 5 var err error for i := 0; i <= maxCost; i++ { buf := new(bytes.Buffer) var img = imageutils.Concat( Must(GetImage(fmt.Sprintf(LinkFormat, takeOne(&ShuffledCardPool)))), Must(GetImage(fmt.Sprintf(LinkFormat, takeOne(&ShuffledCardPool)))), imageutils.Right, ) err = png.Encode(buf, img) if err != nil { log.Println("error on decode:", err) } buttons := []Button{} for j := 0; j < 2; j++ { text := func() (s string) { s = fmt.Sprintf("buy for %d", i) if RupeesOnCards[j] >= i { s += fmt.Sprintf(", get 1") } return }() buttons = append(buttons, Button{Text: text, Data: "something"}) } msg := tg.NewPhoto( update.Message.Chat.ID, tg.FileBytes{Name: "cards", Bytes: buf.Bytes()}, ) fmt.Println(Buttons(buttons)) msg.ReplyMarkup = Buttons(buttons) responseMsg, err := bot.Send(msg) // get response message if err != nil { log.Println("failed to send message on command:", err) } log.Print("message sent. id:", responseMsg.MessageID) } }, // todo "hand": func(update tg.Update, bot *tg.BotAPI) { }, "court": func(update tg.Update, bot *tg.BotAPI) { }, } func Buttons(b []Button) tg.InlineKeyboardMarkup { return tg.NewInlineKeyboardMarkup( func() []tg.InlineKeyboardButton { var row []tg.InlineKeyboardButton for _, Button := range b { row = append(row, tg.NewInlineKeyboardButtonData( Button.Text, Button.Data, ), ) } return row }(), ) } func Must[T any](v T, err error) T { if err != nil { log.Println("ERROR:", err) } return v } func GetImage(link string) (image.Image, error) { resp, err := http.Get(link) if err != nil { return nil, err } defer resp.Body.Close() img, _, err := image.Decode(resp.Body) if err != nil { return nil, err } return img, nil } func HandleCommand(update tg.Update, bot *tg.BotAPI) { Commands[update.Message.Command()](update, bot) } func HandleUpdate(update tg.Update, bot *tg.BotAPI) { switch { case update.Message != nil: log.Print("new message. id:", update.Message.MessageID) if update.Message.IsCommand() { HandleCommand(update, bot) } else { log.Println("message is not a command:\n", update.Message.Text) } case update.CallbackQuery != nil: ConsumeCallback(update, bot) } return } func ConsumeCallback(update tg.Update, bot *tg.BotAPI) { updateMsg := update.CallbackQuery.Message log.Print("new CallbackQuery. id:", updateMsg.MessageID) callback := tg.NewCallback( update.CallbackQuery.ID, update.CallbackQuery.Data) // Recieve callback req, err := bot.Request(callback) if err != nil { log.Println("failed on request:", err) } log.Print("request sent. response:", req.Description) } func main() { bot := Must(tg.NewBotAPI(token.Token())) { log.Printf("authorized on account %s", bot.Self.UserName) u := tg.NewUpdate(0) u.Timeout = 60 updates := bot.GetUpdatesChan(u) for update := range updates { HandleUpdate(update, bot) } } }