191 lines
3.9 KiB
Go
191 lines
3.9 KiB
Go
package draft
|
|
|
|
import "errors"
|
|
|
|
// Errors that can happen during draft
|
|
var (
|
|
ErrNotInPack = errors.New("card picked not in pack")
|
|
ErrNoPacksLeft = errors.New("no packs left to open")
|
|
ErrNoPendingPack = errors.New("no packs received from other players")
|
|
)
|
|
|
|
// PodDirection is the direction packs are passed between players
|
|
type PodDirection string
|
|
|
|
// All rotations
|
|
var (
|
|
PRClockwise PodDirection = "left"
|
|
PRAnticlockwise PodDirection = "right"
|
|
)
|
|
|
|
// Pod is a group of players drafting packs/cubes
|
|
type Pod struct {
|
|
Players []*Player
|
|
Direction PodDirection
|
|
|
|
ReadyNextPick chan bool
|
|
ReadyNextPack chan bool
|
|
}
|
|
|
|
// Player is a single player partecipating in a pod
|
|
type Player struct {
|
|
// Packs and picks
|
|
CurrentPack Pack
|
|
Packs []Pack
|
|
Picks []Card
|
|
|
|
// Nearby players
|
|
left *Player
|
|
right *Player
|
|
|
|
// Pod the player is in
|
|
pod *Pod
|
|
|
|
// Channels for passing stuff around
|
|
newpack chan Pack
|
|
}
|
|
|
|
// MakePod creates a pod with a specified number of players and a given set of packs
|
|
func MakePod(playerCount int, provider PackProvider) *Pod {
|
|
// Make player list
|
|
players := make([]*Player, playerCount)
|
|
|
|
// Make pod
|
|
pod := &Pod{
|
|
Players: players,
|
|
Direction: PRAnticlockwise,
|
|
ReadyNextPick: make(chan bool, 1),
|
|
ReadyNextPack: make(chan bool, 1),
|
|
}
|
|
|
|
// Fill players
|
|
for i := range players {
|
|
players[i] = &Player{
|
|
Packs: provider(),
|
|
Picks: []Card{},
|
|
pod: pod,
|
|
newpack: make(chan Pack, playerCount-1),
|
|
}
|
|
}
|
|
// Second loop to fill nearby players
|
|
for i := range players {
|
|
if i > 0 {
|
|
players[i].left = players[i-1]
|
|
} else {
|
|
players[i].left = players[playerCount-1]
|
|
}
|
|
players[i].right = players[(i+1)%playerCount]
|
|
}
|
|
|
|
return pod
|
|
}
|
|
|
|
// OpenPacks opens the next pack of each player
|
|
func (p *Pod) OpenPacks() error {
|
|
for _, p := range p.Players {
|
|
err := p.OpenPack()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
p.flipDirection()
|
|
return nil
|
|
}
|
|
|
|
// NextPacks makes player exchange packs for the next pick
|
|
func (p *Pod) NextPacks() error {
|
|
for _, p := range p.Players {
|
|
err := p.NextPack()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (p *Pod) flipDirection() {
|
|
if p.Direction == PRClockwise {
|
|
p.Direction = PRAnticlockwise
|
|
} else {
|
|
p.Direction = PRClockwise
|
|
}
|
|
}
|
|
|
|
func (p *Pod) checkPicks() {
|
|
for _, player := range p.Players {
|
|
if len(player.newpack) < 1 {
|
|
// Someone still hasn't passed a pack but has cards
|
|
return
|
|
}
|
|
}
|
|
|
|
// Everyone has new packs to draft
|
|
p.ReadyNextPick <- true
|
|
}
|
|
|
|
func (p *Pod) checkEndPack() {
|
|
for _, player := range p.Players {
|
|
if len(player.CurrentPack) != 0 {
|
|
// Someone still has cards to draft
|
|
return
|
|
}
|
|
}
|
|
|
|
// Everyone needs to open their next pack
|
|
p.ReadyNextPack <- true
|
|
}
|
|
|
|
// OpenPack opens the next pack the player has
|
|
func (p *Player) OpenPack() error {
|
|
if len(p.Packs) < 1 {
|
|
return ErrNoPacksLeft
|
|
}
|
|
p.CurrentPack, p.Packs = p.Packs[0], p.Packs[1:]
|
|
return nil
|
|
}
|
|
|
|
// NextPack picks the next pack passed from other players
|
|
func (p *Player) NextPack() error {
|
|
if len(p.newpack) < 1 {
|
|
return ErrNoPendingPack
|
|
}
|
|
p.CurrentPack = <-p.newpack
|
|
return nil
|
|
}
|
|
|
|
// Pick specified what card a player has picked and gives the pack to the next player
|
|
func (p *Player) Pick(pick Card) error {
|
|
// Check that pack contains specified card
|
|
id := -1
|
|
for i, card := range p.CurrentPack {
|
|
if pick.ID == card.ID {
|
|
id = i
|
|
break
|
|
}
|
|
}
|
|
if id < 0 {
|
|
return ErrNotInPack
|
|
}
|
|
// Take card from pack and put it into the picks
|
|
p.Picks = append(p.Picks, p.CurrentPack[id])
|
|
// Remove pick from pack using slice tricks
|
|
p.CurrentPack[id] = p.CurrentPack[len(p.CurrentPack)-1]
|
|
p.CurrentPack = p.CurrentPack[:len(p.CurrentPack)-1]
|
|
|
|
// Out of cards! Check if everyone else is as well
|
|
if len(p.CurrentPack) == 0 {
|
|
p.pod.checkEndPack()
|
|
return nil
|
|
}
|
|
|
|
// Send pack to next player
|
|
if p.pod.Direction == PRClockwise {
|
|
p.left.newpack <- p.CurrentPack
|
|
} else {
|
|
p.right.newpack <- p.CurrentPack
|
|
}
|
|
|
|
p.pod.checkPicks()
|
|
|
|
return nil
|
|
}
|