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    }