go.charczuk.com@v0.0.0-20240327042549-bc490516bd1a/experiments/matchmaker/pkg/sim/player.go (about)

     1  /*
     2  
     3  Copyright (c) 2024 - Present. Will Charczuk. All rights reserved.
     4  Use of this source code is governed by a MIT license that can be found in the LICENSE file at the root of the repository.
     5  
     6  */
     7  
     8  package sim
     9  
    10  import (
    11  	"slices"
    12  	"time"
    13  
    14  	c9s "go.charczuk.com/sdk/collections"
    15  	"go.charczuk.com/sdk/mathutil"
    16  	"go.charczuk.com/sdk/uuid"
    17  )
    18  
    19  type Player struct {
    20  	ID         uuid.UUID
    21  	IdleAt     time.Time
    22  	QueuedAt   time.Time
    23  	TimedOutAt time.Time
    24  
    25  	Rating       int
    26  	NaturalSkill int
    27  
    28  	Games int
    29  	Wins  int
    30  
    31  	QueuedElapsed []time.Duration
    32  	Recent        *c9s.Queue[*Game]
    33  }
    34  
    35  func (p Player) Key() uuid.UUID { return p.ID }
    36  
    37  func (p Player) IsIdle(ts time.Time) bool {
    38  	return p.IdleAt.Before(ts)
    39  }
    40  
    41  func (p Player) IsTimedOut(ts time.Time) bool {
    42  	return p.TimedOutAt.Before(ts)
    43  }
    44  
    45  func (p Player) QueuedElapsedStats() (min, mean, max, p50, p75, p95 time.Duration) {
    46  	if len(p.QueuedElapsed) == 0 {
    47  		return
    48  	}
    49  	min, max = mathutil.MinMax(p.QueuedElapsed)
    50  	mean = mathutil.MeanDuration(p.QueuedElapsed)
    51  	slices.Sort(p.QueuedElapsed)
    52  	p50 = mathutil.PercentileSorted(p.QueuedElapsed, 50.0)
    53  	p75 = mathutil.PercentileSorted(p.QueuedElapsed, 75.0)
    54  	p95 = mathutil.PercentileSorted(p.QueuedElapsed, 95.0)
    55  	return
    56  }
    57  
    58  func (p Player) Winrate() float64 {
    59  	if p.Games == 0 {
    60  		return 0
    61  	}
    62  	return float64(p.Wins) / float64(p.Games)
    63  }
    64  
    65  func (p Player) WinrateRecent() float64 {
    66  	var wins, total int
    67  	p.Recent.ReverseEach(func(g *Game) {
    68  		playerTeam := g.PlayerTeam(p.ID)
    69  		total++
    70  		if playerTeam == g.Outcome {
    71  			wins++
    72  		}
    73  	})
    74  	return float64(wins) / float64(total)
    75  }