diff --git a/cross-world.crossword-generator/pom.xml b/cross-world.crossword-generator/pom.xml
index 4303f08..7acec4a 100644
--- a/cross-world.crossword-generator/pom.xml
+++ b/cross-world.crossword-generator/pom.xml
@@ -1,37 +1,42 @@
- 4.0.0
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ 4.0.0
- cross-world.crossword-generator
- jar
+ cross-world.crossword-generator
+ jar
- cross-world.crossword-generator
+ cross-world.crossword-generator
-
- UTF-8
-
+
+ UTF-8
+
-
-
- junit
- junit
- 3.8.1
- test
-
-
- team-rocket
- cross-world.commons
- 1.0.0
-
-
- org.mongodb
- mongo-java-driver
- 2.7.2
-
-
-
- team-rocket
- cross-world.parent
- 1.0.0
-
+
+
+ junit
+ junit
+ 3.8.1
+ test
+
+
+ log4j
+ log4j
+ 1.2.16
+
+
+ team-rocket
+ cross-world.commons
+ 1.0.0
+
+
+ org.mongodb
+ mongo-java-driver
+ 2.7.2
+
+
+
+ team-rocket
+ cross-world.parent
+ 1.0.0
+
diff --git a/cross-world.crossword-generator/src/main/java/team_rocket/cross_world/crossword_generator/CrossWorldCrosswordGenerator.java b/cross-world.crossword-generator/src/main/java/team_rocket/cross_world/crossword_generator/CrossWorldCrosswordGenerator.java
index 33155f6..ab52358 100644
--- a/cross-world.crossword-generator/src/main/java/team_rocket/cross_world/crossword_generator/CrossWorldCrosswordGenerator.java
+++ b/cross-world.crossword-generator/src/main/java/team_rocket/cross_world/crossword_generator/CrossWorldCrosswordGenerator.java
@@ -1,6 +1,7 @@
package team_rocket.cross_world.crossword_generator;
import java.net.UnknownHostException;
+import java.util.AbstractMap.SimpleImmutableEntry;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Deque;
@@ -9,7 +10,6 @@
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
-import java.util.AbstractMap.SimpleImmutableEntry;
import java.util.Map.Entry;
import java.util.Random;
import java.util.Set;
@@ -20,17 +20,45 @@
public class CrossWorldCrosswordGenerator implements CrosswordGenerator {
+ // private static Logger logger = Logger
+ // .getLogger(CrossWorldCrosswordGenerator.class);
+
private WordProvider wordProvider;
public static void main(String[] args) throws Exception {
+ // BasicConfigurator.configure();
+ // logger.addAppender(new FileAppender(new SimpleLayout(),
+ // "/crossword-generator.log"));
+ // logger.addAppender(new ConsoleAppender(new SimpleLayout()));
+
CrossWorldCrosswordGenerator cwcg = new CrossWorldCrosswordGenerator(
new WordProvider(new WordDictionaryCreator()));
// cwcg.generateCrossword(3, 5, new int[] { 3, 4, 5, 6, 10, 11, });
// cwcg.generateCrossword(3, 3, new int[] {});
- //cwcg.generateCrossword(5, 5, new int[] {});
- cwcg.generateCrossword(9, 9, new int[] { 0, 1, 2, 6, 7, 8, 9, 10, 16,
- 17, 18, 26, 31, 39, 40, 41, 49, 54, 62, 63, 64, 70, 71, 72, 73,
- 74, 78, 79, 80 });
+ // cwcg.generateCrossword(5, 5, new int[] {});
+// cwcg.generateCrossword(9, 9, new int[] { 0, 1, 2, 6, 7, 8, 9, 10, 16,
+// 17, 18, 26, 31, 39, 40, 41, 49, 54, 62, 63, 64, 70, 71, 72, 73,
+// 74, 78, 79, 80 });
+// cwcg.generateCrossword(13, 13, new int[] {
+// 4, 17, 30, 134, 147, 160, 8, 21, 34, 138, 151, 164,
+// 52, 53, 54, 62, 63, 64, 104, 105, 106, 114, 115, 116,
+// 45,
+// 58,
+// 70, 71, 72,
+// 81, 82, 83, 84, 85, 86, 87,
+// 96, 97, 98,
+// 110,
+// 123
+// });
+ cwcg.generateCrossword(13, 13, new int[] {
+ 4, 17, 30, 134, 147, 160, 8, 21, 34, 138, 151, 164,
+ 52, 53, 54, 62, 63, 64, 104, 105, 106, 114, 115, 116,
+ 58,
+ 70, 71, 72,
+ 82, 83, 84, 85, 86,
+ 96, 97, 98,
+ 110
+ });
}
@@ -66,7 +94,6 @@ private void printState(Map state)
+ wordProvider.getWord(
wordEntry.getValue().getWordLength(),
chosenWordIndex));
-
}
}
@@ -117,6 +144,7 @@ private WordState getMostConstrainedWordState(
private int getBestWordMatch(WordState wordState,
Map state, boolean[] preconditions)
throws UnknownHostException, MongoException {
+ //TODO: extract 10
int wordCount = Math.min(wordState.getNumberOfChoice(), 10);
boolean[] avalableWords = wordState.getAvailableWords();
if (preconditions != null) {
@@ -225,10 +253,64 @@ private Set getRandomAvailableWords(boolean[] availableWords,
}
return chosenWordIndexes;
}
+
+ /**
+ * Creates a starting grid and lists for the starting positions of the words.
+ * crosswordField
must contain 0 in every cell that is considered free and -1 for
+ * every unavailable("blank") cell.
+ * Modifies crosswordField
to contain the starting grid, acrossWords
and
+ * downWords
to contain the start index and position of the across words and down
+ * words.
+ *
+ * @param crosswordField
+ * @param acrossWords
+ * @param downWords
+ */
+ public static void createStartingGrid(int[][] crosswordField, List acrossWords,
+ List downWords) {
+ int wordIndex = 1;
+ int rows = crosswordField.length;
+ int cols = crosswordField[0].length;
+
+ for (int i = 0; i < rows; i++) {
+ for (int j = 0; j < cols; j++) {
+ if (crosswordField[i][j] != -1) {
+ boolean isWordStart = false;
+ if ((i == 0) || (crosswordField[i - 1][j] == -1)) {
+ int k = 0;
+ while ((k + i) < rows && crosswordField[i + k][j] != -1) {
+ k++;
+ }
+ if (k > 2) {
+ downWords.add(new int[] { wordIndex, i, j });
+ isWordStart = true;
+ }
+ }
+ if ((j == 0) || (crosswordField[i][j - 1] == -1)) {
+ int k = 0;
+ while ((j + k) < cols && crosswordField[i][j + k] != -1) {
+ k++;
+ }
+ if (k > 2) {
+ acrossWords.add(new int[] { wordIndex, i, j });
+ isWordStart = true;
+ }
+ }
+
+ if (isWordStart) {
+ crosswordField[i][j] = wordIndex;
+ wordIndex++;
+ }
+ }
+ }
+ }
+ }
+
private boolean getFinalState(Map wordStateMap)
throws UnknownHostException, MongoException {
WordState wordState = null;
+ Map> backtracksPerWordstate = new HashMap>();
Deque crosswordStates = new LinkedList();
boolean[] preconditions = null;
do {
@@ -240,9 +322,7 @@ private boolean getFinalState(Map wordStateMap)
return true;
}
- System.out.println("Processing "
- + wordState.getId().getWordNumber() + ", "
- + (wordState.getId().isAcross() ? "across" : "down"));
+ System.out.println("Processing " + getIdentifierString(wordState));
// get best word match (intelligent instantiation)
int bestWordIndex = getBestWordMatch(wordState, wordStateMap,
@@ -252,25 +332,73 @@ private boolean getFinalState(Map wordStateMap)
String word = wordProvider.getWord(wordState.getWordLength(),
bestWordIndex);
CrosswordState crosswordState = getCurrentState(wordStateMap,
- wordState, word);
+ wordState, word, bestWordIndex);
crosswordStates.addLast(crosswordState);
-
+
changeCurrentState(wordStateMap, wordState, bestWordIndex, word);
wordState = null;
} else {
+ backtracksPerWordstate
+ .put(wordState, new LinkedList());
CrosswordState crosswordState;
+ List backtracksTries;
List backtrackedStates = new LinkedList();
do {
System.out.println("Backtracking");
crosswordState = crosswordStates.removeLast();
backtrackedStates.add(crosswordState);
revertState(wordStateMap, crosswordState);
+ backtracksTries = backtracksPerWordstate
+ .put(crosswordState.wordState,
+ new LinkedList());
} while (getCrossedIndex(wordState, crosswordState.wordState) == -1);
- preconditions = getPreconditions(backtrackedStates, wordState);
+
+ if (backtracksTries == null) {
+ backtracksTries = new LinkedList();
+ }
+
+ boolean calculatePreconditions = true;
+ while (backtracksTries.size() == 5) {
+ calculatePreconditions = false;
+ backtracksPerWordstate.put(crosswordState.wordState,
+ new LinkedList());
+ crosswordState = crosswordStates.removeLast();
+ revertState(wordStateMap, crosswordState);
+ backtracksTries = backtracksPerWordstate
+ .get(crosswordState.wordState);
+ if (backtracksTries == null) {
+ backtracksTries = new LinkedList();
+ }
+ System.out
+ .println("Backtrack count exceeded. Backtracking to "
+ + getIdentifierString(crosswordState.wordState)
+ + " - number of backtracks: "
+ + backtracksTries);
+ }
+ backtracksTries.add(crosswordState.wordIndex);
+ backtracksPerWordstate.put(crosswordState.wordState,
+ backtracksTries);
+ // backtracksPerWordstate.put(crosswordState.wordState,
+ // backtracksTries + 1);
+ if (calculatePreconditions) {
+ preconditions = getPreconditions(backtrackedStates,
+ wordState);
+ } else {
+ preconditions = new boolean[crosswordState.wordState
+ .getAvailableWords().length];
+ for (int i = 0; i < backtracksTries.size(); i++) {
+ preconditions[backtracksTries.get(i)] = true;
+ }
+ }
wordState = crosswordState.wordState;
}
- } while (!crosswordStates.isEmpty());
- return false;
+ } while (true);
+ // return false;
+ }
+
+ private String getIdentifierString(WordState wordState) {
+ return wordState.getId().getWordNumber() + ", "
+ + (wordState.getId().isAcross() ? "across" : "down");
}
private boolean[] getPreconditions(List backtrackedStates,
@@ -343,7 +471,8 @@ private void revertState(Map wordStateMap,
private void changeCurrentState(
Map wordStateMap, WordState wordState,
- int bestWordIndex, String word) throws UnknownHostException, MongoException {
+ int bestWordIndex, String word) throws UnknownHostException,
+ MongoException {
System.out.println("Chose : " + word);
@@ -355,16 +484,20 @@ private void changeCurrentState(
}
wordState.setAvailableWords(availableWords);
wordState.setWord(word);
-
+
// change crossed states
for (int i = 0; i < wordState.getCrossedWords().size(); i++) {
Entry crossedWordEntry = wordState
.getCrossedWords().get(i);
if (crossedWordEntry == null) {
continue;
- }// TODO if is processed dont do that
+ }
WordState crossedWordState = wordStateMap.get(crossedWordEntry
.getKey());
+// TODO if is processed dont do that
+// if(crossedWordState.isProcessed()) {
+// continue;
+// }
boolean[] crossedState = crossedWordState.getAvailableWords();
wordProvider.intersect(crossedState,
crossedWordState.getWordLength(),
@@ -380,7 +513,8 @@ private void changeCurrentState(
}
private CrosswordState getCurrentState(
- Map wordStateMap, WordState wordState, String word) {
+ Map wordStateMap, WordState wordState,
+ String word, int wordIndex) {
boolean[] oldAvailableWords = wordState.getAvailableWords().clone();
boolean[][] oldCrossedWordStates = new boolean[wordState
.getWordLength()][wordState.getAvailableWords().length];
@@ -401,6 +535,7 @@ private CrosswordState getCurrentState(
crosswordState.oldCrossedWordStates = oldCrossedWordStates;
crosswordState.wordState = wordState;
crosswordState.word = word;
+ crosswordState.wordIndex = wordIndex;
return crosswordState;
}
@@ -413,45 +548,47 @@ private Map generateStartingState(int cols,
printCrossword(cols, rows, crosswordField);
- // Fills array with word indexes.
- // Calculates on which index there is a word's start.
- int wordIndex = 1;
- // gridnum, row, col
List acrossWords = new ArrayList();
List downWords = new ArrayList();
- for (int i = 0; i < rows; i++) {
- for (int j = 0; j < cols; j++) {
- if (crosswordField[i][j] != -1) {
- boolean isWordStart = false;
- if ((i == 0) || (crosswordField[i - 1][j] == -1)) {
- int k = 0;
- while ((k + i) < rows && crosswordField[i + k][j] != -1) {
- k++;
- }
- if (k > 2) {
- downWords.add(new int[] { wordIndex, i, j });
- isWordStart = true;
- }
- }
-
- if ((j == 0) || (crosswordField[i][j - 1] == -1)) {
- int k = 0;
- while ((j + k) < cols && crosswordField[i][j + k] != -1) {
- k++;
- }
- if (k > 2) {
- acrossWords.add(new int[] { wordIndex, i, j });
- isWordStart = true;
- }
- }
-
- if (isWordStart) {
- crosswordField[i][j] = wordIndex;
- wordIndex++;
- }
- }
- }
- }
+ createStartingGrid(crosswordField, acrossWords, downWords);
+
+// // Fills array with word indexes.
+// // Calculates on which index there is a word's start.
+// int wordIndex = 1;
+// // gridnum, row, col
+// for (int i = 0; i < rows; i++) {
+// for (int j = 0; j < cols; j++) {
+// if (crosswordField[i][j] != -1) {
+// boolean isWordStart = false;
+// if ((i == 0) || (crosswordField[i - 1][j] == -1)) {
+// int k = 0;
+// while ((k + i) < rows && crosswordField[i + k][j] != -1) {
+// k++;
+// }
+// if (k > 2) {
+// downWords.add(new int[] { wordIndex, i, j });
+// isWordStart = true;
+// }
+// }
+//
+// if ((j == 0) || (crosswordField[i][j - 1] == -1)) {
+// int k = 0;
+// while ((j + k) < cols && crosswordField[i][j + k] != -1) {
+// k++;
+// }
+// if (k > 2) {
+// acrossWords.add(new int[] { wordIndex, i, j });
+// isWordStart = true;
+// }
+// }
+//
+// if (isWordStart) {
+// crosswordField[i][j] = wordIndex;
+// wordIndex++;
+// }
+// }
+// }
+// }
printCrossword(cols, rows, crosswordField);
@@ -536,10 +673,15 @@ private Map generateStartingState(int cols,
private void printCrossword(int cols, int rows, int[][] crosswordField) {
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
- System.out.print(crosswordField[i][j] + " ");
+ // logger.info(crosswordField[i][j] + " ");
+ System.out.print((crosswordField[i][j] >= 0 ? " " : "")
+ + (crosswordField[i][j] < 10 ? " " : "")
+ + crosswordField[i][j] + " ");
}
+ // logger.info("\n");
System.out.println();
}
+ // logger.info("\n");
System.out.println();
}
diff --git a/cross-world.crossword-generator/src/main/java/team_rocket/cross_world/crossword_generator/CrosswordConverter.java b/cross-world.crossword-generator/src/main/java/team_rocket/cross_world/crossword_generator/CrosswordConverter.java
new file mode 100644
index 0000000..b2757eb
--- /dev/null
+++ b/cross-world.crossword-generator/src/main/java/team_rocket/cross_world/crossword_generator/CrosswordConverter.java
@@ -0,0 +1,119 @@
+package team_rocket.cross_world.crossword_generator;
+
+import java.net.UnknownHostException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Random;
+
+import com.mongodb.BasicDBObject;
+import com.mongodb.DB;
+import com.mongodb.DBCollection;
+import com.mongodb.MongoException;
+import com.mongodb.Mongo;
+
+import static team_rocket.cross_world.commons.constants.Constants.Mongo.*;
+import team_rocket.cross_world.commons.data.Crossword;
+
+public class CrosswordConverter {
+
+ private static DBCollection mWordsCollection;
+ private static Random random = new Random();
+
+ public static Crossword convertCrossword(WordProvider wordProvider, int[] blanks, int rows,
+ int cols, Map crossword)
+ throws UnknownHostException, MongoException {
+ int[][] crosswordField = new int[rows][cols];
+ for (int blank : blanks) {
+ crosswordField[blank / cols][blank % cols] = -1;
+ }
+
+ List acrossWords = new ArrayList();
+ List downWords = new ArrayList();
+
+ CrossWorldCrosswordGenerator.createStartingGrid(crosswordField, acrossWords, downWords);
+
+ Map acrossWordsPositions =
+ createWordsIndexGridPositionsMapping(acrossWords);
+ Map downWordsPositions =
+ createWordsIndexGridPositionsMapping(downWords);
+
+ int[] gridNums = createGridNumbers(rows, cols, crosswordField);
+
+ initializaDB();
+
+ char[] grid = new char[rows * cols];
+ List cluesAcross = new ArrayList(acrossWordsPositions.size());
+ List cluesDown = new ArrayList(downWordsPositions.size());
+ for (Map.Entry entry : crossword.entrySet()) {
+ WordState state = entry.getValue();
+ WordIdentifier identifier = entry.getKey();
+
+ int wordIndex = 0;
+ while (!state.getAvailableWords()[wordIndex]) {
+ wordIndex++;
+ }
+ String word = wordProvider.getWord(state.getWordLength(), wordIndex);
+
+ int indexInCrossword = identifier.getWordNumber();
+ int[] wordPositionInCrossword = (identifier.isAcross() ? acrossWordsPositions :
+ downWordsPositions).get(indexInCrossword);
+ int wordPositionInGrid = wordPositionInCrossword[0] * cols + wordPositionInCrossword[1];
+ for (int i = 0; i < word.length(); i++) {
+ grid[wordPositionInGrid + (identifier.isAcross() ? i : i * cols)] = word.charAt(i);
+ }
+
+ String[] clues = (String[])mWordsCollection.findOne(new BasicDBObject(FIELD_WORDS_WORD,
+ word)).get(FIELD_WORDS_CLUES);
+ String clue = indexInCrossword + ". " + clues[random.nextInt(clues.length)];
+ (identifier.isAcross() ? cluesAcross : cluesDown).add(clue);
+ }
+
+ Crossword resultingCrossword = new Crossword();
+ resultingCrossword.setRows(rows);
+ resultingCrossword.setCols(cols);
+ resultingCrossword.setGridNums(gridNums);
+ resultingCrossword.setGrid(grid);
+
+ String[] resultingCluesAcross = new String[cluesAcross.size()];
+ cluesAcross.toArray(resultingCluesAcross);
+ resultingCrossword.setCluesAcross(resultingCluesAcross);
+
+ String[] resultingCluesDown = new String[cluesAcross.size()];
+ cluesDown.toArray(resultingCluesDown);
+ resultingCrossword.setCluesDown(resultingCluesDown);
+
+ return resultingCrossword;
+ }
+
+ private static int[] createGridNumbers(int rows, int cols,
+ int[][] crosswordField) {
+ int[] gridNums = new int[rows * cols];
+ for (int i = 0; i < crosswordField.length; i++) {
+ for (int j = 0; j < crosswordField[i].length; j++) {
+ gridNums[i + j] = crosswordField[i][j] <= 0 ? 0 : crosswordField[i][j];
+ }
+ }
+ return gridNums;
+ }
+
+ private static Map createWordsIndexGridPositionsMapping(
+ List acrossWords) {
+ Map acrossWordsPositions = new HashMap();
+ for (Iterator iterator = acrossWords.iterator(); iterator.hasNext();) {
+ int[] is = (int[]) iterator.next();
+ acrossWordsPositions.put(is[0], new int[] {is[1], is[2]});
+ }
+ return acrossWordsPositions;
+ }
+
+ private static void initializaDB() throws UnknownHostException, MongoException {
+ if (mWordsCollection != null) {
+ Mongo mongo = new Mongo();
+ DB crossWorld = mongo.getDB(DB_NAME);
+ mWordsCollection = crossWorld.getCollection(DB_COLLECTION_WORDS);
+ }
+ }
+}
diff --git a/cross-world.crossword-generator/src/main/java/team_rocket/cross_world/crossword_generator/CrosswordState.java b/cross-world.crossword-generator/src/main/java/team_rocket/cross_world/crossword_generator/CrosswordState.java
index ea6cc1c..c9f6773 100644
--- a/cross-world.crossword-generator/src/main/java/team_rocket/cross_world/crossword_generator/CrosswordState.java
+++ b/cross-world.crossword-generator/src/main/java/team_rocket/cross_world/crossword_generator/CrosswordState.java
@@ -4,5 +4,6 @@ public class CrosswordState {
public boolean[] oldAvailableWords;
public boolean[][] oldCrossedWordStates;
public String word;
+ public int wordIndex;
public WordState wordState;
}
diff --git a/cross-world.crossword-generator/src/main/resources/log4j.properties b/cross-world.crossword-generator/src/main/resources/log4j.properties
new file mode 100644
index 0000000..e4fcb01
--- /dev/null
+++ b/cross-world.crossword-generator/src/main/resources/log4j.properties
@@ -0,0 +1,9 @@
+# Set root logger level to DEBUG and its only appender to A1.
+log4j.rootLogger=DEBUG, A1
+
+# A1 is set to be a ConsoleAppender.
+log4j.appender.A1=org.apache.log4j.ConsoleAppender
+
+# A1 uses PatternLayout.
+log4j.appender.A1.layout=org.apache.log4j.PatternLayout
+log4j.appender.A1.layout.ConversionPattern=%-4r [%t] %-5p %c %x - %m%n
\ No newline at end of file