package main import ( "bufio" "fmt" "io" "sort" "strconv" ) type day07 struct{} type rank int const ( highCard rank = iota onePair twoPair threeOfAKind fullHouse fourOfAKind fiveOfAKind ) type hand struct { cards []rune values []int rank rank bid int } type hands []hand func (h hands) Len() int { return len(h) } func (h hands) Less(i, j int) bool { h1 := h[i] h2 := h[j] if h1.rank < h2.rank { return true } else if h1.rank > h2.rank { return false } else { for k := 0; k < 5; k++ { if h1.values[k] < h2.values[k] { return true } else if h1.values[k] > h2.values[k] { return false } } panic("not reachable") } } func (h hands) Swap(i, j int) { h[i], h[j] = h[j], h[i] } // returns the rank and values of the hand func camelrank(hand hand) (rank, []int) { counts := make([]int, 14) hand.values = make([]int, len(hand.cards)) for i, r := range hand.cards { switch r { case '1': counts[0] = counts[0] + 1 hand.values[i] = 1 case '2': counts[1] = counts[1] + 1 hand.values[i] = 2 case '3': counts[2] = counts[2] + 1 hand.values[i] = 3 case '4': counts[3] = counts[3] + 1 hand.values[i] = 4 case '5': counts[4] = counts[4] + 1 hand.values[i] = 5 case '6': counts[5] = counts[5] + 1 hand.values[i] = 6 case '7': counts[6] = counts[6] + 1 hand.values[i] = 7 case '8': counts[7] = counts[7] + 1 hand.values[i] = 8 case '9': counts[8] = counts[8] + 1 hand.values[i] = 9 case 'T': counts[9] = counts[9] + 1 hand.values[i] = 10 case 'J': counts[10] = counts[10] + 1 hand.values[i] = 11 case 'Q': counts[11] = counts[11] + 1 hand.values[i] = 12 case 'K': counts[12] = counts[12] + 1 hand.values[i] = 13 case 'A': counts[13] = counts[13] + 1 hand.values[i] = 14 } } var ( seenPair bool seenThreeOfAKind bool ) for _, count := range counts { switch count { case 0: case 1: continue case 2: if seenPair { return twoPair, hand.values } else if seenThreeOfAKind { return fullHouse, hand.values } seenPair = true case 3: if seenPair { return fullHouse, hand.values } seenThreeOfAKind = true case 4: return fourOfAKind, hand.values case 5: return fiveOfAKind, hand.values } } if seenPair { return onePair, hand.values } else if seenThreeOfAKind { return threeOfAKind, hand.values } return highCard, hand.values } func camelrankjoker(hand hand) (rank, []int, int) { counts := make([]int, 14) jokers := 0 hand.values = make([]int, len(hand.cards)) for i, r := range hand.cards { switch r { case '1': counts[0] = counts[0] + 1 hand.values[i] = 1 case '2': counts[1] = counts[1] + 1 hand.values[i] = 2 case '3': counts[2] = counts[2] + 1 hand.values[i] = 3 case '4': counts[3] = counts[3] + 1 hand.values[i] = 4 case '5': counts[4] = counts[4] + 1 hand.values[i] = 5 case '6': counts[5] = counts[5] + 1 hand.values[i] = 6 case '7': counts[6] = counts[6] + 1 hand.values[i] = 7 case '8': counts[7] = counts[7] + 1 hand.values[i] = 8 case '9': counts[8] = counts[8] + 1 hand.values[i] = 9 case 'T': counts[9] = counts[9] + 1 hand.values[i] = 10 case 'J': jokers++ hand.values[i] = 1 case 'Q': counts[11] = counts[11] + 1 hand.values[i] = 12 case 'K': counts[12] = counts[12] + 1 hand.values[i] = 13 case 'A': counts[13] = counts[13] + 1 hand.values[i] = 14 } } var ( seenPair bool seenThreeOfAKind bool ) for _, count := range counts { switch count { case 0: case 1: continue case 2: if seenPair { return twoPair, hand.values, jokers } else if seenThreeOfAKind { return fullHouse, hand.values, jokers } seenPair = true case 3: if seenPair { return fullHouse, hand.values, jokers } seenThreeOfAKind = true case 4: return fourOfAKind, hand.values, jokers case 5: return fiveOfAKind, hand.values, jokers } } if seenPair { return onePair, hand.values , jokers } else if seenThreeOfAKind { return threeOfAKind, hand.values, jokers } return highCard, hand.values, jokers } func upgraderank(hand hand, jokers int) rank { var upgrades [4]rank switch hand.rank { case highCard: if jokers == 5 { return fiveOfAKind } upgrades = [4]rank{onePair, threeOfAKind, fourOfAKind, fiveOfAKind} case onePair: upgrades = [4]rank{threeOfAKind, fourOfAKind, fiveOfAKind, fiveOfAKind} case twoPair: upgrades = [4]rank{fullHouse, fullHouse, fullHouse, fullHouse} case threeOfAKind: upgrades = [4]rank{fourOfAKind, fiveOfAKind, fiveOfAKind, fiveOfAKind} case fullHouse: upgrades = [4]rank{fullHouse, fullHouse, fullHouse, fullHouse} case fourOfAKind: upgrades = [4]rank{fiveOfAKind, fiveOfAKind, fiveOfAKind, fiveOfAKind} case fiveOfAKind: upgrades = [4]rank{fiveOfAKind, fiveOfAKind, fiveOfAKind, fiveOfAKind} } if jokers > 0 { return upgrades[jokers-1] } return hand.rank } func (d day07) solve1(r io.Reader) string { total := 0 var hands hands = make([]hand, 0) scanner := bufio.NewScanner(r) scanner.Split(bufio.ScanWords) for i, w := 0, 0; scanner.Scan(); w++ { word := scanner.Text() if w%2 == 0 { hand := hand{cards: []rune(word)} hand.rank, hand.values = camelrank(hand) hands = append(hands, hand) } else { val, err := strconv.ParseInt(word, 10, 64) if err != nil { panic(err) } hands[i].bid = int(val) i++ } } sort.Sort(hands) for i, hand := range hands { total += hand.bid * (i + 1) } return fmt.Sprintf("%d", total) } func (d day07) solve2(r io.Reader) string { total := 0 var hands hands = make([]hand, 0) scanner := bufio.NewScanner(r) scanner.Split(bufio.ScanWords) for i, w := 0, 0; scanner.Scan(); w++ { word := scanner.Text() if w%2 == 0 { hand := hand{cards: []rune(word)} var jokers int hand.rank, hand.values, jokers = camelrankjoker(hand) hand.rank = upgraderank(hand, jokers) hands = append(hands, hand) } else { val, err := strconv.ParseInt(word, 10, 64) if err != nil { panic(err) } hands[i].bid = int(val) i++ } } sort.Sort(hands) for i, hand := range hands { total += hand.bid * (i + 1) } return fmt.Sprintf("%d", total) }