View Javadoc

1   /**
2    * This program is free software: you can redistribute it and/or modify
3    * it under the terms of the GNU General Public License as published by
4    * the Free Software Foundation, version 3.
5    *
6    * This program is distributed in the hope that it will be useful,
7    * but WITHOUT ANY WARRANTY; without even the implied warranty of
8    * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9    * GNU General Public License for more details.
10   *
11   * You should have received a copy of the GNU General Public License
12   * along with this program. If not, see <http://www.gnu.org/licenses/>.
13   */
14  
15  package net.curre.prefcount.service;
16  
17  import java.util.Map;
18  import java.util.logging.Level;
19  import java.util.logging.Logger;
20  
21  import net.curre.prefcount.bean.GameResultBean;
22  import net.curre.prefcount.bean.PlayerStatistics;
23  import net.curre.prefcount.gui.type.Place;
24  import net.curre.prefcount.PrefCountRegistry;
25  
26  /**
27   * This service bean is responsible for
28   * computing game results.
29   * <p/>
30   * Created date: Jul 29, 2007
31   *
32   * @author Yevgeny Nyden
33   */
34  public class ResultService {
35  
36    /** Private class logger. */
37    private static Logger log = Logger.getLogger(ResultService.class.toString());
38  
39    /**
40     * Generates the final player scores. Note that the target
41     * pool must be set to a valid (positive) value.
42     *
43     * @param rBean <code>GameResultBean</code> object that contains
44     *              all necessary game data.
45     */
46    public static void generateFinalResults(GameResultBean rBean) {
47  
48      if (log.isLoggable(Level.FINE)) {
49        log.fine("Generating final results for Bean: " + rBean);
50      }
51  
52      // computing the average and minimum mountain
53      int min = Integer.MAX_VALUE;
54      int sum = 0;
55      int playersNum = rBean.getPlayerStats().size();
56      for (Map.Entry<Place, PlayerStatistics> entry : rBean.getPlayerStats().entrySet()) {
57        PlayerStatistics stats = entry.getValue();
58        int currMountain = stats.getNewMountain();
59        sum += currMountain;
60        if (currMountain < min) {
61          min = currMountain;
62        }
63  
64        // resetting mount fix and whist values maps
65        stats.setMountFix(null);
66        stats.getWhistFixesMap().clear();
67        stats.getWhistSaldoMap().clear();
68      }
69  
70      rBean.setMinMountain(min);
71  
72      // determining the mount fix for the "divisible by N" option
73      int mountFix = 0;
74      if (rBean.isMountDivisibleByN()) {
75        final int remainder = (sum - min * playersNum) % playersNum;
76  
77        if (remainder != 0) {
78          askForAdjustmentPlayer();
79        }
80  
81        mountFix = doFixForDivisibleByN(remainder, rBean.getDivisibleByNPlayer(), rBean.getPlayerStats());
82      }
83      rBean.setAverageMountain((float) (sum + mountFix) / (float) playersNum - min);
84  
85      // computing the whists saldo/balances
86      for (Map.Entry<Place, PlayerStatistics> currEntry : rBean.getPlayerStats().entrySet()) {
87        PlayerStatistics currStats = currEntry.getValue();
88        Place currPlace = currEntry.getKey();
89        int totalSaldo = 0;
90        for (Map.Entry<Place, PlayerStatistics> otherEntry : rBean.getPlayerStats().entrySet()) {
91          Place otherPlace = otherEntry.getKey();
92          PlayerStatistics otherStats = otherEntry.getValue();
93          if (currPlace != otherPlace) {
94            Integer whistSaldo = currStats.getWhistSaldoMap().get(otherPlace);
95            if (whistSaldo == null) {
96              int currWhist = currStats.getWhistsAgainstPlayer(otherPlace);
97              Integer currwhistFix = currStats.getWhistFixAgainstPlayer(otherPlace);
98              if (currwhistFix != null) {
99                currWhist += currwhistFix;
100             }
101             int whistAgainst = otherStats.getWhistsAgainstPlayer(currPlace);
102             Integer whistFixAgainst = otherStats.getWhistFixAgainstPlayer(currPlace);
103             if (whistFixAgainst != null) {
104               whistAgainst += whistFixAgainst;
105             }
106             whistSaldo = currWhist - whistAgainst;
107             currStats.getWhistSaldoMap().put(otherPlace, whistSaldo);
108             otherStats.getWhistSaldoMap().put(currPlace, -1 * whistSaldo);
109           }
110           totalSaldo += whistSaldo;
111         }
112       }
113       // saving total saldo under the same (as the player's place) key
114       currStats.getWhistSaldoMap().put(currEntry.getKey(), totalSaldo);
115     }
116     rBean.setFinalScoresReady();
117   }
118 
119   /**
120    * Clears the final player scores.
121    *
122    * @param rBean <code>GameResultBean</code> object that contains
123    *              all necessary game data.
124    */
125   public static void clearFinalResults(GameResultBean rBean) {
126     // clearing the player whist saldo maps
127     for (PlayerStatistics stats : rBean.getPlayerStats().values()) {
128       stats.getWhistSaldoMap().clear();
129     }
130     rBean.clearResults();
131   }
132 
133   /** Private methods ***********************/
134 
135   /**
136    * Computes and sets the additional mount and whist fields
137    * for the "Divisible by N" option.
138    *
139    * @param remainder   mount remainder.
140    * @param adjustPlace adjustment player's place.
141    * @param playerStats list of player statistics beans.
142    * @return computed mount fix that will make the sum of mounts divisible by N.
143    */
144   private static int doFixForDivisibleByN(int remainder, Place adjustPlace,
145                                           Map<Place, PlayerStatistics> playerStats) {
146     int mountFix = 0;
147 
148     if (remainder != 0) {
149       final int playersNum = playerStats.size();
150 
151       if (playersNum == 4) {
152         if (remainder == 1) {
153           // subtracting 1 from the adjustment player
154           PlayerStatistics stats = playerStats.get(adjustPlace);
155           stats.setMountFix(-1);
156           mountFix = -1;
157           // writing the whists against this player
158           addWhistsFixAgainstSelf(playerStats, adjustPlace, 3);
159 
160         } else if (remainder == 2) {
161           // nothing for the remainder 2
162 
163         } else if (remainder == 3) {
164           // adding 1 to the adjustment player
165           PlayerStatistics stats = playerStats.get(adjustPlace);
166           stats.setMountFix(1);
167           mountFix = 1;
168           // writing the whists against other players
169           addWhistsFixAgainstOthers(playerStats, adjustPlace, 3);
170         }
171 
172       } else {
173         if (remainder == 1) {
174           // subtracting 1 from the adjustment player
175           PlayerStatistics stats = playerStats.get(adjustPlace);
176           stats.setMountFix(-1);
177           mountFix = -1;
178           // writing the whists against this player
179           addWhistsFixAgainstSelf(playerStats, adjustPlace, 3);
180 
181         } else if (remainder == 2) {
182           // adding 1 to the adjustment player
183           PlayerStatistics stats = playerStats.get(adjustPlace);
184           stats.setMountFix(1);
185           mountFix = 1;
186           // writing the whists against other players
187           addWhistsFixAgainstOthers(playerStats, adjustPlace, 3);
188         }
189       }
190     }
191     return mountFix;
192   }
193 
194   /**
195    * Assists with choosing the adjustment player for the
196    * mount divisibility "Divisible by N" option. Note, that in
197    * debug mode (when MainWindow is not visible) this player is
198    * always set to EAST.
199    */
200   private static void askForAdjustmentPlayer() {
201     PrefCountRegistry reg = PrefCountRegistry.getInstance();
202     boolean notDebug = reg.getMainWindow() != null && reg.getMainWindow().isVisible();
203     if (notDebug) {
204       PrefCountRegistry.getInstance().getChoosePlayerDialog();
205     }
206   }
207 
208   /**
209    * Adds whist (additional whist fixes for the "divisible by N" option)
210    * agains all other players provided the current player index.
211    *
212    * @param playerStats list of player statistics beans.
213    * @param place       current player place.
214    * @param value       whist value to add.
215    */
216   private static void addWhistsFixAgainstOthers(Map<Place, PlayerStatistics> playerStats,
217                                                 Place place, int value) {
218     PlayerStatistics stats = playerStats.get(place);
219     for (Map.Entry<Place, PlayerStatistics> entry : playerStats.entrySet()) {
220       if (entry.getKey() != place) {
221         stats.getWhistFixesMap().put(entry.getKey(), value);
222       }
223     }
224   }
225 
226   /**
227    * Adds whist (additional whist fixes for the "divisible by N" option)
228    * for all players agains the given player.
229    *
230    * @param playerStats list of player statistics beans.
231    * @param place       current player place.
232    * @param value       whist value to add.
233    */
234   private static void addWhistsFixAgainstSelf(Map<Place, PlayerStatistics> playerStats,
235                                               Place place, int value) {
236     for (Map.Entry<Place, PlayerStatistics> entry : playerStats.entrySet()) {
237       if (entry.getKey() != place) {
238         entry.getValue().getWhistFixesMap().put(place, value);
239       }
240     }
241   }
242 
243 }