private List <JamPlayer> AddJamPlayers(Dictionary <string, Player> playerMap, Jam jam, IList <PlayerLineupModel> lineups, JamPlayerGateway gateway, ref bool areDupes) { List <JamPlayer> list = new List <JamPlayer>(); List <string> duplicateCheckList = new List <string>(); foreach (PlayerLineupModel lineup in lineups) { if (lineup == null) { Console.WriteLine(jam.ToString() + ": empty player spot"); continue; } if (duplicateCheckList.Contains(lineup.PlayerNumber)) { Console.WriteLine(string.Format("{0}: #{1} in lineup multiple times.", jam, lineup.PlayerNumber)); areDupes = true; } else { duplicateCheckList.Add(lineup.PlayerNumber); Player player = playerMap[lineup.PlayerNumber]; list.Add(gateway.AddJamPlayer(jam.ID, player.ID, player.TeamID, lineup.IsJammer, lineup.IsPivot)); } } return(list); }
private void CheckForBoxTimeMismatch(Dictionary <int, List <BoxTime> > jamBoxTimeMap, List <BoxTime> longServices) { bool exceptions = false; foreach (KeyValuePair <int, List <BoxTime> > kvp in jamBoxTimeMap) { // key is jamId // value is boxTimeList var boxEntireJam = kvp.Value.Where(bt => bt.StartedJamInBox != null && bt.StartedJamInBox == true && bt.EndedJamInBox); var fullyServed = kvp.Value.Where(bt => bt.StartedJamInBox != null && bt.StartedJamInBox == false && !bt.EndedJamInBox); if (fullyServed.Any() && boxEntireJam.Any()) { // if the short service box times are part of a multi-penalty service, they can be ignored foreach (BoxTime fullBT in boxEntireJam) { if (!longServices.Contains(fullBT)) { Jam jam = _jams.Single(j => j.ID == kvp.Key); exceptions = true; Console.WriteLine(jam.ToString() + ": Penalty timing problem"); break; } } } } if (exceptions) { throw new InvalidDataException("Penalty timing problems"); } }
private List <JamPlayer> AddJamPlayers(Dictionary <string, Player> playerMap, Jam jam, IList <PlayerLineupModel> lineups, JamPlayerGateway gateway) { List <JamPlayer> list = new List <JamPlayer>(); foreach (PlayerLineupModel lineup in lineups) { if (lineup == null) { // TODO: handle null players Console.WriteLine(jam.ToString() + ": empty player spot"); continue; } Player player = playerMap[lineup.PlayerNumber]; list.Add(gateway.AddJamPlayer(jam.ID, player.ID, player.TeamID, lineup.IsJammer, lineup.IsPivot)); } return(list); }
private void RemoveLastJamPenalties(Dictionary <int, List <Penalty> > playerPenaltyMap, Dictionary <int, List <BoxTime> > playerBoxTimeMap, List <PenaltyService> services) { var endGame = playerPenaltyMap.Values.SelectMany(p => p).Where(p => p.JamID == _lastJam.ID).ToList(); foreach (Penalty penalty in endGame) { if (playerBoxTimeMap.ContainsKey(penalty.PlayerID) && playerBoxTimeMap[penalty.PlayerID].Any() && playerBoxTimeMap[penalty.PlayerID].Last().JamID == _lastJam.ID) { continue; } Jam penaltyJam = _jams.First(j => j.ID == penalty.JamID); Player penaltyPlayer = _players[penalty.PlayerID]; Console.WriteLine(penaltyJam.ToString() + ": penalty by #" + penaltyPlayer.Number + " in last jam assumed to not have been served"); playerPenaltyMap[penalty.PlayerID].Remove(penalty); PenaltyService service = new PenaltyService(); service.Penalties.Add(penalty); services.Add(service); } }
private List <JamPlayer> AddJamPlayers(Dictionary <string, Player> playerMap, Jam jam, IList <PlayerLineupModel> lineups, JamPlayerGateway gateway) { List <JamPlayer> list = new List <JamPlayer>(); List <string> duplicateCheckList = new List <string>(); foreach (PlayerLineupModel lineup in lineups) { if (lineup == null) { // TODO: handle null players Console.WriteLine(jam.ToString() + ": empty player spot"); continue; } if (duplicateCheckList.Contains(lineup.PlayerNumber)) { throw new InvalidOperationException(string.Format("{0}: #{1} in lineup multiple times.", jam, lineup.PlayerNumber)); } duplicateCheckList.Add(lineup.PlayerNumber); Player player = playerMap[lineup.PlayerNumber]; list.Add(gateway.AddJamPlayer(jam.ID, player.ID, player.TeamID, lineup.IsJammer, lineup.IsPivot)); } return(list); }
private List <PenaltyService> ConvertBoxTimeList(List <BoxTime> playerBoxTimes) { List <PenaltyService> penaltyService = new List <PenaltyService>(); int boxTimeIndex = 0; while (boxTimeIndex < playerBoxTimes.Count) { PenaltyService service = new PenaltyService(); BoxTime lastBoxTime = playerBoxTimes[boxTimeIndex]; service.BoxTimes.Add(lastBoxTime); if (lastBoxTime.MatchingKey != null) { service.ServiceKey = lastBoxTime.MatchingKey; } boxTimeIndex++; while (lastBoxTime.EndedJamInBox && boxTimeIndex < playerBoxTimes.Count) { int nextJamID = GetNextJamID(lastBoxTime.JamID); BoxTime nextBoxTime = playerBoxTimes[boxTimeIndex]; if (nextBoxTime.JamID == nextJamID && (nextBoxTime.StartedJamInBox == null || nextBoxTime.StartedJamInBox == true)) { nextBoxTime.StartedJamInBox = true; service.BoxTimes.Add(nextBoxTime); lastBoxTime = nextBoxTime; boxTimeIndex++; } else { Jam jam = _jams.First(j => j.ID == lastBoxTime.JamID); Player player = _players[lastBoxTime.PlayerID]; Console.WriteLine(string.Format("{0}: No box time continuation for {1} {2}", jam.ToString(), player.Number, player.Name)); break; } } penaltyService.Add(service); } return(penaltyService); }
private void HandleLeftoverPenalties(Dictionary <int, List <Penalty> > playerPenaltyMap, Dictionary <int, List <BoxTime> > playerBoxMap, Dictionary <int, bool> jamFullBoxMap, Dictionary <int, int> endJammerMap, List <PenaltyService> services) { var leftoverPenalties = playerPenaltyMap.Values.SelectMany(p => p).ToList(); var leftoverBoxes = playerBoxMap.Values.SelectMany(p => p).ToList(); // handle penalties with no time served while (leftoverPenalties.Count > 0) { Penalty penalty = leftoverPenalties[0]; Jam penaltyJam = _jams.First(j => j.ID == penalty.JamID); Player penaltyPlayer = _players[penalty.PlayerID]; bool wasEndJammer = endJammerMap.ContainsKey(penaltyJam.ID) && endJammerMap[penaltyJam.ID] == penaltyPlayer.ID; PenaltyService service = new PenaltyService(); service.Penalties.Add(penalty); // if no time was served, it's conceivable the penalty didn't get served until later on // TODO: confirm jammer penalty+service matching var matchingBoxes = leftoverBoxes .Where(bt => (bt.JamID > penalty.JamID && bt.IsJammer == wasEndJammer) || (bt.JamID == penalty.JamID && bt.PlayerID == penalty.PlayerID)) .OrderBy(bt => bt.JamID); if (matchingBoxes.Any()) { BoxTime bestBox = matchingBoxes.First(); Jam boxTimeJam = _jams.First(j => j.ID == bestBox.JamID); Player boxTimePlayer = _players[bestBox.PlayerID]; int nextJamID = GetNextJamID(penaltyJam.ID); if (boxTimeJam.ID - penaltyJam.ID > 1 && (!jamFullBoxMap.ContainsKey(nextJamID) || !jamFullBoxMap[nextJamID])) { string errorString = string.Format("{0}: penalty by {1} {2} does not appear correctly served.", penaltyJam.ToString(), penaltyPlayer.Number, penaltyPlayer.Name); Console.WriteLine(errorString); throw new InvalidDataException(errorString); } Console.WriteLine(string.Format("{0}: penalty by {1} {2} served by {3} {4}", penaltyJam.ToString(), penaltyPlayer.Number, penaltyPlayer.Name, boxTimePlayer.Number, boxTimePlayer.Name)); service.BoxTimes.Add(bestBox); leftoverBoxes.Remove(bestBox); playerBoxMap[bestBox.PlayerID].Remove(bestBox); leftoverPenalties.Remove(penalty); playerPenaltyMap[penalty.PlayerID].Remove(penalty); // see if this penalty has friends var hangersOn = leftoverPenalties.Where(p => p.JamID == penalty.JamID && p.PlayerID == penalty.PlayerID && p.PenaltyNumber != penalty.PenaltyNumber).ToList(); foreach (Penalty extra in hangersOn) { service.Penalties.Add(extra); leftoverPenalties.Remove(extra); playerPenaltyMap[extra.PlayerID].Remove(extra); } // get the ending jam of the service while (bestBox.EndedJamInBox && bestBox.JamID < _lastJam.ID) { BoxTime previousBox = bestBox; bestBox = leftoverBoxes.Where(bt => bt.StartedJamInBox == true && bt.JamID == bestBox.JamID + 1 && bt.PlayerID == bestBox.PlayerID).FirstOrDefault(); if (bestBox == null) { boxTimeJam = _jams.First(j => j.ID == previousBox.JamID); throw new InvalidDataException(boxTimeJam.ToString() + ": box time by #" + boxTimePlayer.Number + " does not appear correctly finished."); } service.BoxTimes.Add(bestBox); leftoverBoxes.Remove(bestBox); playerBoxMap[bestBox.PlayerID].Remove(bestBox); } services.Add(service); } else { Jam jam = _jams.First(j => j.ID == penalty.JamID); Player player = _players[penalty.PlayerID]; Console.WriteLine(string.Format("{0}: Unhandled Penalty for {1} {2}.", jam.ToString(), player.Number, player.Name)); throw new InvalidDataException(string.Format("{0}: Unhandled Penalty for {1} {2}.", jam.ToString(), player.Number, player.Name)); } } }
private void HandlePartialService(Dictionary <int, List <Penalty> > playerPenaltyMap, Dictionary <int, List <BoxTime> > playerBoxMap, List <PenaltyService> services, bool requireSingleMatch) { // if someone picked up their 7+ penalty and either: // 1) didn't serve any time at all, or // 2) was still "in the box" at the end of the jam var incompleteService = services.Where(s => s.BoxTimes.Count > 0 && s.BoxTimes.Last().EndedJamInBox&& !s.BoxTimes.Last().Finished&& s.BoxTimes.Last().JamID != _lastJam.ID); var leftoverBoxes = playerBoxMap.Values.SelectMany(p => p).Where(b => b.FullService != true).ToList(); foreach (PenaltyService service in incompleteService) { Penalty lastPenalty = service.Penalties.Last(); BoxTime lastBox = service.BoxTimes.Last(); Jam penaltyJam = _jams.First(j => j.ID == lastPenalty.JamID); Player penaltyPlayer = _players[lastPenalty.PlayerID]; // when the penalized served some time, we can't be sure it wasn't sufficient time var boxes = leftoverBoxes.Where(bt => bt.JamID == lastPenalty.JamID + 1 && (bt.IsJammer == lastBox.IsJammer) && (bt.IsPivot == lastBox.IsPivot) && (bt.FullService != true)); BoxTime bestBox = boxes.Any() && (!requireSingleMatch || boxes.Count() == 1) ? boxes.First() : null; if (bestBox != null) { Jam boxTimeJam = _jams.First(j => j.ID == bestBox.JamID); Player boxTimePlayer = _players[bestBox.PlayerID]; Console.WriteLine(string.Format("{0}: penalty by {1} {2} continued service by {3} {4}", penaltyJam.ToString(), penaltyPlayer.Number, penaltyPlayer.Name, boxTimePlayer.Number, boxTimePlayer.Name)); service.BoxTimes.Add(bestBox); leftoverBoxes.Remove(bestBox); playerBoxMap[bestBox.PlayerID].Remove(bestBox); //if (bestBox.StartedJamInBox == null) //{ bestBox.StartedJamInBox = true; //} // get the ending jam of the service while (bestBox.EndedJamInBox && bestBox.JamID < _lastJam.ID) { BoxTime previousBox = bestBox; bestBox = leftoverBoxes.Where(bt => bt.StartedJamInBox == true && bt.JamID == bestBox.JamID + 1 && bt.PlayerID == bestBox.PlayerID).FirstOrDefault(); if (bestBox == null) { boxTimeJam = _jams.First(j => j.ID == previousBox.JamID); string errorString = string.Format("{0}: box time by {1} {2} does not appear correctly finished.", boxTimeJam.ToString(), boxTimePlayer.Number, boxTimePlayer.Name); Console.WriteLine(errorString); throw new InvalidDataException(errorString); } service.BoxTimes.Add(bestBox); leftoverBoxes.Remove(bestBox); playerBoxMap[bestBox.PlayerID].Remove(bestBox); } // see if the serving player picked up any other penalties as part of this service if (playerPenaltyMap.Keys.Contains(boxTimePlayer.ID)) { var nextPlayerPenalty = playerPenaltyMap[boxTimePlayer.ID].FirstOrDefault(p => p.JamID >= service.BoxTimes.Last().JamID); if (nextPlayerPenalty != null) { // see if there's a box time for that player that fits that penalty var nextPlayerBoxTime = playerBoxMap[boxTimePlayer.ID].FirstOrDefault(bt => bt.JamID >= nextPlayerPenalty.JamID); if (nextPlayerBoxTime == null || nextPlayerBoxTime.JamID > nextPlayerPenalty.JamID + 1) { service.Penalties.Add(nextPlayerPenalty); playerPenaltyMap[nextPlayerPenalty.PlayerID].Remove(nextPlayerPenalty); } } } } } }
private void CheckForBadFoulOuts(List <PenaltyService> services) { var returnedSeventh = services.Where(s => s.Penalties.Count > 0 && s.BoxTimes.Count > 0 && s.Penalties.Last().PenaltyNumber > 6 && !s.BoxTimes.Last().EndedJamInBox&& s.BoxTimes.Last().PlayerID == s.Penalties.Last().PlayerID); foreach (PenaltyService service in returnedSeventh) { Jam penaltyJam = _jams.First(j => j.ID == service.Penalties.Last().JamID); Player penaltyPlayer = _players[service.Penalties.Last().PlayerID]; // there is a possibility that a player was accidentally allowed to continue to play // if this is a multi-jam penalty service, log a warning and do nothing if (service.BoxTimes.Count > 1) { Console.WriteLine(string.Format("{0}: penalty by {1} {2} was 7th, but continued service in the next jam?", penaltyJam.ToString(), penaltyPlayer.Number, penaltyPlayer.Name)); } else { Console.WriteLine(string.Format("{0}: penalty by {1} {2} was 7th, but returned to track!", penaltyJam.ToString(), penaltyPlayer.Number, penaltyPlayer.Name)); service.BoxTimes.Last().EndedJamInBox = true; service.BoxTimes.Last().Finished = true; } } }
private void ProcessLeftoverBoxes(Dictionary <int, List <Penalty> > playerPenaltyMap, Dictionary <int, List <BoxTime> > playerBoxTimeMap, Dictionary <int, bool> jamFullBoxMap, Dictionary <int, int> endJammerMap, List <PenaltyService> services) { HandleSpecialCases(playerPenaltyMap, playerBoxTimeMap, services); // if there was a penalty in the last jam with no service, ignore it RemoveLastJamPenalties(playerPenaltyMap, playerBoxTimeMap, services); CheckForBadFoulOuts(services); // see if this is for a foul out bool leftoverBoxTimeMap = playerBoxTimeMap.Any(kvp => kvp.Value.Any()); if (leftoverBoxTimeMap) { HandlePartialService(playerPenaltyMap, playerBoxTimeMap, services, true); } bool leftoverPenaltyMap = playerPenaltyMap.Any(kvp => kvp.Value.Any()); if (leftoverPenaltyMap) { HandleLeftoverPenalties(playerPenaltyMap, playerBoxTimeMap, jamFullBoxMap, endJammerMap, services); } leftoverBoxTimeMap = playerBoxTimeMap.Any(kvp => kvp.Value.Any()); if (leftoverBoxTimeMap) { HandlePartialService(playerPenaltyMap, playerBoxTimeMap, services, false); } bool throwException = false; foreach (KeyValuePair <int, List <Penalty> > playerPenalties in playerPenaltyMap) { if (playerPenalties.Value.Any()) { foreach (Penalty penalty in playerPenalties.Value) { Jam jam = _jams.First(j => j.ID == penalty.JamID); Player player = _players[penalty.PlayerID]; Console.WriteLine(string.Format("{0}: Unhandled Penalty for {1} {2}.", jam.ToString(), player.Number, player.Name)); throwException = true; } } } foreach (KeyValuePair <int, List <BoxTime> > playerBoxtimes in playerBoxTimeMap) { if (playerBoxtimes.Value.Any()) { foreach (BoxTime boxTime in playerBoxtimes.Value) { Jam jam = _jams.First(j => j.ID == boxTime.JamID); Player player = _players[boxTime.PlayerID]; Console.WriteLine(string.Format("{0}: Unhandled box time for {1} {2}.", jam.ToString(), player.Number, player.Name)); throwException = true; } } } if (throwException) { throw new InvalidDataException("Unhandled penalties or box times."); } }
private void ProcessPlayerPenalties(List <Penalty> playerPenalties, List <BoxTime> playerBoxTimes, Dictionary <int, List <BoxTime> > jamBoxTimeMap, Dictionary <int, bool> jamFullBoxMap, List <PenaltyService> penaltyService) { int penaltyIndex = 0; int serviceIndex = 0; List <PenaltyService> servicesBoxed = ConvertBoxTimeList(playerBoxTimes); PenaltyService lastPenaltyService = null; // iterate through each penalty for this player while (penaltyIndex < playerPenalties.Count) { Penalty penalty = playerPenalties[penaltyIndex]; while (penalty.MatchingKey != null) { penaltyIndex++; if (penaltyIndex < playerPenalties.Count) { penalty = playerPenalties[penaltyIndex]; } else { break; } } if (penaltyIndex >= playerPenalties.Count) { break; } PenaltyService currentService = null; BoxTime serviceStart = null; if (serviceIndex < servicesBoxed.Count) { currentService = servicesBoxed[serviceIndex]; serviceStart = currentService.BoxTimes.First(); // if this service starts before this penalty, skip it // if this service is a special case, skip it while (CompareJams(_jams.First(j => j.ID == serviceStart.JamID), _jams.First(j => j.ID == penalty.JamID)) < 0 || currentService.ServiceKey != null) { serviceIndex++; if (serviceIndex < servicesBoxed.Count) { currentService = servicesBoxed[serviceIndex]; serviceStart = currentService.BoxTimes.First(); } else { break; } } } if (serviceIndex < servicesBoxed.Count) { if (serviceStart.JamID == penalty.JamID) { // same jam if (serviceStart.StartedJamInBox == false) { // this penalty can be applied to this service currentService.Penalties.Add(penalty); playerPenalties.RemoveAt(penaltyIndex); servicesBoxed.RemoveAt(serviceIndex); penaltyService.Add(currentService); lastPenaltyService = currentService; foreach (BoxTime boxTime in currentService.BoxTimes) { playerBoxTimes.Remove(boxTime); } } else if (serviceStart.StartedJamInBox == null) { // what do we want to do in this case? Player player = _players.Values.First(p => p.ID == penalty.PlayerID); Jam jam = _jams.First(j => j.ID == penalty.JamID); Console.WriteLine(string.Format("{0}: {1} null box time start confusion", jam.ToString(), player.Number)); serviceIndex++; } else { // assume that this box time was for something else and move on serviceIndex++; } } else if (GetNextJamID(penalty.JamID) == serviceStart.JamID) { // next jam // if they started the jam in the box, or // if there were already two people who might have started in the box if (serviceStart.StartedJamInBox == true || jamFullBoxMap[serviceStart.JamID]) { // this penalty can be applied to this service currentService.Penalties.Add(penalty); playerPenalties.RemoveAt(penaltyIndex); servicesBoxed.RemoveAt(serviceIndex); penaltyService.Add(currentService); lastPenaltyService = currentService; foreach (BoxTime boxTime in currentService.BoxTimes) { playerBoxTimes.Remove(boxTime); } } else if (serviceStart.StartedJamInBox == null) { // what do we want to do in this case? Player player = _players.Values.First(p => p.ID == penalty.PlayerID); Jam jam = _jams.First(j => j.ID == penalty.JamID); throw new InvalidOperationException(string.Format("{0}: {1} null box time start confusion", jam.ToString(), player.Number)); } else if (lastPenaltyService != null && CompareJams(_jams.First(j => j.ID == lastPenaltyService.BoxTimes.Last().JamID), _jams.First(j => j.ID == penalty.JamID)) >= 0) { // this penalty fits into the last service lastPenaltyService.Penalties.Add(penalty); playerPenalties.RemoveAt(penaltyIndex); } else { // unexpected not starting jam in box? Player player = _players.Values.First(p => p.ID == penalty.PlayerID); Jam jam = _jams.First(j => j.ID == penalty.JamID); currentService.Penalties.Add(penalty); playerPenalties.RemoveAt(penaltyIndex); servicesBoxed.RemoveAt(serviceIndex); penaltyService.Add(currentService); lastPenaltyService = currentService; foreach (BoxTime boxTime in currentService.BoxTimes) { playerBoxTimes.Remove(boxTime); } Console.WriteLine(string.Format("{0}: {1} did not start in box", jam.ToString(), player.Number)); } } else if (lastPenaltyService != null && CompareJams(_jams.First(j => j.ID == lastPenaltyService.BoxTimes.Last().JamID), _jams.First(j => j.ID == penalty.JamID)) >= 0) { // this penalty fits into the last service lastPenaltyService.Penalties.Add(penalty); playerPenalties.RemoveAt(penaltyIndex); } else { int prevJamID = GetPreviousJamID(serviceStart.JamID); int nextJamID = GetNextJamID(penalty.JamID); if (prevJamID != -1 && nextJamID != -1 && !serviceStart.IsJammer && serviceStart.StartedJamInBox == true && jamFullBoxMap.ContainsKey(prevJamID) && jamFullBoxMap[prevJamID] && GetNextJamID(nextJamID) == serviceStart.JamID) { Player player = _players.Values.First(p => p.ID == penalty.PlayerID); Jam jam = _jams.First(j => j.ID == serviceStart.JamID); Jam jam2 = _jams.First(j => j.ID == penalty.JamID); Console.WriteLine(string.Format("{0}: {1} did not fit in the box in {2}", jam.ToString(), player.Number, jam2.ToString())); // there was no room in the box during the next jam, // so see if they started in the box in the subsequent jam // this penalty can be applied to this service currentService.Penalties.Add(penalty); playerPenalties.RemoveAt(penaltyIndex); servicesBoxed.RemoveAt(serviceIndex); penaltyService.Add(currentService); lastPenaltyService = currentService; foreach (BoxTime boxTime in currentService.BoxTimes) { playerBoxTimes.Remove(boxTime); } } else if (penalty.PenaltyNumber < 7) { // subsequent jam Player player = _players.Values.First(p => p.ID == penalty.PlayerID); Jam jam = _jams.First(j => j.ID == penalty.JamID); Console.WriteLine(string.Format("{0}: {1} missing penalty service", jam.ToString(), player.Number)); penaltyIndex++; } else { serviceIndex++; } } } else if (lastPenaltyService != null && CompareJams(_jams.First(j => j.ID == lastPenaltyService.BoxTimes.Last().JamID), _jams.First(j => j.ID == penalty.JamID)) >= 0 && (penalty.PenaltyNumber < 7 || lastPenaltyService.BoxTimes.Last().EndedJamInBox)) { // if this player previously served time in the box, that service may be for this penalty if: // 1) this penalty occurred before that box service ended, and // 2) if it was a foul out, the service did not end with the player back on the track lastPenaltyService.Penalties.Add(penalty); playerPenalties.RemoveAt(penaltyIndex); } else { penaltyIndex++; } } // run through to see if any of the penalties could be given to }