private void FindPossessor(ref Player possessor, ref Side possessionTeam, Coordinate startLocation = default(Coordinate)) { if (startLocation == default(Coordinate)) { startLocation = Coordinate.Random(); } var homeTeamStartPlayer = TeamFormationAttributes.GetNearestPlayer(true, startLocation); var awayTeamStartPlayer = TeamFormationAttributes.GetNearestPlayer(false, startLocation); Log(string.Format("Battle for possession between {0} and {1} at {2}", homeTeamStartPlayer.LastName, awayTeamStartPlayer.LastName, startLocation)); possessionTeam = homeTeamStartPlayer.Rating > awayTeamStartPlayer.Rating ? Side.Home : Side.Away; possessor = possessionTeam == Side.Home ? homeTeamStartPlayer : awayTeamStartPlayer; }
public MatchSimulator(IDictionary <int, Player> homeTeamFormation, IDictionary <int, Player> awayTeamFormation) { Log = s => { if (this.PlayerMatch) { logger.Debug(s); } }; Random = new Random(); HomeTeamPlayers = homeTeamFormation.Values.ToList(); AwayTeamPlayers = awayTeamFormation.Values.ToList(); TeamFormationAttributes = new TeamFormationAttributes(HomeTeamPlayers, AwayTeamPlayers, Log); HomeGoal = new Coordinate { X = 0.5d, Y = 0d }; AwayGoal = new Coordinate { X = 0.5d, Y = 1d }; }
private void LogRatingBattle() { var height = 120; var width = 25; var stringBuilder = new StringBuilder("\n"); stringBuilder.AppendLine(string.Join("", Enumerable.Repeat("_", height).ToArray())); for (var i = 1; i < width; ++i) { for (var j = 0; j < height; ++j) { if (j == 0 || j == height - 1) { stringBuilder.Append("|"); continue; } if (j == 1 && i % 2 == 0) { stringBuilder.Append(" "); continue; } var rating = (int)(TeamFormationAttributes.TeamStrength(true, new Coordinate { X = (double)i / width, Y = (double)j / height }) - TeamFormationAttributes.TeamStrength(false, new Coordinate { X = (double)i / width, Y = (double)j / height })); stringBuilder.Append(rating); j += (int)rating == 0 ? 1 : (int)Math.Log10(Math.Abs(rating)) + 1; if (rating < 0) { ++j; } if (j == height) { stringBuilder.Append("|"); } else if (j == height - 1) { stringBuilder.Append(" |"); } else if (j == height - 2) { stringBuilder.Append(" |"); j += 2; } else { stringBuilder.Append(" "); } } stringBuilder.AppendLine(); } stringBuilder.AppendLine(string.Join("", Enumerable.Repeat("_", height).ToArray())); Log(stringBuilder.ToString()); }
private void PlayPhase(IFixture fixture, Action <double, double[, ]> updateUi, ref Player possessor, ref Side possessionTeam, ref PossessionGraph <Player> possessionGraph) { if (possessor == null) { FindPossessor(ref possessor, ref possessionTeam); Log(string.Format("{0} wins it for {1}", possessor.LastName, possessor.TeamName)); } possessionGraph = possessionTeam == Side.Home ? TeamFormationAttributes.HomeTeamPossessionGraph() : TeamFormationAttributes.AwayTeamPossessionGraph(); if (TeamFormationAttributes.DelmeFlag) { var ignore = possessionTeam == Side.Away ? TeamFormationAttributes.HomeTeamPossessionGraph() : TeamFormationAttributes.AwayTeamPossessionGraph(); TeamFormationAttributes.DelmeFlag = false; } var possessionIterations = 0; var option = default(int); // TODO: Modifier for +ve Team Balance, -ve Defensive shape? while (possessionIterations++ < 15) { ++PhasesOfPlay; if (PlayerMatch) { updateUi(HomeTouches / (HomeTouches + AwayTouches), ColourHeatMap(possessor.Location.RandomNear())); Thread.Sleep(500); // TODO: put back to 100 to speed it up again // make it a reasonable pace } var isShooting = default(bool); option = possessionGraph.PhaseOfPlay(ref possessor, out isShooting); if (possessionTeam == Side.Home) { ++HomeTouches; } else { ++AwayTouches; } if (option < 750) { PossessionGraph <Player> .Chain.WriteLine("\"{0}\",{1},{2},lost", possessor.TeamName, possessionIterations, isShooting); PossessionGraph <Player> .Chain.Flush(); break; } if (option < 1250) { PossessionGraph <Player> .Chain.WriteLine("\"{0}\",{1},{2},restart", possessor.TeamName, possessionIterations, isShooting); PossessionGraph <Player> .Chain.Flush(); possessor = TeamFormationAttributes.GetNearestPlayer(possessionTeam == Side.Home, RestartedBallPosition(possessionTeam, (option - 500d) / 1000)); Log(string.Format("Working from the back with {0}", possessor.LastName)); continue; } if (isShooting) { PossessionGraph <Player> .Chain.WriteLine("\"{0}\",{1},true,shoot", possessor.TeamName, possessionIterations); PossessionGraph <Player> .Chain.Flush(); if (possessionTeam == Side.Home) { ++fixture.ChancesHome; } else { ++fixture.ChancesAway; } if (option > 2000) { Log(string.Format("He shoots, he scores! Goal for {0}", possessor.LastName)); if (possessionTeam == Side.Home) { ++fixture.GoalsHome; } else { ++fixture.GoalsAway; } ++possessor.Goals; option = 500; // to allow the restarted position (see GetNearestPlayer invocation below) to be at the halfway line } else { Log(string.Format("Shot from {0} but no goal", possessor.LastName)); } break; } } FindPossessor(ref possessor, ref possessionTeam, possessor.Location.RandomNear()); Log(string.Format("Restart for {0} with {1} at {2}", possessor.TeamName, possessor.LastName, possessor.Location)); }
public void Play(IFixture fixture, Action <double, double[, ]> updateUi) { HeatMap = new double[Configuration.HeatMapDimensions.Item1, Configuration.HeatMapDimensions.Item2]; if (PlayerMatch) { updateUi(0.5d, null); } var ballPosition = new Coordinate { X = 0.5d, Y = 0.5d }; var kickoff = DateTime.Now; PlayerMatch = updateUi != null; PhasesOfPlay = 0; if (PlayerMatch) { updateUi(0.5d, HeatMap); Thread.Sleep(5000); } LogTeam(Side.Home); LogRatingBattle(Side.Home); LogTeam(Side.Away); LogRatingBattle(Side.Away); LogRatingBattle(); fixture.PlayingPeriod = PlayingPeriod.FirstHalf; PlayHalf(fixture, updateUi); fixture.PlayingPeriod = PlayingPeriod.HalfTime; HeatMap = new double[Configuration.HeatMapDimensions.Item1, Configuration.HeatMapDimensions.Item2]; if (PlayerMatch) { updateUi(HomeTouches / (HomeTouches + AwayTouches), null); Thread.Sleep(5000); } PhasesOfPlay = 0; fixture.PlayingPeriod = PlayingPeriod.SecondHalf; var temp = HomeGoal; HomeGoal = AwayGoal; AwayGoal = temp; // Switching sides at halftime is covered by the ViewModel bound animation. // Non-player matches have to do this here. if (!PlayerMatch) { HomeTeamPlayers.Concat(AwayTeamPlayers).Execute(p => p.Location.Invert()); } TeamFormationAttributes.SecondHalf(); PlayHalf(fixture, updateUi); fixture.PlayingPeriod = PlayingPeriod.FullTime; }