1 /*******************************************************************************
2 * jhunters: Pool League
3 * Copyright 2015 Tony Washer
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 ********************************************************************************/
17 package net.sourceforge.jhunters.pool.data;
18
19 import java.security.SecureRandom;
20 import java.time.LocalDate;
21 import java.util.ArrayList;
22 import java.util.Collections;
23 import java.util.HashMap;
24 import java.util.Iterator;
25 import java.util.List;
26 import java.util.Map;
27
28 /**
29 * Fixture Generator.
30 */
31 public class FixtureGenerator {
32 /**
33 * Map of players.
34 */
35 private final Map<Integer, Player> theMap;
36
37 /**
38 * List of players.
39 */
40 private final List<Player> thePlayers;
41
42 /**
43 * SecureRandom instance.
44 */
45 private final SecureRandom theRandom;
46
47 /**
48 * The number of players.
49 */
50 private Integer theNumPlayers;
51
52 /**
53 * Do we have a bye each week?
54 */
55 private boolean hasBye;
56
57 /**
58 * The maximum player.
59 */
60 private Integer theMaxPlayer;
61
62 /**
63 * Constructor.
64 */
65 public FixtureGenerator() {
66 /* Create the map and list */
67 theMap = new HashMap<Integer, Player>();
68 thePlayers = new ArrayList<Player>();
69
70 /* Create the secureRandom instance */
71 theRandom = new SecureRandom();
72 theRandom.setSeed(System.nanoTime());
73 }
74
75 /**
76 * Set the player list.
77 * @param pPlayers the players
78 */
79 public void setPlayers(final PlayerList pPlayers) {
80 /* Reset the list */
81 thePlayers.clear();
82
83 /* Build the map */
84 Iterator<Player> myIterator = pPlayers.playerIterator();
85 while (myIterator.hasNext()) {
86 Player myPlayer = myIterator.next();
87
88 /* Only copy selected players */
89 if (myPlayer.isSelected()) {
90 /* Store player in the list */
91 thePlayers.add(myPlayer);
92 }
93 }
94
95 /* Store various details */
96 theNumPlayers = thePlayers.size();
97 hasBye = (theNumPlayers % 2) != 0;
98 theMaxPlayer = hasBye
99 ? theNumPlayers
100 : theNumPlayers - 1;
101 }
102
103 /**
104 * randomise the players.
105 */
106 private void randomisePlayers() {
107 /* Reset the map */
108 theMap.clear();
109
110 /* Shuffle the players */
111 Collections.shuffle(thePlayers, theRandom);
112
113 /* Build the map */
114 int i = 1;
115 Iterator<Player> myIterator = thePlayers.iterator();
116 while (myIterator.hasNext()) {
117 Player myPlayer = myIterator.next();
118
119 /* Store player in the map */
120 theMap.put(i++, myPlayer);
121 }
122 }
123
124 /**
125 * Create CompetitionFixtures.
126 * @param pDate the starting date
127 * @return the fixtures
128 */
129 public FixtureList createFixtures(final LocalDate pDate) {
130 /* create the fixture set */
131 FixtureList myFixtures = new FixtureList();
132
133 /* Randomise the players */
134 randomisePlayers();
135
136 /* Loop through the players */
137 for (int i = 1; i <= theMaxPlayer; i++) {
138 /* Create fixture set */
139 FixtureSet mySet = createFixtureSet(i);
140
141 /* Add it to the competition */
142 myFixtures.addFixtureSet(mySet);
143 }
144
145 /* If we do not actually have a bye fixture */
146 if (!hasBye) {
147 /* record the final player in place of the bye */
148 myFixtures.setByePlayer(theMap.get(theNumPlayers));
149 }
150
151 /* randomise the fixtures */
152 myFixtures.randomise(theRandom);
153
154 /* Set dates for fixtures */
155 myFixtures.setDates(pDate);
156
157 /* return the fixture list */
158 return myFixtures;
159 }
160
161 /**
162 * Create FixtureSet.
163 * @param pBye the player top receive a bye
164 * @return the fixture set
165 */
166 private FixtureSet createFixtureSet(final Integer pBye) {
167 /* create the fixture set */
168 FixtureSet mySet = new FixtureSet();
169
170 /* Determine number of fixtures */
171 int myNumFixtures = theMaxPlayer / 2;
172
173 /* Determine number of players */
174 int myHome = pBye + 1;
175 int myAway = pBye - 1;
176
177 /* Loop through the fixtures */
178 for (int i = 0; i < myNumFixtures; i++) {
179 /* Adjust for boundaries */
180 if (myHome > theMaxPlayer) {
181 myHome = 1;
182 }
183 if (myAway == 0) {
184 myAway = theMaxPlayer;
185 }
186
187 /* generate the fixture */
188 mySet.addFixture(theMap.get(myHome), theMap.get(myAway));
189
190 /* Adjust players */
191 myHome++;
192 myAway--;
193 }
194
195 /* generate the bye fixture */
196 if ((pBye % 2) == 0) {
197 mySet.addFixture(theMap.get(pBye), null);
198 } else {
199 mySet.addFixture(null, theMap.get(pBye));
200 }
201
202 /* return the fixture list */
203 return mySet;
204 }
205 }