001 ///////////////////////////////////////////////////////////////////////////////
002 // Copyright (c) 2006, Frank S. Nestel, All Rights Reserved.
003 //
004 // This library is free software; you can redistribute it and/or
005 // modify it under the terms of the GNU Lesser General Public
006 // License as published by the Free Software Foundation; either
007 // version 2.1 of the License, or (at your option) any later version.
008 //
009 // This library is distributed in the hope that it will be useful,
010 // but WITHOUT ANY WARRANTY; without even the implied warranty of
011 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
012 // GNU General Public License for more details.
013 //
014 // You should have received a copy of the GNU Lesser General Public
015 // License along with this program; if not, write to the Free Software
016 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
017 ///////////////////////////////////////////////////////////////////////////////
018
019 package de.spieleck.app.turn;
020
021 import java.io.File;
022 import java.io.IOException;
023 import java.io.PrintWriter;
024 import java.io.InputStreamReader;
025 import java.util.ArrayList;
026 import java.util.Random;
027 import java.util.Iterator;
028 import java.util.Random;
029
030 import org.apache.log4j.Logger;
031
032 import gnu.trove.TIntObjectHashMap;
033
034 /**
035 * The Simulator is a tool to create artifical game results.
036 * <br />
037 * The artificial game results follow prescribed distributions
038 * depending on the {@link ScoringMode} employed.
039 * <br />
040 * The Simulator corresponds to the {@link Run} facade since
041 * it actually patches the "internal" fileformats of it with
042 * its artificial results.
043 *
044 * <p><a href="$URL: https://svn.sourceforge.net/svnroot/jtourney/src/de/spieleck/app/turn/Simulator.java $">$URL: https://svn.sourceforge.net/svnroot/jtourney/src/de/spieleck/app/turn/Simulator.java $</a></p>
045 *
046 * @author Frank S. Nestel
047 * @author $Author: nestefan $
048 * @version $Revision: 2 $ $Date: 2006-03-20 14:33:27 +0100 (Mo, 20 Mrz 2006) $ $Author: nestefan $
049 */
050 public class Simulator
051 extends Run
052 {
053 private final static Logger L = Logger.getLogger(Simulator.class);
054
055 private TIntObjectHashMap samples = new TIntObjectHashMap();
056
057 private Random rand = new Random();
058
059 public static void main(String[] args)
060 {
061 File fi = new File(args[0]);
062 if ( !fi.isDirectory() )
063 {
064 L.error("First param must be a directory.");
065 return;
066 }
067 try
068 {
069 Simulator sim = new Simulator();
070 sim.init(fi);
071 sim.readSamples();
072 sim.sim();
073 }
074 catch ( Exception e )
075 {
076 e.printStackTrace();
077 }
078 }
079
080 /**
081 * Read scoring samples for the given scoring mode.
082 */
083 public void readSamples()
084 throws Exception
085 {
086 String simType = scoringMode.toString();
087 InputStreamReader ir = new InputStreamReader(getClass()
088 .getResourceAsStream("samples-"+simType));
089 LineSource ls = new LineSource(ir);
090 int count = 0;
091 while ( true )
092 {
093 String line = ls.line();
094 if ( line == null ) break;
095 String[] pieces = FileProxy.SPLITTER.split(line);
096 PlayerGameScore pgs[] = new PlayerGameScore[pieces.length];
097 for(int i = 0; i < pgs.length; i++)
098 {
099 pgs[i] = scoringMode.parseRawScore(pieces[i]);
100 }
101 String msg = scoringMode.checkScore(pgs);
102 if ( msg != null )
103 {
104 throw new Exception("Invalid score in <"+line+">: "+msg);
105 }
106 // Need it unadjusted ! pgs = scoringMode.adjustScore(pgs);
107 ArrayList<PlayerGameScore[]> l =
108 (ArrayList<PlayerGameScore[]>) samples.get(pgs.length);
109 if ( l == null )
110 {
111 l = new ArrayList<PlayerGameScore[]>();
112 samples.put(pgs.length, l);
113 }
114 l.add(pgs);
115 count++;
116 }
117 L.info("Number of simulation samples for "+simType+" = "+count);
118 }
119
120
121 private void sim()
122 throws Exception
123 {
124 if ( round <= 1 )
125 {
126 L.warn("Nothing to simulate.");
127 return;
128 }
129 String roundName = FileProxy.makeRoundName(round - 1);
130 LineSource ls;
131 ls = new LineSource(root, roundName);
132 GameResult[] results = fileProx.readRound(ls, false);
133 for(int i = 0; i < results.length; i++)
134 {
135 // choose a random result for the right number of players
136 int l = results[i].size();
137 ArrayList<PlayerGameScore[]> list =
138 (ArrayList<PlayerGameScore[]>) samples.get(l);
139 int r = rand.nextInt(list.size());
140 PlayerGameScore[] pgs = list.get(r);
141 // Mix the random result with the read players to a new result
142 GameResult newResult = new GameResult(results[i].getId());
143 Iterator<Player> iter = results[i].players();
144 for(int j = 0; j < l; j++)
145 {
146 newResult.add(iter.next(), pgs[j]);
147 }
148 results[i] = newResult;
149 }
150 PrintWriter pw = writer(roundName);
151 fileProx.writeRound(pw, "Simulated", results);
152 }
153 }