Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import java.io.IOException;
- import java.nio.file.Files;
- import java.nio.file.Path;
- import java.nio.file.Paths;
- import java.nio.file.StandardOpenOption;
- import java.text.SimpleDateFormat;
- import java.util.Date;
- import java.util.Map;
- import java.util.Random;
- import java.util.TreeMap;
- /**
- * <p>
- * Endlessly flip a coin and report on how long it took to get the same result
- * 10, 20, 30, 40 etc times in a row.
- * </p>
- *
- * <p>
- * Compiled and run in JDK 7.
- * </p>
- *
- * <p>
- * Discuss this code:
- * http://robertmarkbramprogrammer.blogspot.com.au/2014/09/flip
- * -and-coin-and-get-same-results-100.html or http://bit.ly/1p1zRtM.
- * </p>
- *
- * <p>
- * See this code in pastebin: http://pastebin.com/7PAGyQcU.
- * </p>
- *
- * <p>
- * See results so far from one continuous run: http://pastebin.com/MG50TYED.
- * </p>
- *
- * <p>
- * Updates.
- * </p>
- * <ol>
- * <li>Tuesday 09 September 2014, 12:33:53 PM. Replaced ints with longs for
- * numbers that are getting long. Allow path to be set for where to write log.
- * Changed time format.</li>
- * <li>Wednesday 10 September 2014, 04:31:31 PM. Added a bit more time
- * information when reporting new counts.</li>
- * </ol>
- *
- * @author Robert Mark Bram
- */
- public final class RandomInARow implements Runnable {
- /** File we write the log to. */
- private Path file;
- /** Where to put logs. */
- private String pathToLogs = "";
- /** Time we started this run. */
- private long start;
- /** How many milliseconds in a second. */
- final static int TIME_MILLISECONDS_IN_A_SECOND = 1000;
- /** How many milliseconds in a minute. */
- final static int TIME_SECONDS_IN_A_MINUTE = TIME_MILLISECONDS_IN_A_SECOND * 60;
- /** How many milliseconds in an hour. */
- final static int TIME_MINUTES_IN_AN_HOUR = TIME_SECONDS_IN_A_MINUTE * 60;
- /** How many milliseconds in a day. */
- final static int TIME_HOURS_IN_A_DAY = TIME_MINUTES_IN_AN_HOUR * 24;
- /** Timestamp format for the log when I wish to report on events. */
- public static final ThreadLocal<SimpleDateFormat> FORMAT_TIMESTAMP = new ThreadLocal<SimpleDateFormat>() {
- @Override
- protected synchronized SimpleDateFormat initialValue() {
- return new SimpleDateFormat("dd MMM yyyy, hh:mm:ss.SSS a");
- }
- };
- /** Timestamp format for the log file name. */
- public static final ThreadLocal<SimpleDateFormat> FORMAT_FILE = new ThreadLocal<SimpleDateFormat>() {
- @Override
- protected synchronized SimpleDateFormat initialValue() {
- return new SimpleDateFormat("yyyyMMddHHmmssSSS");
- }
- };
- /**
- * Run the simulation.
- *
- * @param args
- * 0 - path to put logs file, can be null/empty.
- */
- public static void main(String[] args) {
- String path = null;
- if (args.length > 0) {
- path = args[0];
- }
- new RandomInARow(path).run();
- }
- /**
- * @param thePathToLogs
- * - where to store logs. May be null or empty.
- */
- public RandomInARow(final String thePathToLogs) {
- if (thePathToLogs != null && thePathToLogs.length() > 0) {
- pathToLogs = thePathToLogs;
- }
- }
- /* Endlessly run the simulation, starting at 10 tosses in a row and
- * incrementing by 10 each time. */
- public void run() {
- int target = 10;
- while (true) {
- repeatUntilWeGetCount(target);
- target += 10;
- }
- }
- /**
- * @param target
- * keep going until we get this number of repetitions of the same
- * flip result
- */
- public void repeatUntilWeGetCount(final int target) {
- start = reportPhase(true);
- final TreeMap<Integer, Long> counts = new TreeMap<Integer, Long>();
- final Random random = new Random();
- while (true) {
- rememberCountOfContiguousOccurences(random, counts);
- if (counts.lastKey() >= target) {
- break;
- }
- }
- long finish = reportPhase(false);
- message("-----\nIt took " + reportTime(finish - start) + " to get ["
- + target + "] results in a row.\n");
- outputResult(counts);
- }
- /**
- * Return a string such as
- * "hours, [0], minutes [0], seconds [0], milliseconds [59]" based on a
- * millisecond timestamp.
- *
- * @param millisecondsTotal
- * milliseconds taken to perform task
- * @return stringing saying how many hours, minutes, seconds and
- * milliseconds were taken by <code>millisecondsTotal</code>
- */
- private String reportTime(final long millisecondsTotal) {
- long left = 0;
- // Milliseconds.
- long milliseconds = millisecondsTotal % TIME_MILLISECONDS_IN_A_SECOND;
- left = millisecondsTotal - milliseconds;
- // Seconds.
- long seconds = (left % TIME_SECONDS_IN_A_MINUTE)
- / TIME_MILLISECONDS_IN_A_SECOND;
- left = left - (TIME_MILLISECONDS_IN_A_SECOND * seconds);
- // Minutes.
- long minutes = (left % TIME_MINUTES_IN_AN_HOUR)
- / TIME_SECONDS_IN_A_MINUTE;
- left = left - (TIME_SECONDS_IN_A_MINUTE * minutes);
- // Hours.
- long hours = (left % TIME_HOURS_IN_A_DAY) / TIME_MINUTES_IN_AN_HOUR;
- left = left - (TIME_MINUTES_IN_AN_HOUR * hours);
- // Days
- long days = left / TIME_HOURS_IN_A_DAY;
- left = left - (TIME_HOURS_IN_A_DAY * days);
- // Formulate time string.
- StringBuilder sb = new StringBuilder();
- if (days > 0) {
- sb.append(days).append(" days, ");
- }
- if (hours > 0 || days > 0) {
- sb.append(hours).append(" hours, ");
- }
- if (minutes > 0 || hours > 0 || days > 0) {
- sb.append(minutes).append(" minutes, ");
- }
- if (seconds > 0 || minutes > 0 || hours > 0 || days > 0) {
- sb.append(seconds).append(" seconds and ");
- }
- sb.append(milliseconds).append(" milliseconds");
- return sb.toString();
- }
- /**
- * Report start or finish.
- *
- * @param start
- * true if this is reporting the start, false to report the end
- * @return new Date().getTime() - millsecond time stamp.
- */
- private long reportPhase(final boolean start) {
- Date date = new Date();
- long millis = date.getTime();
- String prefix = start ? "\nStarted" : "Finished";
- String suffix = start ? "\n" : "\n";
- message(prefix + " at [" + FORMAT_TIMESTAMP.get().format(date) + "]"
- + suffix);
- return millis;
- }
- /**
- * Output results.
- *
- * @param counts
- * map of (count, occurrences of count). Count = number of times
- * we got same result in a row. Occurrences of count = number of
- * times we kept flipping and got that count.
- */
- private void outputResult(final Map<Integer, Long> counts) {
- for (Integer count : counts.keySet()) {
- message(String.format("How often we flipped the same result [%4d] "
- + "times in a row: %d.\n", count, counts.get(count)));
- }
- }
- /**
- * Flip a coin and count how many times we got the same result. Increment
- * the count for that number.
- *
- * @param random
- * random number generator
- * @param counts
- * map of (count, occurrences of count). Count = number of times
- * we got same result in a row. Occurrences of count = number of
- * times we kept flipping and got that count.
- */
- private void rememberCountOfContiguousOccurences(final Random random,
- final Map<Integer, Long> counts) {
- Integer count = countContiguousOccurences(random);
- if (counts.containsKey(count)) {
- Long countOccurences = counts.get(count);
- countOccurences++;
- counts.put(count, countOccurences);
- } else {
- counts.put(count, 1l);
- Date currentTime = new Date();
- message(String.format("New count [%3d] at [" //
- + FORMAT_TIMESTAMP.get().format(currentTime)
- + "] after %s.\n", count, reportTime(currentTime.getTime()
- - start)));
- }
- }
- /**
- * Flip a coin repeatedly until we get a different result to the first toss
- *
- * @param random
- * random number generator
- * @return number of times we tossed and got the same result
- */
- private int countContiguousOccurences(final Random random) {
- int count = 1;
- final int first = random.nextInt(2);
- while (random.nextInt(2) == first) {
- count++;
- }
- return count;
- }
- /**
- * Output message to file and standard out.
- *
- * @param message
- * message to output
- * @throws IOException
- * if there is a problem writing to log
- */
- private void message(final String message) {
- if (file == null) {
- file = Paths.get(pathToLogs,
- "results_" + FORMAT_FILE.get().format(new Date()) + ".txt");
- }
- System.out.print(message);
- try {
- Files.write(file, message.getBytes(), StandardOpenOption.CREATE,
- StandardOpenOption.APPEND);
- } catch (IOException ioe) {
- System.err.println("Failed to write message [" + message + "].");
- throw new RuntimeException(ioe);
- }
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement