eu.lp0.cursus.scoring.scores.impl.GenericRacePositionsData.java Source code

Java tutorial

Introduction

Here is the source code for eu.lp0.cursus.scoring.scores.impl.GenericRacePositionsData.java

Source

/*
   cursus - Race series management program
   Copyright 2012-2014  Simon Arlott
    
   This program is free software: you can redistribute it and/or modify
   it under the terms of the GNU Affero General Public License as published by
   the Free Software Foundation, either version 3 of the License, or
   (at your option) any later version.
    
   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU Affero General Public License for more details.
    
   You should have received a copy of the GNU Affero General Public License
   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package eu.lp0.cursus.scoring.scores.impl;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;

import com.google.common.base.Predicates;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.LinkedListMultimap;
import com.google.common.collect.Multimaps;
import com.google.common.collect.Ordering;
import com.google.common.collect.Sets;
import com.google.common.collect.TreeMultimap;

import eu.lp0.cursus.db.data.Pilot;
import eu.lp0.cursus.db.data.Race;
import eu.lp0.cursus.scoring.data.RaceLapsData;
import eu.lp0.cursus.scoring.data.RacePenaltiesData;
import eu.lp0.cursus.scoring.data.RacePointsData;
import eu.lp0.cursus.scoring.data.ScoredData;
import eu.lp0.cursus.scoring.scores.base.AbstractRacePositionsData;
import eu.lp0.cursus.util.PilotRaceNumberComparator;

public class GenericRacePositionsData<T extends ScoredData & RaceLapsData & RacePointsData & RacePenaltiesData>
        extends AbstractRacePositionsData<T> {
    private final EqualPositioning equalPositioning;
    private final boolean simulatedToEnd;

    public enum EqualPositioning {
        ALWAYS, WITHOUT_LAPS, NEVER;
    }

    public GenericRacePositionsData(T scores, EqualPositioning equalPositioning) {
        this(scores, equalPositioning, false);
    }

    public GenericRacePositionsData(T scores, EqualPositioning equalPositioning, boolean simulatedToEnd) {
        super(scores);

        this.equalPositioning = equalPositioning;
        this.simulatedToEnd = simulatedToEnd;
    }

    @Override
    protected LinkedListMultimap<Integer, Pilot> calculateRacePositionsWithOrder(Race race) {
        // Create a lap order list containing all pilots
        List<Pilot> lapOrder = new ArrayList<Pilot>(scores.getPilots().size());
        lapOrder.addAll(scores.getLapOrder(race));
        Set<Pilot> pilotsWithLaps = ImmutableSet.copyOf(lapOrder);
        SortedSet<Pilot> pilotsWithoutLaps = new TreeSet<Pilot>(new PilotRaceNumberComparator());
        pilotsWithoutLaps.addAll(Sets.difference(scores.getPilots(), pilotsWithLaps));
        lapOrder.addAll(pilotsWithoutLaps);

        // Add penalties to race points
        Map<Pilot, Integer> racePoints = scores.getRacePoints(race);
        Map<Pilot, Integer> racePenalties = scores.getRacePenalties(race);
        Map<Pilot, Integer> racePointsWithPenalties = new HashMap<Pilot, Integer>(scores.getPilots().size() * 2);
        for (Pilot pilot : scores.getPilots()) {
            racePointsWithPenalties.put(pilot, racePoints.get(pilot) + racePenalties.get(pilot));
        }

        // Invert race points with ordered lists of pilots
        TreeMultimap<Integer, Pilot> invRacePoints = TreeMultimap.create(Ordering.natural(),
                Ordering.explicit(lapOrder));
        Multimaps.invertFrom(Multimaps.forMap(racePointsWithPenalties), invRacePoints);

        // Calculate race positions
        LinkedListMultimap<Integer, Pilot> racePositions = LinkedListMultimap.create();
        LinkedList<SortedSet<Pilot>> pilotPointsOrdering = new LinkedList<SortedSet<Pilot>>();
        int position = 1;

        if (simulatedToEnd) {
            Set<Pilot> simulatedRacePoints = scores.getSimulatedRacePoints(race);
            for (Integer points : invRacePoints.keySet()) {
                SortedSet<Pilot> pilots = Sets.filter(invRacePoints.get(points),
                        Predicates.not(Predicates.in(simulatedRacePoints)));
                if (!pilots.isEmpty()) {
                    pilotPointsOrdering.add(pilots);
                }
            }
            for (Integer points : invRacePoints.keySet()) {
                SortedSet<Pilot> pilots = Sets.filter(invRacePoints.get(points),
                        Predicates.in(simulatedRacePoints));
                if (!pilots.isEmpty()) {
                    pilotPointsOrdering.add(pilots);
                }
            }
        } else {
            for (Integer points : invRacePoints.keySet()) {
                pilotPointsOrdering.add(invRacePoints.get(points));
            }
        }

        for (SortedSet<Pilot> pilots : pilotPointsOrdering) {
            switch (equalPositioning) {
            case ALWAYS:
                // Always put pilots with the same points in the same position
                racePositions.putAll(position, pilots);
                position += pilots.size();
                break;

            case WITHOUT_LAPS:
                // Add everyone with laps (by removing pilots without laps from the set) in separate positions
                for (Pilot pilot : Sets.difference(pilots, pilotsWithoutLaps)) {
                    racePositions.put(position, pilot);
                    position++;
                }

                // Add everyone without laps (by removing pilots with laps from the set) in the same position
                Set<Pilot> pilots2 = Sets.difference(pilots, pilotsWithLaps);
                racePositions.putAll(position, pilots2);
                position += pilots2.size();
                break;

            case NEVER:
                // Always put pilots with the same points in separate positions
                for (Pilot pilot : pilots) {
                    racePositions.put(position, pilot);
                    position++;
                }
                break;
            }
        }

        return racePositions;
    }
}