Initial commit

This commit is contained in:
Minecon724 2024-10-04 14:50:40 +02:00
commit f83c07c460
Signed by: Minecon724
GPG key ID: 3CCC4D267742C8E8
14 changed files with 470 additions and 0 deletions

38
.gitignore vendored Normal file
View file

@ -0,0 +1,38 @@
target/
!.mvn/wrapper/maven-wrapper.jar
!**/src/main/**/target/
!**/src/test/**/target/
### IntelliJ IDEA ###
.idea/modules.xml
.idea/jarRepositories.xml
.idea/compiler.xml
.idea/libraries/
*.iws
*.iml
*.ipr
### Eclipse ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
.sts4-cache
### NetBeans ###
/nbproject/private/
/nbbuild/
/dist/
/nbdist/
/.nb-gradle/
build/
!**/src/main/**/build/
!**/src/test/**/build/
### VS Code ###
.vscode/
### Mac OS ###
.DS_Store

3
.idea/.gitignore vendored Normal file
View file

@ -0,0 +1,3 @@
# Default ignored files
/shelf/
/workspace.xml

7
.idea/encodings.xml Normal file
View file

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Encoding">
<file url="file://$PROJECT_DIR$/src/main/java" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/src/main/resources" charset="UTF-8" />
</component>
</project>

14
.idea/misc.xml Normal file
View file

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="MavenProjectsManager">
<option name="originalFiles">
<list>
<option value="$PROJECT_DIR$/pom.xml" />
</list>
</option>
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_21" default="true" project-jdk-name="graalvm-ce-21" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/out" />
</component>
</project>

124
.idea/uiDesigner.xml Normal file
View file

@ -0,0 +1,124 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Palette2">
<group name="Swing">
<item class="com.intellij.uiDesigner.HSpacer" tooltip-text="Horizontal Spacer" icon="/com/intellij/uiDesigner/icons/hspacer.svg" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="1" hsize-policy="6" anchor="0" fill="1" />
</item>
<item class="com.intellij.uiDesigner.VSpacer" tooltip-text="Vertical Spacer" icon="/com/intellij/uiDesigner/icons/vspacer.svg" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="1" anchor="0" fill="2" />
</item>
<item class="javax.swing.JPanel" icon="/com/intellij/uiDesigner/icons/panel.svg" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3" />
</item>
<item class="javax.swing.JScrollPane" icon="/com/intellij/uiDesigner/icons/scrollPane.svg" removable="false" auto-create-binding="false" can-attach-label="true">
<default-constraints vsize-policy="7" hsize-policy="7" anchor="0" fill="3" />
</item>
<item class="javax.swing.JButton" icon="/com/intellij/uiDesigner/icons/button.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="3" anchor="0" fill="1" />
<initial-values>
<property name="text" value="Button" />
</initial-values>
</item>
<item class="javax.swing.JRadioButton" icon="/com/intellij/uiDesigner/icons/radioButton.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
<initial-values>
<property name="text" value="RadioButton" />
</initial-values>
</item>
<item class="javax.swing.JCheckBox" icon="/com/intellij/uiDesigner/icons/checkBox.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
<initial-values>
<property name="text" value="CheckBox" />
</initial-values>
</item>
<item class="javax.swing.JLabel" icon="/com/intellij/uiDesigner/icons/label.svg" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="0" anchor="8" fill="0" />
<initial-values>
<property name="text" value="Label" />
</initial-values>
</item>
<item class="javax.swing.JTextField" icon="/com/intellij/uiDesigner/icons/textField.svg" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
<preferred-size width="150" height="-1" />
</default-constraints>
</item>
<item class="javax.swing.JPasswordField" icon="/com/intellij/uiDesigner/icons/passwordField.svg" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
<preferred-size width="150" height="-1" />
</default-constraints>
</item>
<item class="javax.swing.JFormattedTextField" icon="/com/intellij/uiDesigner/icons/formattedTextField.svg" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
<preferred-size width="150" height="-1" />
</default-constraints>
</item>
<item class="javax.swing.JTextArea" icon="/com/intellij/uiDesigner/icons/textArea.svg" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JTextPane" icon="/com/intellij/uiDesigner/icons/textPane.svg" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JEditorPane" icon="/com/intellij/uiDesigner/icons/editorPane.svg" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JComboBox" icon="/com/intellij/uiDesigner/icons/comboBox.svg" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="2" anchor="8" fill="1" />
</item>
<item class="javax.swing.JTable" icon="/com/intellij/uiDesigner/icons/table.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JList" icon="/com/intellij/uiDesigner/icons/list.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="2" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JTree" icon="/com/intellij/uiDesigner/icons/tree.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JTabbedPane" icon="/com/intellij/uiDesigner/icons/tabbedPane.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
<preferred-size width="200" height="200" />
</default-constraints>
</item>
<item class="javax.swing.JSplitPane" icon="/com/intellij/uiDesigner/icons/splitPane.svg" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
<preferred-size width="200" height="200" />
</default-constraints>
</item>
<item class="javax.swing.JSpinner" icon="/com/intellij/uiDesigner/icons/spinner.svg" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
</item>
<item class="javax.swing.JSlider" icon="/com/intellij/uiDesigner/icons/slider.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
</item>
<item class="javax.swing.JSeparator" icon="/com/intellij/uiDesigner/icons/separator.svg" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3" />
</item>
<item class="javax.swing.JProgressBar" icon="/com/intellij/uiDesigner/icons/progressbar.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1" />
</item>
<item class="javax.swing.JToolBar" icon="/com/intellij/uiDesigner/icons/toolbar.svg" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1">
<preferred-size width="-1" height="20" />
</default-constraints>
</item>
<item class="javax.swing.JToolBar$Separator" icon="/com/intellij/uiDesigner/icons/toolbarSeparator.svg" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="0" anchor="0" fill="1" />
</item>
<item class="javax.swing.JScrollBar" icon="/com/intellij/uiDesigner/icons/scrollbar.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="0" anchor="0" fill="2" />
</item>
</group>
</component>
</project>

6
.idea/vcs.xml Normal file
View file

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>

26
pom.xml Normal file
View file

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>eu.m724</groupId>
<artifactId>crossword-generator</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>21</maven.compiler.source>
<maven.compiler.target>21</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<!-- https://mvnrepository.com/artifact/org.jfree/org.jfree.svg -->
<dependency>
<groupId>org.jfree</groupId>
<artifactId>org.jfree.svg</artifactId>
<version>5.0.6</version>
</dependency>
</dependencies>
</project>

View file

@ -0,0 +1,25 @@
package eu.m724;
/**
* Represents the crossword<br>
* A tile is a single letter
*
* @param width Width (x) in tiles
* @param height Height (y) in tiles
* @param solution The solution
* @param words Words of the crossword
*/
public record Crossword(
int width, int height,
String solution,
PlacedWord[] words
) {
/**
* Render as SVG
*
* @return SVG file content
*/
public String render() {
return Renderer.render(this);
}
}

View file

@ -0,0 +1,96 @@
package eu.m724;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
/**
* Easily builds {@link Crossword}s<br>
* TODO bad javadoc
*/
public class CrosswordBuilder {
private int width, height;
private String solution;
private Set<Word> words = new HashSet<>();
private Set<PlacedWord> placedWords = new HashSet<>();
/**
* Creates a new {@link CrosswordBuilder}
*
* @param width The width of the crossword
* @param height The height of the crossword
* @param solution The solution
*/
public CrosswordBuilder(int width, int height, String solution) {
this.width = width;
this.height = height;
this.solution = solution.toLowerCase();
System.out.printf("Initialized builder of %dx%d with solution \"%s\"\n", width, height, solution);
}
/**
* Add a word.
*
* @param word The word
* @param hint the hint / clue
* @return This exact {@link CrosswordBuilder}
*/
public CrosswordBuilder addWord(String word, String hint) {
return addWord(new Word(word.toLowerCase(), hint));
}
/**
* Add a word.
*
* @param word The word
* @return This exact {@link CrosswordBuilder}
*/
public CrosswordBuilder addWord(Word word) {
this.words.add(word);
System.out.println("Word added: " + word.word());
return this;
}
/**
* Add multiple words.
*
* @param words The words
* @return This exact {@link CrosswordBuilder}
*/
public CrosswordBuilder addWords(Word... words) {
this.words.addAll(Set.of(words));
System.out.println("Multiple words added: " + String.join(", ", Arrays.stream(words).map(Word::word).toList()));
return this;
}
public CrosswordBuilder generate() {
System.out.println("Generator invoked");
placedWords = Generator.generate(width, height, solution, words.toArray(Word[]::new));
System.out.println("Generator done");
return this;
}
/**
* Builds a {@link Crossword}
*
* @throws SizeMismatchException When not all words have been placed. Or too many, for some reason.
* @return The {@link Crossword}
*/
public Crossword build() throws SizeMismatchException { // TODO maybe it should be unchecked
System.out.println("Building");
// TODO
if (words.size() != placedWords.size()) {
throw new SizeMismatchException("Words: %d, placed: %d".formatted(words.size(), placedWords.size()));
}
return new Crossword(width, height, solution, placedWords.toArray(PlacedWord[]::new));
}
/**
* When not all words have been placed. Or too many, for some reason.
*/
public static class SizeMismatchException extends Exception {
public SizeMismatchException(String message) {
super(message);
}
}
}

View file

@ -0,0 +1,45 @@
package eu.m724;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.ThreadLocalRandom;
public class Generator {
public static Set<PlacedWord> generate(int width, int height, String solution, Word[] words) {
ThreadLocalRandom random = ThreadLocalRandom.current();
Set<PlacedWord> placedWords = new HashSet<>(words.length);
System.out.printf("Generator running with %d words\n", words.length);
boolean vertical = random.nextBoolean();
for (int i=0; i<words.length; i++) {
Word word = words[i];
placedWords.add(new PlacedWord(0, i, false, word));
vertical = !vertical;
}
return placedWords;
}
private static PlacedWord getWordAt(int x, int y, Set<PlacedWord> placedWords) {
for (PlacedWord placedWord : placedWords) {
if (placedWord == null) continue;
if (placedWord.vertical()) {
if (placedWord.x() == x) {
if (y >= placedWord.y() && y <= placedWord.y() + placedWord.wordLength() - 1) {
return placedWord;
}
}
} else {
if (placedWord.y() == y) {
if (x >= placedWord.x() && x <= placedWord.y() + placedWord.wordLength() - 1) {
return placedWord;
}
}
}
}
return null;
}
}

View file

@ -0,0 +1,20 @@
package eu.m724;
public class Main {
public static void main(String[] args) throws CrosswordBuilder.SizeMismatchException {
CrosswordBuilder builder = new CrosswordBuilder(20, 20, "ardour")
.addWord("cat", "Furry feline pet")
.addWord("sun", "Bright star in our sky")
.addWord("book", "Bound pages with a story")
.addWord("tree", "Woody plant with branches")
.addWord("blue", "Color of a clear sky")
.addWord("door", "Entrance to a room")
.generate();
Crossword crossword = builder.build();
System.out.println(crossword.render());
System.out.println("Hello world!");
}
}

View file

@ -0,0 +1,20 @@
package eu.m724;
/**
* Represents a placement of a word
*
* @param x x of the first letter
* @param y y of the first letter
* @param vertical is the word, from the first letter, downwards (true), or rightwards (false)
* @param word the word
*/
public record PlacedWord(
int x,
int y,
boolean vertical,
Word word
) {
public int wordLength() {
return word.word().length();
}
}

View file

@ -0,0 +1,29 @@
package eu.m724;
import org.jfree.svg.SVGGraphics2D;
import java.awt.*;
public class Renderer {
public static String render(Crossword crossword) {
SVGGraphics2D g2 = new SVGGraphics2D(crossword.width() * 10, crossword.height() * 10);
g2.setPaint(Color.BLACK);
for (PlacedWord word : crossword.words()) {
int x = word.x();
int y = word.y();
if (word.vertical()) {
for (int _y=y; _y<y+word.wordLength(); _y++) {
g2.draw(new Rectangle(x * 10, _y * 10, 10, 10));
}
} else {
for (int _x=x; _x<x+word.wordLength(); _x++) {
g2.draw(new Rectangle(_x * 10, y * 10, 10, 10));
}
}
}
//g2.draw(new Rectangle(10, 10, 280, 180));
return g2.getSVGDocument();
}
}

View file

@ -0,0 +1,17 @@
package eu.m724;
/**
* Represents a word and a hint.<br>
* The word should be lowercase. TODO make that not a requirement
*
* @param word the word
* @param hint the hint / clue
*/
public record Word(
String word,
String hint
) {
public int length() {
return word.length();
}
}