private TimelineLiveElement getBaseDiff(LiveElementBase curr) { var diff = new TimelineLiveElement() { id = curr.id }; var diffExplains = new List <Explain>(); foreach (var explain in curr.explain) { var diffExplain = new Explain() { fixture = explain.fixture }; diff.explain.Add(diffExplain); var diffStats = new List <ExplainElement>(); foreach (var stat in explain.stats) { if (stat.points != 0 || stat.value != 0) { diffStats.Add(stat); } } if (diffStats.Count > 0) { diffExplain.stats = diffStats; } } diff.CalcScore(); var anyStats = diff.explain.Any(ex => ex.stats.Count > 0); return(anyStats ? diff : null); }
public async Task <TimelineLiveElement> Predict(TimelineLiveElement current) { var prediction = new TimelineLiveElement(current); foreach (var fixturePrediction in prediction.explain) { var fixtureId = fixturePrediction.fixture; var fixtures = await _client.GetFixtures(_gameweek); var fixture = fixtures.FirstOrDefault(f => f.id == fixtureId); if (fixture != null) { MakePrediction(current, fixture, fixturePrediction); } // Ideas: /* * If fixture is on: * If player is playing: +1 (don't bother adding? since it gets added anyway) * If player is playing, <60min and could possibly get to 60min, +1 * If gk/def still has CS (note: goals scored while player is out don't count... check CS rules): +4 * If mid still has CS: +1 * Mid/striker +avg, scale down based on time left in fixture, floor it on actual score * * Potential subs???? Add sub pts (if sub is valid) * "High" prediction: */ } prediction.CalcScore(); return(prediction); }
private TimelineLiveElement Compare(LiveElementBase prev, LiveElementBase curr) { var diff = new TimelineLiveElement() { id = curr.id }; for (var i = 0; i < curr.explain.Count; i++) { var allExplainIdentifiers = new HashSet <string>(curr.explain[i].stats.Select(s => s.identifier).ToHashSet()); if (prev != null && prev.explain != null && prev.explain.Count > i) { foreach (var stat in prev.explain[i].stats) { allExplainIdentifiers.Add(stat.identifier); } } var currFixtureExplain = curr.explain[i]; var prevFixtureExplain = prev != null && prev.explain != null && prev.explain.Count > i ? prev.explain[i] : null; var diffExplain = new Explain() { fixture = currFixtureExplain.fixture, stats = new List <ExplainElement>() }; diff.explain.Add(diffExplain); foreach (var explainIdentifier in allExplainIdentifiers) { var currStat = currFixtureExplain.stats.FirstOrDefault(e => e.identifier.Equals(explainIdentifier)); var prevStat = prevFixtureExplain != null?prevFixtureExplain.stats.FirstOrDefault(s => s.identifier.Equals(explainIdentifier)) : null; if (prevStat == null) { prevStat = new ExplainElement() { identifier = explainIdentifier }; } if (currStat == null) { currStat = new ExplainElement() { identifier = explainIdentifier }; } var statDiff = GetExplainDiff(currStat, prevStat); if (statDiff != null) { diffExplain.stats.Add(statDiff); } } } var saveDiff = diff.explain.Any(ex => ex.stats.Count > 0); if (saveDiff) { diff.CalcScore(); return(diff); } return(null); }
private void AddPotential(TimelineLiveElement current, Fixture fixture, Explain explain) { var fixtureMinutes = GetEstimatedFixtureMinutes(fixture); var minutesExplain = GetMinutes(explain); var bonusExplain = GetBonus(explain); var element = GetElement(current.id); if (minutesExplain == null) { explain.stats.Add(new ExplainElement() { identifier = "minutes", value = 0, points = 0 }); } // Add minutes (assume > 60min if it is still possible) if (minutesExplain.value > 0 && minutesExplain.value < 60) { var maxMinutes = (90 - fixtureMinutes) + minutesExplain.value; if (maxMinutes > 60) { minutesExplain.value = 61; minutesExplain.points = 2; } } else if (minutesExplain.value == 0) { // No minutes yet if (fixture.started && !fixture.finished_provisional) { // Fixture is on, how many can we get? var maxMinutes = (90 - fixtureMinutes) + minutesExplain.value; minutesExplain.value = (int)Math.Round(maxMinutes); minutesExplain.points = maxMinutes >= 60 ? 2 : 1; } else if (!fixture.started) { // Fixture hasn't started, assume start minutesExplain.value = 90; minutesExplain.points = 2; } } // Goalkeepers and defenders get CS, if playing and eligible if (IsMidGkOrDef(element)) { var csExplain = GetCS(explain); if (csExplain == null) { if (!HasOtherTeamScored(element, fixture)) { // Player has no CS and is playing... var maxMinutes = 93.0 - fixtureMinutes + minutesExplain.value; if (maxMinutes >= 60.0) { explain.stats.Add(new ExplainElement() { identifier = "clean_sheets", value = 1, points = element.element_type == 3 ? 1 : 4 }); } } else { explain.stats.Add(new ExplainElement() { identifier = "clean_sheets", value = 0, points = 0 }); } } } // Get any potential BPS if (bonusExplain == null) { // Fixture has started, and not completely finished? if (fixture.started && !fixture.finished) { var rank = GetBpsRankInFixture(element, fixture); var points = 0; if (rank == 1) { points = 3; } else if (rank == 2) { points = 2; } else if (rank == 3) { points = 1; } if (points > 0) { explain.stats.Add(new ExplainElement() { identifier = "bonus", value = points, points = points }); } } } var currentScore = new ScoreCalculator().calculateFootballerScore(explain); var avg = GetAverage(element); // If fixture has started, scale the average based on minutes played is player is in if (fixtureMinutes > 1.0e-6 && minutesExplain != null) { avg.points = (int)Math.Round(avg.points * (1.0 - fixtureMinutes / 90.0)); avg.value = 0; } // Only use average if average is > than the current + potential CS. If using average, only use the difference between avg and current if (avg.points > currentScore) { // If fixture hasn't started, use the average avg.points = avg.points - currentScore; explain.stats.Add(avg); } }
private void MakePrediction(TimelineLiveElement current, Fixture fixture, Explain explain) { AddPotential(current, fixture, explain); }
public TimelineLiveElement(TimelineLiveElement other) : base(other) { score = other.score; }