Compare commits
4 commits
472106ba3a
...
500dcc1b9a
Author | SHA1 | Date | |
---|---|---|---|
500dcc1b9a | |||
45a9ae4f20 | |||
6aab6e4b96 | |||
79dbff72c1 |
4 changed files with 87 additions and 13 deletions
10
README.md
Normal file
10
README.md
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
# Crossword generator
|
||||||
|
|
||||||
|
### Usage
|
||||||
|
See `src/main/java/eu/m724/crossword/Main.java`
|
||||||
|
|
||||||
|
### Speed
|
||||||
|
Generally, slow. \
|
||||||
|
Compared to mining:
|
||||||
|
- difficulty: the "tighter", the slower. It has to fit the words on the surface somehow, it bruteforces a good placement, if it's more crowded it'll have to try harder
|
||||||
|
- luck
|
|
@ -80,6 +80,11 @@ public class Generator {
|
||||||
}
|
}
|
||||||
System.out.println("Possible placements: " + possiblePlacements.size() + " * 2");
|
System.out.println("Possible placements: " + possiblePlacements.size() + " * 2");
|
||||||
|
|
||||||
|
int totalCharacters = Arrays.stream(words).map(w -> w.length() + 1).reduce(0, Integer::sum);
|
||||||
|
if (totalCharacters > possiblePlacements.size()) {
|
||||||
|
System.out.printf("Warning: there might be no solution (%d > %d)", totalCharacters, possiblePlacements.size());
|
||||||
|
}
|
||||||
|
|
||||||
/*for (Word word : words) {
|
/*for (Word word : words) {
|
||||||
PlacedWord placedWord = null;
|
PlacedWord placedWord = null;
|
||||||
|
|
||||||
|
@ -144,11 +149,14 @@ public class Generator {
|
||||||
|
|
||||||
List<Vec> currentPossiblePlacements = new ArrayList<>(possiblePlacements);
|
List<Vec> currentPossiblePlacements = new ArrayList<>(possiblePlacements);
|
||||||
shuffle(currentPossiblePlacements);
|
shuffle(currentPossiblePlacements);
|
||||||
//Collections.shuffle(currentPossiblePlacements);
|
|
||||||
|
|
||||||
boolean vertical = random.nextBoolean();
|
boolean vertical = random.nextBoolean();
|
||||||
Word word = words[wordIndex];
|
Word word = words[wordIndex];
|
||||||
|
|
||||||
|
// TODO optimize. maybe make this a list. and consider if this is really necessary.
|
||||||
|
Map<Integer, List<PlacedWord>> rankedPlacements = new LinkedHashMap<>();
|
||||||
|
int hi = -1;
|
||||||
|
|
||||||
for (int i=0; i<2; i++) { // repeating twice to pass horizontal and vertical
|
for (int i=0; i<2; i++) { // repeating twice to pass horizontal and vertical
|
||||||
vertical = !vertical;
|
vertical = !vertical;
|
||||||
|
|
||||||
|
@ -162,9 +170,59 @@ public class Generator {
|
||||||
}
|
}
|
||||||
|
|
||||||
PlacedWord candidate = new PlacedWord(placement, vertical, word);
|
PlacedWord candidate = new PlacedWord(placement, vertical, word);
|
||||||
|
int placementResult = grid.canPlace(candidate);
|
||||||
|
|
||||||
if (grid.canPlace(candidate)) {
|
if (placementResult != -1) {
|
||||||
System.out.println(" Found candidate");
|
//System.out.println(" Found candidate");
|
||||||
|
rankedPlacements.computeIfAbsent(placementResult, k -> new ArrayList<>()).add(candidate);
|
||||||
|
if (placementResult > hi) hi = placementResult;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
System.out.println("hi " + hi);
|
||||||
|
|
||||||
|
for (int i=hi; i>=0; i--) {
|
||||||
|
//List<PlacedWord> candidates = rankedPlacements.getOrDefault(i, new ArrayList<>());
|
||||||
|
//System.out.println(" Candidates: " + candidates.size());
|
||||||
|
for (PlacedWord candidate : rankedPlacements.getOrDefault(i, new ArrayList<>())) {
|
||||||
|
Set<PlacedWord> potentialChain = new HashSet<>(placedChain);
|
||||||
|
|
||||||
|
potentialChain.add(candidate);
|
||||||
|
|
||||||
|
Grid newGrid = grid.clone();
|
||||||
|
newGrid.placeWord(candidate);
|
||||||
|
|
||||||
|
Set<PlacedWord> newChain = follow(newGrid, potentialChain, wordIndex + 1);
|
||||||
|
System.out.println("Back to depth " + wordIndex);
|
||||||
|
|
||||||
|
// if it's null it means there's no good placement, and we should continue searching at this depth
|
||||||
|
if (newChain != null) {
|
||||||
|
System.out.println(" Done here");
|
||||||
|
return newChain;
|
||||||
|
} else {
|
||||||
|
System.out.println(" Looking further");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*for (int i=0; i<2; i++) { // repeating twice to pass horizontal and vertical
|
||||||
|
vertical = !vertical;
|
||||||
|
|
||||||
|
for (Vec placement : currentPossiblePlacements) {
|
||||||
|
if (vertical) {
|
||||||
|
int y = placement.y();
|
||||||
|
if (y == 0 || y + word.length() >= height) continue;
|
||||||
|
} else {
|
||||||
|
int x = placement.x();
|
||||||
|
if (x == 0 || x + word.length() >= width) continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
PlacedWord candidate = new PlacedWord(placement, vertical, word);
|
||||||
|
|
||||||
|
if (grid.canPlace(candidate) != -1) {
|
||||||
|
//System.out.println(" Found candidate");
|
||||||
Set<PlacedWord> potentialChain = new HashSet<>(placedChain);
|
Set<PlacedWord> potentialChain = new HashSet<>(placedChain);
|
||||||
potentialChain.add(candidate);
|
potentialChain.add(candidate);
|
||||||
|
|
||||||
|
@ -172,18 +230,18 @@ public class Generator {
|
||||||
newGrid.placeWord(candidate);
|
newGrid.placeWord(candidate);
|
||||||
|
|
||||||
Set<PlacedWord> newChain = follow(newGrid, potentialChain, wordIndex + 1);
|
Set<PlacedWord> newChain = follow(newGrid, potentialChain, wordIndex + 1);
|
||||||
System.out.println("Back to depth " + wordIndex);
|
//System.out.println("Back to depth " + wordIndex);
|
||||||
|
|
||||||
// if it's null it means there's no good placement, and we should continue searching at this depth
|
// if it's null it means there's no good placement, and we should continue searching at this depth
|
||||||
if (newChain != null) {
|
if (newChain != null) {
|
||||||
System.out.println(" Unfolding"); // is that a correct word?
|
//System.out.println(" Unfolding"); // is that a correct word?
|
||||||
return newChain;
|
return newChain;
|
||||||
} else {
|
} else {
|
||||||
System.out.println(" Looking further");
|
//System.out.println(" Looking further");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}*/
|
||||||
|
|
||||||
System.out.println(" No solution");
|
System.out.println(" No solution");
|
||||||
// no placement at this depth
|
// no placement at this depth
|
||||||
|
|
|
@ -46,9 +46,11 @@ public class Grid implements Cloneable {
|
||||||
* Can a word be placed, will it not collide
|
* Can a word be placed, will it not collide
|
||||||
*
|
*
|
||||||
* @param word The word
|
* @param word The word
|
||||||
* @return can it be placed
|
* @return can it be placed. -1 = no, 0 = yes, >0 = yes and will be over n characters
|
||||||
*/
|
*/
|
||||||
public boolean canPlace(PlacedWord word) {
|
public int canPlace(PlacedWord word) {
|
||||||
|
int cols = 0;
|
||||||
|
|
||||||
int x = word.pos().x();
|
int x = word.pos().x();
|
||||||
int y = word.pos().y();
|
int y = word.pos().y();
|
||||||
|
|
||||||
|
@ -67,12 +69,16 @@ public class Grid implements Cloneable {
|
||||||
c = word.word().text().charAt(i);
|
c = word.word().text().charAt(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (charArray[_x][_y] != 0 && charArray[_x][_y] != c) {
|
if (charArray[_x][_y] != 0) {
|
||||||
return false;
|
if (charArray[_x][_y] != c) {
|
||||||
|
return -1;
|
||||||
|
} else {
|
||||||
|
cols++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return cols;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -2,7 +2,7 @@ package eu.m724.crossword;
|
||||||
|
|
||||||
public class Main {
|
public class Main {
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
CrosswordBuilder builder = new CrosswordBuilder(12, 12, "crossword")
|
CrosswordBuilder builder = new CrosswordBuilder(20, 20, "crossword")
|
||||||
.addWord("cat", "Furry feline pet")
|
.addWord("cat", "Furry feline pet")
|
||||||
.addWord("owl", "Nocturnal bird of prey")
|
.addWord("owl", "Nocturnal bird of prey")
|
||||||
.addWord("kite", "Flying toy on a string")
|
.addWord("kite", "Flying toy on a string")
|
||||||
|
|
Loading…
Reference in a new issue