Add day 7 part 2
parent
440c89b9b2
commit
b2c9a13c51
151
day7/main.go
151
day7/main.go
|
@ -14,7 +14,8 @@ import (
|
||||||
type Card int
|
type Card int
|
||||||
|
|
||||||
const (
|
const (
|
||||||
Two Card = iota + 2
|
Joker Card = iota + 1
|
||||||
|
Two
|
||||||
Three
|
Three
|
||||||
Four
|
Four
|
||||||
Five
|
Five
|
||||||
|
@ -49,29 +50,75 @@ type Player struct {
|
||||||
hand Hand
|
hand Hand
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Kind gets the "Kind" of the hand, which determines its value.
|
||||||
func (hand Hand) Kind() (HandKind, error) {
|
func (hand Hand) Kind() (HandKind, error) {
|
||||||
handCounts := map[HandKind][]int{
|
type kindMapping struct {
|
||||||
FiveOfAKind: {5},
|
kind HandKind
|
||||||
FourOfAKind: {1, 4},
|
distinctCounts []int
|
||||||
FullHouse: {2, 3},
|
|
||||||
ThreeOfAKind: {1, 1, 3},
|
|
||||||
TwoPair: {1, 2, 2},
|
|
||||||
OnePair: {1, 1, 1, 2},
|
|
||||||
HighCard: {1, 1, 1, 1, 1},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
distinctCounts := hand.CountDistinct()
|
// Must iterate in order so we try each kind first
|
||||||
|
handCounts := []kindMapping{
|
||||||
|
{
|
||||||
|
kind: FiveOfAKind,
|
||||||
|
distinctCounts: []int{5},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
kind: FourOfAKind,
|
||||||
|
distinctCounts: []int{1, 4},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
kind: FullHouse,
|
||||||
|
distinctCounts: []int{2, 3},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
kind: ThreeOfAKind,
|
||||||
|
distinctCounts: []int{1, 1, 3},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
kind: TwoPair,
|
||||||
|
distinctCounts: []int{1, 2, 2},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
kind: OnePair,
|
||||||
|
distinctCounts: []int{1, 1, 1, 2},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
kind: HighCard,
|
||||||
|
distinctCounts: []int{1, 1, 1, 1, 1},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
handWithoutJokers, numJokers := hand.WithoutCard(Joker)
|
||||||
|
distinctCounts := handWithoutJokers.CountDistinct()
|
||||||
cardCounts := mapValues(distinctCounts)
|
cardCounts := mapValues(distinctCounts)
|
||||||
slices.Sort(cardCounts)
|
slices.Sort(cardCounts)
|
||||||
for kind, kindCounts := range handCounts {
|
for _, mapping := range handCounts {
|
||||||
if slices.Equal(cardCounts, kindCounts) {
|
if canMakeKindWithCardCombo(cardCounts, mapping.distinctCounts, numJokers) {
|
||||||
return kind, nil
|
return mapping.kind, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return UnknownKind, errors.New("got it")
|
return UnknownKind, errors.New("no known kind for hand")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WithoutCard will return a copy of the Hand without the given card, toRemove
|
||||||
|
func (hand Hand) WithoutCard(toRemove Card) (Hand, int) {
|
||||||
|
newHand := Hand{}
|
||||||
|
numRemoved := 0
|
||||||
|
for _, card := range hand {
|
||||||
|
if card == toRemove {
|
||||||
|
numRemoved++
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
newHand = append(newHand, card)
|
||||||
|
}
|
||||||
|
|
||||||
|
return newHand, numRemoved
|
||||||
|
}
|
||||||
|
|
||||||
|
// CountDistinct returns a count of distinct cards by each card type
|
||||||
func (hand Hand) CountDistinct() map[Card]int {
|
func (hand Hand) CountDistinct() map[Card]int {
|
||||||
buckets := make(map[Card]int)
|
buckets := make(map[Card]int)
|
||||||
for _, card := range hand {
|
for _, card := range hand {
|
||||||
|
@ -111,15 +158,22 @@ func main() {
|
||||||
panic(fmt.Sprintf("failed to parse races: %s", err))
|
panic(fmt.Sprintf("failed to parse races: %s", err))
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, player := range players {
|
|
||||||
kind, _ := player.hand.Kind()
|
|
||||||
fmt.Printf("%+v %+v\n", player.hand, kind)
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Printf("Part 1: %d\n", part1(players))
|
fmt.Printf("Part 1: %d\n", part1(players))
|
||||||
|
fmt.Printf("Part 2: %d\n", part2(players))
|
||||||
}
|
}
|
||||||
|
|
||||||
func part1(players []Player) int {
|
func part1(players []Player) int {
|
||||||
|
return findWinnings(players)
|
||||||
|
}
|
||||||
|
|
||||||
|
func part2(originalPlayers []Player) int {
|
||||||
|
players := makePart2Players(originalPlayers)
|
||||||
|
|
||||||
|
return findWinnings(players)
|
||||||
|
}
|
||||||
|
|
||||||
|
// findWinnings finds the winning for each game
|
||||||
|
func findWinnings(players []Player) int {
|
||||||
sortedPlayers := slices.Clone(players)
|
sortedPlayers := slices.Clone(players)
|
||||||
slices.SortFunc(sortedPlayers, func(a, b Player) int {
|
slices.SortFunc(sortedPlayers, func(a, b Player) int {
|
||||||
aKind, err := a.hand.Kind()
|
aKind, err := a.hand.Kind()
|
||||||
|
@ -148,6 +202,65 @@ func part1(players []Player) int {
|
||||||
return winnings
|
return winnings
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// makePart2Players prepares the players for part 2 by replacing Jacks with Jokers
|
||||||
|
func makePart2Players(players []Player) []Player {
|
||||||
|
newPlayers := slices.Clone(players)
|
||||||
|
for i, player := range newPlayers {
|
||||||
|
updPlayer := player
|
||||||
|
updPlayer.hand = makePart2Hand(player.hand)
|
||||||
|
newPlayers[i] = updPlayer
|
||||||
|
}
|
||||||
|
|
||||||
|
return newPlayers
|
||||||
|
}
|
||||||
|
|
||||||
|
// makePart2Hand makes replaces Jacks with Jokers in each hand for part 2
|
||||||
|
func makePart2Hand(hand Hand) Hand {
|
||||||
|
newHand := slices.Clone(hand)
|
||||||
|
for i, card := range newHand {
|
||||||
|
if card == Jack {
|
||||||
|
newHand[i] = Joker
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return newHand
|
||||||
|
}
|
||||||
|
|
||||||
|
// canMakeKindWithCardCombo checks that if we can make the kind given. This is done by taking a sorted list of
|
||||||
|
// each of the number of each type of card. For instance, 55766 would be [2, 2, 1]
|
||||||
|
func canMakeKindWithCardCombo(handDistinctCardCounts []int, kindCardCounts []int, numJokers int) bool {
|
||||||
|
if numJokers == 0 {
|
||||||
|
return slices.Equal(kindCardCounts, handDistinctCardCounts)
|
||||||
|
} else if len(handDistinctCardCounts) == 0 && numJokers == 5 && slices.Equal(kindCardCounts, []int{5}) {
|
||||||
|
// If we have five jokers, we must act as a five of a kind (most valuable)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
permutations := permutationsOfJokers(handDistinctCardCounts, numJokers)
|
||||||
|
|
||||||
|
for _, permutation := range permutations {
|
||||||
|
if slices.Equal(permutation, kindCardCounts) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find all the positions where our sets of jokers could be located in in the distinct card count set
|
||||||
|
func permutationsOfJokers(distinctCardCounts []int, numJokers int) [][]int {
|
||||||
|
if numJokers == 0 {
|
||||||
|
return [][]int{distinctCardCounts}
|
||||||
|
}
|
||||||
|
|
||||||
|
permutations := [][]int{}
|
||||||
|
for i, count := range distinctCardCounts {
|
||||||
|
newCounts := slices.Clone(distinctCardCounts)
|
||||||
|
newCounts[i] = count + 1
|
||||||
|
permutations = append(permutations, permutationsOfJokers(newCounts, numJokers-1)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
return permutations
|
||||||
|
}
|
||||||
|
|
||||||
func parsePlayers(inputLines []string) ([]Player, error) {
|
func parsePlayers(inputLines []string) ([]Player, error) {
|
||||||
players := make([]Player, 0, len(inputLines))
|
players := make([]Player, 0, len(inputLines))
|
||||||
for i, line := range inputLines {
|
for i, line := range inputLines {
|
||||||
|
|
Loading…
Reference in New Issue