99import java .util .stream .Collectors ;
1010
1111import javax .annotation .Nullable ;
12+ import javax .annotation .concurrent .Immutable ;
1213import javax .annotation .concurrent .NotThreadSafe ;
1314
1415import com .google .common .base .Optional ;
1516import com .google .common .base .Preconditions ;
1617import com .google .common .collect .HashMultiset ;
1718import com .google .common .collect .ImmutableList ;
19+ import com .google .common .collect .ImmutableMap ;
20+ import com .google .common .collect .ImmutableMultiset ;
1821import com .google .common .collect .ImmutableSet ;
1922import com .google .common .collect .Lists ;
2023import com .google .common .collect .Maps ;
2124import com .google .common .collect .Multiset ;
25+ import com .google .common .collect .Multiset .Entry ;
2226import com .google .common .collect .Ordering ;
2327import com .google .common .collect .SetMultimap ;
2428import com .google .common .collect .Sets ;
@@ -52,6 +56,7 @@ private static class SwissFormatSimulator {
5256 private final int stageNum ;
5357 private final Seeding initialSeeding ;
5458 private final ImmutableList <RoundSpec > rounds ;
59+ private final ImmutableSet <MatchResult > resultsFromEarlierStages ;
5560 private final ImmutableSet <MatchResult > resultsInStage ;
5661 private final Set <MatchSetup > matchesToRun = Sets .newHashSet ();
5762 //TODO: Double-check that all these stats are updated appropriately
@@ -66,28 +71,39 @@ private static class SwissFormatSimulator {
6671 private final List <Ranking > standingsHistory = Lists .newArrayList ();
6772
6873 private SwissFormatSimulator (String tournamentInternalName , int stageNum , Seeding initialSeeding ,
69- ImmutableList <RoundSpec > rounds , ImmutableSet <MatchResult > resultsSoFar ) {
74+ ImmutableList <RoundSpec > rounds , ImmutableSet <MatchResult > resultsFromEarlierStages ,
75+ ImmutableSet <MatchResult > resultsInStage ) {
7076 this .tournamentInternalName = tournamentInternalName ;
7177 this .stageNum = stageNum ;
7278 this .initialSeeding = initialSeeding ;
7379 this .rounds = rounds ;
74- this .resultsInStage = resultsSoFar ;
80+ this .resultsFromEarlierStages = resultsFromEarlierStages ;
81+ this .resultsInStage = resultsInStage ;
7582 }
7683
7784 public static SwissFormatSimulator createAndRun (String tournamentInternalName , int stageNum , Seeding initialSeeding ,
78- ImmutableList <RoundSpec > rounds , Set <MatchResult > resultsSoFar ) {
79- Set <MatchResult > resultsInStage = MatchResults .filterByStage (resultsSoFar , stageNum );
85+ ImmutableList <RoundSpec > rounds , Set <MatchResult > allResultsSoFar ) {
86+ Set <MatchResult > resultsFromEarlierStages = MatchResults .getResultsPriorToStage (allResultsSoFar , stageNum );
87+ Set <MatchResult > resultsInStage = MatchResults .filterByStage (allResultsSoFar , stageNum );
8088 SwissFormatSimulator simulator = new SwissFormatSimulator (tournamentInternalName , stageNum , initialSeeding ,
81- rounds , ImmutableSet .copyOf (resultsInStage ));
89+ rounds , ImmutableSet .copyOf (resultsFromEarlierStages ), ImmutableSet . copyOf ( resultsInStage ));
8290 simulator .run ();
8391 return simulator ;
8492 }
8593
8694 private void run () {
8795 setInitialTotalsToZero ();
88-
96+ int roundNum = 0 ;
8997 SetMultimap <Integer , MatchResult > matchesByRound = MatchResults .mapByRound (resultsInStage , stageNum );
90- for (int roundNum = 0 ; roundNum < rounds .size (); roundNum ++) {
98+
99+ @ Nullable EndOfRoundState endOfRoundState = TournamentStateCache .getLatestCachedEndOfRoundState (tournamentInternalName , initialSeeding , resultsFromEarlierStages , stageNum , resultsInStage );
100+ if (endOfRoundState != null ) {
101+ Swiss1EndOfRoundState state = (Swiss1EndOfRoundState ) endOfRoundState ;
102+ roundNum = state .roundNum + 1 ;
103+ loadCachedState (state );
104+ }
105+
106+ for (/* roundNum already set */ ; roundNum < rounds .size (); roundNum ++) {
91107 RoundSpec round = rounds .get (roundNum );
92108 Set <MatchResult > roundResults = matchesByRound .get (roundNum );
93109 runRound (round , roundNum , roundResults );
@@ -96,13 +112,48 @@ private void run() {
96112 return ;
97113 }
98114 //If we didn't run the round due to the number of players being too low,
99- //skip the standings
115+ //skip the standings and caching
100116 if (!roundResults .isEmpty ()) {
101117 standingsHistory .add (getStandings ());
118+ Swiss1EndOfRoundState state = Swiss1EndOfRoundState .create (roundNum ,
119+ mostRecentGame , totalPointsScored , pointsScoredByGame ,
120+ pointsFromByes , totalMatchupsSoFar , matchupsSoFarByGame ,
121+ nonFixedSumMatchupsSoFarByNumPlayers , standingsHistory );
122+
123+ TournamentStateCache .cacheEndOfRoundState (tournamentInternalName , initialSeeding , resultsFromEarlierStages , stageNum , resultsInStage , state );
102124 }
103125 }
104126 }
105127
128+ private void loadCachedState (Swiss1EndOfRoundState state ) {
129+ totalPointsScored .putAll (state .totalPointsScored );
130+ pointsFromByes .putAll (state .pointsFromByes );
131+
132+ Set <Integer > possiblePlayerCounts = Sets .newHashSet ();
133+ for (Game game : RoundSpec .getAllGames (rounds )) {
134+ Map <Player , Double > pointsScoredForGame = pointsScoredByGame .get (game );
135+ for (Player player : initialSeeding .getPlayersBestFirst ()) {
136+ pointsScoredForGame .put (player , state .pointsScoredByGame .get (game ).get (player ));
137+ }
138+ for (Entry <ImmutableSet <Player >> entry : state .matchupsSoFarByGame .get (game ).entrySet ()) {
139+ matchupsSoFarByGame .get (game ).add (Sets .newHashSet (entry .getElement ()), entry .getCount ());
140+ }
141+ possiblePlayerCounts .add (game .getNumRoles ());
142+ }
143+ for (int playerCount : possiblePlayerCounts ) {
144+ for (Entry <ImmutableSet <Player >> entry : state .nonFixedSumMatchupsSoFarByNumPlayers .get (playerCount ).entrySet ()) {
145+ nonFixedSumMatchupsSoFarByNumPlayers .get (playerCount ).add (Sets .newHashSet (entry .getElement ()), entry .getCount ());
146+ }
147+ }
148+
149+ mostRecentGame = state .mostRecentGame ;
150+ standingsHistory .addAll (state .standingsHistory );
151+
152+ for (Entry <ImmutableSet <Player >> entry : state .totalMatchupsSoFar .entrySet ()) {
153+ totalMatchupsSoFar .add (Sets .newHashSet (entry .getElement ()), entry .getCount ());
154+ }
155+ }
156+
106157 private void runRound (RoundSpec round , int roundNum , Set <MatchResult > roundResults ) {
107158 //...there should be only one match per round, I think?
108159 //Or at least they must involve the same game?
@@ -160,7 +211,6 @@ private void runRound(RoundSpec round, int roundNum, Set<MatchResult> roundResul
160211 }
161212 //Also...
162213 updateMatchupStats (game , playerGroups );
163- // this.mostRecentGame = game;
164214 }
165215 }
166216
@@ -584,4 +634,173 @@ public void validateRounds(ImmutableList<RoundSpec> rounds) {
584634 getOnlyGame (round );
585635 }
586636 }
637+
638+ @ Immutable
639+ private static class Swiss1EndOfRoundState implements EndOfRoundState {
640+ private final int roundNum ;
641+ private final Game mostRecentGame ;
642+ private final ImmutableMap <Player , Double > totalPointsScored ;
643+ private final ImmutableMap <Game , ImmutableMap <Player , Double >> pointsScoredByGame ;
644+ private final ImmutableMap <Player , Double > pointsFromByes ;
645+ private final ImmutableMultiset <ImmutableSet <Player >> totalMatchupsSoFar ;
646+ private final ImmutableMap <Game , ImmutableMultiset <ImmutableSet <Player >>> matchupsSoFarByGame ;
647+ private final ImmutableMap <Integer , ImmutableMultiset <ImmutableSet <Player >>> nonFixedSumMatchupsSoFarByNumPlayers ;
648+ private final ImmutableList <Ranking > standingsHistory ;
649+
650+ private Swiss1EndOfRoundState (int roundNum , Game mostRecentGame , ImmutableMap <Player , Double > totalPointsScored ,
651+ ImmutableMap <Game , ImmutableMap <Player , Double >> pointsScoredByGame ,
652+ ImmutableMap <Player , Double > pointsFromByes , ImmutableMultiset <ImmutableSet <Player >> totalMatchupsSoFar ,
653+ ImmutableMap <Game , ImmutableMultiset <ImmutableSet <Player >>> matchupsSoFarByGame ,
654+ ImmutableMap <Integer , ImmutableMultiset <ImmutableSet <Player >>> nonFixedSumMatchupsSoFarByNumPlayers ,
655+ ImmutableList <Ranking > standingsHistory ) {
656+ this .roundNum = roundNum ;
657+ this .mostRecentGame = mostRecentGame ;
658+ this .totalPointsScored = totalPointsScored ;
659+ this .pointsScoredByGame = pointsScoredByGame ;
660+ this .pointsFromByes = pointsFromByes ;
661+ this .totalMatchupsSoFar = totalMatchupsSoFar ;
662+ this .matchupsSoFarByGame = matchupsSoFarByGame ;
663+ this .nonFixedSumMatchupsSoFarByNumPlayers = nonFixedSumMatchupsSoFarByNumPlayers ;
664+ this .standingsHistory = standingsHistory ;
665+ }
666+
667+ public static Swiss1EndOfRoundState create (int roundNum ,
668+ Game mostRecentGame ,
669+ Map <Player , Double > totalPointsScored ,
670+ Map <Game , Map <Player , Double >> pointsScoredByGame ,
671+ Map <Player , Double > pointsFromByes ,
672+ Multiset <Set <Player >> totalMatchupsSoFar ,
673+ Map <Game , Multiset <Set <Player >>> matchupsSoFarByGame ,
674+ Map <Integer , Multiset <Set <Player >>> nonFixedSumMatchupsSoFarByNumPlayers ,
675+ List <Ranking > standingsHistory ) {
676+ return new Swiss1EndOfRoundState (roundNum ,
677+ mostRecentGame ,
678+ ImmutableMap .copyOf (totalPointsScored ),
679+ toImmutableMapValuedMap (pointsScoredByGame ),
680+ ImmutableMap .copyOf (pointsFromByes ),
681+ toImmutableSetEntriedMultiset (totalMatchupsSoFar ),
682+ toImmutableMultisetOfSetsValuedMap (matchupsSoFarByGame ),
683+ toImmutableMultisetOfSetsValuedMap (nonFixedSumMatchupsSoFarByNumPlayers ),
684+ ImmutableList .copyOf (standingsHistory ));
685+ }
686+
687+ private static <K ,T > ImmutableMap <K , ImmutableMultiset <ImmutableSet <T >>> toImmutableMultisetOfSetsValuedMap (
688+ Map <K , Multiset <Set <T >>> map ) {
689+ return ImmutableMap .copyOf (Maps .transformValues (map , Swiss1EndOfRoundState ::toImmutableSetEntriedMultiset ));
690+ }
691+
692+ private static <T > ImmutableMultiset <ImmutableSet <T >> toImmutableSetEntriedMultiset (
693+ Multiset <Set <T >> multiset ) {
694+ ImmutableMultiset .Builder <ImmutableSet <T >> builder = ImmutableMultiset .builder ();
695+ for (Entry <Set <T >> entry : multiset .entrySet ()) {
696+ builder .addCopies (ImmutableSet .copyOf (entry .getElement ()), entry .getCount ());
697+ }
698+ return builder .build ();
699+ }
700+
701+ private static <K1 ,K2 ,V2 > ImmutableMap <K1 , ImmutableMap <K2 , V2 >> toImmutableMapValuedMap (
702+ Map <K1 , Map <K2 , V2 >> map ) {
703+ return ImmutableMap .copyOf (Maps .transformValues (map , ImmutableMap ::copyOf ));
704+ }
705+
706+ @ Override
707+ public int hashCode () {
708+ final int prime = 31 ;
709+ int result = 1 ;
710+ result = prime * result + ((matchupsSoFarByGame == null ) ? 0 : matchupsSoFarByGame .hashCode ());
711+ result = prime * result + ((mostRecentGame == null ) ? 0 : mostRecentGame .hashCode ());
712+ result = prime * result + ((nonFixedSumMatchupsSoFarByNumPlayers == null ) ? 0
713+ : nonFixedSumMatchupsSoFarByNumPlayers .hashCode ());
714+ result = prime * result + ((pointsFromByes == null ) ? 0 : pointsFromByes .hashCode ());
715+ result = prime * result + ((pointsScoredByGame == null ) ? 0 : pointsScoredByGame .hashCode ());
716+ result = prime * result + roundNum ;
717+ result = prime * result + ((standingsHistory == null ) ? 0 : standingsHistory .hashCode ());
718+ result = prime * result + ((totalMatchupsSoFar == null ) ? 0 : totalMatchupsSoFar .hashCode ());
719+ result = prime * result + ((totalPointsScored == null ) ? 0 : totalPointsScored .hashCode ());
720+ return result ;
721+ }
722+
723+ @ Override
724+ public boolean equals (Object obj ) {
725+ if (this == obj ) {
726+ return true ;
727+ }
728+ if (obj == null ) {
729+ return false ;
730+ }
731+ if (getClass () != obj .getClass ()) {
732+ return false ;
733+ }
734+ Swiss1EndOfRoundState other = (Swiss1EndOfRoundState ) obj ;
735+ if (matchupsSoFarByGame == null ) {
736+ if (other .matchupsSoFarByGame != null ) {
737+ return false ;
738+ }
739+ } else if (!matchupsSoFarByGame .equals (other .matchupsSoFarByGame )) {
740+ return false ;
741+ }
742+ if (mostRecentGame == null ) {
743+ if (other .mostRecentGame != null ) {
744+ return false ;
745+ }
746+ } else if (!mostRecentGame .equals (other .mostRecentGame )) {
747+ return false ;
748+ }
749+ if (nonFixedSumMatchupsSoFarByNumPlayers == null ) {
750+ if (other .nonFixedSumMatchupsSoFarByNumPlayers != null ) {
751+ return false ;
752+ }
753+ } else if (!nonFixedSumMatchupsSoFarByNumPlayers .equals (other .nonFixedSumMatchupsSoFarByNumPlayers )) {
754+ return false ;
755+ }
756+ if (pointsFromByes == null ) {
757+ if (other .pointsFromByes != null ) {
758+ return false ;
759+ }
760+ } else if (!pointsFromByes .equals (other .pointsFromByes )) {
761+ return false ;
762+ }
763+ if (pointsScoredByGame == null ) {
764+ if (other .pointsScoredByGame != null ) {
765+ return false ;
766+ }
767+ } else if (!pointsScoredByGame .equals (other .pointsScoredByGame )) {
768+ return false ;
769+ }
770+ if (roundNum != other .roundNum ) {
771+ return false ;
772+ }
773+ if (standingsHistory == null ) {
774+ if (other .standingsHistory != null ) {
775+ return false ;
776+ }
777+ } else if (!standingsHistory .equals (other .standingsHistory )) {
778+ return false ;
779+ }
780+ if (totalMatchupsSoFar == null ) {
781+ if (other .totalMatchupsSoFar != null ) {
782+ return false ;
783+ }
784+ } else if (!totalMatchupsSoFar .equals (other .totalMatchupsSoFar )) {
785+ return false ;
786+ }
787+ if (totalPointsScored == null ) {
788+ if (other .totalPointsScored != null ) {
789+ return false ;
790+ }
791+ } else if (!totalPointsScored .equals (other .totalPointsScored )) {
792+ return false ;
793+ }
794+ return true ;
795+ }
796+
797+ @ Override
798+ public String toString () {
799+ return "Swiss1EndOfRoundState [roundNum=" + roundNum + ", mostRecentGame=" + mostRecentGame
800+ + ", totalPointsScored=" + totalPointsScored + ", pointsScoredByGame=" + pointsScoredByGame
801+ + ", pointsFromByes=" + pointsFromByes + ", totalMatchupsSoFar=" + totalMatchupsSoFar
802+ + ", matchupsSoFarByGame=" + matchupsSoFarByGame + ", nonFixedSumMatchupsSoFarByNumPlayers="
803+ + nonFixedSumMatchupsSoFarByNumPlayers + ", standingsHistory=" + standingsHistory + "]" ;
804+ }
805+ }
587806}
0 commit comments