EnglishWords.java

package net.morimekta.providence.testing.util;

import net.morimekta.util.ExtraStreams;
import net.morimekta.util.collect.UnmodifiableList;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.annotation.Nonnull;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UncheckedIOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static net.morimekta.util.Strings.capitalize;

/**
 * This is a very light-weight version of fairy, which just generates
 * simple pseudo-sentences in repeated SVO patterns.
 */
public class EnglishWords {
    private static final Logger LOGGER = LoggerFactory.getLogger(EnglishWords.class);

    private static final List<String> nouns;
    private static final List<String> adjectives;
    private static final List<String> verbs;
    private static final Random random;

    static {
        try (InputStream in = EnglishWords.class.getResourceAsStream("/net/morimekta/providence/testing/words.txt");
             InputStreamReader reader = new InputStreamReader(in);
             BufferedReader bufferedReader = new BufferedReader(reader);
             Stream<String> lines = bufferedReader.lines()) {
            List<String> nounsB = new ArrayList<>();
            List<String> adjectivesB = new ArrayList<>();
            List<String> verbsB = new ArrayList<>();

            lines.forEach(line -> {
                String[] word = line.split(" ", 3);
                if (word.length != 3) return;
                if (word[2].contains("adjective")) {
                    adjectivesB.add(word[0]);
                } else if (word[2].contains("verb")) {
                    verbsB.add(word[0]);
                } else if (word[2].contains("noun")) {
                    nounsB.add(word[0]);
                }
            });

            nouns = UnmodifiableList.copyOf(nounsB);
            adjectives = UnmodifiableList.copyOf(adjectivesB);
            verbs = UnmodifiableList.copyOf(verbsB);
            random = new Random();
        } catch (IOException e) {
            LOGGER.error("Failed to load words: {}", e.getMessage(), e);
            throw new UncheckedIOException(e.getMessage(), e);
        }
    }

    @Nonnull
    public static String noun() {
        return nouns.get(random.nextInt(nouns.size()));
    }

    @Nonnull
    public static String thing() {
        if (random.nextBoolean()) {
            return adjective() + " " + noun();
        }
        return noun();
    }

    @Nonnull
    public static String adjective() {
        return adjectives.get(random.nextInt(adjectives.size()));
    }

    @Nonnull
    public static String verb() {
        return verbs.get(random.nextInt(verbs.size()));
    }

    @Nonnull
    public static String sentence(int minLength) {
        StringBuilder sentence = new StringBuilder();
        while (sentence.length() < minLength) {
            if (sentence.length() > 0) {
                sentence.append(", and ")
                        .append(thing());
            } else {
                sentence.append(capitalize(thing()));
            }
            sentence.append(" ")
                    .append(verb())
                    .append(" ")
                    .append(thing());
        }
        return sentence.toString();
    }

    @Nonnull
    public static String paragraph(int sentences) {
        return ExtraStreams.times(sentences)
                           .sequential()
                           .map(i -> random.nextInt(50) + 20)
                           .mapToObj(EnglishWords::sentence)
                           .collect(Collectors.joining(". ")) + ".";
    }
}