<commit_before>package moves

import (
	"errors"
	"github.com/jkomoros/boardgame"
	"github.com/jkomoros/boardgame/moves/moveinterfaces"
)

type sourceDestinationStacker interface {
	moveinterfaces.SourceStacker
	moveinterfaces.DestinationStacker
}

//MoveCountComponents is a move that will move components, one at a time, from
//SourceStack() to DestinationStack() until TargetCount() components have been
//moved. It is like DealComponents or CollectComponnets, except instead of
//working on a certain stack for each player, it operates on two fixed stacks.
//Other MoveComponents-style moves derive from this. When using it you must
//implement moveinterfaces.SourceStacker and moveinterfaces.DestinationStacker
//to encode which stacks to use. You may also want to override TargetCount()
//if you want to move more than one component.
type MoveCountComponents struct {
	ApplyCountTimes
}

func (m *MoveCountComponents) ValidConfiguration(exampleState boardgame.MutableState) error {
	if err := m.ApplyUntilCount.ValidConfiguration(exampleState); err != nil {
		return err
	}

	if _, ok := m.TopLevelStruct().(sourceDestinationStacker); !ok {
		return errors.New("EmbeddingMove doesn't have Source/Destination stacker.")
	}

	return nil
}

//stacks returns the source and desitnation so you don't have to do the cast.
func (m *MoveCountComponents) stacks(state boardgame.State) (source, destination boardgame.MutableStack) {

	//TODO: this is a total hack
	mState := state.(boardgame.MutableState)

	stacker, ok := m.TopLevelStruct().(sourceDestinationStacker)

	if !ok {
		return nil, nil
	}

	return stacker.SourceStack(mState), stacker.DestinationStack(mState)

}

//Apply by default moves one component from SourceStack() to
//DestinationStack(). You likely do not need to override this method.
func (m *MoveCountComponents) Apply(state boardgame.MutableState) error {

	source, destination := m.stacks(state)

	if source == nil {
		return errors.New("Source was nil")
	}

	if destination == nil {
		return errors.New("Destination was nil")
	}

	return source.MoveComponent(boardgame.FirstComponentIndex, destination, boardgame.NextSlotIndex)

}

//MoveComponentsUntilCountReached is a move that will move components, one at
//a time, from SourceStack() to DestinationStack() until the target stack is
//up to having TargetCount components in it. See also
//MoveComponentsUntilCountLeft for a slightly different end condition.
type MoveComponentsUntilCountReached struct {
	MoveCountComponents
}

//CountDown returns false, because as we move components from source to
//destination, destination will be getting larger.
func (m *MoveComponentsUntilCountReached) CountDown(state boardgame.State) bool {
	return false
}

//Count returns the number of components in DestinationStack().
func (m *MoveComponentsUntilCountReached) Count(state boardgame.State) int {

	_, targetStack := m.stacks(state)

	if targetStack == nil {
		return 0
	}

	return targetStack.NumComponents()
}

//MoveComponentsUntilCountLeft is a move that will move components, one at a
//time, from SourceStack() to DestinationStack() until the source stack is
//down to having  TargetCount components in it. Its primary difference from
//MoveComponentsUntilCountReached is that its target is based on reducing the
//size of SourceStack to a target size.
type MoveComponentsUntilCountLeft struct {
	MoveCountComponents
}

//Count returns the number of components in the SourceStack().
func (m *MoveComponentsUntilCountLeft) Count(state boardgame.State) int {
	targetStack, _ := m.stacks(state)

	if targetStack == nil {
		return 0
	}

	return targetStack.NumComponents()
}

//CountDown returns true, because as we move components from source to
//destination, source will be getting smaller and smaller.
func (m *MoveComponentsUntilCountLeft) CountDown(state boardgame.State) bool {
	return true
}
<commit_msg>Reasonable defaults for Move* Components in DefaultConfig. Part of #528.<commit_after>package moves

import (
	"errors"
	"github.com/jkomoros/boardgame"
	"github.com/jkomoros/boardgame/moves/moveinterfaces"
)

type sourceDestinationStacker interface {
	moveinterfaces.SourceStacker
	moveinterfaces.DestinationStacker
}

//MoveCountComponents is a move that will move components, one at a time, from
//SourceStack() to DestinationStack() until TargetCount() components have been
//moved. It is like DealComponents or CollectComponnets, except instead of
//working on a certain stack for each player, it operates on two fixed stacks.
//Other MoveComponents-style moves derive from this. When using it you must
//implement moveinterfaces.SourceStacker and moveinterfaces.DestinationStacker
//to encode which stacks to use. You may also want to override TargetCount()
//if you want to move more than one component.
type MoveCountComponents struct {
	ApplyCountTimes
}

func (m *MoveCountComponents) ValidConfiguration(exampleState boardgame.MutableState) error {
	if err := m.ApplyUntilCount.ValidConfiguration(exampleState); err != nil {
		return err
	}

	if _, ok := m.TopLevelStruct().(sourceDestinationStacker); !ok {
		return errors.New("EmbeddingMove doesn't have Source/Destination stacker.")
	}

	return nil
}

//stacks returns the source and desitnation so you don't have to do the cast.
func (m *MoveCountComponents) stacks(state boardgame.State) (source, destination boardgame.MutableStack) {

	//TODO: this is a total hack
	mState := state.(boardgame.MutableState)

	stacker, ok := m.TopLevelStruct().(sourceDestinationStacker)

	if !ok {
		return nil, nil
	}

	return stacker.SourceStack(mState), stacker.DestinationStack(mState)

}

func (m *MoveCountComponents) stackNames(state boardgame.MutableState) (starter, destination string) {
	starterStack, destinationStack := m.stacks(state)

	starter = "unknown stack"
	destination = "unknown stack"

	if name := stackPropName(starterStack, state); name != "" {
		starter = name
	}

	if name := stackPropName(destinationStack, state); name != "" {
		destination = name
	}

	return starter, destination
}

//Apply by default moves one component from SourceStack() to
//DestinationStack(). You likely do not need to override this method.
func (m *MoveCountComponents) Apply(state boardgame.MutableState) error {

	source, destination := m.stacks(state)

	if source == nil {
		return errors.New("Source was nil")
	}

	if destination == nil {
		return errors.New("Destination was nil")
	}

	return source.MoveComponent(boardgame.FirstComponentIndex, destination, boardgame.NextSlotIndex)

}

func (m *MoveCountComponents) MoveTypeName(manager *boardgame.GameManager) string {

	source, destination := m.stackNames(manager.ExampleState())

	return "Move " + m.targetCountString() + " Components From " + source + " To " + destination
}

func (m *MoveCountComponents) MoveTypeHelpText(manager *boardgame.GameManager) string {
	source, destination := m.stackNames(manager.ExampleState())

	return "Moves " + m.targetCountString() + " components from " + source + " to " + destination
}

//MoveComponentsUntilCountReached is a move that will move components, one at
//a time, from SourceStack() to DestinationStack() until the target stack is
//up to having TargetCount components in it. See also
//MoveComponentsUntilCountLeft for a slightly different end condition.
type MoveComponentsUntilCountReached struct {
	MoveCountComponents
}

//CountDown returns false, because as we move components from source to
//destination, destination will be getting larger.
func (m *MoveComponentsUntilCountReached) CountDown(state boardgame.State) bool {
	return false
}

//Count returns the number of components in DestinationStack().
func (m *MoveComponentsUntilCountReached) Count(state boardgame.State) int {

	_, targetStack := m.stacks(state)

	if targetStack == nil {
		return 0
	}

	return targetStack.NumComponents()
}

func (m *MoveComponentsUntilCountReached) MoveTypeName(manager *boardgame.GameManager) string {

	source, destination := m.stackNames(manager.ExampleState())

	return "Move Components From " + source + " Until " + destination + " Has " + m.targetCountString()
}

func (m *MoveComponentsUntilCountReached) MoveTypeHelpText(manager *boardgame.GameManager) string {
	source, destination := m.stackNames(manager.ExampleState())

	return "Moves components from " + source + " to " + destination + " until " + destination + " has " + m.targetCountString()
}

//MoveComponentsUntilCountLeft is a move that will move components, one at a
//time, from SourceStack() to DestinationStack() until the source stack is
//down to having  TargetCount components in it. Its primary difference from
//MoveComponentsUntilCountReached is that its target is based on reducing the
//size of SourceStack to a target size.
type MoveComponentsUntilCountLeft struct {
	MoveCountComponents
}

//Count returns the number of components in the SourceStack().
func (m *MoveComponentsUntilCountLeft) Count(state boardgame.State) int {
	targetStack, _ := m.stacks(state)

	if targetStack == nil {
		return 0
	}

	return targetStack.NumComponents()
}

//CountDown returns true, because as we move components from source to
//destination, source will be getting smaller and smaller.
func (m *MoveComponentsUntilCountLeft) CountDown(state boardgame.State) bool {
	return true
}

func (m *MoveComponentsUntilCountLeft) MoveTypeName(manager *boardgame.GameManager) string {

	source, destination := m.stackNames(manager.ExampleState())

	return "Move Components To " + destination + " Until " + source + " Has " + m.targetCountString()
}

func (m *MoveComponentsUntilCountLeft) MoveTypeHelpText(manager *boardgame.GameManager) string {
	source, destination := m.stackNames(manager.ExampleState())

	return "Moves components from " + source + " to " + destination + " until " + source + " has " + m.targetCountString() + " left"
}

{'fraction_non_alphanumeric': 0.09012395854501118, 'fraction_numerical': 0.0007112375533428165, 'mean_word_length': 5.046068796068796, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3677469', 'n_tokens_mistral': 2765, 'n_tokens_neox': 2690, 'n_words': 958}