Пример #1
0
        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);
        }
Пример #2
0
        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");
            }
        }
Пример #3
0
        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);
        }
Пример #4
0
        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);
            }
        }
Пример #5
0
        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);
        }
Пример #6
0
        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);
        }
Пример #7
0
        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));
                }
            }
        }
Пример #8
0
        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);
                            }
                        }
                    }
                }
            }
        }
Пример #9
0
        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;
                }
            }
        }
Пример #10
0
        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.");
            }
        }
Пример #11
0
        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
        }