mirror of
https://github.com/tiennm99/noitu.git
synced 2026-10-20 02:18:08 +00:00
refactor(server): share env parsing, shutdown and score capping helpers
Collapse the three env parsers into one generic helper, the duplicated graceful-shutdown block into shutdownServer, and the score cap into pointsFor. Behaviour is unchanged.
This commit is contained in:
1 parent
97a352f9f5
commit
5848751c6b
6 files changed
+56
-100
No files matched your search
@@ -298,44 +298,30 @@ func (e *Engine) pointsFor(syllables int, link string, now time.Time) (int, []Po
|
||||
{Kind: PointKindSpeed, Value: e.speedPoints(now)},
|
||||
{Kind: PointKindRarity, Value: e.rarityPoints(link)},
|
||||
}
|
||||
parts = capParts(parts)
|
||||
|
||||
total := 0
|
||||
for _, p := range parts {
|
||||
total += p.Value
|
||||
// Anything over maxPointsPerWord is trimmed from the end: rarity first,
|
||||
// then speed, then syllables. Base and the chain term never need touching
|
||||
// to make room — the chain term is itself capped at chainBonusWords words
|
||||
// (10 base + 2*15 chain = 40 at most), well under the cap — so the loop
|
||||
// always finds enough in the later terms and stops before reaching them.
|
||||
for i, overflow := len(parts)-1, sumParts(parts)-maxPointsPerWord; i >= 0 && overflow > 0; i-- {
|
||||
cut := min(parts[i].Value, overflow)
|
||||
parts[i].Value -= cut
|
||||
overflow -= cut
|
||||
}
|
||||
return total, parts
|
||||
|
||||
// A PointPart exists only for a term that actually contributed.
|
||||
parts = slices.DeleteFunc(parts, func(p PointPart) bool { return p.Value <= 0 })
|
||||
return sumParts(parts), parts
|
||||
}
|
||||
|
||||
// capParts trims a word's score down to maxPointsPerWord when the terms
|
||||
// pointsFor computed add up to more, and drops whatever term that leaves at
|
||||
// zero — a PointPart exists only for a term that actually contributed.
|
||||
//
|
||||
// Trimmed from the end: rarity first, then speed, then syllables, then chain.
|
||||
// Base and the chain term never need touching to make room — the chain term
|
||||
// is itself capped at chainBonusWords words (10 base + 2*15 chain = 40 at
|
||||
// most), well under the cap — so the loop always finds enough in the later
|
||||
// terms and stops before reaching them.
|
||||
func capParts(parts []PointPart) []PointPart {
|
||||
// sumParts is the total a word's score breakdown adds up to.
|
||||
func sumParts(parts []PointPart) int {
|
||||
total := 0
|
||||
for _, p := range parts {
|
||||
total += p.Value
|
||||
}
|
||||
if overflow := total - maxPointsPerWord; overflow > 0 {
|
||||
for i := len(parts) - 1; i >= 0 && overflow > 0; i-- {
|
||||
cut := min(parts[i].Value, overflow)
|
||||
parts[i].Value -= cut
|
||||
overflow -= cut
|
||||
}
|
||||
}
|
||||
|
||||
kept := parts[:0]
|
||||
for _, p := range parts {
|
||||
if p.Value > 0 {
|
||||
kept = append(kept, p)
|
||||
}
|
||||
}
|
||||
return kept
|
||||
return total
|
||||
}
|
||||
|
||||
// speedPoints pays for the share of the turn the player left on the clock.
|
||||
|
||||
@@ -477,14 +477,6 @@ func TestSubmitScoringPartsAreTrimmedAtTheCap(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func sumParts(parts []PointPart) int {
|
||||
sum := 0
|
||||
for _, p := range parts {
|
||||
sum += p.Value
|
||||
}
|
||||
return sum
|
||||
}
|
||||
|
||||
func TestPointKindStrings(t *testing.T) {
|
||||
seen := map[string]bool{}
|
||||
for k := PointKind(0); k < NumPointKinds; k++ {
|
||||
|
||||
@@ -198,7 +198,7 @@ type State struct {
|
||||
Over bool
|
||||
Winner PlayerID
|
||||
EndReason EndReason
|
||||
// Standings is the final table, best first. Meaningless while the game is
|
||||
// in play, for the same reason Winner is.
|
||||
// Standings is the final table, best first. Nil while the game is in
|
||||
// play, when it would be meaningless for the same reason Winner is.
|
||||
Standings []Standing
|
||||
}
|
||||
Reference in new issue
Block a user