You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							327 lines
						
					
					
						
							6.2 KiB
						
					
					
				
			
		
		
		
			
			
			
				
					
				
				
					
				
			
		
		
	
	
							327 lines
						
					
					
						
							6.2 KiB
						
					
					
				
								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)
							 | 
						|
								}
							 | 
						|
								
							 |