blah/main.go

139 lines
3.5 KiB
Go

package main
import (
"flag"
"fmt"
"log"
"math/rand"
"os"
"strings"
)
const (
identifierURL = "https://mtgjson.com/api/v5/AllIdentifiers.json"
pricesURL = "https://mtgjson.com/api/v5/AllPricesToday.json"
)
type CardRecord struct {
card Card `json:"card"`
price CardPriceEntry `json:"price"`
}
func main() {
identifierFile := flag.String("i", "AllIdentifiers.json", "identifier file (AllIdentifiers.json), if not found it will be downloaded")
pricesFile := flag.String("p", "AllPricesToday.json", "prices file (AllPricesToday.json), if not found it will be downloaded")
priceFilter := flag.Float64("price", 0.04, "Maximum card price allowed (in whole units of any currency)")
typeFilter := flag.String("remove-types", "token,emblem,sticker,card,hero,plane,scheme", "comma-separated list of card types to remove")
cardsPerDraft := flag.Int("packSize", 100, "How many cards to put in each \"dollar store\" pack")
packCount := flag.Int("packCount", 2, "How many \"dollar store\" pack to generate")
landLimit := flag.Int("landLimit", 5, "Limit how many lands to put in each pack (0 to disable)")
flag.Parse()
priceChan := make(chan []CardPriceEntry)
cardChan := make(chan map[string]Card)
log.Println(" == Loading data... ==")
go loadAsync(loadCardInfos(*identifierFile), cardChan)
go loadAsync(loadPrices(*pricesFile, *priceFilter), priceChan)
cards := <-cardChan
prices := <-priceChan
// Filter cards
forbiddenTypes := make(map[string]struct{})
for _, t := range strings.Split(*typeFilter, ",") {
forbiddenTypes[t] = struct{}{}
}
var filtered []CardRecord
for _, price := range prices {
entry := cards[price.UUID]
// Filter card types we don't want
typeOk := true
for _, t := range entry.Types {
if _, ok := forbiddenTypes[strings.ToLower(t)]; ok {
typeOk = false
break
}
}
if !typeOk {
continue
}
filtered = append(filtered, CardRecord{
card: entry,
price: price,
})
}
types := make(map[string]int)
for _, record := range filtered {
log.Printf("Price for %s: %.2f %s at %s\n", record.card.Name, record.price.Price, record.price.Currency, record.price.Seller)
for _, t := range record.card.Types {
types[strings.ToUpper(t)[0:1]+t[1:]]++
}
}
log.Println(" == Stats ==")
log.Printf("Found %d cards\n", len(filtered))
for t, count := range types {
log.Printf(" - %s: %d\n", t, count)
}
log.Println(" == Generating packs... ==")
for i := 0; i < *packCount; i++ {
pack := generatePack(filtered, *cardsPerDraft, *landLimit)
checkErr(os.WriteFile(fmt.Sprintf("pack-%d.txt", i), []byte(serializePack(pack)), 0644))
}
log.Println(" == Done ==")
}
func isType(card Card, askingType string) bool {
for _, t := range card.Types {
if strings.ToLower(t) == strings.ToLower(askingType) {
return true
}
}
return false
}
func serializePack(pack []CardRecord) (out string) {
for _, card := range pack {
out += "1 " + card.card.Name + "\n"
}
return
}
func generatePack(filtered []CardRecord, cardsPerDraft, landLimit int) []CardRecord {
// Pick random cards
randCards := make([]CardRecord, 0)
landCount := 0
for len(randCards) < cardsPerDraft {
pick := filtered[rand.Intn(len(filtered))]
if isType(pick.card, "land") {
if landLimit > 0 && landCount >= landLimit {
continue
} else {
landCount++
}
}
randCards = append(randCards, pick)
}
return randCards
}
func checkErr(err error) {
if err != nil {
log.Printf("Fatal error: %s\n", err.Error())
os.Exit(1)
}
}
func loadAsync[T any](fn func() (T, error), chn chan T) {
out, err := fn()
checkErr(err)
chn <- out
}