AoC Day 7, Parts 1 and 2 (Solved)
This commit is contained in:
285
2023/07/code.go
Normal file
285
2023/07/code.go
Normal file
@@ -0,0 +1,285 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"unicode"
|
||||
|
||||
"github.com/jpillora/puzzler/harness/aoc"
|
||||
)
|
||||
|
||||
func main() {
|
||||
aoc.Harness(run)
|
||||
}
|
||||
|
||||
type Hand struct {
|
||||
Cards string
|
||||
Bid int
|
||||
}
|
||||
|
||||
func getCardPower(card rune) int {
|
||||
if unicode.IsNumber(card) {
|
||||
i, _ := strconv.Atoi(string(card))
|
||||
return i
|
||||
}
|
||||
|
||||
if card == 'T' {
|
||||
return 10
|
||||
}
|
||||
|
||||
if card == 'J' {
|
||||
return 11
|
||||
}
|
||||
|
||||
if card == 'Q' {
|
||||
return 12
|
||||
}
|
||||
|
||||
if card == 'K' {
|
||||
return 13
|
||||
}
|
||||
|
||||
if card == 'A' {
|
||||
return 14
|
||||
}
|
||||
|
||||
panic(fmt.Sprintf("Bad card %v", card))
|
||||
}
|
||||
|
||||
func getCardPowerJokerRules(card rune) int {
|
||||
if unicode.IsNumber(card) {
|
||||
i, _ := strconv.Atoi(string(card))
|
||||
return i
|
||||
}
|
||||
|
||||
if card == 'T' {
|
||||
return 10
|
||||
}
|
||||
|
||||
if card == 'J' {
|
||||
return 0
|
||||
}
|
||||
|
||||
if card == 'Q' {
|
||||
return 12
|
||||
}
|
||||
|
||||
if card == 'K' {
|
||||
return 13
|
||||
}
|
||||
|
||||
if card == 'A' {
|
||||
return 14
|
||||
}
|
||||
|
||||
panic(fmt.Sprintf("Bad card %v", card))
|
||||
}
|
||||
|
||||
func getHandTypeRanking(hand Hand) int {
|
||||
cardUniq := make(map[string]int)
|
||||
|
||||
for _, c := range strings.Split(hand.Cards, "") {
|
||||
if _, ok := cardUniq[c]; !ok {
|
||||
cardUniq[c] = 0
|
||||
}
|
||||
cardUniq[c] += 1
|
||||
}
|
||||
|
||||
if len(cardUniq) == 1 {
|
||||
// Full house, top priority
|
||||
return 7
|
||||
}
|
||||
|
||||
if len(cardUniq) == 2 {
|
||||
// Either four of a kind or full house
|
||||
for _, x := range cardUniq {
|
||||
if x == 4 || x == 1 {
|
||||
// Four of a kind
|
||||
return 6
|
||||
} else {
|
||||
// Must be full house
|
||||
return 5
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(cardUniq) == 3 {
|
||||
// Either three of a kind or two pair
|
||||
for _, x := range cardUniq {
|
||||
if x == 3 {
|
||||
// Three of a kind
|
||||
return 4
|
||||
} else if x == 2 {
|
||||
// Two pair
|
||||
return 3
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(cardUniq) == 4 {
|
||||
// Must be one pair
|
||||
return 2
|
||||
}
|
||||
|
||||
// Must be high card
|
||||
return 1
|
||||
}
|
||||
func getHandTypeRankingJokerRules(hand Hand) int {
|
||||
cardUniq := make(map[string]int)
|
||||
|
||||
jokerCount := 0
|
||||
for _, c := range strings.Split(hand.Cards, "") {
|
||||
if _, ok := cardUniq[c]; !ok {
|
||||
cardUniq[c] = 0
|
||||
}
|
||||
cardUniq[c] += 1
|
||||
|
||||
if c == "J" {
|
||||
jokerCount += 1
|
||||
}
|
||||
}
|
||||
|
||||
if len(cardUniq) == 1 {
|
||||
// Full house, top priority
|
||||
return 7
|
||||
}
|
||||
|
||||
if len(cardUniq) == 2 {
|
||||
// Either four of a kind or full house
|
||||
for _, x := range cardUniq {
|
||||
if x == 4 || x == 1 {
|
||||
// Four of a kind
|
||||
if jokerCount == 4 || jokerCount == 1 {
|
||||
// Can be converted to 5oac
|
||||
return 7
|
||||
}
|
||||
return 6
|
||||
} else {
|
||||
// Must be full house
|
||||
if jokerCount == 3 || jokerCount == 2 {
|
||||
// Can be converted to 5oac
|
||||
return 7
|
||||
}
|
||||
return 5
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(cardUniq) == 3 {
|
||||
// Either three of a kind or two pair
|
||||
for _, x := range cardUniq {
|
||||
if x == 3 {
|
||||
// Three of a kind
|
||||
if jokerCount == 1 || jokerCount == 3 {
|
||||
// Can be converted to 4oac
|
||||
return 6
|
||||
}
|
||||
return 4
|
||||
} else if x == 2 {
|
||||
// Two pair
|
||||
if jokerCount == 2 {
|
||||
// Can be converted to 4oac
|
||||
return 6
|
||||
} else if jokerCount == 1 {
|
||||
// Can be converted to full house
|
||||
return 5
|
||||
}
|
||||
return 3
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(cardUniq) == 4 {
|
||||
// Must be one pair
|
||||
if jokerCount == 2 || jokerCount == 1 {
|
||||
// Can be converted to 3oac
|
||||
return 4
|
||||
}
|
||||
return 2
|
||||
}
|
||||
|
||||
// Must be high card
|
||||
if jokerCount == 1 {
|
||||
// Converted to one pair
|
||||
return 2
|
||||
}
|
||||
return 1
|
||||
}
|
||||
|
||||
// on code change, run will be executed 4 times:
|
||||
// 1. with: false (part1), and example input
|
||||
// 2. with: true (part2), and example input
|
||||
// 3. with: false (part1), and user input
|
||||
// 4. with: true (part2), and user input
|
||||
// the return value of each run is printed to stdout
|
||||
func run(part2 bool, input string) any {
|
||||
hands := make([]Hand, 0)
|
||||
|
||||
for _, line := range strings.Split(input, "\n") {
|
||||
if line == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
lspl := strings.Split(line, " ")
|
||||
bid, _ := strconv.Atoi(lspl[1])
|
||||
|
||||
hands = append(hands, Hand{lspl[0], bid})
|
||||
}
|
||||
|
||||
if part2 {
|
||||
sort.SliceStable(hands, func(i, j int) bool {
|
||||
// First compare rank
|
||||
hRank1 := getHandTypeRankingJokerRules(hands[i])
|
||||
hRank2 := getHandTypeRankingJokerRules(hands[j])
|
||||
|
||||
if hRank1 != hRank2 {
|
||||
return hRank1 < hRank2
|
||||
}
|
||||
|
||||
// Otherwise, compare cards
|
||||
for k := 0; k < 5; k++ {
|
||||
cRank1 := getCardPowerJokerRules(rune(hands[i].Cards[k]))
|
||||
cRank2 := getCardPowerJokerRules(rune(hands[j].Cards[k]))
|
||||
|
||||
if cRank1 != cRank2 {
|
||||
return cRank1 < cRank2
|
||||
}
|
||||
}
|
||||
|
||||
panic(fmt.Sprintf("Could not sort %v and %v", hands[i].Cards, hands[j].Cards))
|
||||
})
|
||||
|
||||
} else {
|
||||
sort.SliceStable(hands, func(i, j int) bool {
|
||||
// First compare rank
|
||||
hRank1 := getHandTypeRanking(hands[i])
|
||||
hRank2 := getHandTypeRanking(hands[j])
|
||||
|
||||
if hRank1 != hRank2 {
|
||||
return hRank1 < hRank2
|
||||
}
|
||||
|
||||
// Otherwise, compare cards
|
||||
for k := 0; k < 5; k++ {
|
||||
cRank1 := getCardPower(rune(hands[i].Cards[k]))
|
||||
cRank2 := getCardPower(rune(hands[j].Cards[k]))
|
||||
|
||||
if cRank1 != cRank2 {
|
||||
return cRank1 < cRank2
|
||||
}
|
||||
}
|
||||
|
||||
panic(fmt.Sprintf("Could not sort %v and %v", hands[i].Cards, hands[j].Cards))
|
||||
})
|
||||
}
|
||||
// solve part 1 here
|
||||
|
||||
winnings := 0
|
||||
for i, hand := range hands {
|
||||
winnings += (i + 1) * hand.Bid
|
||||
}
|
||||
|
||||
return winnings
|
||||
}
|
||||
Reference in New Issue
Block a user