207 lines
5.3 KiB
Go
207 lines
5.3 KiB
Go
package mlp
|
|
|
|
import (
|
|
"math/rand"
|
|
|
|
"git.fromouter.space/mcg/draft"
|
|
)
|
|
|
|
// I8PCube is a cube that uses I8Pages' pack schema.
|
|
// I8Pages' cube uses different kinds of packs, so a single schema is not possible.
|
|
// Therefore, I8PCube itself is not a valid set, but contains two valid sets for
|
|
// both types of packs (main deck / problems)
|
|
//
|
|
// Infos on I8Pages' cube:
|
|
// https://docs.google.com/spreadsheets/d/1Ufz4QLwLCZ1vLemAhE6cuAmu2lq_VAN7RhLO9p1opNQ
|
|
type I8PCube struct {
|
|
Main *I8PSet
|
|
Problems *I8PSet
|
|
}
|
|
|
|
// I8PSet is one of the sets of packs contained in a I8PCube
|
|
type I8PSet struct {
|
|
Cards I8PPool
|
|
Schema draft.PackSchema
|
|
}
|
|
|
|
// I8PType is a category of cards to be seeded into packs
|
|
type I8PType string
|
|
|
|
// I8PSchema is a schema to seed a single I8PCube pack
|
|
type I8PSchema []I8PSchemaSlot
|
|
|
|
// I8PSchemaSlot is a single slot of a I8PSchema
|
|
type I8PSchemaSlot struct {
|
|
Amount int
|
|
Type I8PType
|
|
}
|
|
|
|
// All types used for seeding packs
|
|
const (
|
|
I8PTypeBlue I8PType = "blue"
|
|
I8PTypeOrange I8PType = "orange"
|
|
I8PTypePink I8PType = "pink"
|
|
I8PTypePurple I8PType = "purple"
|
|
I8PTypeWhite I8PType = "white"
|
|
I8PTypeYellow I8PType = "yellow"
|
|
I8PTypeNone I8PType = "none"
|
|
I8PTypeMulti I8PType = "multi"
|
|
I8PTypeEntry I8PType = "entry"
|
|
I8PTypeProblem I8PType = "problem"
|
|
|
|
// Special types
|
|
I8PTypeAll I8PType = "all" // all means "from any other non-problem type"
|
|
)
|
|
|
|
// I8PPool is a pool of card divided into categories
|
|
type I8PPool map[I8PType][]Card
|
|
|
|
// MakeI8PCube takes an organized set of cards and sorts them into a draftable I8PCube
|
|
func MakeI8PCube(cards I8PPool, schema I8PSchema) *I8PCube {
|
|
return &I8PCube{
|
|
Main: makeMainSet(cards, schema),
|
|
Problems: makeProblemSet(cards),
|
|
}
|
|
}
|
|
|
|
func makeMainSet(cards I8PPool, schema I8PSchema) (set *I8PSet) {
|
|
// Create set with the given card pool
|
|
set = &I8PSet{
|
|
Cards: I8PPool{
|
|
I8PTypeBlue: cards[I8PTypeBlue],
|
|
I8PTypeOrange: cards[I8PTypeOrange],
|
|
I8PTypePink: cards[I8PTypePink],
|
|
I8PTypePurple: cards[I8PTypePurple],
|
|
I8PTypeWhite: cards[I8PTypeWhite],
|
|
I8PTypeYellow: cards[I8PTypeYellow],
|
|
I8PTypeNone: cards[I8PTypeNone],
|
|
I8PTypeMulti: cards[I8PTypeMulti],
|
|
I8PTypeEntry: cards[I8PTypeEntry],
|
|
},
|
|
}
|
|
// Build PackSchema from given I8PSchema
|
|
var slots []draft.PackSlot
|
|
for _, slot := range schema {
|
|
// Check for special cases
|
|
var provider draft.CardProvider
|
|
switch slot.Type {
|
|
case I8PTypeAll:
|
|
provider = set.ProviderOther()
|
|
default:
|
|
provider = set.ProviderByType(slot.Type)
|
|
}
|
|
// Add slot
|
|
slots = append(slots, draft.PackSlot{
|
|
Amount: slot.Amount,
|
|
Provider: provider,
|
|
})
|
|
}
|
|
set.Schema = draft.PackSchema{
|
|
Slots: slots,
|
|
}
|
|
return
|
|
}
|
|
|
|
func makeProblemSet(cards I8PPool) (set *I8PSet) {
|
|
set = &I8PSet{
|
|
Cards: I8PPool{
|
|
I8PTypeProblem: cards[I8PTypeProblem],
|
|
},
|
|
}
|
|
set.Schema = draft.PackSchema{
|
|
Slots: []draft.PackSlot{
|
|
{
|
|
Amount: 12,
|
|
Provider: set.ProviderByType(I8PTypeProblem),
|
|
},
|
|
},
|
|
}
|
|
return
|
|
}
|
|
|
|
// ProviderByType provides cards from a specified category
|
|
func (s *I8PSet) ProviderByType(typ I8PType) draft.CardProvider {
|
|
return func(n int) (out []draft.Card) {
|
|
s.shuffle(typ)
|
|
if len(s.Cards[typ]) < n {
|
|
n = len(s.Cards[typ])
|
|
}
|
|
out, s.Cards[typ] = toDraft(s.Cards[typ][:n]), s.Cards[typ][n:]
|
|
return
|
|
}
|
|
}
|
|
|
|
// ProviderOther picks a random card for any available set (except Problems)
|
|
func (s *I8PSet) ProviderOther() draft.CardProvider {
|
|
choices := []I8PType{
|
|
I8PTypeBlue,
|
|
I8PTypeOrange,
|
|
I8PTypePink,
|
|
I8PTypePurple,
|
|
I8PTypeWhite,
|
|
I8PTypeYellow,
|
|
I8PTypeNone,
|
|
I8PTypeMulti,
|
|
I8PTypeEntry,
|
|
}
|
|
return func(n int) (out []draft.Card) {
|
|
// Filter types that have enough cards for what we need
|
|
// n is almost always 1, so this should not introduce bias
|
|
available := []I8PType{}
|
|
for _, typ := range choices {
|
|
if len(s.Cards[typ]) >= n {
|
|
available = append(available, typ)
|
|
}
|
|
}
|
|
|
|
// Check if there are no pools we can pick stuff from, and exit early
|
|
// THIS IS NOT NORMAL, AND YOU SHOULD FIX YOUR CUBE!
|
|
if len(available) < 1 {
|
|
return
|
|
}
|
|
|
|
typ := available[rand.Intn(len(available))]
|
|
return s.ProviderByType(typ)(n)
|
|
}
|
|
}
|
|
|
|
// PackSchema returns the pack schema for building packs from a I8PCube
|
|
func (s *I8PSet) PackSchema() draft.PackSchema {
|
|
return s.Schema
|
|
}
|
|
|
|
func (s *I8PSet) shuffle(typ I8PType) {
|
|
rand.Shuffle(len(s.Cards[typ]), func(i, j int) {
|
|
s.Cards[typ][i], s.Cards[typ][j] = s.Cards[typ][j], s.Cards[typ][i]
|
|
})
|
|
}
|
|
|
|
// DefaultI8PSchema returns I8Pages' schema as specified in his docs
|
|
func DefaultI8PSchema() I8PSchema {
|
|
return I8PSchema{
|
|
{Amount: 1, Type: I8PTypeBlue},
|
|
{Amount: 1, Type: I8PTypeOrange},
|
|
{Amount: 1, Type: I8PTypePink},
|
|
{Amount: 1, Type: I8PTypePurple},
|
|
{Amount: 1, Type: I8PTypeWhite},
|
|
{Amount: 1, Type: I8PTypeYellow},
|
|
{Amount: 1, Type: I8PTypeNone},
|
|
{Amount: 2, Type: I8PTypeMulti},
|
|
{Amount: 2, Type: I8PTypeEntry},
|
|
{Amount: 1, Type: I8PTypeAll},
|
|
}
|
|
}
|
|
|
|
// PackProvider returns a PackProvider for a given number of main and problem packs
|
|
func (c *I8PCube) PackProvider(mainPacks, problemPacks int) draft.PackProvider {
|
|
return func() []draft.Pack {
|
|
packs := make([]draft.Pack, mainPacks+problemPacks)
|
|
for main := 0; main < mainPacks; main++ {
|
|
packs[main] = draft.MakePack(c.Main)
|
|
}
|
|
for problem := 0; problem < problemPacks; problem++ {
|
|
packs[mainPacks+problem] = draft.MakePack(c.Problems)
|
|
}
|
|
return packs
|
|
}
|
|
}
|