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 }