<commit_before>package poker

import (
	"fmt"
	"log"
	"reflect"
	"sort"
)

type Hand struct {
	rawHand string
	cards   []Card
}

func NewHand(rawHand string) (hand Hand, err error) {
	cards, err := parseCards(rawHand)
	if err != nil {
		return Hand{}, err
	}
	return Hand{
		rawHand: rawHand,
		cards:   cards,
	}, nil

}

func parseHands(rawHands []string) (hands []Hand, err error) {
	for _, rawHand := range rawHands {
		hand, err := NewHand(rawHand)
		if err != nil {
			return []Hand{}, err
		}
		hands = append(hands, hand)
	}
	return hands, nil
}

func (h Hand) Ranks() (ranks []Rank) {
	for _, card := range h.cards {
		ranks = append(ranks, card.rank)
	}
	return ranks
}

// compare returns 0 if both hands have equal score
// compare returns a positive number if the score of h is less than the score of o
// compare returns a negative number if the score of h is greater than the score of o
func (h Hand) compare(o Hand) int {
	if h.handType() == o.handType() {
		return h.tiebreak(o)
	}
	return int(h.handType()) - int(o.handType())
}

// compare returns 0 if both hands have equal score
// compare returns a positive number if the score of h is less than the score of o
// compare returns a negative number if the score of h is greater than the score of o
func (h Hand) tiebreak(o Hand) int {
	if h.handType() != o.handType() {
		log.Fatalf("tiebreak invoked with unequal hand types %v and %v", h, o)
	}

	switch h.handType() {
	default:
		return h.compareByHighestCard(o)
	}
}

func (h Hand) compareByHighestCard(o Hand) int {
	descendingRanksH := h.descendingRanks()
	descendingRanksO := o.descendingRanks()

	for i := range descendingRanksH {
		rankH := descendingRanksH[i]
		rankO := descendingRanksO[i]
		if rankH != rankO {
			return int(rankH) - int(rankO)
		}
	}
	return 0
}

func (h Hand) descendingRanks() (ranks []Rank) {
	for _, card := range h.cards {
		ranks = append(ranks, card.rank)
	}

	sort.Sort(sort.Reverse(ByRank(ranks)))
	return ranks
}

func (h Hand) handType() HandType {
	switch {
	case h.isStraightFlush():
		return StraightFlush
	case h.isFourOfKind():
		return FourOfKind
	case h.isFullHouse():
		return FullHouse
	case h.isFlush():
		return Flush
	case h.isStraight():
		return Straight
	case h.isThreeOfKind():
		return ThreeOfKind
	case h.isTwoPairs():
		return TwoPairs
	case h.isTwoOfKind():
		return Pair
	default:
		return Nothing
	}
}

func (h Hand) String() string {
	return fmt.Sprintf("rawHand %v cards %v handType %v", h.rawHand, h.cards, h.handType())
}

func (h Hand) isStraightFlush() bool {
	return h.isStraight() && h.isFlush()
}

func (h Hand) isFourOfKind() bool {
	rankToOccurences := h.getRankToOccurences()
	for _, occurences := range rankToOccurences {
		if occurences == 4 {
			return true
		}
	}
	return false
}

func (h Hand) isFullHouse() bool {
	rankToOccurences := h.getRankToOccurences()
	occurences := getValues(rankToOccurences)
	sort.Ints(occurences)
	fullHouse := []int{2, 3}
	return reflect.DeepEqual(occurences, fullHouse)
}

func (h Hand) isFlush() bool {
	suitToOccurences := h.getSuitToOccurences()
	for _, occurences := range suitToOccurences {
		if occurences != 5 {
			return false
		}
	}
	return true
}

func (h Hand) isStraight() bool {
	ranks := h.Ranks()
	sort.Sort(ByRank(ranks))
	for i, rank := range ranks {
		if i == 0 {
			continue
		}
		if int(ranks[i-1]) != int(rank)-1 {
			return false
		}
	}
	return true
}

func (h Hand) isThreeOfKind() bool {
	rankToOccurences := h.getRankToOccurences()
	for _, occurences := range rankToOccurences {
		if occurences == 3 {
			return true
		}
	}
	return false
}

func (h Hand) isTwoPairs() bool {
	rankToOccurences := h.getRankToOccurences()
	occurences := getValues(rankToOccurences)
	sort.Ints(occurences)
	twoPairs := []int{1, 2, 2}
	return reflect.DeepEqual(occurences, twoPairs)
}

func (h Hand) isTwoOfKind() bool {<commit_msg>Ace can start a straight<commit_after>package poker

import (
	"fmt"
	"log"
	"reflect"
	"sort"
)

type Hand struct {
	rawHand string
	cards   []Card
}

func NewHand(rawHand string) (hand Hand, err error) {
	cards, err := parseCards(rawHand)
	if err != nil {
		return Hand{}, err
	}
	return Hand{
		rawHand: rawHand,
		cards:   cards,
	}, nil

}

func parseHands(rawHands []string) (hands []Hand, err error) {
	for _, rawHand := range rawHands {
		hand, err := NewHand(rawHand)
		if err != nil {
			return []Hand{}, err
		}
		hands = append(hands, hand)
	}
	return hands, nil
}

func (h Hand) Ranks() (ranks []Rank) {
	for _, card := range h.cards {
		ranks = append(ranks, card.rank)
	}
	return ranks
}

// compare returns 0 if both hands have equal score
// compare returns a positive number if the score of h is less than the score of o
// compare returns a negative number if the score of h is greater than the score of o
func (h Hand) compare(o Hand) int {
	if h.handType() == o.handType() {
		return h.tiebreak(o)
	}
	return int(h.handType()) - int(o.handType())
}

// compare returns 0 if both hands have equal score
// compare returns a positive number if the score of h is less than the score of o
// compare returns a negative number if the score of h is greater than the score of o
func (h Hand) tiebreak(o Hand) int {
	if h.handType() != o.handType() {
		log.Fatalf("tiebreak invoked with unequal hand types %v and %v", h, o)
	}

	switch h.handType() {
	default:
		return h.compareByHighestCard(o)
	}
}

func (h Hand) compareByHighestCard(o Hand) int {
	descendingRanksH := h.descendingRanks()
	descendingRanksO := o.descendingRanks()

	for i := range descendingRanksH {
		rankH := descendingRanksH[i]
		rankO := descendingRanksO[i]
		if rankH != rankO {
			return int(rankH) - int(rankO)
		}
	}
	return 0
}

func (h Hand) descendingRanks() (ranks []Rank) {
	for _, card := range h.cards {
		ranks = append(ranks, card.rank)
	}

	sort.Sort(sort.Reverse(ByRank(ranks)))
	return ranks
}

func (h Hand) handType() HandType {
	switch {
	case h.isStraightFlush():
		return StraightFlush
	case h.isFourOfKind():
		return FourOfKind
	case h.isFullHouse():
		return FullHouse
	case h.isFlush():
		return Flush
	case h.isStraight():
		return Straight
	case h.isThreeOfKind():
		return ThreeOfKind
	case h.isTwoPairs():
		return TwoPairs
	case h.isTwoOfKind():
		return Pair
	default:
		return Nothing
	}
}

func (h Hand) String() string {
	return fmt.Sprintf("rawHand %v cards %v handType %v", h.rawHand, h.cards, h.handType())
}

func (h Hand) isStraightFlush() bool {
	return h.isStraight() && h.isFlush()
}

func (h Hand) isFourOfKind() bool {
	rankToOccurences := h.getRankToOccurences()
	for _, occurences := range rankToOccurences {
		if occurences == 4 {
			return true
		}
	}
	return false
}

func (h Hand) isFullHouse() bool {
	rankToOccurences := h.getRankToOccurences()
	occurences := getValues(rankToOccurences)
	sort.Ints(occurences)
	fullHouse := []int{2, 3}
	return reflect.DeepEqual(occurences, fullHouse)
}

func (h Hand) isFlush() bool {
	suitToOccurences := h.getSuitToOccurences()
	for _, occurences := range suitToOccurences {
		if occurences != 5 {
			return false
		}
	}
	return true
}

func (h Hand) isStraight() bool {
	if h.isStraightStartingWithAce() {
		return true
	}

	ranks := h.Ranks()
	sort.Sort(ByRank(ranks))
	for i, rank := range ranks {
		if i == 0 {
			continue
		}
		if int(ranks[i-1]) != int(rank)-1 {
			return false
		}
	}
	return true
}

func (h Hand) isStraightStartingWithAce() bool {
	ranks := h.Ranks()
	sort.Sort(ByRank(ranks))
	straightStartingWithAce := []Rank{Two, Three, Four, Five, Ace}
	return reflect.DeepEqual(ranks, straightStartingWithAce)
}

func (h Hand) isThreeOfKind() bool {
	rankToOccurences := h.getRankToOccurences()
	for _, occurences := range rankToOccurences {
		if occurences == 3 {
			return true
		}
	}
	return false
}

func (h Hand) isTwoPairs() bool {
	rankToOccurences := h.getRankToOccurences()
	occurences := getValues(rankToOccurences)
	sort.Ints(occurences)
	twoPairs := []int{1, 2, 2}
	return reflect.DeepEqual(occurences, twoPairs)
}

func (h Hand) isTwoOfKind() bool {
{'fraction_non_alphanumeric': 0.12383090160867939, 'fraction_numerical': 0.003491707195410899, 'mean_word_length': 3.842995169082126, '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': '3692855', 'n_tokens_mistral': 3140, 'n_tokens_neox': 2956, 'n_words': 875}