|
|
|
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)
|
|
|
|
}
|