SHARE
TWEET

Flip a coin endlessly and report on x same results in a row

robertmarkbram Sep 8th, 2014 311 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. import java.io.IOException;
  2. import java.nio.file.Files;
  3. import java.nio.file.Path;
  4. import java.nio.file.Paths;
  5. import java.nio.file.StandardOpenOption;
  6. import java.text.SimpleDateFormat;
  7. import java.util.Date;
  8. import java.util.Map;
  9. import java.util.Random;
  10. import java.util.TreeMap;
  11.  
  12. /**
  13.  * <p>
  14.  * Endlessly flip a coin and report on how long it took to get the same result
  15.  * 10, 20, 30, 40 etc times in a row.
  16.  * </p>
  17.  *
  18.  * <p>
  19.  * Compiled and run in JDK 7.
  20.  * </p>
  21.  *
  22.  * <p>
  23.  * Discuss this code:
  24.  * http://robertmarkbramprogrammer.blogspot.com.au/2014/09/flip
  25.  * -and-coin-and-get-same-results-100.html or http://bit.ly/1p1zRtM.
  26.  * </p>
  27.  *
  28.  * <p>
  29.  * See this code in pastebin: http://pastebin.com/7PAGyQcU.
  30.  * </p>
  31.  *
  32.  * <p>
  33.  * See results so far from one continuous run: http://pastebin.com/MG50TYED.
  34.  * </p>
  35.  *
  36.  * <p>
  37.  * Updates.
  38.  * </p>
  39.  * <ol>
  40.  * <li>Tuesday 09 September 2014, 12:33:53 PM. Replaced ints with longs for
  41.  * numbers that are getting long. Allow path to be set for where to write log.
  42.  * Changed time format.</li>
  43.  * <li>Wednesday 10 September 2014, 04:31:31 PM. Added a bit more time
  44.  * information when reporting new counts.</li>
  45.  * </ol>
  46.  *
  47.  * @author Robert Mark Bram
  48.  */
  49. public final class RandomInARow implements Runnable {
  50.  
  51.         /** File we write the log to. */
  52.         private Path file;
  53.  
  54.         /** Where to put logs. */
  55.         private String pathToLogs = "";
  56.  
  57.         /** Time we started this run. */
  58.         private long start;
  59.  
  60.         /** How many milliseconds in a second. */
  61.         final static int TIME_MILLISECONDS_IN_A_SECOND = 1000;
  62.         /** How many milliseconds in a minute. */
  63.         final static int TIME_SECONDS_IN_A_MINUTE = TIME_MILLISECONDS_IN_A_SECOND * 60;
  64.         /** How many milliseconds in an hour. */
  65.         final static int TIME_MINUTES_IN_AN_HOUR = TIME_SECONDS_IN_A_MINUTE * 60;
  66.         /** How many milliseconds in a day. */
  67.         final static int TIME_HOURS_IN_A_DAY = TIME_MINUTES_IN_AN_HOUR * 24;
  68.  
  69.         /** Timestamp format for the log when I wish to report on events. */
  70.         public static final ThreadLocal<SimpleDateFormat> FORMAT_TIMESTAMP = new ThreadLocal<SimpleDateFormat>() {
  71.                 @Override
  72.                 protected synchronized SimpleDateFormat initialValue() {
  73.                         return new SimpleDateFormat("dd MMM yyyy, hh:mm:ss.SSS a");
  74.                 }
  75.         };
  76.  
  77.         /** Timestamp format for the log file name. */
  78.         public static final ThreadLocal<SimpleDateFormat> FORMAT_FILE = new ThreadLocal<SimpleDateFormat>() {
  79.                 @Override
  80.                 protected synchronized SimpleDateFormat initialValue() {
  81.                         return new SimpleDateFormat("yyyyMMddHHmmssSSS");
  82.                 }
  83.         };
  84.  
  85.         /**
  86.          * Run the simulation.
  87.          *
  88.          * @param args
  89.          *            0 - path to put logs file, can be null/empty.
  90.          */
  91.         public static void main(String[] args) {
  92.                 String path = null;
  93.                 if (args.length > 0) {
  94.                         path = args[0];
  95.                 }
  96.                 new RandomInARow(path).run();
  97.         }
  98.  
  99.         /**
  100.          * @param thePathToLogs
  101.          *            - where to store logs. May be null or empty.
  102.          */
  103.         public RandomInARow(final String thePathToLogs) {
  104.                 if (thePathToLogs != null && thePathToLogs.length() > 0) {
  105.                         pathToLogs = thePathToLogs;
  106.                 }
  107.         }
  108.  
  109.         /* Endlessly run the simulation, starting at 10 tosses in a row and
  110.          * incrementing by 10 each time. */
  111.         public void run() {
  112.                 int target = 10;
  113.                 while (true) {
  114.                         repeatUntilWeGetCount(target);
  115.                         target += 10;
  116.                 }
  117.         }
  118.  
  119.         /**
  120.          * @param target
  121.          *            keep going until we get this number of repetitions of the same
  122.          *            flip result
  123.          */
  124.         public void repeatUntilWeGetCount(final int target) {
  125.                 start = reportPhase(true);
  126.  
  127.                 final TreeMap<Integer, Long> counts = new TreeMap<Integer, Long>();
  128.                 final Random random = new Random();
  129.                 while (true) {
  130.                         rememberCountOfContiguousOccurences(random, counts);
  131.                         if (counts.lastKey() >= target) {
  132.                                 break;
  133.                         }
  134.                 }
  135.                 long finish = reportPhase(false);
  136.                 message("-----\nIt took " + reportTime(finish - start) + " to get ["
  137.                                 + target + "] results in a row.\n");
  138.                 outputResult(counts);
  139.         }
  140.  
  141.         /**
  142.          * Return a string such as
  143.          * "hours, [0], minutes [0], seconds [0], milliseconds [59]" based on a
  144.          * millisecond timestamp.
  145.          *
  146.          * @param millisecondsTotal
  147.          *            milliseconds taken to perform task
  148.          * @return stringing saying how many hours, minutes, seconds and
  149.          *         milliseconds were taken by <code>millisecondsTotal</code>
  150.          */
  151.         private String reportTime(final long millisecondsTotal) {
  152.                 long left = 0;
  153.  
  154.                 // Milliseconds.
  155.                 long milliseconds = millisecondsTotal % TIME_MILLISECONDS_IN_A_SECOND;
  156.                 left = millisecondsTotal - milliseconds;
  157.  
  158.                 // Seconds.
  159.                 long seconds = (left % TIME_SECONDS_IN_A_MINUTE)
  160.                                 / TIME_MILLISECONDS_IN_A_SECOND;
  161.                 left = left - (TIME_MILLISECONDS_IN_A_SECOND * seconds);
  162.  
  163.                 // Minutes.
  164.                 long minutes = (left % TIME_MINUTES_IN_AN_HOUR)
  165.                                 / TIME_SECONDS_IN_A_MINUTE;
  166.                 left = left - (TIME_SECONDS_IN_A_MINUTE * minutes);
  167.  
  168.                 // Hours.
  169.                 long hours = (left % TIME_HOURS_IN_A_DAY) / TIME_MINUTES_IN_AN_HOUR;
  170.                 left = left - (TIME_MINUTES_IN_AN_HOUR * hours);
  171.  
  172.                 // Days
  173.                 long days = left / TIME_HOURS_IN_A_DAY;
  174.                 left = left - (TIME_HOURS_IN_A_DAY * days);
  175.  
  176.                 // Formulate time string.
  177.                 StringBuilder sb = new StringBuilder();
  178.                 if (days > 0) {
  179.                         sb.append(days).append(" days, ");
  180.                 }
  181.                 if (hours > 0 || days > 0) {
  182.                         sb.append(hours).append(" hours, ");
  183.                 }
  184.                 if (minutes > 0 || hours > 0 || days > 0) {
  185.                         sb.append(minutes).append(" minutes, ");
  186.                 }
  187.                 if (seconds > 0 || minutes > 0 || hours > 0 || days > 0) {
  188.                         sb.append(seconds).append(" seconds and ");
  189.                 }
  190.                 sb.append(milliseconds).append(" milliseconds");
  191.                 return sb.toString();
  192.         }
  193.  
  194.         /**
  195.          * Report start or finish.
  196.          *
  197.          * @param start
  198.          *            true if this is reporting the start, false to report the end
  199.          * @return new Date().getTime() - millsecond time stamp.
  200.          */
  201.         private long reportPhase(final boolean start) {
  202.                 Date date = new Date();
  203.                 long millis = date.getTime();
  204.                 String prefix = start ? "\nStarted" : "Finished";
  205.                 String suffix = start ? "\n" : "\n";
  206.                 message(prefix + " at [" + FORMAT_TIMESTAMP.get().format(date) + "]"
  207.                                 + suffix);
  208.                 return millis;
  209.         }
  210.  
  211.         /**
  212.          * Output results.
  213.          *
  214.          * @param counts
  215.          *            map of (count, occurrences of count). Count = number of times
  216.          *            we got same result in a row. Occurrences of count = number of
  217.          *            times we kept flipping and got that count.
  218.          */
  219.         private void outputResult(final Map<Integer, Long> counts) {
  220.                 for (Integer count : counts.keySet()) {
  221.                         message(String.format("How often we flipped the same result [%4d] "
  222.                                         + "times in a row: %d.\n", count, counts.get(count)));
  223.                 }
  224.         }
  225.  
  226.         /**
  227.          * Flip a coin and count how many times we got the same result. Increment
  228.          * the count for that number.
  229.          *
  230.          * @param random
  231.          *            random number generator
  232.          * @param counts
  233.          *            map of (count, occurrences of count). Count = number of times
  234.          *            we got same result in a row. Occurrences of count = number of
  235.          *            times we kept flipping and got that count.
  236.          */
  237.         private void rememberCountOfContiguousOccurences(final Random random,
  238.                         final Map<Integer, Long> counts) {
  239.                 Integer count = countContiguousOccurences(random);
  240.                 if (counts.containsKey(count)) {
  241.                         Long countOccurences = counts.get(count);
  242.                         countOccurences++;
  243.                         counts.put(count, countOccurences);
  244.                 } else {
  245.                         counts.put(count, 1l);
  246.                         Date currentTime = new Date();
  247.                         message(String.format("New count [%3d] at [" //
  248.                                         + FORMAT_TIMESTAMP.get().format(currentTime)
  249.                                         + "] after %s.\n", count, reportTime(currentTime.getTime()
  250.                                         - start)));
  251.                 }
  252.  
  253.         }
  254.  
  255.         /**
  256.          * Flip a coin repeatedly until we get a different result to the first toss
  257.          *
  258.          * @param random
  259.          *            random number generator
  260.          * @return number of times we tossed and got the same result
  261.          */
  262.         private int countContiguousOccurences(final Random random) {
  263.                 int count = 1;
  264.                 final int first = random.nextInt(2);
  265.                 while (random.nextInt(2) == first) {
  266.                         count++;
  267.                 }
  268.                 return count;
  269.         }
  270.  
  271.         /**
  272.          * Output message to file and standard out.
  273.          *
  274.          * @param message
  275.          *            message to output
  276.          * @throws IOException
  277.          *             if there is a problem writing to log
  278.          */
  279.         private void message(final String message) {
  280.                 if (file == null) {
  281.                         file = Paths.get(pathToLogs,
  282.                                         "results_" + FORMAT_FILE.get().format(new Date()) + ".txt");
  283.                 }
  284.                 System.out.print(message);
  285.                 try {
  286.                         Files.write(file, message.getBytes(), StandardOpenOption.CREATE,
  287.                                         StandardOpenOption.APPEND);
  288.                 } catch (IOException ioe) {
  289.                         System.err.println("Failed to write message [" + message + "].");
  290.                         throw new RuntimeException(ioe);
  291.                 }
  292.         }
  293.  
  294. }
RAW Paste Data
We use cookies for various purposes including analytics. By continuing to use Pastebin, you agree to our use of cookies as described in the Cookies Policy. OK, I Understand
Not a member of Pastebin yet?
Sign Up, it unlocks many cool features!
 
Top