package com.github.donkirkby.vograbulary.ultraghost; import java.util.Random; /** * Source of random choices for Ultraghost. Pulled into a separate class to * make it easier to mock out in tests. * @author don * */ public class UltraghostRandom { private Random random; // Each entry holds the odds of that letter appearing in that position. private double[] startingOdds; private double[] interiorOdds; private double[] endingOdds; public UltraghostRandom() { this(new Random()); } public UltraghostRandom(Random random) { this.random = random; } /** * Generate a new puzzle. * @return a string with three upper-case letters */ public String generatePuzzle() { StringBuilder builder = new StringBuilder(3); builder.append(generateLetter(startingOdds)); builder.append(generateLetter(interiorOdds)); builder.append(generateLetter(endingOdds)); return builder.toString(); } /** * Choose the index of the starting student. * @param studentCount the total number of students. */ public int chooseStartingStudent(int studentCount) { return random.nextInt(studentCount); } private char generateLetter(double[] letterOdds) { double remaining = random.nextDouble(); int i = 0; boolean isDone = false; while ( ! isDone) { remaining -= letterOdds[i]; if (i < letterOdds.length-1 && remaining >= 0) { i++; } else { isDone = true; } } return (char) ('A' + i); } /** * Load a list of words that can be used to choose letter frequencies * for generating puzzles. */ public void loadWordList(Iterable<String> wordList) { int alphabetSize = 26; startingOdds = new double[alphabetSize]; interiorOdds = new double[alphabetSize]; endingOdds = new double[alphabetSize]; int wordCount = 0; int interiorCount = 0; for (String word : wordList) { wordCount++; startingOdds[word.charAt(0) - 'A'] += 1; endingOdds[word.charAt(word.length()-1) - 'A'] += 1; for (int i = 1; i < word.length()-1; i++) { interiorCount++; interiorOdds[word.charAt(i) - 'A'] += 1; } } for (int i = 0; i < alphabetSize; i++) { startingOdds[i] /= wordCount; interiorOdds[i] /= interiorCount; endingOdds[i] /= wordCount; } } }