-
[RESOLVED] Simple to understand, complex to code; help!
I'm writing a Fantasy Football GM/Coach evaluator.
Quickly, in FF you pick a set of NFL players who score fantasy points for you based on what they do in their real game. Each fantasy team has arond 16 players on it, around 9 of whom "start" each week. You only score points from your 9 starters.
In the real NFL, the General Manager (GM) makes personnel decisions. He (along with input from the coach) decides what players to draft, trade, sign and cut. The head coach then takes all the players the GM gives him and decides who should get the most playing time.
In fantasy, a common source of "Doh!" is when you don't start a guy who has a monster game. Those points don't count for you, which is annoying.
The purpose of my GM/Coach evaluator is to go through each team and calculate the most points you could have scored if you started all the right people. In other words, how good a job the fantasy player did in assembling their raw team. The Coach part will be a percentage, the actual score / potential score. Given your raw talent, how good a job did you do deciding who to start?
This is all very simple and straightforward and, in fact, mostly implemented. The complex logic comes in with flex spots. A typical FF starting roster looks like this:
1 QB
2 RB
2 WR
1 TE
1 DEF
1 K
If that were all there was, I'd already be done with it. But flex spots let you choose who to start. The three flavors of flex spots are:
WR/RB
WR/TE
RB/WR/TE
To further complicate things, some actual NFL players are listed as having multiple positions. For example, a guy could be listed as "RB,WR" for position, meaning you can start him at RB, WR, WR/RB, or RB/WR/TE. Some of these guys are high scorers, so they can't be ignored.
I'm having trouble designing the logic to calculate who the best 9 starters should be. If you want to just post a high-concept description of how to do it in narrative (instead of code) form, by all means please do so. If you want to take a crack at the actual coding logic, in the next post is attached the project as it stands now.
My logic so far is to go through every dedicated (non-flex) position and pick the highest-scoring guy of that position who isn't already starting.
-
1 Attachment(s)
Re: Simple to understand, complex to code; help!
Note that I just started working on this last week, so it's thrown together pretty haphazardly. (I'm writing this in VB6 because it's so fast to code.) It's intended to be shared with random people met over the internet, so installation programs are a no-go. To that end, no components or references allowed.
It's mostly finished, but I only brought in a little bit of data for testing. For a player with multiple real-life positions, Dexter McCluster is the best candidate. In the He Hate Me league he's owned by Fightin' Quakers. In the Dynasty league he's owned by Awful Offals. (I am New York Fanboys.)
The code that calculates the potential scores is the function CalculatePotential() in the module basData.
-
Re: Simple to understand, complex to code; help!
I know 2 thirds of nothing about Football and even less about FF, however from what you are describing I understand that a given player can play in up to 3 different positions and as coach you have to decide which position you will put that player in for a given Game (given you pick that player for the fantasy squad).
Question: Is it possible / likely that a player may start a real Game in one position and later on in the same Game move to another position? If that can happen then recording their actual performance will depend upon how long they played in each position and how they performed, which could complicate the logic further.
Apart from that I don't see (ie understand) the problem. When collecting 'scores' for players after a real Game, don't you just collect the position they played and the performance points they earned in the Game. Having collected that, compare your fantasy squad, ie the 9 players, and positions to what happened in the real Game.
So, if I was multi-skilled and could play either WR or RB and in the real game played a blinder as WR and earned 1000 points, if you picked me in your fantasy squad as RB you'd get zilch points but you could have got 1000.
In other words when assessing the scores you have to take the position the player played into account, as well as the player themselves. Perhaps it might become clearer if you thought of every player being capable of playing in 'n' positions where some of the 'n' for a given player are null.
EDIT: Looking at your UDTs I think what I am proposing is that DepthChart should be a Dynamic Array holding the enumeration for all the possible positions the player can play. Then when you're looking at the points you input the Player, Posititon they played in and Points scored, if you match the Player and position you get the points, otherwise you don't, but whatever happens, the score that player actually got, goes into the 'could have got' pot when you calculate the percentages
(Or have I just demonstrated my ignorance in Spades ?) :blush:
-
Re: Simple to understand, complex to code; help!
The player's position is fixed for the entire season. Once a WR, always a WR.
To me this is so complex that I have trouble even coming up with examples for why it's complicated. But let me take a crack at it. We can ignore QB, DEF and K because those are always dedicated position, both in fantasy and in the real NFL. That just leaves RB, WR and TE.
Let's say the starting spots are:
A) RB
B) RB
C) WR
D) WR
E) TE
F) WR/RB
G) WR/TE
Let's say my team roster includes the following players, with their scores for this week:
RB Ronald 22
RB Robert 20
RB Reggie 16
RB Ralph 15
WR Wayne 20
WR Wilson 19
WR Walter 18
WR Warren 15
TE Terence 18
TE Tony 17
TE Thomas 15
WR,RB Frank 16
WR,TE Felix 16
I'm pretty confident in my first step, which is to place the highest scoring dedicated players in the dedicated spots. So after step 1 we have:
A) RB Ronald 22
B) RB Robert 20
C) WR Wayne 20
D) WR Wilson 19
E) TE Terence 18
F) WR/RB ???
G) WR/TE ???
The remaining players available:
RB Reggie 16
RB Ralph 15
WR Walter 18
WR Warren 15
TE Tony 17
TE Thomas 15
WR,RB Frank 16
WR,TE Felix 16
The ideal solution would be to put Walter in the WR/RB slot and Tony in the WR/TE spot. But I only know this because it's obvious just by looking at it. How would I write code that figures this out?
Consider if Walter goes in the WR/TE spot. Now Tony can't play because he's neither a RB nor a WR, so that would mean Warren or Thomas (both 15s) would have to go in the WR/TE spot, which isn't the maximum potential.
The multi-position NFL guys (Frank and Felix in this example) add another layer of complexity, but I'm thinking maybe hold them out until all the positions are filled and then swap them in if they scored more than someone else. Maybe. Not sure.
-
Re: Simple to understand, complex to code; help!
Quote:
Originally Posted by
Doogle
EDIT: Looking at your UDTs I think what I am proposing is that DepthChart should be a Dynamic Array holding the enumeration for all the possible positions the player can play. Then when you're looking at the points you input the Player, Posititon they played in and Points scored, if you match the Player and position you get the points, otherwise you don't, but whatever happens, the score that player actually got, goes into the 'could have got' pot when you calculate the percentages
This sounds intriguing.
The DepthChart array handles other logic (namely the order the names appear in in the roster screens) so that isn't changing, but that's a single league-wide value anyway. It sounds like you're talking about a player-specific dynamic array. I'm down with that, but I don't completely follow what youi're saying.
Given the above example, I think you're saying to create an array for each player like so:
A) RB
B) RB
C) WR
D) WR
E) TE
F) WR/RB
G) WR/TE
RB Ronald 22 (A, B, F)
RB Robert 20 (A, B, F)
RB Reggie 16 (A, B, F)
RB Ralph 15 (A, B, F)
WR Wayne 20 (C, D, F, G)
WR Wilson 19 (C, D, F, G)
WR Walter 18 (C, D, F, G)
WR Warren 15 (C, D, F, G)
TE Terence 18 (E, G)
TE Tony 17 (E, G)
TE Thomas 15 (E, G)
WR,RB Frank 16 (A, B, C, D, F, G)
WR,TE Felix 16 (C, D, E, F, G)
Is that what you mean? And if so, could you clarify what the next step would be?
-
Re: Simple to understand, complex to code; help!
Quote:
Originally Posted by
Ellis Dee
The ideal solution would be to put Walter in the WR/RB slot and Tony in the WR/TE spot. But I only know this because it's obvious just by looking at it.
What you've done intuitively is to look at WR/TE and ask the question "Who's the player with the largest score who can play in that spot" Answer is Tony. Then, with Tony out of the way you look at WR/RB ask the same question and get Walter.
Whilst your Step1 is logical I wonder whether you should select from the entire team based upon the number of players available to fill a particular spot and start with the spot which has the fewest players available, rather than place the highest scoring dedicated players in the dedicated spots.
-
Re: Simple to understand, complex to code; help!
I agree that starting with the spots that have the fewest candidates increases the odds that I'll get an ideal fill, but it wouldn't be a guaranteed best fill. I'm hoping to set up the algorithm to always get an ideal fill. Also, getting the best fits for the dedicated spots out of the way first can't hurt and it helps to simplify things.
My current idea, after taking care of the dedicated spots first, is this:
1) Count the total number of open flex spots. Let's call this number x. (For the above example, x=2.)
2) Find the top x scoring players not yet assigned a spot who qualify for any of the flex spots.
3) For each player identified in step 2, count how many flex spots they qualify for.
4) The highest scoring player from group 2 who qualifies for exactly one spot gets put in that spot.
5) Return to step 1 until there are no more spots to fill.
I think this is pretty good, but am unable to determine if it will always return the best case. For clarity, here are those steps in action for the example above.
1) Two flex spots
2) Top two scorers that fit either flex spot are Warren and Tony.
3) Of those two, Tony is the highest scoring player who only qualifies for one spot.
4) Tony goes in that one spot (WR/TE)
1) One flex spot
2) Top qualifying scorer is Warren
3) Warren is the highest scorer
4) Warren gets that spot
1) No flex spots remain open
This happens to work nicely for this example, but I can imagine much uglier scenarios. (Some leagues have nothing but flex spots, for example. *shudder*)
-
Re: Simple to understand, complex to code; help!
Quote:
(I am New York Fanboys.)
I saw that one coming ;)
So you have two problems: flex positions and flex players. I think you can take the same approach for both problems, which is to iterate through the permutations. That way, for each iteration, you never actually deal with either flex players or flex positions. The downside of this is that it is algorithmically inefficient, since it is an O(nm) algorithm, where n is product of the number of positions each of your players can play (so if everybody can only play 1 position, then n = 1) and m is the product of the number of positions that each starting slot can take (aka 1 * 1 * 1 * 1 * 1 * 2 * 2 = 4). However, since n is typically going to be 1 or 2, and m is also going to be fairly small, the inefficiency is rather trivial in this case.
So here's a general algorithm layout:
Code:
For each permutation of flex players
For each permutation of flex positions
Assign players according to best fit
Measure point total
Retain point total and lineup if this is the highest score so far
That's it. It sounds like you have the inner part of the loop already. All you need to do is put a nested loop around it and iterate over the flex players and positions and you'll get what you want.
-
Re: Simple to understand, complex to code; help!
Okay, I'm pretty confident I solved the problem of getting the best fit every time. Here are the steps in narrative form:
1) Fill dedicated (non-flex) spots with highest scoring single-position players
2) Main Loop to fill flex spots with any players (including multi-position players)
- Count total number of flex spots, any flavor. (total = x)
- If x=0 exit loop
- Identify x top-scoring players who qualify for any flex position
- If x=1, put that one guy in that one spot and exit loop
- If x>1, look for the highest scoring player who qualifies for exactly 1 spot
- If found, put that guy in his one spot and restart main loop (Step 2)
- If all x players qualify for multiple flex spots, put top guy in first slot he qualifies for and restart main loop (Step 2)
3) Check all non-starting multi-position players one by one in order of highest scorer first
- Look at all starters whose spot this player qualifies for, starting with lowest scorer first
- If the multi-pos bench player scored more than the starter, swap them and restart loop (Step 3)
I don't have the mathematical expertise to prove that this always gives optimal results, but I'm pretty confident it does. Enough so that I'm going to go ahead and mark this thread resolved. Thanks much for the help with bouncing ideas around.
-
Re: [RESOLVED] Simple to understand, complex to code; help!
This problem gave me something to puzzle over during my commute and I think I figured out a flaw. Let's take your example from the fourth post:
Quote:
A) RB
B) RB
C) WR
D) WR
E) TE
F) WR/RB
G) WR/TE
RB Ronald 22
RB Robert 20
RB Reggie 16
RB Ralph 15
WR Wayne 20
WR Wilson 19
WR Walter 18
WR Warren 15
TE Terence 18
TE Tony 17
TE Thomas 15
WR,RB Frank 16
WR,TE Felix 16
A) RB Ronald 22
B) RB Robert 20
C) WR Wayne 20
D) WR Wilson 19
E) TE Terence 18
F) WR/RB Reggie 16
G) WR/TE Walter 18
If your algorithm always loops first to RBs, then WRs, and then TEs, you might end up with this solution:
A) RB Ronald 22
B) RB Robert 20
C) WR Wayne 20
D) WR Wilson 19
E) TE Terence 18
F) WR/RB Reggie 16
G) WR/TE Walter 18
However, the actual best solution would have Walter play in the flex WR/RB slot and Tony play in the flex WR/TE slot. Yet when you perform step 3, there is no single position that Tony plays where a lower scoring player is in that slot. To start Tony, you must first move Walter to Reggie's position, and I don't see a mechanism in your algorithm to do that.
Anyway, thanks for the puzzler. It sure beat listening to the radio and hearing how injuries are impacting my own team :mad:
-
Re: [RESOLVED] Simple to understand, complex to code; help!
Quote:
Originally Posted by
Lenggries
If your algorithm always loops first to RBs, then WRs, and then TEs, you might end up with this solution:
I probably didn't explain it properly; this isn't how it works. You have the first part right, where all the dedicated position get filled as you say:
A) RB Ronald 22
B) RB Robert 20
C) WR Wayne 20
D) WR Wilson 19
E) TE Terence 18
The next step is to fill all the flex spots. Those are:
F) WR/RB
G) WR/TE
The algorithm first counts the open spots. In this case, there are two open flex spots. Next it identifies the top two scorers (since there are two spots to fill) that qualify for any of the flex spots. The top two scorers who qualify for either WR/RB or WR/TE are:
WR Walter 18
TE Tony 17
By definition, if we can fit these two guys into the two open slots, this solution is optimal.
Now we check each of these guys one at a time, counting how many of the open spots they qualify for, starting with the highest scorer and working down. We're looking for a player in this group who only qualifies for one spot. The first one we find goes in his one spot and we start over.
Walter gets checked first, he qualifies for two spots, so we move on.
Tony gets checked next, and he only qualifies for one spot. That means Tony gets put in the one spot he qualifies for, the WR/TE position. Now we go back to the beginning of the loop.
A) RB Ronald 22
B) RB Robert 20
C) WR Wayne 20
D) WR Wilson 19
E) TE Terence 18
F) WR/RB
G) WR/TE Tony 17
First thing we do is count the open flex spots, which is now 1. Then we find the 1 highest scoring guy who qualifies, and put him in there. That's Walter. With no open spots left, we're done filling flex spots so we kick out of this loop and start the final loop.
The final loop looks for multi-pos players and starts them over any starter with fewer points, checking the starters by lowest points first.
-
Re: [RESOLVED] Simple to understand, complex to code; help!
I see. I got too hung up on step 3 that I misread step 2. Thanks for clarifying. It may be possible to find a combination which is sub-optimal if you have a slew of flex-players, but given their scarcity in the real NFL, I'd say even if that gap did exist, the odds of a team having enough flex players to cause a problem is next to zero, and not worth investigating. Still, the whole purpose of the program puzzles me... I know I'm a terrible manager, the last thing I need is my own program to tell me just how bad I am ;)
-
Re: [RESOLVED] Simple to understand, complex to code; help!
hehheh. But that's just it: Are you a bad manager, or a bad coach? Generally speaking, I'm a bad manager and a pretty good coach, so I get the most out of my crappy drafts. heh.
I agree that a slew of high-scoring multi-pos players could result in a sub-optimal roster. Or worse, one of those fantasy leagues where every position is a flex position. Combine the two and my head would explode.
-
Re: [RESOLVED] Simple to understand, complex to code; help!
You could get ultra-clever and as time goes on, analyse the delta points per player per game, then forecast their likely points for the next game and use the forecast values to select the team. You'd then (possibly) pick up some players who were improving and drop those whos performance is droping but still have enough points to get selected.
After all, you have to take some risks ;)
(of course, you'd only put that in your version of the program)
-
Re: [RESOLVED] Simple to understand, complex to code; help!
With my luck I'd spend months fine tuning such an analysis only to end up with the exact algorithm yahoo uses for their "projected points."
-
Re: [RESOLVED] Simple to understand, complex to code; help!
It's a fact, no matter what you try to do,someone has already done it !! :D
-
Re: [RESOLVED] Simple to understand, complex to code; help!
The real problem regarding automatic projection of NFL games is the tiny sample size. With only 16 (or soon 18) games in a season, and at most two games against the same opponent, there simply isn't enough data to make a decent projection, especially for skill positions in which the number of touchdowns scored can dramatically impact the fantasy value. This is why various projections tend to draw heavily from perceived knowledge, rather than pure data mining.
-
Re: [RESOLVED] Simple to understand, complex to code; help!
I don't buy into the NFL having a small sample size. People just see that baseball has 10 times the games and assume that means it has 10 times the decisions, but it does not. The average MLB player has roughly the same number of at-bats in a season as the average NFL starting QB has pass attempts.
If you consider that each team runs around 65 plays per game, that's over a thousand plays a season.
-
Re: [RESOLVED] Simple to understand, complex to code; help!
Yes, but for the purposes of this program, are you really interested in the number of pass attempts per season, or are you interested in the number of touchdown passes in the next game? Statistics such as pass attempts and yards tend to get smoothed out. Number of touchdowns in a given game not so much, and in fantasy terms, touchdowns tend to dominate fantasy scoring systems (just like in baseball wins are an important fantasy statistic even though they can be quite erratic from year to year and not at all correlated with other pitching stats, such as WHIP and ERA). While I completely agree that NFL statistics are plentiful enough when examining a complete season, which is important during draft time, they are less helpful when forecasting a particular game, for the simple reason that touchdowns cause there to be a large variance. Building a projections system to calculate a mean is one thing, but I don't know of any statistical method that can predict the spikes in variance that would lead to one of those epically high-scoring games that can carry a fantasy team in a given week.
-
Re: [RESOLVED] Simple to understand, complex to code; help!
Oh, I thought you meant in general. For predicting stats/outcome of specific games, I agree 100% for all the reasons you stated.