<commit_before>package game

import (
	"fmt"
	"github.com/dougfort/gocards"
)

// EnumerateMoves lists all possible legal moves in the current Tableau.
// The returned slice is in no patricular order
func (t Tableau) EnumerateMoves() []MoveType {
	var moves []MoveType

FROM_LOOP:
	for from := 0; from < TableauWidth; from++ {
		if len(t[from].Cards) == 0 {
			continue FROM_LOOP
		}

	TO_LOOP:
		for to := 0; to < TableauWidth; to++ {

			if to == from {
				continue TO_LOOP
			}

			// we could weed out a lot of these before validating,
			// but why bother, it would just make the code more confusing
		ROW_LOOP:
			for i := 0; i < len(t[from].Cards); i++ {
				row := t[from].HiddenCount + i
				move := MoveType{FromCol: from, FromRow: row, ToCol: to}
				if err := t.ValidateMove(move); err != nil {
					continue ROW_LOOP
				}
				moves = append(moves, move)
			}
		}
	}

	return moves
}

// ValidateMove returns nil if the move is valid in the Tableau
// A Move is valid if
// 1. The slice of Cards at 'From' is all of the same Suit
// 2. The slice of Cards at 'From' is in order by Rank from top to bottom
// 3. The bottom Card at 'To' is successor by Rank of the top Card moved
func (t Tableau) ValidateMove(m MoveType) error {
	var err error
	var s gocards.Cards

	if s, err = t.getSliceToMove(m); err != nil {
		return err
	}

	if !stackIndexValid(m.ToCol) || m.ToCol == m.FromCol {
		return fmt.Errorf("invalid ToCol: %d", m.FromCol)
	}

	if len(t[m.ToCol].Cards) > 0 {
		bottomCard := t.getBottomCard(m.ToCol)
		if s[0].Rank != bottomCard.Rank-1 {
			return fmt.Errorf("Rank of move slice top (%d) does not fit ToCol bottom (%d)",
				s[0].Rank, bottomCard.Rank)
		}
	}

	return nil
}

func stackIndexValid(index int) bool {
	return index >= 0 && index < TableauWidth
}

func (t Tableau) getSliceToMove(m MoveType) (gocards.Cards, error) {
	if !stackIndexValid(m.FromCol) {
		return nil, fmt.Errorf("m.FromCol invalid: %d", m.FromCol)
	}

	row := m.FromRow - t[m.FromCol].HiddenCount
	if !(row >= 0 && row < len(t[m.FromCol].Cards)) {
		return nil, fmt.Errorf("m.FromRow invalid: %d", m.FromRow)
	}

	s := t[m.FromCol].Cards[row:]

	var prev gocards.Card
	// interate from the top (highest Rank) card downto the bottom (lowest Rank)
	for i, card := range s {
		if i > 0 {
			if card.Suit != prev.Suit {
				return nil, fmt.Errorf("move slice not all the same Suit at %d", i)
			}
			if card.Rank != prev.Rank-1 {
				return nil, fmt.Errorf("move slice out of order %d %d at %d",<commit_msg>more replacements with <NAME>'s 'errors'<commit_after>package game

import (
	"github.com/pkg/errors"

	"github.com/dougfort/gocards"
)

// EnumerateMoves lists all possible legal moves in the current Tableau.
// The returned slice is in no patricular order
func (t Tableau) EnumerateMoves() []MoveType {
	var moves []MoveType

FROM_LOOP:
	for from := 0; from < TableauWidth; from++ {
		if len(t[from].Cards) == 0 {
			continue FROM_LOOP
		}

	TO_LOOP:
		for to := 0; to < TableauWidth; to++ {

			if to == from {
				continue TO_LOOP
			}

			// we could weed out a lot of these before validating,
			// but why bother, it would just make the code more confusing
		ROW_LOOP:
			for i := 0; i < len(t[from].Cards); i++ {
				row := t[from].HiddenCount + i
				move := MoveType{FromCol: from, FromRow: row, ToCol: to}
				if err := t.ValidateMove(move); err != nil {
					continue ROW_LOOP
				}
				moves = append(moves, move)
			}
		}
	}

	return moves
}

// ValidateMove returns nil if the move is valid in the Tableau
// A Move is valid if
// 1. The slice of Cards at 'From' is all of the same Suit
// 2. The slice of Cards at 'From' is in order by Rank from top to bottom
// 3. The bottom Card at 'To' is successor by Rank of the top Card moved
func (t Tableau) ValidateMove(m MoveType) error {
	var err error
	var s gocards.Cards

	if s, err = t.getSliceToMove(m); err != nil {
		return err
	}

	if !stackIndexValid(m.ToCol) || m.ToCol == m.FromCol {
		return errors.Errorf("invalid ToCol: %d", m.FromCol)
	}

	if len(t[m.ToCol].Cards) > 0 {
		bottomCard := t.getBottomCard(m.ToCol)
		if s[0].Rank != bottomCard.Rank-1 {
			return errors.Errorf("Rank of move slice top (%d) does not fit ToCol bottom (%d)",
				s[0].Rank, bottomCard.Rank)
		}
	}

	return nil
}

func stackIndexValid(index int) bool {
	return index >= 0 && index < TableauWidth
}

func (t Tableau) getSliceToMove(m MoveType) (gocards.Cards, error) {
	if !stackIndexValid(m.FromCol) {
		return nil, errors.Errorf("m.FromCol invalid: %d", m.FromCol)
	}

	row := m.FromRow - t[m.FromCol].HiddenCount
	if !(row >= 0 && row < len(t[m.FromCol].Cards)) {
		return nil, errors.Errorf("m.FromRow invalid: %d", m.FromRow)
	}

	s := t[m.FromCol].Cards[row:]

	var prev gocards.Card
	// interate from the top (highest Rank) card downto the bottom (lowest Rank)
	for i, card := range s {
		if i > 0 {
			if card.Suit != prev.Suit {
				return nil, errors.Errorf("move slice not all the same Suit at %d", i)
			}
			if card.Rank != prev.Rank-1 {
				return nil, errors.Errorf("move slice out of order %d %d at %d",
{'fraction_non_alphanumeric': 0.13115399763686492, 'fraction_numerical': 0.005907837731390311, 'mean_word_length': 3.1529026982829107, 'pattern_counts': {'":': 0, '<': 14, '<?xml version=': 0, '>': 12, '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': '5851629', 'n_tokens_mistral': 2025, 'n_tokens_neox': 1833, 'n_words': 625}