Day10 Overlapping Example

昨天已经看过我们在实务上可能会遇到的需求,利用多个可能重复范围的配对池,当作匹配搜寻条件,今天让我们用实作范例来观察其效果。

角色等级 Overlapping 范例

本范例同样基於官方 demo,藉由更改范例内容重新 build images 後完成。

Images

  • weiweiwesley/open-match:overlapping
  • weiweiwesley/mmf:overlapping

Yaml

Install

~ kubectl create namespace open-match-demo

~ kubectl apply -n open-match-demo -f ~/open-match/overlapping.yml

Result

https://i.imgur.com/fe4toQh.gif

Client

随机产生不同等级条件 tickets,这段跟之前相同不赘述,请参考 client.go#95

Director

这是产生 overlapping MatchProfile 的部分,不同的 MatchProfile,以不同的等级上下限表示不同的配对池。以下这些 MatchProfile 会被 Director 向核心询问,并且呼叫 MMF 执行配对判断,你可以把它想成像是不同的阶级如:

  • 新手场

    req := &pb.FetchMatchesRequest{
    			Config: &pb.FunctionConfig{
    				Host: "om-function.open-match-demo.svc.cluster.local",
    				Port: 50502,
    				Type: pb.FunctionConfig_GRPC,
    			},
    			Profile: &pb.MatchProfile{
    				Name: "MatchProfile1",
    				Pools: []*pb.Pool{
    					{
    						Name: "low level",
    						DoubleRangeFilters: []*pb.DoubleRangeFilter{
    							{
    								DoubleArg: "level",
    								Max:       10,
    								Min:       0,
    							},
    						},
    					},
    				},
    			},
    		}
    
  • 中级场

    req := &pb.FetchMatchesRequest{
    			Config: &pb.FunctionConfig{
    				Host: "om-function.open-match-demo.svc.cluster.local",
    				Port: 50502,
    				Type: pb.FunctionConfig_GRPC,
    			},
    			Profile: &pb.MatchProfile{
    				Name: "MatchProfile2",
    				Pools: []*pb.Pool{
    					{
    						Name: "mid level",
    						DoubleRangeFilters: []*pb.DoubleRangeFilter{
    							{
    								DoubleArg: "level",
    								Max:       28,
    								Min:       10,
    							},
    						},
    					},
    				},
    			},
    		}
    
  • 高手场

    req := &pb.FetchMatchesRequest{
    			Config: &pb.FunctionConfig{
    				Host: "om-function.open-match-demo.svc.cluster.local",
    				Port: 50502,
    				Type: pb.FunctionConfig_GRPC,
    			},
    			Profile: &pb.MatchProfile{
    				Name: "MatchProfile3",
    				Pools: []*pb.Pool{
    					{
    						Name: "high level",
    						DoubleRangeFilters: []*pb.DoubleRangeFilter{
    							{
    								DoubleArg: "level",
    								Max:       30,
    								Min:       25,
    							},
    						},
    					},
    				},
    			},
    		}
    

MMF

特此告知 makeMatches() 是直接使用 Skill Based Match Function,我只修改 SearchFields “level” 的部分。说明一下程序内容,与官方 demo 不同的地方在於,建立了 computeQuality() 计算出每场配对的等差,并将这项资讯回填於 Match.Extensions["evaluation_input"],这个资讯会被我们建立的 default Evaluator 所采用,pb.DefaultEvaluationCriteria 内记载的 Score,将用来比较最适合的配对组合。

From: https://gist.github.com/syntxerror/c634dccb96c686b50fee67f801d6e671

func makeMatches(p *pb.MatchProfile, poolTickets map[string][]*pb.Ticket) ([]*pb.Match, error) {
	// Create a colletion to hold match proposals
	var matches []*pb.Match
	count := 0
	for {
		insufficientTickets := false
		// Create a collection to hold tickets selected for a match
		matchTickets := []*pb.Ticket{}
		for pool, tickets := range poolTickets {
			// Set flag if there are not enough tickets to create a match
			if len(tickets) < ticketsPerPoolPerMatch {
				insufficientTickets = true
				break
			}
			// Sort the tickets based on skill
			sort.Slice(tickets, func(i, j int) bool {
				return tickets[i].SearchFields.DoubleArgs["mmr"] < tickets[j].SearchFields.DoubleArgs["mmr"]
			})

			// Remove the Tickets from this pool and add to the match proposal.
			matchTickets = append(matchTickets, tickets[0:ticketsPerPoolPerMatch]...)
			poolTickets[pool] = tickets[ticketsPerPoolPerMatch:]
		}

		if insufficientTickets {
			break
		}
		// Compute the match quality/score
		matchQuality := computeQuality(matchTickets)
		evaluationInput, err := ptypes.MarshalAny(&pb.DefaultEvaluationCriteria{
			Score: matchQuality,
		})

		if err != nil {
			log.Printf("Failed to marshal DefaultEvaluationCriteria, got %s.", err.Error())
			return nil, fmt.Errorf("Failed to marshal DefaultEvaluationCriteria, got %w", err)
		}
		// Output the match quality for our sanity
		log.Printf("Quality for the generated match is %v", matchQuality)
		// Create a match proposal
		matches = append(matches, &pb.Match{
			MatchId:       fmt.Sprintf("profile-%v-time-%v-%v", p.GetName(), time.Now().Format("2006-01-02T15:04:05.00"), count),
			MatchProfile:  p.GetName(),
			MatchFunction: matchName,
			Tickets:       matchTickets,
			Extensions: map[string]*any.Any{
				"evaluation_input": evaluationInput,
			},
		})

		count++
	}

	return matches, nil
}

// Compute the quality as a difference in the highest and lowest player skill levels. This can be used to determine if the match is outside a given skill differential
func computeQuality(tickets []*pb.Ticket) float64 {
	quality := 0.0
	high := 0.0
	low := tickets[0].SearchFields.DoubleArgs["mmr"]
	for _, ticket := range tickets {
		if high < ticket.SearchFields.DoubleArgs["mmr"] {
			high = ticket.SearchFields.DoubleArgs["mmr"]
		}
		if low > ticket.SearchFields.DoubleArgs["mmr"] {
			low = ticket.SearchFields.DoubleArgs["mmr"]
		}
	}
	quality = high - low

	return quality
}

Reference


<<:  Day 03:观察资料夹

>>:  亏损也是获利的一环

[DAY8]k8s必学的设定档-yaml (上)

YAML(/ˈjæməl/,尾音类似camel骆驼)是一个可读性高,用来表达资料序列化的格式。YA...

乙太网路光纤通道标准(FCoE)

-FCoE 融合网络适配器(来源:维基百科) 乙太网路光纤通道标准 (FCoE) 乙太网路光纤通道...

Day-22 更加灵活的神经网路,我们可以做哪些变化

今天我们来还债 XDD,还之前跳过的很多解释,还有如何更加灵活的调整神经网路 那就让我们一步一步来...

【Day 27】Hook 07:useMemo

useMemo 用於性能优化,避免重复执行高效能的渲染 如果传入的参数未改变,就直接沿用上次的计算结...

day24 : kong api gateway(上)

到今天为止介绍了不少应用於k8s上的服务,并且大部分都可以透过operator的方式进行同性质的服务...