昨天已经看过我们在实务上可能会遇到的需求,利用多个可能重复范围的配对池,当作匹配搜寻条件,今天让我们用实作范例来观察其效果。
本范例同样基於官方 demo,藉由更改范例内容重新 build images 後完成。
~ kubectl create namespace open-match-demo
~ kubectl apply -n open-match-demo -f ~/open-match/overlapping.yml
随机产生不同等级条件 tickets,这段跟之前相同不赘述,请参考 client.go#95
这是产生 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,
},
},
},
},
},
}
特此告知 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
}
YAML(/ˈjæməl/,尾音类似camel骆驼)是一个可读性高,用来表达资料序列化的格式。YA...
-FCoE 融合网络适配器(来源:维基百科) 乙太网路光纤通道标准 (FCoE) 乙太网路光纤通道...
今天我们来还债 XDD,还之前跳过的很多解释,还有如何更加灵活的调整神经网路 那就让我们一步一步来...
useMemo 用於性能优化,避免重复执行高效能的渲染 如果传入的参数未改变,就直接沿用上次的计算结...
到今天为止介绍了不少应用於k8s上的服务,并且大部分都可以透过operator的方式进行同性质的服务...