diff --git a/book/.classpath b/book/.classpath
new file mode 100644
index 0000000..64b6aef
--- /dev/null
+++ b/book/.classpath
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
diff --git a/book/.project b/book/.project
new file mode 100644
index 0000000..e8edbae
--- /dev/null
+++ b/book/.project
@@ -0,0 +1,17 @@
+
+
+ vograbulary-book
+
+
+
+
+
+ org.eclipse.jdt.core.javabuilder
+
+
+
+
+
+ org.eclipse.jdt.core.javanature
+
+
diff --git a/book/lib/pdfclown-0.1.2-javadoc.jar b/book/lib/pdfclown-0.1.2-javadoc.jar
new file mode 100644
index 0000000..64dc7c8
Binary files /dev/null and b/book/lib/pdfclown-0.1.2-javadoc.jar differ
diff --git a/book/lib/pdfclown-0.1.2-sources.jar b/book/lib/pdfclown-0.1.2-sources.jar
new file mode 100644
index 0000000..65853b8
Binary files /dev/null and b/book/lib/pdfclown-0.1.2-sources.jar differ
diff --git a/book/lib/pdfclown.jar b/book/lib/pdfclown.jar
new file mode 100644
index 0000000..4b23324
Binary files /dev/null and b/book/lib/pdfclown.jar differ
diff --git a/book/src/com/github/donkirkby/vograbulary/VograbularyBook.java b/book/src/com/github/donkirkby/vograbulary/VograbularyBook.java
new file mode 100644
index 0000000..fb14700
--- /dev/null
+++ b/book/src/com/github/donkirkby/vograbulary/VograbularyBook.java
@@ -0,0 +1,117 @@
+package com.github.donkirkby.vograbulary;
+
+import java.awt.geom.Dimension2D;
+import java.awt.geom.Rectangle2D;
+import java.io.IOException;
+import java.util.Date;
+
+import org.pdfclown.documents.Document;
+import org.pdfclown.documents.Page;
+import org.pdfclown.documents.contents.composition.BlockComposer;
+import org.pdfclown.documents.contents.composition.PrimitiveComposer;
+import org.pdfclown.documents.contents.composition.XAlignmentEnum;
+import org.pdfclown.documents.contents.composition.YAlignmentEnum;
+import org.pdfclown.documents.contents.fonts.StandardType1Font;
+import org.pdfclown.documents.interaction.viewer.ViewerPreferences;
+import org.pdfclown.documents.interchange.metadata.Information;
+import org.pdfclown.files.File;
+import org.pdfclown.files.SerializationModeEnum;
+
+public class VograbularyBook {
+ public static void main(String[] args) {
+ try {
+ File file = new File();
+ Document document = file.getDocument();
+ populate(document);
+ serialize(file, "vograbulary.pdf");
+
+ System.out.println("Done.");
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ private static void populate(Document document) {
+ Page page = new Page(document); // Instantiates the page inside the
+ // document context.
+ document.getPages().add(page); // Puts the page in the pages collection.
+
+ PrimitiveComposer composer = new PrimitiveComposer(page);
+ BlockComposer blockComposer = new BlockComposer(composer);
+
+ StandardType1Font titleFont = new StandardType1Font(
+ document,
+ StandardType1Font.FamilyEnum.Helvetica,
+ true, // bold
+ false); // italic
+ int titleFontSize = 20;
+ StandardType1Font textFont = new StandardType1Font(
+ document,
+ StandardType1Font.FamilyEnum.Times,
+ false, // bold
+ false); // italic
+ int textFontSize = 12;
+ StandardType1Font puzzleFont = new StandardType1Font(
+ document,
+ StandardType1Font.FamilyEnum.Courier,
+ false, // bold
+ false); // italic
+ int puzzleFontSize = 12;
+
+ Dimension2D pageSize = page.getSize();
+ Rectangle2D titleFrame = new Rectangle2D.Double(
+ 20,
+ 50,
+ pageSize.getWidth() - 90,
+ pageSize.getHeight() - 250
+ );
+ blockComposer.begin(titleFrame, XAlignmentEnum.Center, YAlignmentEnum.Top);
+ composer.setFont(titleFont, titleFontSize);
+ blockComposer.showText("Vograbulary");
+ blockComposer.end();
+ Rectangle2D usedSpace = blockComposer.getBoundBox();
+ Rectangle2D bodyFrame = new Rectangle2D.Double(
+ titleFrame.getX(),
+ usedSpace.getMaxY() + 10,
+ titleFrame.getWidth(),
+ titleFrame.getHeight() - usedSpace.getHeight());
+ blockComposer.begin(bodyFrame, XAlignmentEnum.Left, YAlignmentEnum.Top);
+ composer.setFont(textFont, textFontSize);
+ blockComposer.showText(
+ "Each puzzle starts with a poem, then the letters in each " +
+ "word are sorted. To solve the puzzle, find the original " +
+ "words and read the poem. Solutions are listed at the end.");
+ blockComposer.showBreak();
+ composer.setFont(puzzleFont, puzzleFontSize);
+ blockComposer.showText("ARX 23");
+ blockComposer.showBreak();
+ blockComposer.showText("ARX 25");
+ blockComposer.end();
+
+ composer.flush();
+ }
+
+ private static String serialize(File file, String filePath) throws IOException {
+ applyDocumentSettings(file.getDocument());
+
+ java.io.File outputFile = new java.io.File(filePath);
+ file.save(outputFile, SerializationModeEnum.Standard);
+
+ return outputFile.getPath();
+ }
+
+ private static void applyDocumentSettings(Document document) {
+ ViewerPreferences view = new ViewerPreferences(document);
+ document.setViewerPreferences(view);
+ view.setDisplayDocTitle(true);
+
+ Information info = document.getInformation();
+ info.clear();
+ info.setAuthor("Don Kirkby");
+ info.setCreationDate(new Date());
+ info.setCreator("Don Kirkby");
+ info.setTitle("Vograbulary");
+ info.setSubject("Word puzzles from the Vograbulary project");
+ info.setKeywords("word puzzles");
+ }
+}
\ No newline at end of file
diff --git a/core/src/com/github/donkirkby/vograbulary/poemsorting/Poem.java b/core/src/com/github/donkirkby/vograbulary/poemsorting/Poem.java
new file mode 100644
index 0000000..c4d22d1
--- /dev/null
+++ b/core/src/com/github/donkirkby/vograbulary/poemsorting/Poem.java
@@ -0,0 +1,68 @@
+package com.github.donkirkby.vograbulary.poemsorting;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+public class Poem {
+ private String title;
+ private ArrayList lines;
+
+ public static List load(String... lines) {
+ return load(Arrays.asList(lines));
+ }
+
+ public static List load(List lines) {
+ List poems = new ArrayList();
+ Poem poem = null;
+ String title = null;
+ for (String line : lines) {
+ if (line.startsWith("#")) {
+ if (poem != null) {
+ poems.add(poem);
+ poem = null;
+ }
+ title = line.replaceAll("^#+\\s*(.*\\S)\\s*#+$", "$1");
+ }
+ else {
+ if (poem == null){
+ poem = new Poem();
+ poem.title = title;
+ poem.lines = new ArrayList();
+ }
+ poem.lines.add(line);
+ }
+ }
+ poems.add(poem);
+ return poems;
+ }
+
+ public String getTitle() {
+ return title;
+ }
+
+ public List getLines() {
+ return lines;
+ }
+
+ public Poem sortWords() {
+ Poem poem = new Poem();
+ poem.lines = new ArrayList();
+ char[] buffer = new char[1000];
+ for (String line : lines) {
+ StringBuilder sortedWords = new StringBuilder();
+ String[] words = line.toLowerCase().split(" ");
+ for (int i = 0; i < words.length; i++) {
+ String word = words[i];
+ if (i > 0) {
+ sortedWords.append(" ");
+ }
+ word.getChars(0, word.length(), buffer, 0);
+ Arrays.sort(buffer, 0, word.length());
+ sortedWords.append(buffer, 0, word.length());
+ }
+ poem.lines.add(sortedWords.toString());
+ }
+ return poem;
+ }
+}
diff --git a/vograbulary-test/src/com/github/donkirkby/vograbulary/poemsorting/PoemTest.java b/vograbulary-test/src/com/github/donkirkby/vograbulary/poemsorting/PoemTest.java
new file mode 100644
index 0000000..6edc841
--- /dev/null
+++ b/vograbulary-test/src/com/github/donkirkby/vograbulary/poemsorting/PoemTest.java
@@ -0,0 +1,69 @@
+package com.github.donkirkby.vograbulary.poemsorting;
+
+import static org.junit.Assert.*;
+import static org.hamcrest.Matchers.*;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.junit.Test;
+
+public class PoemTest {
+ @Test
+ public void loadLines() {
+ List poems = Poem.load("The first line,", "And the second.");
+
+ assertThat("poems length", poems.size(), is(1));
+ Poem poem = poems.get(0);
+ List lines = poem.getLines();
+ assertThat("line count", lines.size(), is(2));
+ assertThat("second line", lines.get(1), is("And the second."));
+ }
+
+ @Test
+ public void loadTitle() {
+ List poems = Poem.load(
+ "# A Poem #",
+ "The first line,",
+ "And the second.");
+
+ assertThat("poems length", poems.size(), is(1));
+ Poem poem = poems.get(0);
+ List lines = poem.getLines();
+ assertThat("line count", lines.size(), is(2));
+ assertThat("second line", lines.get(1), is("And the second."));
+ assertThat("title", poem.getTitle(), is("A Poem"));
+ }
+
+ @Test
+ public void loadTwoPoems() {
+ List poems = Poem.load(
+ "# A Poem #",
+ "The first line,",
+ "And the second.",
+ "# Another Poem #",
+ "With one line");
+
+ assertThat("poems length", poems.size(), is(2));
+ assertThat("first line count", poems.get(0).getLines().size(), is(2));
+ assertThat("first title", poems.get(0).getTitle(), is("A Poem"));
+ assertThat("second line count", poems.get(1).getLines().size(), is(1));
+ assertThat("second title", poems.get(1).getTitle(), is("Another Poem"));
+ }
+
+ @Test
+ public void sortWords() {
+ List poems = Poem.load(
+ "# A Poem #",
+ "The first line,",
+ "And the second.");
+ Poem poem = poems.get(0);
+
+ Poem sorted = poem.sortWords();
+
+ assertThat("lines", sorted.getLines(), is(Arrays.asList(
+ "eht first ,eiln",
+ "adn eht .cdenos")));
+ assertThat("title", poem.getTitle(), is("A Poem"));
+ }
+}
diff --git a/wordpile/pinagrams.py b/wordpile/pinagrams.py
new file mode 100644
index 0000000..15b7787
--- /dev/null
+++ b/wordpile/pinagrams.py
@@ -0,0 +1,44 @@
+from collections import defaultdict
+from nltk.corpus import brown
+from nltk.corpus import gutenberg
+
+from word_loader import WordLoader
+
+
+def print_anagrams(sorted_words, all_words):
+ match_count = 0
+ valid_set = set(all_words)
+ matches = defaultdict(list) # {sorted_letters: [word]}
+ for word in sorted_words:
+ if word in valid_set:
+ sorted_letters = ''.join(sorted(word))
+ matching_words = matches[sorted_letters]
+ matching_words.append(word)
+ if len(matching_words) > 1:
+ print '\n'.join(matching_words)
+ print
+ match_count += 1
+ if match_count > 100:
+ return
+
+
+def main():
+ loader = WordLoader()
+ loader.load_valid_words_from_aspell("en_GB")
+ loader.load_valid_words_from_aspell("en_US")
+ all_words = brown.words() + gutenberg.words()
+ sorted_words_filename = 'sorted_words.txt'
+ loader.write_sorted_words(all_words, sorted_words_filename)
+ sorted_words = loader.sorted_words
+ print_anagrams(sorted_words, all_words)
+
+
+def test():
+ all_words = 'abcd efgh dabc'.split()
+ sorted_words = 'abcd dabc efgh'.split()
+ print_anagrams(sorted_words, all_words)
+
+if __name__ == '__main__':
+ main()
+elif __name__ == '__live_coding__':
+ test()