From f48bae3bc3147a3dad5f196d70786b6ea9da04b3 Mon Sep 17 00:00:00 2001 From: Davide Oddone Date: Fri, 8 Dec 2023 13:12:41 +0000 Subject: [PATCH] Working day07, huge mess --- day07/cards.go | 451 +++++++++++++++++++++++++++++-------------------- 1 file changed, 267 insertions(+), 184 deletions(-) diff --git a/day07/cards.go b/day07/cards.go index f01133c..4cd409c 100644 --- a/day07/cards.go +++ b/day07/cards.go @@ -1,44 +1,58 @@ package main import ( - "fmt" - "strings" - "bufio" - "math" -// "math/rand" - "os" - "strconv" -// "regexp" + "bufio" + "fmt" + "math" + "strings" + "os" + "strconv" "sync" ) -var mapSeeds = map[string]int{ - "A": 12, - "K": 11, - "Q": 10, - "J": 9, - "T": 8, - "9": 7, - "8": 6, - "7": 5, - "6": 4, - "5": 3, - "4": 2, - "3": 1, - "2": 0, +var mapSeedsFirst = map[string]int{ + "A": 12, + "K": 11, + "Q": 10, + "J": 9, + "T": 8, + "9": 7, + "8": 6, + "7": 5, + "6": 4, + "5": 3, + "4": 2, + "3": 1, + "2": 0, +} + +var mapSeedsSecond = map[string]int{ + "A": 12, + "K": 11, + "Q": 10, + "T": 9, + "9": 8, + "8": 7, + "7": 6, + "6": 5, + "5": 4, + "4": 3, + "3": 2, + "2": 1, + "J": 0, } type Game struct { - mu sync.Mutex - ranks []int + mu sync.Mutex + ranks []int // 0: High card, 1: One pair, 2: Two pair, 3: Three of a kind // 4: Full house, 5: Four of a kind, 6: Five of a kind - typeOfHand [7][]string - indexOfHand [7][]int - baseThirteen [7][]int + typeOfHand [7][]string + indexOfHand [7][]int + baseThirteen [7][]int } -func (g *Game) ChangeBase(hType, index int, wg *sync.WaitGroup) { +func (g *Game) ChangeBase(hType, index int, mapSeeds map[string]int, wg *sync.WaitGroup) { // Starting from the first char [0], we create the base13 num chars := len(g.typeOfHand[hType][index]) baseTN := g.typeOfHand[hType][index] @@ -46,159 +60,220 @@ func (g *Game) ChangeBase(hType, index int, wg *sync.WaitGroup) { for i := 0; i < chars; i++ { // This should be refactored to be a bit more legible // It just computes N * 13^i and adds it over - decNum += int(float64(mapSeeds[string(baseTN[i])]) * math.Pow(13, float64(chars - i))) } + decNum += int(float64(mapSeeds[string(baseTN[i])]) * math.Pow(13, float64(chars-i))) + } g.baseThirteen[hType][index] = decNum - wg.Done() + wg.Done() } -func (g *Game) DetermineType(cards string, index int, wg *sync.WaitGroup) int { - // We create a map and we check the length. Depending on the length, we - // insert the string in a specific type +func (g *Game) AnalyzeMap(cards string, index, mapSize, offset int) { + // The offset defaults to 0 for the regular game + // it is +1 for a game with Jokers\ + mapSeed := mapSeedsFirst + if offset != 0 { + mapSeed = mapSeedsSecond + } + switch mapSize { + // Five of a kind + case 1: + g.mu.Lock() + g.typeOfHand[6] = append(g.typeOfHand[6], cards) + g.indexOfHand[6] = append(g.indexOfHand[6], index) + g.mu.Unlock() + // Four of a kind || Full House + case 2: + i := FullOrFour(cards, offset, mapSeed) + g.mu.Lock() + g.typeOfHand[i] = append(g.typeOfHand[i], cards) + g.indexOfHand[i] = append(g.indexOfHand[i], index) + g.mu.Unlock() + // Three of a kind || Two pair + case 3: + i := ThreeOrTwo(cards, offset, mapSeed) + g.mu.Lock() + g.typeOfHand[i] = append(g.typeOfHand[i], cards) + g.indexOfHand[i] = append(g.indexOfHand[i], index) + g.mu.Unlock() + // One pair + case 4: + g.mu.Lock() + g.typeOfHand[1] = append(g.typeOfHand[1], cards) + g.indexOfHand[1] = append(g.indexOfHand[1], index) + g.mu.Unlock() + // High card + case 5: + g.mu.Lock() + g.typeOfHand[0] = append(g.typeOfHand[0], cards) + g.indexOfHand[0] = append(g.indexOfHand[0], index) + g.mu.Unlock() + } +} + +func (g *Game) DetermineType(cards string, index int, wg *sync.WaitGroup) { + // We create a map and we check the length. Depending on the length, we + // insert the string in a specific type m := make(map[string]int) - for i := 0; i < len(cards); i++ { - key := string(cards[i]) - m[key] = mapSeeds[key] - } - // Now, depending on the number of elements in the map, we can assign - // append cards to a specific rank - mapSize := len(m) + for i := 0; i < len(cards); i++ { + key := string(cards[i]) + m[key] = mapSeedsFirst[key] + } + // Now, depending on the number of elements in the map, we can assign + // append cards to a specific rank + mapSize := len(m) + g.AnalyzeMap(cards, index, mapSize, 0) - switch mapSize { - // Five of a kind - case 1: - g.mu.Lock() - g.typeOfHand[6] = append(g.typeOfHand[6], cards) - g.indexOfHand[6] = append(g.indexOfHand[6], index) - g.mu.Unlock() - // Four of a kind || Full House - case 2: - i := FullOrFour(cards) - g.mu.Lock() - g.typeOfHand[i] = append(g.typeOfHand[i], cards) - g.indexOfHand[i] = append(g.indexOfHand[i], index) - g.mu.Unlock() - // Three of a kind || Two pair - case 3: - i := ThreeOrTwo(cards) - g.mu.Lock() - g.typeOfHand[i] = append(g.typeOfHand[i], cards) - g.indexOfHand[i] = append(g.indexOfHand[i], index) - g.mu.Unlock() - // One pair - case 4: - g.mu.Lock() - g.typeOfHand[1] = append(g.typeOfHand[1], cards) - g.indexOfHand[1] = append(g.indexOfHand[1], index) - g.mu.Unlock() - // High card - case 5: - g.mu.Lock() - g.typeOfHand[0] = append(g.typeOfHand[0], cards) - g.indexOfHand[0] = append(g.indexOfHand[0], index) - g.mu.Unlock() - } - wg.Done() - - return 1 + wg.Done() } -func ThreeOrTwo(cards string) int { - m := make(map[string]int) - for i := 0; i < len(cards); i++ { - key := string(cards[i]) - m[key] += 1 - } - // m[i] returns 0 if the element is not in the map. I take advantage - // of that - for i := range mapSeeds { - // If an element has 3 values, we have a three of a kind - if m[i] == 3 { - return 3 - /// If an element has 2 values, we have a two pair - } else if m[i] == 2 { - return 2 - } - } - return -1 +func (g *Game) SecondGame(cards string, index int, wg *sync.WaitGroup) { + // If I don't have Js, run the standard DetermineType + m := make(map[string]int) + n := make(map[string]int) + for i := 0; i < len(cards); i++ { + key := string(cards[i]) + // We need to track the number of Js + m[key] += 1 + // This is to track the type of hand, knowing the number of Js + n[key] = mapSeedsSecond[key] + } + mapSize := len(n) + switch m["J"] { + case 0: + // We have a hand without Js + wg.Add(1) + g.DetermineType(cards, index, wg) + case 1: + // If there is a J, J can be use is not adding information, therefore -1 + g.AnalyzeMap(cards, index, (mapSize - 1), 1) + case 2: + g.AnalyzeMap(cards, index, (mapSize - 1), 2) + case 3: + g.AnalyzeMap(cards, index, (mapSize - 1), 3) + case 4: + g.AnalyzeMap(cards, index, (mapSize - 1), 4) + case 5: + wg.Add(1) + g.DetermineType(cards, index, wg) + } + wg.Done() } -func FullOrFour(cards string) int { - m := make(map[string]int) - for i := 0; i < len(cards); i++ { - key := string(cards[i]) - m[key] += 1 - } - // m[i] returns 0 if the element is not in the map. I take advantage - // of that - for i := range mapSeeds { - // If an element has four values, we have a Four of a kind - if m[i] == 4 { - return 5 - /// If an element has 3 values, we have a Full House - } else if m[i] == 3 { - return 4 - } - } - return -1 + +func ThreeOrTwo(cards string, offset int, mapSeed map[string]int) int { + m := make(map[string]int) + for i := 0; i < len(cards); i++ { + key := string(cards[i]) + m[key] += 1 + } + // If we are in the second game, remove J + if mapSeed["J"] == 0 { + m["J"] = 0 + } + // m[i] returns 0 if the element is not in the map. I take advantage + // of that + tempNum := 0 + for i := range mapSeed { + if m[i] > tempNum { + tempNum = m[i] + } + } + // If an element has 3 values, we have a three of a kind + if tempNum+offset == 3 { + return 3 + /// If an element has 2 values, we have a two pair + } else if tempNum+offset == 2 { + return 2 + } + PrintAndWait("This has run for ", cards) + return -1 +} +func FullOrFour(cards string, offset int, mapSeed map[string]int) int { + m := make(map[string]int) + for i := 0; i < len(cards); i++ { + key := string(cards[i]) + m[key] += 1 + } + // If we are in the second game, remove J + if mapSeed["J"] == 0 { + m["J"] = 0 + } + // m[i] returns 0 if the element is not in the map. I take advantage + // of that + // Better to save the maximum number + tempNum := 0 + for i := range mapSeed { + if m[i] > tempNum { + tempNum = m[i] + } + } + // If an element has four values, we have a Four of a kind + if tempNum+offset == 4 { + return 5 + /// If an element has 3 values, we have a Full House + } else if tempNum+offset == 3 { + return 4 + } + return -1 } func check(e error) { - if e != nil { - panic(e) - } + if e != nil { + panic(e) + } } func PrintAndWait(x ...any) { - fmt.Print(x...) - fmt.Scanln() + fmt.Print(x...) + fmt.Scanln() } // https://www.golangprograms.com/golang-program-for-implementation-of-quick-sort.html // I need to learn how this shing works func quicksort(a, h []int, hType int) []int { - if len(a) < 2 { - return a - } - - left, right := 0, len(a)-1 - - pivot := 0 - - a[pivot], a[right] = a[right], a[pivot] - h[pivot], h[right] = h[right], h[pivot] - - for i, _ := range a { - if a[i] < a[right] { - a[left], a[i] = a[i], a[left] - h[left], h[i] = h[i], h[left] - left++ - } - } - - a[left], a[right] = a[right], a[left] - h[left], h[right] = h[right], h[left] - - - quicksort(a[:left], h[:left], hType) - quicksort(a[left+1:], h[left+1:], hType) - - return a + if len(a) < 2 { + return a + } + + left, right := 0, len(a)-1 + + pivot := 0 + + a[pivot], a[right] = a[right], a[pivot] + h[pivot], h[right] = h[right], h[pivot] + + for i, _ := range a { + if a[i] < a[right] { + a[left], a[i] = a[i], a[left] + h[left], h[i] = h[i], h[left] + left++ + } + } + + a[left], a[right] = a[right], a[left] + h[left], h[right] = h[right], h[left] + + quicksort(a[:left], h[:left], hType) + quicksort(a[left+1:], h[left+1:], hType) + + return a } func main() { - file, err := os.Open("./inputs/day07_input") + file, err := os.Open("./inputs/day7_try") check(err) defer file.Close() - // Struct for multiple races + // Struct for regular game g := Game{} + // Struct for the Joker game + jo := Game{} // Variable where we store every line in the file lines := make([]string, 0) scanner := bufio.NewScanner(file) for scanner.Scan() { - lines = append(lines, scanner.Text()) + lines = append(lines, scanner.Text()) } // Array of strings, set of cards var cards []string @@ -206,13 +281,14 @@ func main() { var bet []int // Now, split the lines for i := 0; i < len(lines); i++ { - tempString := strings.Split(lines[i], " ") - cards = append(cards, tempString[0]) - tempNum, _ := strconv.Atoi(tempString[1]) - bet = append(bet, tempNum) + tempString := strings.Split(lines[i], " ") + cards = append(cards, tempString[0]) + tempNum, _ := strconv.Atoi(tempString[1]) + bet = append(bet, tempNum) } // Rank will be from 1 to len(lines) g.ranks = make([]int, len(lines)) + jo.ranks = make([]int, len(lines)) // What do we know for sure? 5 identical seeds are the highest ranks, // 5 completely different seeds are the lowest ranks. // We can iterate for every set of cards, and do different things @@ -225,9 +301,10 @@ func main() { // // With this, I put every typeOfHand in a different array var wg sync.WaitGroup - wg.Add(len(lines)) + wg.Add(2 * len(lines)) for i := 0; i < len(lines); i++ { - go g.DetermineType(cards[i], i, &wg) + g.DetermineType(cards[i], i, &wg) + jo.SecondGame(cards[i], i, &wg) } wg.Wait() @@ -238,46 +315,52 @@ func main() { // For every type of hand for i := range g.typeOfHand { - // As many wait groups as the element we will iterate - wg.Add(len(g.typeOfHand[i])) - // We also need to initialize the array g.baseThirteen so we can - // keep the same index - g.baseThirteen[i] = make([]int, len(g.typeOfHand[i])) - // For every element in a single type of hand - for j := range g.typeOfHand[i] { - go g.ChangeBase(i, j, &wg) - } + // As many wait groups as the element we will iterate + wg.Add(len(g.typeOfHand[i])) + wg.Add(len(jo.typeOfHand[i])) + // We also need to initialize the array g.baseThirteen so we can + // keep the same index + g.baseThirteen[i] = make([]int, len(g.typeOfHand[i])) + jo.baseThirteen[i] = make([]int, len(jo.typeOfHand[i])) + // For every element in a single type of hand + for j := range g.typeOfHand[i] { + g.ChangeBase(i, j, mapSeedsFirst, &wg) + } + for j := range jo.typeOfHand[i] { + jo.ChangeBase(i, j, mapSeedsSecond, &wg) + } } wg.Wait() - - // PrintAndWait(g.typeOfHand[0]) - // PrintAndWait(g.typeOfHand[1]) - // PrintAndWait(g.typeOfHand[2]) - // PrintAndWait(g.typeOfHand[3]) - // PrintAndWait(g.typeOfHand[4]) - // PrintAndWait(g.typeOfHand[5]) - // PrintAndWait(g.typeOfHand[6]) // A sort of some kind. Important is to also move the index with the number as // well. - // for i := range g.baseThirteen { - quicksort(g.baseThirteen[i], g.indexOfHand[i], i) + quicksort(g.baseThirteen[i], g.indexOfHand[i], i) + quicksort(jo.baseThirteen[i], jo.indexOfHand[i], i) } - + curRank := 1 rank := 0 // Iter every array for i := range g.typeOfHand { - for j := range g.typeOfHand[i] { - //fmt.Printf("For the array %d, element %d, ", i, j) - index := g.indexOfHand[i][j] - //fmt.Printf("I gather index %d ", index) - rank += curRank * bet[index] - //fmt.Printf("and finally I multiply %d and %d.\n", curRank, bet[index]) - //fmt.Scanln() - curRank++ - } + for j := range g.typeOfHand[i] { + index := g.indexOfHand[i][j] + rank += curRank * bet[index] + curRank++ + } } - fmt.Print(rank) + fmt.Printf("Rank: %d\n", rank) + + curRank = 1 + rank = 0 + // Iter every array + for i := range jo.typeOfHand { + for j := range jo.typeOfHand[i] { + index := jo.indexOfHand[i][j] + rank += curRank * bet[index] + curRank++ + } + } + fmt.Printf("Rank: %d\n", rank) + }