PageRenderTime 44ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/java/org/bolson/vote/countvotes.java

https://code.google.com/p/voteutil/
Java | 448 lines | 406 code | 10 blank | 32 comment | 153 complexity | 5b342122789d4e751310a7e29d2cd2e8 MD5 | raw file
  1. package org.bolson.vote;
  2. import java.io.BufferedReader;
  3. import java.io.InputStream;
  4. import java.io.InputStreamReader;
  5. import java.io.PrintWriter;
  6. import java.util.Vector;
  7. /**
  8. * command line utility for counting votes.
  9. @author Brian Olson
  10. */
  11. public class countvotes {
  12. // TODO WRITEME comma-separated-value input mode
  13. // TODO WRITEME interpret number values as 1,2,3... rankings
  14. public static final String[] usage = {
  15. "countvotes [--urlencoded|--whitespace|--votespec][--histMax n][--histMin n][-m method.class.name]",
  16. "\t[-i votedata|-igz gzipped-votedata]",
  17. "\t[--dump][--disable-all][--enable-all][--seats n]",
  18. "\t[--disable method][--enable method][--explain][--full-html|--no-full-html|--text|--short]",
  19. "\t[--histMax n][--histMin n][--rankings]",
  20. "\t[--time]",
  21. "\t[-- args to methods [debug]] < votedata"
  22. };
  23. public static void printUsage() {
  24. for ( int i = 0; i < usage.length; i++ ) {
  25. System.err.println(usage[i]);
  26. }
  27. }
  28. public static class ShortNameClassName {
  29. public String shortName;
  30. public String className;
  31. public boolean enabled;
  32. public boolean testable;
  33. /**
  34. @param short_name
  35. @param class_name
  36. */
  37. public ShortNameClassName(String short_name, String class_name) {
  38. shortName = short_name;
  39. className = class_name;
  40. enabled = false;
  41. testable = true;
  42. }
  43. /**
  44. @param short_name
  45. @param class_name
  46. @param default_enabled Set whether method will be in the default enabled set of methods before --enable --disable command line options.
  47. @param test_enabled this method will be included in --test output
  48. */
  49. public ShortNameClassName(String short_name, String class_name,
  50. boolean default_enabled, boolean test_enabled) {
  51. shortName = short_name;
  52. className = class_name;
  53. enabled = default_enabled;
  54. testable = test_enabled;
  55. }
  56. }
  57. public static final String[] enableNames = {
  58. "hist","irnr","vrr","rp","raw","irv","stv"
  59. };
  60. public static final String[] enableClassNames = {
  61. "org.bolson.vote.Histogram", "org.bolson.vote.IRNR", "org.bolson.vote.VRR", "org.bolson.vote.RankedPairs", "org.bolson.vote.Raw", "org.bolson.vote.IRV", "org.bolson.vote.STV"
  62. };
  63. public static final ShortNameClassName[] methodNames = {
  64. new ShortNameClassName("hist", "org.bolson.vote.Histogram", true, true),
  65. new ShortNameClassName("irnr", "org.bolson.vote.IRNR", true, true),
  66. new ShortNameClassName("vrr", "org.bolson.vote.VRR", true, true),
  67. new ShortNameClassName("rp", "org.bolson.vote.RankedPairs", false, true),
  68. new ShortNameClassName("raw", "org.bolson.vote.Raw", true, true),
  69. new ShortNameClassName("irv", "org.bolson.vote.IRV", true, true),
  70. new ShortNameClassName("stv", "org.bolson.vote.STV", false, false),
  71. new ShortNameClassName("irnrp", "org.bolson.vote.IRNRP", false, false),
  72. };
  73. public static final int MODE_URL = 1;
  74. public static final int MODE_WS_NAMEQ = 2;
  75. public static final int MODE_GTEQ_SPEC = 3;
  76. public static final int MODE_CSV = 4;
  77. public static final int OUT_FULL_HTML = 1;
  78. public static final int OUT_PART_HTML = 2;
  79. public static final int OUT_TEXT = 3;
  80. public static final int OUT_SHORT = 4;
  81. public static final int OUT_TEST = 5;
  82. public static final boolean isHtml(int outmode) {
  83. return (outmode == OUT_FULL_HTML) || (outmode == OUT_PART_HTML);
  84. }
  85. public static void main( String[] argv ) {
  86. long startTime = System.currentTimeMillis();
  87. boolean debug = false;
  88. InputStream fin = System.in;
  89. String[] methodArgs = null;
  90. int histMin = -10, histMax = 10;
  91. Vector countClasses = new Vector();
  92. int mode = MODE_URL; // 1 = url encoded, 2 = whitespace separated
  93. boolean redumpVotes = false;
  94. int outmode = OUT_FULL_HTML;
  95. boolean explain = false;
  96. PrintWriter out = null;
  97. int seats = 1;
  98. boolean printTime = false;
  99. boolean rankings = false;
  100. Histogram histInstance = null;
  101. NameVotingSystem firstWinner = null;
  102. //boolean[] enabled = new boolean[]{ true,true,true,true,true,false };
  103. /*countClasses.add( enableClassNames[0] );
  104. countClasses.add( enableClassNames[1] );
  105. countClasses.add( enableClassNames[2] );
  106. countClasses.add( enableClassNames[3] );
  107. countClasses.add( enableClassNames[4] );*/
  108. for ( int i = 0; i < methodNames.length; i++ ) {
  109. if ( methodNames[i].enabled ) {
  110. countClasses.add( methodNames[i].className );
  111. }
  112. }
  113. for ( int i = 0; i < argv.length; i++ ) {
  114. if ( argv[i].equals("-i") ) {
  115. i++;
  116. try {
  117. fin = new java.io.FileInputStream(argv[i]);
  118. } catch ( Exception e ) {
  119. e.printStackTrace();
  120. System.exit(1);
  121. }
  122. } else if ( argv[i].equals("-igz") ) {
  123. i++;
  124. try {
  125. fin = new java.util.zip.GZIPInputStream(new java.io.FileInputStream(argv[i]));
  126. } catch ( Exception e ) {
  127. e.printStackTrace();
  128. System.exit(1);
  129. }
  130. } else if ( argv[i].equals("--disable-all") ) {
  131. countClasses = new Vector();
  132. } else if ( argv[i].equals("--enable-all") ) {
  133. for ( int j = 0; j < methodNames.length; j++ ) {
  134. countClasses.add( methodNames[j].className );
  135. }
  136. } else if ( argv[i].equals("--disable") ) {
  137. boolean any = false;
  138. i++;
  139. for ( int j = 0; j < methodNames.length; j++ ) {
  140. if ( methodNames[j].shortName.equals( argv[i] ) ) {
  141. countClasses.remove( methodNames[j].className );
  142. any = true;
  143. }
  144. }
  145. if ( ! any ) {
  146. System.err.println("bogus --disable: " + argv[i] );
  147. System.exit(1);
  148. }
  149. } else if ( argv[i].equals("--enable") ) {
  150. boolean any = false;
  151. i++;
  152. for ( int j = 0; j < methodNames.length; j++ ) {
  153. if ( methodNames[j].shortName.equals( argv[i] ) ) {
  154. countClasses.add( methodNames[j].className );
  155. any = true;
  156. }
  157. }
  158. if ( ! any ) {
  159. System.err.println("bogus --enable: " + argv[i] );
  160. System.exit(1);
  161. }
  162. } else if ( argv[i].equals("--seats") ) {
  163. i++;
  164. seats = Integer.parseInt(argv[i]);
  165. countClasses = new Vector();
  166. countClasses.add( "org.bolson.vote.STV" );
  167. countClasses.add( "org.bolson.vote.Histogram" );
  168. } else if ( argv[i].equals("--urlencoded") ) {
  169. mode = MODE_URL;
  170. } else if ( argv[i].equals("--whitespace") ) {
  171. mode = MODE_WS_NAMEQ;
  172. } else if ( argv[i].equals("--votespec") ) {
  173. mode = MODE_GTEQ_SPEC;
  174. } else if ( argv[i].equals("--explain") ) {
  175. explain = true;
  176. } else if ( argv[i].equals("--rankings") ) {
  177. rankings = true;
  178. } else if ( argv[i].equals("--full-html") ) {
  179. outmode = OUT_FULL_HTML;
  180. } else if ( argv[i].equals("--no-full-html") ) {
  181. outmode = OUT_PART_HTML;
  182. } else if ( argv[i].equals("--test") ) {
  183. outmode = OUT_TEST;
  184. countClasses = new Vector();
  185. // start at 1, skip histogram
  186. for ( int j = 1; j < methodNames.length; j++ ) {
  187. if ( methodNames[j].testable ) {
  188. countClasses.add( methodNames[j].className );
  189. }
  190. }
  191. } else if ( argv[i].equals("--text") ) {
  192. outmode = OUT_TEXT;
  193. } else if ( argv[i].equals("--time") ) {
  194. printTime = true;
  195. } else if ( argv[i].equals("--short") ) {
  196. outmode = OUT_SHORT;
  197. } else if ( argv[i].equals("--dump") ) {
  198. redumpVotes = true;
  199. } else if ( argv[i].equals("--help") || argv[i].equals("-help") || argv[i].equals("-h") ) {
  200. printUsage();
  201. System.out.println("available election methods:");
  202. for ( int j = 0; j < methodNames.length; j++ ) {
  203. System.out.print( methodNames[j].shortName );
  204. if ( (j+1) < methodNames.length ) {
  205. System.out.print( ", " );
  206. }
  207. }
  208. System.out.println();
  209. return;
  210. } else if ( argv[i].equals("--histMax") ) {
  211. i++;
  212. histMax = Integer.parseInt( argv[i] );
  213. } else if ( argv[i].equals("--histMin") ) {
  214. i++;
  215. histMin = Integer.parseInt( argv[i] );
  216. } else if ( argv[i].equals("--out") ||
  217. argv[i].equals("-o") ) {
  218. i++;
  219. try {
  220. out = new PrintWriter(new java.io.FileWriter( argv[i] ));
  221. } catch (java.io.IOException e) {
  222. e.printStackTrace();
  223. return;
  224. }
  225. } else if ( argv[i].equals("-m") ) {
  226. i++;
  227. countClasses.add( argv[i] );
  228. } else if ( argv[i].equals("--") ) {
  229. i++;
  230. int j = 0;
  231. methodArgs = new String[argv.length - i];
  232. while ( i < argv.length ) {
  233. if ( argv[i].equals("debug") ) {
  234. debug = true;
  235. }
  236. methodArgs[j] = argv[i];
  237. i++; j++;
  238. }
  239. break;
  240. } else {
  241. System.err.println("bogus arg \"" + argv[i] + "\"" );
  242. System.exit(1);
  243. }
  244. }
  245. if ( out == null ) {
  246. out = new PrintWriter(new java.io.OutputStreamWriter(System.out));
  247. }
  248. if ( outmode == OUT_FULL_HTML ) {
  249. out.println("<html><head><title>vote results</title></head><body bgcolor=\"#ffffff\" text=\"#000000\">");
  250. }
  251. // setup methods to count into
  252. if ( debug ) {
  253. if ( isHtml(outmode) ) {
  254. out.print("<pre>");
  255. }
  256. out.println("debug:");
  257. }
  258. NameVotingSystem[] vs;
  259. String initArgs[] = null;
  260. if ( seats != 1 ) {
  261. initArgs = new String[2];
  262. initArgs[0] = "seats";
  263. initArgs[1] = Integer.toString( seats );
  264. }
  265. if ( countClasses.size() > 0 ) {
  266. vs = new NameVotingSystem[countClasses.size()];
  267. for ( int i = 0; i < vs.length; i++ ) {
  268. String cn;
  269. cn = (String)countClasses.get(i);
  270. if ( cn.equals( "Histogram" ) || cn.equals("Histogram") || cn.equals("org.bolson.vote.Histogram") ) {
  271. histInstance = new Histogram( histMin, histMax );
  272. vs[i] = histInstance;
  273. } else {
  274. vs[i] = getMethodInstance( cn );
  275. if ( firstWinner == null ) {
  276. firstWinner = vs[i];
  277. }
  278. if ( vs[i] == null ) {
  279. System.err.println( cn + " failed to instantiate");
  280. return;
  281. }
  282. if ( initArgs != null ) {
  283. vs[i].init( (String[])initArgs.clone() );
  284. }
  285. }
  286. }
  287. } else {
  288. histInstance = new Histogram( histMin, histMax );
  289. firstWinner = new IRNR();
  290. vs = new NameVotingSystem[] {
  291. histInstance,
  292. firstWinner,
  293. new VRR(),
  294. new Raw(),
  295. new IRV(),
  296. };
  297. }
  298. if (histInstance != null && rankings) {
  299. histInstance.setRankingMode();
  300. }
  301. for ( int vi = 0; vi < vs.length; vi++ ) {
  302. if ( methodArgs == null ) {
  303. vs[vi].init( null );
  304. } else {
  305. vs[vi].init( (String[])methodArgs.clone() );
  306. }
  307. }
  308. // done setting up, read input and count votes
  309. try {
  310. String line;
  311. BufferedReader r = new BufferedReader( new InputStreamReader( fin ) );
  312. while ( (line = r.readLine()) != null ) {
  313. NameVotingSystem.NameVote[] nv;
  314. //nv = NameVotingSystem.voteSpecToNameVoteArray( line );
  315. if ( mode == MODE_URL ) {
  316. nv = NameVotingSystem.fromUrlEncoded( line );
  317. } else if ( mode == MODE_WS_NAMEQ ) {
  318. nv = NameVotingSystem.nameEqStrToVoteArray( line );
  319. } else if ( mode == MODE_GTEQ_SPEC ) {
  320. nv = NameVotingSystem.voteSpecToNameVoteArray( line );
  321. } else {
  322. System.err.println("ICE");
  323. return;
  324. }
  325. if ( redumpVotes ) {
  326. out.print( NameVotingSystem.urlEncode(nv) );
  327. out.println();
  328. }
  329. for ( int vi = 0; vi < vs.length; vi++ ) {
  330. if (rankings) {
  331. vs[vi].voteRanking( nv );
  332. } else {
  333. vs[vi].voteRating( nv );
  334. }
  335. }
  336. }
  337. } catch ( Exception e ) {
  338. e.printStackTrace();
  339. }
  340. if ( debug && isHtml(outmode) ) {
  341. out.println( "</pre>" );
  342. }
  343. // display results, various modes
  344. if ( outmode == OUT_TEST ) {
  345. // minimal and easily regular output so that a good test result has no diff to standard output
  346. for ( int vi = 0; vi < vs.length; vi++ ) {
  347. out.print( vs[vi].name() + ": " );
  348. try {
  349. NameVotingSystem.NameVote[] winners = vs[vi].getWinners();
  350. if ( winners == null || winners.length == 0 ) {
  351. out.println();
  352. continue;
  353. }
  354. out.print( winners[0].name );
  355. for ( int i = 1; i < winners.length; i++ ) {
  356. out.print( ", " );
  357. out.print( winners[i].name );
  358. }
  359. } catch (Exception e) {
  360. e.printStackTrace();
  361. out.print( "fail" );
  362. }
  363. out.println();
  364. }
  365. out.flush();
  366. } else if ( outmode == OUT_TEXT ) {
  367. // simple plain text output
  368. for ( int vi = 0; vi < vs.length; vi++ ) {
  369. out.println( vs[vi].name() );
  370. }
  371. out.flush();
  372. } else if ( outmode == OUT_SHORT ) {
  373. } else {
  374. // only HTML outputting modes remain below here
  375. for ( int vi = 0; vi < vs.length; vi++ ) {
  376. out.print( "<h2>" );
  377. out.print( vs[vi].name() );
  378. out.print( "</h2>" );
  379. String hs = null;
  380. if ( vs[vi] == histInstance && firstWinner != null ) {
  381. hs = histInstance.htmlSummary( new StringBuffer(), firstWinner.getWinners() ).toString();
  382. } else if ( explain ) {
  383. hs = vs[vi].htmlExplain();
  384. } else {
  385. hs = vs[vi].htmlSummary();
  386. }
  387. if ( debug ) {
  388. String dbs = vs[vi].getDebug();
  389. if ( dbs != null && dbs.length() > 0 ) {
  390. out.println( "<h3>debug:</h3><pre>" );
  391. out.println( dbs );
  392. out.println( "</pre>" );
  393. }
  394. }
  395. out.println( hs );
  396. }
  397. if ( outmode == OUT_FULL_HTML ) {
  398. out.println("</body></html>");
  399. }
  400. out.flush();
  401. }
  402. if (printTime) {
  403. long doneTime = System.currentTimeMillis();
  404. double dt = (doneTime - startTime) / 1000.0;
  405. System.err.println(dt + " seconds");
  406. }
  407. }
  408. protected static final String[] gmiPrefixes = {
  409. "", "", "org.bolson.vote.", "org.bolson.vote."
  410. };
  411. public static NameVotingSystem getMethodInstance(String name) {
  412. Class c;
  413. StringBuffer errors = new StringBuffer();
  414. for ( int i = 0; i < gmiPrefixes.length; i++ ) {
  415. try {
  416. String cn = gmiPrefixes[i] + name;
  417. c = Class.forName( cn );
  418. // can this return null or does it just throw?
  419. if ( c != null ) {
  420. if ( NameVotingSystem.class.isAssignableFrom(c) ) {
  421. try {
  422. return (NameVotingSystem)c.newInstance();
  423. } catch ( Exception e ) {
  424. e.printStackTrace();
  425. }
  426. return null;
  427. } else {
  428. errors.append("found class ").append(cn).append(" but it is not a NameVotingSystem").append('\n');
  429. }
  430. }
  431. } catch ( ClassNotFoundException e ) {
  432. // don't care. try next prefix
  433. }
  434. }
  435. System.err.println(errors.toString());
  436. return null;
  437. }
  438. }