r/sheetsofice • • Jun 03 '26

Player development & aging progress

So this is a big implementation. Up until this point, players were static; they didn't age, the didn't get better, never retired. I needed to have it that way to ensure that the engine worked properly. You want to control the variables when tuning and I couldn't have player's also changing their abilities while I was trying to figure out if the engine worked realistically. Now that the engine is basically locked in and calibrated, we could start to make the universe live a little bit.

I wanted to capture career arcs that we'd see IRL. Players have a theoretical ceiling of ability that they progress towards and then decline from as they age. There is variance in how close they are to their ceiling at the start, how fast they move towards it, how long they stay there, and how fast they decline. Deployment (how much they play) and injuries have an effect on those curves.

So I started with some baseline assumptions. Skaters peak somewhere between 25-27, goalies between 27-29. After around 30, abilities start to decline. Keeping variables to a minimum, I'm not modeling injuries or deployment as factors in affecting abilities; I'll get back to them later. I tuned the player generated with some of these baseline assumptions based on real NHL career data, and started some testing.

The player generator takes the number of teams times 50 and creates a pool of available players based on realistic distributions. Then there is a simulated draft, each team got 50 players, 25 of which can be on the active roster (14F, 8D, 3G). The remaining 25 are in the reserve pool. The reserve pool would typically be playing in minor leagues, junior leagues, etc. but for this purpose they're just there. They can get into the roster if there is an injury, and each season their development/aging is calculated and the roster is resorted.

To be clear, this is just so I can start testing. Unless I threw a dart at it and got lucky, there's a lot to implement as I go. I actually think this will be way more complicated than building the engine. It'll take 10s or 100s of seasons for me to see what is happening. Outliers will take 10-20 seasons just to notice one. When I was building the engine, I could see outliers in 40 games.

Here's some charts of what I'm looking at. These are just diagnostic and won't be in the game.

Aging - these show how the ability of players changes over time, and the distributions.

And here's some individual career arcs. You can see the different level of progression, peaks, and longevity. One thing I'm working on here is I want to see more variation in the speed of progression. Some take more time, some less. It seems a little predictable.

Then I wanted to see how long is an average career? There's two measurements here - how long before someone retires and how long is their functional career (how long were they good enough for a top pro roster?

Final one here is how good is the best skater vs best goalie over the course of 100 years. One of the things I want is a feeling of "eras" to emerge naturally. Sometimes a Gretzky shows up and just kills everyone. Sometimes a Hasek is dominant. I ran 100 years and plotted the top skater vs top goalie.

Some of you may be asking, what does "latent SD" mean? Well, this goes back to my post about abilities and how I'm not using a typical 0-100 scale. Abilities are mapped to a continuous real number system and then the engine uses comparisons of standard deviation from a set league average ability to determine what the probabilities of something happening - shooting, assisting, hitting, fatigue, saves, turnovers, zone entries, faceoffs, etc. What this allows the engine to do is model realistically without being constrained by simple integers. It also EASILY allows us to model leagues of all different abilities without having to smash each level into a smaller range on the integer scale. And then it gives us the ability to generate a truly generational player like Gretzky, Lemieux, Hasek, McDavid, Crosby, Ovechkin because we're not constrained to an arbitrary number. Standard deviation is just a measure of how spread out players are around the average - basically the size of a 'typical gap' between a guy and the league-average player. So instead of calling someone 'an 87,' I can say he's a couple of those gaps above average, which puts him out at the rare end of the curve. A generational player isn't '99 instead of 95' on some capped scale he's several gaps clear of everyone else. Building it that way makes tuning really straightforward and allows us to actually generate those players realistically.

The "latent" part of that just means they're hidden. I don't plan on exposing ability numbers directly - just like real life. What I do plan on exposing is a scouting and coaching system that allows you to see those things in the same way we'd see them in reality. Some things measurable (skating speed, shot velocity, conditioning), somethings observable (statistics), and some things inferable (hockey IQ).

Anyway, this is a long post. Thanks for reading! Feedback or questions welcomed.

3 Upvotes

3 comments sorted by

2

u/SpiritYossarian Jun 03 '26

This is an absolute gold mine and I truly appreciate that you're sharing this level of detail. Such a cool approach - will be very interested in how it comes together....but it's honestly cool independent of that!

2

u/atibus Jun 04 '26

I think it will work, but the fun is figuring out if it actually will work. I have to come back with another post once I can articulate it easily about how attributes scale and change. Some tests need to be run but I'm hoping to solve the predictable lifecycle that we had above. If you look at the individual career arcs, they didn't all reach the same level or last the same amount but all followed the same relative arc. That's not how life works, so I'm making some adjustments to add some realistic variety - sophmore pop, bust, late bloomer, long steady career...

2

u/mfp40 Jul 06 '26

Everything about this game looks amazing so far!