From 8b929212303e020db4476842566449f7a3b605fc Mon Sep 17 00:00:00 2001 From: kercylan98 Date: Mon, 31 Jul 2023 10:01:10 +0800 Subject: [PATCH] =?UTF-8?q?revert:=20=E7=A7=BB=E9=99=A4=20poker=20?= =?UTF-8?q?=E5=8C=85=E7=9A=84=20matcher=EF=BC=8C=E6=94=B9=E4=B8=BA?= =?UTF-8?q?=E4=BD=BF=E7=94=A8=20combination=20=E5=8C=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- game/poker/matcher.go | 52 ------- game/poker/matcher_filter.go | 42 ------ game/poker/matcher_options.go | 271 ---------------------------------- game/poker/matcher_test.go | 117 --------------- 4 files changed, 482 deletions(-) delete mode 100644 game/poker/matcher.go delete mode 100644 game/poker/matcher_filter.go delete mode 100644 game/poker/matcher_options.go delete mode 100644 game/poker/matcher_test.go diff --git a/game/poker/matcher.go b/game/poker/matcher.go deleted file mode 100644 index e76d2c6..0000000 --- a/game/poker/matcher.go +++ /dev/null @@ -1,52 +0,0 @@ -package poker - -import ( - "github.com/kercylan98/minotaur/utils/generic" - "github.com/kercylan98/minotaur/utils/hash" -) - -// NewMatcher 创建一个新的匹配器 -// - evaluate: 用于评估一组扑克牌的分值,分值最高的组合将被选中 -func NewMatcher[P, C generic.Number, T Card[P, C]]() *Matcher[P, C, T] { - matcher := &Matcher[P, C, T]{ - filter: map[string]*MatcherFilter[P, C, T]{}, - } - return matcher -} - -// Matcher 匹配器 -// - 用于匹配扑克牌型,筛选分组等 -type Matcher[P, C generic.Number, T Card[P, C]] struct { - filter map[string]*MatcherFilter[P, C, T] - sort []string -} - -// RegType 注册一个新的牌型 -// - name: 牌型名称 -// - evaluate: 用于评估一组扑克牌的分值,分值最高的组合将被选中 -// - options: 牌型选项 -func (slf *Matcher[P, C, T]) RegType(name string, evaluate func([]T) int64, options ...MatcherOption[P, C, T]) *Matcher[P, C, T] { - if hash.Exist(slf.filter, name) { - panic("exist of the same type") - } - filter := &MatcherFilter[P, C, T]{ - evaluate: evaluate, - } - for _, option := range options { - option(filter) - } - slf.filter[name] = filter - slf.sort = append(slf.sort, name) - return slf -} - -// Group 将一组扑克牌按照匹配器的规则分组,并返回最佳组合及其牌型名称 -func (slf *Matcher[P, C, T]) Group(cards []T) (name string, result []T) { - for _, n := range slf.sort { - result = slf.filter[n].group(cards) - if len(result) > 0 { - return n, result - } - } - return -} diff --git a/game/poker/matcher_filter.go b/game/poker/matcher_filter.go deleted file mode 100644 index 2047a89..0000000 --- a/game/poker/matcher_filter.go +++ /dev/null @@ -1,42 +0,0 @@ -package poker - -import "github.com/kercylan98/minotaur/utils/generic" - -type MatcherFilter[P, C generic.Number, T Card[P, C]] struct { - evaluate func([]T) int64 - handles []func(cards []T) [][]T - asc bool -} - -func (slf *MatcherFilter[P, C, T]) AddHandle(handle func(cards []T) [][]T) { - slf.handles = append(slf.handles, handle) -} - -func (slf *MatcherFilter[P, C, T]) group(cards []T) []T { - var bestCombination = cards - - for _, handle := range slf.handles { - var bestScore int64 - filteredCombinations := handle(bestCombination) - if len(filteredCombinations) == 0 { - return []T{} - } - for _, combination := range filteredCombinations { - score := slf.evaluate(combination) - if slf.asc { - if score < bestScore || bestCombination == nil { - bestCombination = combination - bestScore = score - } - } else { - if score > bestScore || bestCombination == nil { - bestCombination = combination - bestScore = score - } - } - - } - } - - return bestCombination -} diff --git a/game/poker/matcher_options.go b/game/poker/matcher_options.go deleted file mode 100644 index 0045329..0000000 --- a/game/poker/matcher_options.go +++ /dev/null @@ -1,271 +0,0 @@ -package poker - -import ( - "fmt" - "github.com/kercylan98/minotaur/utils/generic" - "github.com/kercylan98/minotaur/utils/slice" - "reflect" - "sort" -) - -// MatcherOption 匹配器选项 -type MatcherOption[P, C generic.Number, T Card[P, C]] func(matcher *MatcherFilter[P, C, T]) - -// WithMatcherScoreAsc 通过升序评估分数创建匹配器 -// - 用于评估一组扑克牌的分值,分值最低的组合将被选中 -// - 默认为分数最高的组合将被选中 -func WithMatcherScoreAsc[P, C generic.Number, T Card[P, C]]() MatcherOption[P, C, T] { - return func(matcher *MatcherFilter[P, C, T]) { - matcher.asc = true - } -} - -// WithMatcherLeastLength 通过匹配最小长度的扑克牌创建匹配器 -// - length: 牌型的长度,表示需要匹配的扑克牌最小数量 -func WithMatcherLeastLength[P, C generic.Number, T Card[P, C]](length int) MatcherOption[P, C, T] { - return func(matcher *MatcherFilter[P, C, T]) { - matcher.AddHandle(func(cards []T) [][]T { - var combinations [][]T - combinations = slice.LimitedCombinations(cards, length, len(cards)) - return combinations - }) - } -} - -// WithMatcherLength 通过匹配长度的扑克牌创建匹配器 -// - length: 牌型的长度,表示需要匹配的扑克牌数量 -func WithMatcherLength[P, C generic.Number, T Card[P, C]](length int) MatcherOption[P, C, T] { - return func(matcher *MatcherFilter[P, C, T]) { - matcher.AddHandle(func(cards []T) [][]T { - var combinations [][]T - combinations = slice.LimitedCombinations(cards, length, length) - return combinations - }) - } -} - -// WithMatcherContinuity 通过匹配连续的扑克牌创建匹配器 -func WithMatcherContinuity[P, C generic.Number, T Card[P, C]]() MatcherOption[P, C, T] { - return func(matcher *MatcherFilter[P, C, T]) { - matcher.AddHandle(func(cards []T) [][]T { - var combinations [][]T - n := len(cards) - - if n <= 0 { - return combinations - } - - // 对扑克牌按点数进行排序 - sort.Slice(cards, func(i, j int) bool { - return cards[i].GetPoint() < cards[j].GetPoint() - }) - - // 查找连续的牌型组合 - for i := 0; i < n; i++ { - combination := []T{cards[i]} - for j := i + 1; j < n; j++ { - if cards[j].GetPoint()-combination[len(combination)-1].GetPoint() == 1 { - combination = append(combination, cards[j]) - } else { - break - } - } - if len(combination) >= 2 { - combinations = append(combinations, combination) - } - } - - return combinations - }) - } -} - -// WithMatcherContinuityPointOrder 通过匹配连续的扑克牌创建匹配器,与 WithMatcherContinuity 不同的是,该选项将按照自定义的点数顺序进行匹配 -func WithMatcherContinuityPointOrder[P, C generic.Number, T Card[P, C]](order map[P]int) MatcherOption[P, C, T] { - return func(matcher *MatcherFilter[P, C, T]) { - var getOrder = func(card T) P { - if v, ok := order[card.GetPoint()]; ok { - return P(v) - } - return card.GetPoint() - } - matcher.AddHandle(func(cards []T) [][]T { - var combinations [][]T - n := len(cards) - - if n <= 0 { - return combinations - } - - // 对扑克牌按点数进行排序 - sort.Slice(cards, func(i, j int) bool { - return getOrder(cards[i]) < getOrder(cards[j]) - }) - - // 查找连续的牌型组合 - for i := 0; i < n; i++ { - combination := []T{cards[i]} - for j := i + 1; j < n; j++ { - if getOrder(cards[j])-getOrder(combination[len(combination)-1]) == 1 { - combination = append(combination, cards[j]) - } else { - break - } - } - if len(combination) >= 2 { - combinations = append(combinations, combination) - } - } - - return combinations - }) - } -} - -// WithMatcherFlush 通过匹配同花的扑克牌创建匹配器 -func WithMatcherFlush[P, C generic.Number, T Card[P, C]]() MatcherOption[P, C, T] { - return func(matcher *MatcherFilter[P, C, T]) { - matcher.AddHandle(func(cards []T) [][]T { - var combinations [][]T - - groups := GroupByColor[P, C, T](cards...) - for _, group := range groups { - combinations = append(combinations, slice.Combinations(group)...) - } - - return combinations - }) - } -} - -// WithMatcherTie 通过匹配相同点数的扑克牌创建匹配器 -func WithMatcherTie[P, C generic.Number, T Card[P, C]]() MatcherOption[P, C, T] { - return func(matcher *MatcherFilter[P, C, T]) { - matcher.AddHandle(func(cards []T) [][]T { - var combinations [][]T - groups := GroupByPoint[P, C, T](cards...) - for _, group := range groups { - for _, ts := range slice.Combinations(group) { - combinations = append(combinations, ts) - } - } - return combinations - }) - } -} - -// WithMatcherTieCount 通过匹配相同点数的特定数量的扑克牌创建匹配器 -// - count: 牌型中相同点数的牌的数量 -func WithMatcherTieCount[P, C generic.Number, T Card[P, C]](count int) MatcherOption[P, C, T] { - return func(matcher *MatcherFilter[P, C, T]) { - matcher.AddHandle(func(cards []T) [][]T { - var combinations [][]T - groups := GroupByPoint[P, C, T](cards...) - for _, group := range groups { - if len(group) < count { - continue - } - for _, ts := range slice.Combinations(group) { - if len(ts) == count { - combinations = append(combinations, ts) - } - } - } - return combinations - }) - } -} - -// WithMatcherTieCountNum 通过匹配相同点数的特定数量的扑克牌创建匹配器 -// - count: 牌型中相同点数的牌的数量 -// - num: 牌型中相同点数的牌的数量 -func WithMatcherTieCountNum[P, C generic.Number, T Card[P, C]](count, num int) MatcherOption[P, C, T] { - return func(matcher *MatcherFilter[P, C, T]) { - matcher.AddHandle(func(cards []T) [][]T { - var combinations [][]T - cs := slice.LimitedCombinations(cards, count*num, count*num) - var pointCount = make(map[P]int) - for _, group := range cs { - var ok = false - for _, t := range group { - pointCount[t.GetPoint()]++ - if len(pointCount) == 2 { - var matchCount = true - for _, n := range pointCount { - if n != num { - matchCount = false - break - } - } - if matchCount { - ok = true - break - } - } - } - if ok { - combinations = append(combinations, group) - } - for point := range pointCount { - delete(pointCount, point) - } - } - return combinations - }) - } -} - -// WithMatcherNCarryM 通过匹配N带相同点数M的扑克牌创建匹配器 -// - n: 需要匹配的主牌数量 -// - m: 需要匹配的附加牌数量 -func WithMatcherNCarryM[P, C generic.Number, T Card[P, C]](n, m int) MatcherOption[P, C, T] { - return func(matcher *MatcherFilter[P, C, T]) { - matcher.AddHandle(func(cards []T) [][]T { - var combinations [][]T - groups := GroupByPoint[P, C, T](cards...) - for _, group := range groups { - if len(group) != n { - continue - } - ms := slice.Combinations(slice.SubWithCheck(cards, group, func(a, b T) bool { return reflect.DeepEqual(a, b) })) - for i := 0; i < len(ms); i++ { - ts := GroupByPoint[P, C, T](ms[i]...) - for _, cs := range ts { - if len(cs) == m { - combinations = append(combinations, slice.Merge(group, cs)) - } - } - } - } - return combinations - }) - } -} - -// WithMatcherNCarryMSingle 通过匹配N带M的扑克牌创建匹配器 -// - n: 需要匹配的主牌数量 -// - m: 需要匹配的附加牌数量 -func WithMatcherNCarryMSingle[P, C generic.Number, T Card[P, C]](n, m int) MatcherOption[P, C, T] { - return func(matcher *MatcherFilter[P, C, T]) { - matcher.AddHandle(func(cards []T) [][]T { - var combinations [][]T - groups := GroupByPoint[P, C, T](cards...) - for _, group := range groups { - if len(group) != n { - continue - } - ms := slice.Combinations(slice.SubWithCheck(cards, group, func(a, b T) bool { return reflect.DeepEqual(a, b) })) - for i := 0; i < len(ms); i++ { - ts := ms[i] - if len(ts) == m { - combinations = append(combinations, slice.Merge(group, ts)) - } - } - } - if len(combinations) > 0 { - fmt.Println(len(combinations)) - } - return combinations - }) - } -} diff --git a/game/poker/matcher_test.go b/game/poker/matcher_test.go deleted file mode 100644 index 346fd88..0000000 --- a/game/poker/matcher_test.go +++ /dev/null @@ -1,117 +0,0 @@ -package poker_test - -import ( - "fmt" - "github.com/kercylan98/minotaur/game/poker" - "github.com/kercylan98/minotaur/utils/generic" - "github.com/kercylan98/minotaur/utils/slice" - "testing" - "time" -) - -type Card[P, C generic.Number] struct { - guid int64 - point P - color C -} - -func (slf *Card[P, C]) GetGuid() int64 { - return slf.guid -} - -func (slf *Card[P, C]) GetPoint() P { - return slf.point -} - -func (slf *Card[P, C]) GetColor() C { - return slf.color -} - -func TestMatcher_Group(t *testing.T) { - - evaluate := func(cards []*Card[int, int]) int64 { - score := int64(0) - for _, card := range cards { - if card.point == 1 { - score += 14 - continue - } - score += int64(card.GetPoint()) - } - return score - } - - matcher := poker.NewMatcher[int, int, *Card[int, int]]() - //matcher.RegType("三条", evaluate, - // poker.WithMatcherNCarryMSingle[*Card](3, 2)) - matcher.RegType("皇家同花顺", evaluate, - poker.WithMatcherFlush[int, int, *Card[int, int]](), - poker.WithMatcherContinuityPointOrder[int, int, *Card[int, int]](map[int]int{1: 14}), - poker.WithMatcherLength[int, int, *Card[int, int]](5), - ).RegType("同花顺", evaluate, - poker.WithMatcherFlush[int, int, *Card[int, int]](), - poker.WithMatcherContinuityPointOrder[int, int, *Card[int, int]](map[int]int{1: 14}), - poker.WithMatcherLeastLength[int, int, *Card[int, int]](3), - ).RegType("四条", evaluate, - poker.WithMatcherTieCount[int, int, *Card[int, int]](4), - ).RegType("葫芦", evaluate, - poker.WithMatcherNCarryM[int, int, *Card[int, int]](3, 2), - ).RegType("顺子", evaluate, - poker.WithMatcherContinuityPointOrder[int, int, *Card[int, int]](map[int]int{1: 14}), - poker.WithMatcherLength[int, int, *Card[int, int]](5), - ).RegType("三条", evaluate, - poker.WithMatcherNCarryMSingle[int, int, *Card[int, int]](3, 2), - ).RegType("两对", evaluate, - poker.WithMatcherTieCountNum[int, int, *Card[int, int]](2, 2), - ).RegType("一对", evaluate, - poker.WithMatcherTieCount[int, int, *Card[int, int]](2), - ).RegType("高牌", evaluate, - poker.WithMatcherTieCount[int, int, *Card[int, int]](1), - ) - - var pub = []*Card[int, int]{ - {point: 4, color: 3}, - {point: 5, color: 2}, - {point: 6, color: 1}, - {point: 6, color: 2}, - {point: 13, color: 2}, - } - - var pri = []*Card[int, int]{ - {point: 1, color: 1}, - {point: 1, color: 2}, - {point: 4, color: 3}, - {point: 5, color: 4}, - } - - var start = time.Now() - var usePub, usePri = slice.LimitedCombinations(pub, 3, 3), slice.LimitedCombinations(pri, 2, 2) - - var topResult []*Card[int, int] - var topScore int64 - var topName string - var source []*Card[int, int] - for _, handCards := range usePri { - for _, pubCards := range usePub { - cards := append(handCards, pubCards...) - name, result := matcher.Group(cards) - score := evaluate(result) - if score > topScore || topResult == nil { - topScore = score - topResult = result - topName = name - source = cards - } - } - } - - fmt.Println("time:", time.Since(start)) - fmt.Println("result:", topName) - for _, card := range topResult { - fmt.Println(fmt.Sprintf("Point: %d Color: %d", card.GetPoint(), card.GetColor())) - } - fmt.Println("source:", topScore) - for _, card := range source { - fmt.Println(fmt.Sprintf("Point: %d Color: %d", card.GetPoint(), card.GetColor())) - } -}