package main

// containsCard проверяет наличие конкретной карты в срезе.
func containsCard(cards []Card, target Card) bool {
	for _, c := range cards {
		if c == target {
			return true
		}
	}
	return false
}

// wouldFormMeld проверяет, образует ли candidate валидную
// комбинацию (сет или сиквенс) вместе с картами руки.
func wouldFormMeld(hand []Card, candidate Card) bool {
	trial := append(append([]Card{}, hand...), candidate)
	for _, s := range FindAllSets(trial) {
		if containsCard(s, candidate) {
			return true
		}
	}
	for _, s := range FindAllSequences(trial) {
		if containsCard(s, candidate) {
			return true
		}
	}
	return false
}

// cardPotential — грубая эвристика полезности карты для будущих
// комбинаций: сколько других карт руки поддерживают её как часть
// сета (тот же ранг) или сиквенса (та же масть, ранг отличается не
// больше чем на 2 — то есть в пределах будущей связки).
func cardPotential(hand []Card, card Card) int {
	support := 0
	for _, other := range hand {
		if other == card {
			continue
		}
		if other.Rank == card.Rank {
			support++
		}
		if other.Suit == card.Suit {
			diff := int(other.Rank) - int(card.Rank)
			if diff < 0 {
				diff = -diff
			}
			if diff <= 2 {
				support++
			}
		}
	}
	return support
}

// deadestCard находит карту руки с наименьшим потенциалом
// (см. cardPotential); при равенстве потенциала предпочитает карту
// с наибольшей очковой стоимостью — чтобы избавляться от тяжёлого
// "мёртвого груза" в первую очередь.
func deadestCard(hand []Card) Card {
	best := hand[0]
	bestPotential := cardPotential(hand, best)
	for _, c := range hand[1:] {
		p := cardPotential(hand, c)
		if p < bestPotential || (p == bestPotential && c.Value() > best.Value()) {
			best = c
			bestPotential = p
		}
	}
	return best
}

// layAllAvailableMelds выкладывает на стол все комбинации, которые
// может собрать текущий игрок из своей руки, повторяя поиск после
// каждой выкладки (так как рука меняется). Возвращает количество
// выложенных комбинаций.
func layAllAvailableMelds(g *GameState) int {
	laid := 0
	for {
		hand := g.current().Hand
		sets := FindAllSets(hand)
		seqs := FindAllSequences(hand)

		var best []Card
		for _, s := range sets {
			if len(s) > len(best) {
				best = s
			}
		}
		for _, s := range seqs {
			if len(s) > len(best) {
				best = s
			}
		}
		if best == nil {
			return laid
		}
		if err := g.LayNewMeld(best); err != nil {
			return laid
		}
		laid++
		if g.Phase == PhaseGameOver {
			return laid
		}
	}
}

// tryExtendTableMelds пытается подложить карты руки к уже
// существующим на столе комбинациям (в том числе чужим). Полезно
// боту любого уровня, чтобы не копить карты, которые уже подходят
// под стол.
func tryExtendTableMelds(g *GameState) {
	for {
		extended := false
		for i := range g.Table {
			for _, card := range g.current().Hand {
				if g.AddToMeld(i, card) == nil {
					extended = true
					break
				}
			}
			if g.Phase == PhaseGameOver {
				return
			}
			if extended {
				break
			}
		}
		if !extended {
			return
		}
	}
}
