Compare commits
40 Commits
Author | SHA1 | Date | |
---|---|---|---|
2b18a6bd9f | |||
ea70aa5181 | |||
ef8050a5f9 | |||
7d7e660c77 | |||
acaa18ffcc | |||
c781b364d8 | |||
d681f20b90 | |||
ef569e1bcb | |||
74ba71d52c | |||
7708654bdb | |||
004fe776eb | |||
c2c5ac6e68 | |||
0198ba6e56 | |||
![]() |
f5ca09cc67 | ||
1187bedc5b | |||
21fa946011 | |||
2827d79556 | |||
![]() |
367ad5921a | ||
![]() |
fd82088a08 | ||
8e836b1183 | |||
44125ce13a | |||
76b44d22cf | |||
d19f9899cf | |||
![]() |
7e536cf644 | ||
![]() |
f5c63f9401 | ||
c72efa8b44 | |||
07ab0b898f | |||
ffaa310dbe | |||
7323fa8fb8 | |||
543d868bef | |||
223a92910e | |||
![]() |
d25cd93736 | ||
![]() |
d5fc28d743 | ||
![]() |
72f36b2fe1 | ||
![]() |
46f3cb1386 | ||
![]() |
79a1f939e6 | ||
![]() |
2592ca511f | ||
![]() |
3e5e2e01ec | ||
![]() |
21125ed895 | ||
![]() |
dddfb6f622 |
7
.gitignore
vendored
7
.gitignore
vendored
@ -41,4 +41,9 @@ bin/
|
|||||||
### Mac OS ###
|
### Mac OS ###
|
||||||
.DS_Store
|
.DS_Store
|
||||||
.idea
|
.idea
|
||||||
lib
|
lib
|
||||||
|
target
|
||||||
|
.mvn
|
||||||
|
src/main/resources/META-INF
|
||||||
|
mvnw
|
||||||
|
mvnw.cmd
|
||||||
|
8
.idea/.gitignore
generated
vendored
8
.idea/.gitignore
generated
vendored
@ -1,8 +0,0 @@
|
|||||||
# Default ignored files
|
|
||||||
/shelf/
|
|
||||||
/workspace.xml
|
|
||||||
# Editor-based HTTP Client requests
|
|
||||||
/httpRequests/
|
|
||||||
# Datasource local storage ignored files
|
|
||||||
/dataSources/
|
|
||||||
/dataSources.local.xml
|
|
15
.idea/checkstyle-idea.xml
generated
15
.idea/checkstyle-idea.xml
generated
@ -1,15 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="CheckStyle-IDEA" serialisationVersion="2">
|
|
||||||
<checkstyleVersion>10.15.0</checkstyleVersion>
|
|
||||||
<scanScope>JavaOnly</scanScope>
|
|
||||||
<option name="thirdPartyClasspath" />
|
|
||||||
<option name="activeLocationIds" />
|
|
||||||
<option name="locations">
|
|
||||||
<list>
|
|
||||||
<ConfigurationLocation id="bundled-sun-checks" type="BUNDLED" scope="All" description="Sun Checks">(bundled)</ConfigurationLocation>
|
|
||||||
<ConfigurationLocation id="bundled-google-checks" type="BUNDLED" scope="All" description="Google Checks">(bundled)</ConfigurationLocation>
|
|
||||||
</list>
|
|
||||||
</option>
|
|
||||||
</component>
|
|
||||||
</project>
|
|
16
.idea/gradle.xml
generated
16
.idea/gradle.xml
generated
@ -1,16 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="GradleMigrationSettings" migrationVersion="1" />
|
|
||||||
<component name="GradleSettings">
|
|
||||||
<option name="linkedExternalProjectsSettings">
|
|
||||||
<GradleProjectSettings>
|
|
||||||
<option name="externalProjectPath" value="$PROJECT_DIR$" />
|
|
||||||
<option name="modules">
|
|
||||||
<set>
|
|
||||||
<option value="$PROJECT_DIR$" />
|
|
||||||
</set>
|
|
||||||
</option>
|
|
||||||
</GradleProjectSettings>
|
|
||||||
</option>
|
|
||||||
</component>
|
|
||||||
</project>
|
|
204
.idea/intellij-javadocs-4.0.1.xml
generated
204
.idea/intellij-javadocs-4.0.1.xml
generated
@ -1,204 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="JavaDocConfiguration">
|
|
||||||
<GENERAL>
|
|
||||||
<MODE>UPDATE</MODE>
|
|
||||||
<OVERRIDDEN_METHODS>false</OVERRIDDEN_METHODS>
|
|
||||||
<SPLITTED_CLASS_NAME>true</SPLITTED_CLASS_NAME>
|
|
||||||
<LEVELS>
|
|
||||||
<LEVEL>METHOD</LEVEL>
|
|
||||||
<LEVEL>TYPE</LEVEL>
|
|
||||||
<LEVEL>FIELD</LEVEL>
|
|
||||||
</LEVELS>
|
|
||||||
<VISIBILITIES>
|
|
||||||
<VISIBILITY>DEFAULT</VISIBILITY>
|
|
||||||
<VISIBILITY>PROTECTED</VISIBILITY>
|
|
||||||
<VISIBILITY>PUBLIC</VISIBILITY>
|
|
||||||
</VISIBILITIES>
|
|
||||||
</GENERAL>
|
|
||||||
<TEMPLATES>
|
|
||||||
<CLASSES>
|
|
||||||
<CLASS>
|
|
||||||
<KEY>^.*(public|protected|private)*.+interface\s+\w+.*</KEY>
|
|
||||||
<VALUE>/**\n
|
|
||||||
* The interface ${name}.\n
|
|
||||||
<#if element.typeParameters?has_content> * \n
|
|
||||||
</#if>
|
|
||||||
<#list element.typeParameters as typeParameter>
|
|
||||||
* @param <${typeParameter.name}> the type parameter\n
|
|
||||||
</#list>
|
|
||||||
*/</VALUE>
|
|
||||||
</CLASS>
|
|
||||||
<CLASS>
|
|
||||||
<KEY>^.*(public|protected|private)*.+enum\s+\w+.*</KEY>
|
|
||||||
<VALUE>/**\n
|
|
||||||
* The enum ${name}.\n
|
|
||||||
*/</VALUE>
|
|
||||||
</CLASS>
|
|
||||||
<CLASS>
|
|
||||||
<KEY>^.*(public|protected|private)*.+class\s+\w+.*</KEY>
|
|
||||||
<VALUE>/**\n
|
|
||||||
* The type ${name}.\n
|
|
||||||
<#if element.typeParameters?has_content> * \n
|
|
||||||
</#if>
|
|
||||||
<#list element.typeParameters as typeParameter>
|
|
||||||
* @param <${typeParameter.name}> the type parameter\n
|
|
||||||
</#list>
|
|
||||||
*/</VALUE>
|
|
||||||
</CLASS>
|
|
||||||
<CLASS>
|
|
||||||
<KEY>.+</KEY>
|
|
||||||
<VALUE>/**\n
|
|
||||||
* The type ${name}.\n
|
|
||||||
*/</VALUE>
|
|
||||||
</CLASS>
|
|
||||||
</CLASSES>
|
|
||||||
<CONSTRUCTORS>
|
|
||||||
<CONSTRUCTOR>
|
|
||||||
<KEY>.+</KEY>
|
|
||||||
<VALUE>/**\n
|
|
||||||
* Instantiates a new ${name}.\n
|
|
||||||
<#if element.parameterList.parameters?has_content>
|
|
||||||
*\n
|
|
||||||
</#if>
|
|
||||||
<#list element.parameterList.parameters as parameter>
|
|
||||||
* @param ${parameter.name} the ${paramNames[parameter.name]}\n
|
|
||||||
</#list>
|
|
||||||
<#if element.throwsList.referenceElements?has_content>
|
|
||||||
*\n
|
|
||||||
</#if>
|
|
||||||
<#list element.throwsList.referenceElements as exception>
|
|
||||||
* @throws ${exception.referenceName} the ${exceptionNames[exception.referenceName]}\n
|
|
||||||
</#list>
|
|
||||||
*/</VALUE>
|
|
||||||
</CONSTRUCTOR>
|
|
||||||
</CONSTRUCTORS>
|
|
||||||
<METHODS>
|
|
||||||
<METHOD>
|
|
||||||
<KEY>^.*(public|protected|private)*\s*.*(\w(\s*<.+>)*)+\s+get\w+\s*\(.*\).+</KEY>
|
|
||||||
<VALUE>/**\n
|
|
||||||
* Gets ${partName}.\n
|
|
||||||
<#if element.typeParameters?has_content> * \n
|
|
||||||
</#if>
|
|
||||||
<#list element.typeParameters as typeParameter>
|
|
||||||
* @param <${typeParameter.name}> the type parameter\n
|
|
||||||
</#list>
|
|
||||||
<#if element.parameterList.parameters?has_content>
|
|
||||||
*\n
|
|
||||||
</#if>
|
|
||||||
<#list element.parameterList.parameters as parameter>
|
|
||||||
* @param ${parameter.name} the ${paramNames[parameter.name]}\n
|
|
||||||
</#list>
|
|
||||||
<#if isNotVoid>
|
|
||||||
*\n
|
|
||||||
* @return the ${partName}\n
|
|
||||||
</#if>
|
|
||||||
<#if element.throwsList.referenceElements?has_content>
|
|
||||||
*\n
|
|
||||||
</#if>
|
|
||||||
<#list element.throwsList.referenceElements as exception>
|
|
||||||
* @throws ${exception.referenceName} the ${exceptionNames[exception.referenceName]}\n
|
|
||||||
</#list>
|
|
||||||
*/</VALUE>
|
|
||||||
</METHOD>
|
|
||||||
<METHOD>
|
|
||||||
<KEY>^.*(public|protected|private)*\s*.*(void|\w(\s*<.+>)*)+\s+set\w+\s*\(.*\).+</KEY>
|
|
||||||
<VALUE>/**\n
|
|
||||||
* Sets ${partName}.\n
|
|
||||||
<#if element.typeParameters?has_content> * \n
|
|
||||||
</#if>
|
|
||||||
<#list element.typeParameters as typeParameter>
|
|
||||||
* @param <${typeParameter.name}> the type parameter\n
|
|
||||||
</#list>
|
|
||||||
<#if element.parameterList.parameters?has_content>
|
|
||||||
*\n
|
|
||||||
</#if>
|
|
||||||
<#list element.parameterList.parameters as parameter>
|
|
||||||
* @param ${parameter.name} the ${paramNames[parameter.name]}\n
|
|
||||||
</#list>
|
|
||||||
<#if isNotVoid>
|
|
||||||
*\n
|
|
||||||
* @return the ${partName}\n
|
|
||||||
</#if>
|
|
||||||
<#if element.throwsList.referenceElements?has_content>
|
|
||||||
*\n
|
|
||||||
</#if>
|
|
||||||
<#list element.throwsList.referenceElements as exception>
|
|
||||||
* @throws ${exception.referenceName} the ${exceptionNames[exception.referenceName]}\n
|
|
||||||
</#list>
|
|
||||||
*/</VALUE>
|
|
||||||
</METHOD>
|
|
||||||
<METHOD>
|
|
||||||
<KEY>^.*((public\s+static)|(static\s+public))\s+void\s+main\s*\(\s*String\s*(\[\s*\]|\.\.\.)\s+\w+\s*\).+</KEY>
|
|
||||||
<VALUE>/**\n
|
|
||||||
* The entry point of application.\n
|
|
||||||
|
|
||||||
<#if element.parameterList.parameters?has_content>
|
|
||||||
*\n
|
|
||||||
</#if>
|
|
||||||
* @param ${element.parameterList.parameters[0].name} the input arguments\n
|
|
||||||
<#if element.throwsList.referenceElements?has_content>
|
|
||||||
*\n
|
|
||||||
</#if>
|
|
||||||
<#list element.throwsList.referenceElements as exception>
|
|
||||||
* @throws ${exception.referenceName} the ${exceptionNames[exception.referenceName]}\n
|
|
||||||
</#list>
|
|
||||||
*/</VALUE>
|
|
||||||
</METHOD>
|
|
||||||
<METHOD>
|
|
||||||
<KEY>.+</KEY>
|
|
||||||
<VALUE>/**\n
|
|
||||||
* ${name}<#if isNotVoid> ${return}</#if>.\n
|
|
||||||
<#if element.typeParameters?has_content> * \n
|
|
||||||
</#if>
|
|
||||||
<#list element.typeParameters as typeParameter>
|
|
||||||
* @param <${typeParameter.name}> the type parameter\n
|
|
||||||
</#list>
|
|
||||||
<#if element.parameterList.parameters?has_content>
|
|
||||||
*\n
|
|
||||||
</#if>
|
|
||||||
<#list element.parameterList.parameters as parameter>
|
|
||||||
* @param ${parameter.name} the ${paramNames[parameter.name]}\n
|
|
||||||
</#list>
|
|
||||||
<#if isNotVoid>
|
|
||||||
*\n
|
|
||||||
* @return the ${return}\n
|
|
||||||
</#if>
|
|
||||||
<#if element.throwsList.referenceElements?has_content>
|
|
||||||
*\n
|
|
||||||
</#if>
|
|
||||||
<#list element.throwsList.referenceElements as exception>
|
|
||||||
* @throws ${exception.referenceName} the ${exceptionNames[exception.referenceName]}\n
|
|
||||||
</#list>
|
|
||||||
*/</VALUE>
|
|
||||||
</METHOD>
|
|
||||||
</METHODS>
|
|
||||||
<FIELDS>
|
|
||||||
<FIELD>
|
|
||||||
<KEY>^.*(public|protected|private)*.+static.*(\w\s\w)+.+</KEY>
|
|
||||||
<VALUE>/**\n
|
|
||||||
* The constant ${element.getName()}.\n
|
|
||||||
*/</VALUE>
|
|
||||||
</FIELD>
|
|
||||||
<FIELD>
|
|
||||||
<KEY>^.*(public|protected|private)*.*(\w\s\w)+.+</KEY>
|
|
||||||
<VALUE>/**\n
|
|
||||||
<#if element.parent.isInterface()>
|
|
||||||
* The constant ${element.getName()}.\n
|
|
||||||
<#else>
|
|
||||||
* The ${name}.\n
|
|
||||||
</#if> */</VALUE>
|
|
||||||
</FIELD>
|
|
||||||
<FIELD>
|
|
||||||
<KEY>.+</KEY>
|
|
||||||
<VALUE>/**\n
|
|
||||||
<#if element.parent.isEnum()>
|
|
||||||
*${name} ${typeName}.\n
|
|
||||||
<#else>
|
|
||||||
* The ${name}.\n
|
|
||||||
</#if>*/</VALUE>
|
|
||||||
</FIELD>
|
|
||||||
</FIELDS>
|
|
||||||
</TEMPLATES>
|
|
||||||
</component>
|
|
||||||
</project>
|
|
17
.idea/misc.xml
generated
17
.idea/misc.xml
generated
@ -1,17 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="ExternalStorageConfigurationManager" enabled="true" />
|
|
||||||
<component name="FrameworkDetectionExcludesConfiguration">
|
|
||||||
<file type="web" url="file://$PROJECT_DIR$" />
|
|
||||||
</component>
|
|
||||||
<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="21" project-jdk-type="JavaSDK">
|
|
||||||
<output url="file://$PROJECT_DIR$/out" />
|
|
||||||
</component>
|
|
||||||
</project>
|
|
124
.idea/uiDesigner.xml
generated
124
.idea/uiDesigner.xml
generated
@ -1,124 +0,0 @@
|
|||||||
<?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
generated
6
.idea/vcs.xml
generated
@ -1,6 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="VcsDirectoryMappings">
|
|
||||||
<mapping directory="" vcs="Git" />
|
|
||||||
</component>
|
|
||||||
</project>
|
|
40
README.md
Normal file
40
README.md
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
# Libremines
|
||||||
|
|
||||||
|
"named this way because i didn't realise there was another libremines!"
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
## Building
|
||||||
|
|
||||||
|
### Requirements:
|
||||||
|
- Java 21
|
||||||
|
- Maven
|
||||||
|
|
||||||
|
### Instructions:
|
||||||
|
|
||||||
|
This will automatically fetch dependencies and run the project:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
mvn javafx:run
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
#### Native Image:
|
||||||
|
|
||||||
|
##### Requirements:
|
||||||
|
- GraalVM
|
||||||
|
- Maven 3.8.8
|
||||||
|
|
||||||
|
Create the maven wrapper at version 3.8.8. GluonFX does not work with newer versions as of 2024-07-27.
|
||||||
|
|
||||||
|
```shell
|
||||||
|
mvn wrapper:wrapper -Dmaven=3.8.8
|
||||||
|
```
|
||||||
|
|
||||||
|
Install dependencies, build and run:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
./mvnw dependency:resolve gluonfx:build
|
||||||
|
```
|
||||||
|
|
||||||
|
A native binary should be placed at `target/gluonfx/<your architecture>/libremines`
|
29
pom.xml
29
pom.xml
@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
<groupId>com.shr4pnel.minesweeper</groupId>
|
<groupId>com.shr4pnel.minesweeper</groupId>
|
||||||
<artifactId>libremines</artifactId>
|
<artifactId>libremines</artifactId>
|
||||||
<version>1.0-SNAPSHOT</version>
|
<version>1.0</version>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<maven.compiler.source>21</maven.compiler.source>
|
<maven.compiler.source>21</maven.compiler.source>
|
||||||
@ -17,12 +17,12 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.openjfx</groupId>
|
<groupId>org.openjfx</groupId>
|
||||||
<artifactId>javafx-controls</artifactId>
|
<artifactId>javafx-controls</artifactId>
|
||||||
<version>21.0.3</version>
|
<version>21.0.4</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.openjfx</groupId>
|
<groupId>org.openjfx</groupId>
|
||||||
<artifactId>javafx-fxml</artifactId>
|
<artifactId>javafx-fxml</artifactId>
|
||||||
<version>21.0.3</version>
|
<version>21.0.4</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
<build>
|
<build>
|
||||||
@ -35,6 +35,27 @@
|
|||||||
<mainClass>libremines/com.shr4pnel.minesweeper.Main</mainClass>
|
<mainClass>libremines/com.shr4pnel.minesweeper.Main</mainClass>
|
||||||
</configuration>
|
</configuration>
|
||||||
</plugin>
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
|
<version>3.13.0</version>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>com.gluonhq</groupId>
|
||||||
|
<artifactId>gluonfx-maven-plugin</artifactId>
|
||||||
|
<version>1.0.22</version>
|
||||||
|
<configuration>
|
||||||
|
<mainClass>com.shr4pnel.minesweeper.Main</mainClass>
|
||||||
|
<reflectionList>
|
||||||
|
com.shr4pnel.minesweeper.Controller
|
||||||
|
</reflectionList>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-wrapper-plugin</artifactId>
|
||||||
|
<version>3.3.1</version>
|
||||||
|
</plugin>
|
||||||
</plugins>
|
</plugins>
|
||||||
</build>
|
</build>
|
||||||
</project>
|
</project>
|
||||||
|
@ -1,43 +1,168 @@
|
|||||||
package com.shr4pnel.minesweeper;
|
package com.shr4pnel.minesweeper;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Timer;
|
import java.util.Timer;
|
||||||
import java.util.TimerTask;
|
import java.util.TimerTask;
|
||||||
|
|
||||||
|
import javafx.event.ActionEvent;
|
||||||
|
import javafx.event.EventHandler;
|
||||||
import javafx.fxml.FXML;
|
import javafx.fxml.FXML;
|
||||||
|
import javafx.fxml.FXMLLoader;
|
||||||
import javafx.scene.Node;
|
import javafx.scene.Node;
|
||||||
|
import javafx.scene.Parent;
|
||||||
|
import javafx.scene.Scene;
|
||||||
import javafx.scene.control.Button;
|
import javafx.scene.control.Button;
|
||||||
|
import javafx.scene.control.MenuItem;
|
||||||
|
import javafx.scene.control.RadioMenuItem;
|
||||||
import javafx.scene.image.Image;
|
import javafx.scene.image.Image;
|
||||||
import javafx.scene.image.ImageView;
|
import javafx.scene.image.ImageView;
|
||||||
import javafx.scene.input.MouseButton;
|
import javafx.scene.input.MouseButton;
|
||||||
import javafx.scene.input.MouseEvent;
|
import javafx.scene.input.MouseEvent;
|
||||||
import javafx.scene.layout.GridPane;
|
import javafx.scene.layout.GridPane;
|
||||||
|
import javafx.stage.Stage;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The JavaFX controller for minesweeper.fxml.
|
||||||
|
* Handles all operations performed within the GUI.
|
||||||
|
* @author shrapnelnet admin@shr4pnel.com
|
||||||
|
*/
|
||||||
public class Controller {
|
public class Controller {
|
||||||
|
/**
|
||||||
|
* The grid within the FXML holding all the tiles.
|
||||||
|
*/
|
||||||
@FXML
|
@FXML
|
||||||
private GridPane grid;
|
private GridPane grid;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Images within the FXML structure.
|
||||||
|
*/
|
||||||
@FXML
|
@FXML
|
||||||
private ImageView smiley, time_1, time_2, time_3, bomb_2, bomb_3;
|
private ImageView smiley, time_1, time_2, time_3, bomb_2, bomb_3;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Menu items
|
||||||
|
*/
|
||||||
|
@FXML
|
||||||
|
private RadioMenuItem color, marks;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The menu item "about".
|
||||||
|
*/
|
||||||
|
@FXML
|
||||||
|
private MenuItem about;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The underlying 2D array representing where bombs are on the grid.
|
||||||
|
*/
|
||||||
private Grid gridHandler;
|
private Grid gridHandler;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A wrapper to make operations on the underlying grid easier.
|
||||||
|
*/
|
||||||
private GridWrapper wrapper;
|
private GridWrapper wrapper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles the grid during a game over state preventing further clicking of the grid.
|
||||||
|
*/
|
||||||
private boolean gameOver = false;
|
private boolean gameOver = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A variable specifying if the game has been loaded for the first time.
|
||||||
|
*/
|
||||||
private boolean isFirstLoad = true;
|
private boolean isFirstLoad = true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The game timer.
|
||||||
|
*/
|
||||||
static Timer timer = new Timer();
|
static Timer timer = new Timer();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The time that has elapsed since the game started.
|
||||||
|
*/
|
||||||
private int time = 0;
|
private int time = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The time the game was started at.
|
||||||
|
*/
|
||||||
private long startTime;
|
private long startTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The number of bombs on the grid.
|
||||||
|
*/
|
||||||
private int bombCount = 99;
|
private int bombCount = 99;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A 2D array holding all tiles that have previously recursively been expanded.
|
||||||
|
*/
|
||||||
private boolean[][] expandedTiles;
|
private boolean[][] expandedTiles;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A boolean that shows if the user has performed their first click on the GridPane.
|
||||||
|
*/
|
||||||
|
private boolean isFirstClick = true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets important variables on Main class initialization
|
||||||
|
*/
|
||||||
@FXML
|
@FXML
|
||||||
private void initialize() {
|
private void initialize() {
|
||||||
|
setNotYetImplemented(color);
|
||||||
|
setNotYetImplemented(marks);
|
||||||
|
about.setOnAction(this::openAbout);
|
||||||
setupGrid();
|
setupGrid();
|
||||||
gridHandler = new Grid();
|
gridHandler = new Grid();
|
||||||
wrapper = gridHandler.grid;
|
wrapper = gridHandler.grid;
|
||||||
expandedTiles = new boolean[30][16];
|
expandedTiles = new boolean[30][16];
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Opens the about window when the radiomenuitem is clicked
|
||||||
|
*
|
||||||
|
* @param actionEvent The node that the window opens on, on click
|
||||||
|
*/
|
||||||
|
private void openAbout(ActionEvent actionEvent) {
|
||||||
|
try {
|
||||||
|
Parent root = FXMLLoader.load(getClass().getResource("about.fxml"));
|
||||||
|
Stage stage = new Stage();
|
||||||
|
stage.setTitle("About");
|
||||||
|
stage.setMinWidth(455);
|
||||||
|
stage.setMinHeight(275);
|
||||||
|
stage.setScene(new Scene(root));
|
||||||
|
stage.show();
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Opens a window if an unimplemented menu item is clicked
|
||||||
|
*
|
||||||
|
* @param node The node that the window opens on, on click
|
||||||
|
*/
|
||||||
|
private void setNotYetImplemented(RadioMenuItem node) {
|
||||||
|
node.setOnAction(new EventHandler<>() {
|
||||||
|
@Override
|
||||||
|
public void handle(ActionEvent actionEvent) {
|
||||||
|
try {
|
||||||
|
Parent root = FXMLLoader.load(getClass().getResource("unimplemented.fxml"));
|
||||||
|
Stage stage = new Stage();
|
||||||
|
stage.setTitle("Unimplemented!");
|
||||||
|
stage.setMinHeight(420);
|
||||||
|
stage.setMinWidth(525);
|
||||||
|
stage.setScene(new Scene(root));
|
||||||
|
stage.show();
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fills the GridPane with blank buttons
|
||||||
|
*/
|
||||||
private void setupGrid() {
|
private void setupGrid() {
|
||||||
for (int column = 0; column < 30; ++column) {
|
for (int column = 0; column < 30; ++column) {
|
||||||
for (int row = 0; row < 16; ++row) {
|
for (int row = 0; row < 16; ++row) {
|
||||||
@ -47,17 +172,51 @@ public class Controller {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used during initialization to fill the board
|
||||||
|
*
|
||||||
|
* @return A blank button
|
||||||
|
*/
|
||||||
private Button createBlankButton() {
|
private Button createBlankButton() {
|
||||||
Image blank =
|
Image blank = new Image(String.valueOf(getClass().getResource("img/blank.png")), 16, 16, true, false);
|
||||||
new Image(String.valueOf(getClass().getResource("img/blank.png")), 16, 16, true, true);
|
|
||||||
ImageView blankImage = new ImageView(blank);
|
ImageView blankImage = new ImageView(blank);
|
||||||
Button blankButton = new Button();
|
Button blankButton = new Button();
|
||||||
blankButton.setGraphic(blankImage);
|
blankButton.setGraphic(blankImage);
|
||||||
blankButton.setMinSize(16, 16);
|
blankButton.setMinSize(16, 16);
|
||||||
blankButton.setOnMouseClicked(this::buttonClicked);
|
blankButton.setOnMouseClicked(this::buttonClicked);
|
||||||
|
blankButton.setOnMousePressed(this::mouseHeld);
|
||||||
|
blankButton.setOnMouseReleased(this::mouseReleased);
|
||||||
return blankButton;
|
return blankButton;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Changes smiley face to concerned look when the mouse is held
|
||||||
|
*
|
||||||
|
* @param mouseEvent Stub, required by EventHandler interface
|
||||||
|
*/
|
||||||
|
private void mouseHeld(MouseEvent mouseEvent) {
|
||||||
|
if (gameOver)
|
||||||
|
return;
|
||||||
|
setImage(smiley, "img/face_ooh.png");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Changes smiley face back to smiling after mouse release
|
||||||
|
*
|
||||||
|
* @param mouseEvent Stub, required by EventHandler interface
|
||||||
|
*/
|
||||||
|
private void mouseReleased(MouseEvent mouseEvent) {
|
||||||
|
if (gameOver)
|
||||||
|
return;
|
||||||
|
setImage(smiley, "img/face_smile.png");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles the main GridPane being clicked
|
||||||
|
* Identifies the intention of the click (e.g. flag, open tile)
|
||||||
|
*
|
||||||
|
* @param e The event fired on click
|
||||||
|
*/
|
||||||
private void buttonClicked(MouseEvent e) {
|
private void buttonClicked(MouseEvent e) {
|
||||||
if (gameOver) {
|
if (gameOver) {
|
||||||
return;
|
return;
|
||||||
@ -78,25 +237,182 @@ public class Controller {
|
|||||||
if (buttonImage.getUrl().contains("flagged.png")) {
|
if (buttonImage.getUrl().contains("flagged.png")) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (buttonImage.getUrl().contains("num") && !buttonImage.getUrl().contains("num_0.png")) {
|
||||||
|
chord(clicked, buttonImage.getUrl());
|
||||||
|
return;
|
||||||
|
}
|
||||||
handlePrimaryClick(clicked, column, row);
|
handlePrimaryClick(clicked, column, row);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private int adjacentFlagCount(int column, int row) {
|
||||||
|
int flagCount = 0;
|
||||||
|
for (int innerColumn = column - 1; innerColumn <= column + 1; innerColumn++) {
|
||||||
|
for (int innerRow = row - 1; innerRow <= row + 1; innerRow++) {
|
||||||
|
if (innerColumn == column && innerRow == row)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!wrapper.atColumn(innerColumn).atRow(innerRow).isValid()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
Button b = (Button) getNodeByColumnRowIndex(innerColumn, innerRow);
|
||||||
|
String bURL = getButtonURL(b);
|
||||||
|
if (bURL.contains("flag")) {
|
||||||
|
flagCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return flagCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Button[] chordTilesToOpen(int column, int row) {
|
||||||
|
ArrayList<Button> buttons = new ArrayList<>(8);
|
||||||
|
for (int innerColumn = column - 1; innerColumn <= column + 1; innerColumn++) {
|
||||||
|
for (int innerRow = row - 1; innerRow <= row + 1; innerRow++) {
|
||||||
|
if (innerColumn == column && innerRow == row)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!wrapper.atColumn(innerColumn).atRow(innerRow).isValid()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
Button b = (Button) getNodeByColumnRowIndex(innerColumn, innerRow);
|
||||||
|
String bURL = getButtonURL(b);
|
||||||
|
// if the tile is unflagged and unopened:
|
||||||
|
if (bURL.contains("blank")) {
|
||||||
|
buttons.add(b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return buttons.toArray(Button[]::new);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void chord(Button clicked, String clickedURL) {
|
||||||
|
int column = GridPane.getColumnIndex(clicked);
|
||||||
|
int row = GridPane.getRowIndex(clicked);
|
||||||
|
int urlLength = clickedURL.length();
|
||||||
|
char requiredAdjacentChar = clickedURL.charAt(urlLength-5);
|
||||||
|
int requiredAdjacent = Integer.parseInt(Character.toString(requiredAdjacentChar));
|
||||||
|
int actualAdjacent = adjacentFlagCount(column, row);
|
||||||
|
if (requiredAdjacent != actualAdjacent) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Button[] buttons = chordTilesToOpen(column, row);
|
||||||
|
for (Button b: buttons) {
|
||||||
|
expandTile(b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If the first tile clicked was a bomb, move that bomb to the first available column on row 0 before opening it
|
||||||
|
*
|
||||||
|
* @param column The column of the clicked tile
|
||||||
|
* @param row The row of the clicked tile
|
||||||
|
* @return An array containing the column and row the bomb was moved to
|
||||||
|
*/
|
||||||
|
private int[] setBombIfFirstTileIsBomb(int column, int row) {
|
||||||
|
for (int c = 0; c < 30; ++c) {
|
||||||
|
for (int r = 0; r < 16; ++r) {
|
||||||
|
if (!wrapper.atColumn(c).atRow(r).isBomb()) {
|
||||||
|
wrapper.setBomb();
|
||||||
|
wrapper.updateGrid(column, row, c, r);
|
||||||
|
return new int[]{c, r};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
System.out.println("If you see this, congrats! this should never happen. please email me.");
|
||||||
|
return new int[]{0, 0};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extracts the URL of a given button
|
||||||
|
*
|
||||||
|
* @param button A javafx.scene.control.Button object
|
||||||
|
* @return A string representation of the image URL
|
||||||
|
*/
|
||||||
|
private String getButtonURL(Button button) {
|
||||||
|
ImageView graphic = (ImageView) button.getGraphic();
|
||||||
|
Image image = graphic.getImage();
|
||||||
|
return image.getUrl();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Iterates through the grid to find all tiles that are either blank or flagged.
|
||||||
|
* Used to check if win condition has been met
|
||||||
|
*
|
||||||
|
* @return The number of tiles that were blank or flagged
|
||||||
|
*/
|
||||||
|
private int numberOfUnrevealedTiles() {
|
||||||
|
int unrevealedTiles = 0;
|
||||||
|
int column, row;
|
||||||
|
for (column = 0; column < 30; ++column) {
|
||||||
|
for (row = 0; row < 16; ++row) {
|
||||||
|
Button current = (Button) getNodeByColumnRowIndex(column, row);
|
||||||
|
// this will hopefully never happen..... or will it ......
|
||||||
|
if (current == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
String currentURL = getButtonURL(current);
|
||||||
|
if (currentURL.contains("blank.png") || currentURL.contains("flagged.png")) {
|
||||||
|
unrevealedTiles++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return unrevealedTiles;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the number of unrevealed tiles is equal to 99 (the win condition)
|
||||||
|
*
|
||||||
|
* @return A boolean representing if the game has been won
|
||||||
|
* @see #numberOfUnrevealedTiles()
|
||||||
|
*/
|
||||||
|
private boolean checkWinCondition() {
|
||||||
|
int unrevealedTiles = numberOfUnrevealedTiles();
|
||||||
|
return unrevealedTiles == 99;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles a left mouse click on an unopened tile
|
||||||
|
*
|
||||||
|
* @param clicked The button that was clicked
|
||||||
|
* @param column The column that it was clicked at
|
||||||
|
* @param row The row that it was clicked at
|
||||||
|
*/
|
||||||
private void handlePrimaryClick(Button clicked, int column, int row) {
|
private void handlePrimaryClick(Button clicked, int column, int row) {
|
||||||
if (wrapper.atColumn(column).atRow(row).isBomb()) {
|
if (wrapper.atColumn(column).atRow(row).isBomb() && !isFirstClick) {
|
||||||
gameOver(clicked);
|
gameOver(clicked);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (wrapper.isBomb() && isFirstClick) {
|
||||||
|
int[] chosenColumnAndRow = setBombIfFirstTileIsBomb(column, row);
|
||||||
|
int columnMovedTo = chosenColumnAndRow[0];
|
||||||
|
int rowMovedTo = chosenColumnAndRow[1];
|
||||||
|
wrapper.atColumn(column).atRow(row).switchBomb(columnMovedTo, rowMovedTo);
|
||||||
|
recursiveExpandTiles(column, row);
|
||||||
|
clicked = (Button) getNodeByColumnRowIndex(column, row);
|
||||||
|
}
|
||||||
|
isFirstClick = false;
|
||||||
int adjacentBombs = wrapper.adjacentBombCount();
|
int adjacentBombs = wrapper.adjacentBombCount();
|
||||||
setAdjacentCount(clicked, adjacentBombs);
|
setAdjacentCount(clicked, adjacentBombs);
|
||||||
if (adjacentBombs == 0) {
|
if (adjacentBombs == 0) {
|
||||||
recursiveExpandTiles(column, row);
|
recursiveExpandTiles(column, row);
|
||||||
}
|
}
|
||||||
|
boolean win = checkWinCondition();
|
||||||
|
if (win) {
|
||||||
|
win();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If a tile is surrounded by tiles with no adjacent bombs, open all the tiles recursively
|
||||||
|
*
|
||||||
|
* @param column The column that was clicked
|
||||||
|
* @param row The row that was clicked
|
||||||
|
* @see #expandTile(int, int)
|
||||||
|
*/
|
||||||
private void recursiveExpandTiles(int column, int row) {
|
private void recursiveExpandTiles(int column, int row) {
|
||||||
if (column < 0 || column >= 30 || row < 0 || row >= 16 ||
|
if (column < 0 || column >= 30 || row < 0 || row >= 16 ||
|
||||||
expandedTiles[column][row] && !wrapper.atColumn(column).atRow(row).isBomb()) {
|
expandedTiles[column][row] && !wrapper.atColumn(column).atRow(row).isBomb()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
expandTile(column, row);
|
expandTile(column, row);
|
||||||
@ -112,8 +428,14 @@ public class Controller {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Opens a tile, and adds it to an array to prevent overflow
|
||||||
|
*
|
||||||
|
* @param column The column of the button to open
|
||||||
|
* @param row The row of the button to open
|
||||||
|
*/
|
||||||
private void expandTile(int column, int row) {
|
private void expandTile(int column, int row) {
|
||||||
Node tile = getNodeByRowColumnIndex(row, column);
|
Node tile = getNodeByColumnRowIndex(column, row);
|
||||||
if (tile != null) {
|
if (tile != null) {
|
||||||
Button button = (Button) tile;
|
Button button = (Button) tile;
|
||||||
if (button.isVisible()) {
|
if (button.isVisible()) {
|
||||||
@ -127,7 +449,31 @@ public class Controller {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Node getNodeByRowColumnIndex(int row, int column) {
|
private void expandTile(Button button) {
|
||||||
|
Node node = (Node) button;
|
||||||
|
int column = GridPane.getColumnIndex(node);
|
||||||
|
int row = GridPane.getRowIndex(node);
|
||||||
|
if (wrapper.atColumn(column).atRow(row).isBomb()) {
|
||||||
|
gameOver(node);
|
||||||
|
}
|
||||||
|
if (button.isVisible()) {
|
||||||
|
int adjacentBombs = wrapper.atColumn(column).atRow(row).adjacentBombCount();
|
||||||
|
setAdjacentCount(button, adjacentBombs);
|
||||||
|
if (adjacentBombs == 0 && !expandedTiles[column][row]) {
|
||||||
|
expandedTiles[column][row] = true;
|
||||||
|
recursiveExpandTiles(column, row);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Iterates over the grid and returns the node when it's at the correct child
|
||||||
|
*
|
||||||
|
* @param row The desired row to find
|
||||||
|
* @param column The desired column to find
|
||||||
|
* @return The node at the specified position
|
||||||
|
*/
|
||||||
|
private Node getNodeByColumnRowIndex(int column, int row) {
|
||||||
for (Node node : grid.getChildren()) {
|
for (Node node : grid.getChildren()) {
|
||||||
if (GridPane.getRowIndex(node) == row && GridPane.getColumnIndex(node) == column) {
|
if (GridPane.getRowIndex(node) == row && GridPane.getColumnIndex(node) == column) {
|
||||||
return node;
|
return node;
|
||||||
@ -136,8 +482,12 @@ public class Controller {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resets important state variables on restart
|
||||||
|
*/
|
||||||
@FXML
|
@FXML
|
||||||
private void reinitialize() {
|
private void reinitialize() {
|
||||||
|
gameOver = false;
|
||||||
bombCount = 99;
|
bombCount = 99;
|
||||||
updateBombCounter();
|
updateBombCounter();
|
||||||
resetTimer();
|
resetTimer();
|
||||||
@ -145,8 +495,14 @@ public class Controller {
|
|||||||
gridHandler = new Grid();
|
gridHandler = new Grid();
|
||||||
wrapper = gridHandler.grid;
|
wrapper = gridHandler.grid;
|
||||||
expandedTiles = new boolean[30][16];
|
expandedTiles = new boolean[30][16];
|
||||||
|
isFirstClick = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resets the timer to 0
|
||||||
|
*
|
||||||
|
* @see #reinitialize()
|
||||||
|
*/
|
||||||
private void resetTimer() {
|
private void resetTimer() {
|
||||||
URL zeroSecondURL = getClass().getResource("img/0_seconds.png");
|
URL zeroSecondURL = getClass().getResource("img/0_seconds.png");
|
||||||
time_1.setImage(new Image(String.valueOf(zeroSecondURL)));
|
time_1.setImage(new Image(String.valueOf(zeroSecondURL)));
|
||||||
@ -157,6 +513,11 @@ public class Controller {
|
|||||||
timer = new Timer();
|
timer = new Timer();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// todo figure out why createBlankButton errors here
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Refills the grid with new blank buttons
|
||||||
|
*/
|
||||||
private void resetGrid() {
|
private void resetGrid() {
|
||||||
URL blank = getClass().getResource("img/blank.png");
|
URL blank = getClass().getResource("img/blank.png");
|
||||||
for (Node node : grid.getChildren()) {
|
for (Node node : grid.getChildren()) {
|
||||||
@ -165,6 +526,11 @@ public class Controller {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When a bomb is clicked, change the smiley, set gameOver to true.
|
||||||
|
*
|
||||||
|
* @param tileClicked The node that was clicked, to set the correct image
|
||||||
|
*/
|
||||||
private void gameOver(Node tileClicked) {
|
private void gameOver(Node tileClicked) {
|
||||||
gameOver = true;
|
gameOver = true;
|
||||||
timer.cancel();
|
timer.cancel();
|
||||||
@ -173,12 +539,45 @@ public class Controller {
|
|||||||
showAllBombs(GridPane.getColumnIndex(tileClicked), GridPane.getRowIndex(tileClicked));
|
showAllBombs(GridPane.getColumnIndex(tileClicked), GridPane.getRowIndex(tileClicked));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a win state, change the smiley.
|
||||||
|
*/
|
||||||
|
private void win() {
|
||||||
|
gameOver = true;
|
||||||
|
timer.cancel();
|
||||||
|
setImage(smiley, "img/face_win.png");
|
||||||
|
flagAllRemaining();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* After a win, set every bomb tile that is unflagged to flagged.
|
||||||
|
*/
|
||||||
|
private void flagAllRemaining() {
|
||||||
|
int column, row;
|
||||||
|
for (column = 0; column < 30; ++column) {
|
||||||
|
for (row = 0; row < 16; ++row) {
|
||||||
|
Button current = (Button) getNodeByColumnRowIndex(column, row);
|
||||||
|
assert current != null;
|
||||||
|
String currentURL = getButtonURL(current);
|
||||||
|
boolean tileIsBomb = wrapper.atColumn(column).atRow(row).isBomb();
|
||||||
|
if (currentURL.contains("blank.png") && tileIsBomb) {
|
||||||
|
setImage(current, "img/bomb_flagged.png");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a flag on a tile, representing a tile that the user suspects has a bomb behind it.
|
||||||
|
* This prevents the tile being clicked on.
|
||||||
|
*
|
||||||
|
* @param tileClicked The tile that the user clicks.
|
||||||
|
*/
|
||||||
private void flag(Node tileClicked) {
|
private void flag(Node tileClicked) {
|
||||||
Button tileAsButton = (Button) tileClicked;
|
Button tileAsButton = (Button) tileClicked;
|
||||||
ImageView tileGraphic = (ImageView) tileAsButton.getGraphic();
|
ImageView tileGraphic = (ImageView) tileAsButton.getGraphic();
|
||||||
Image tileGraphicImage = tileGraphic.getImage();
|
Image tileGraphicImage = tileGraphic.getImage();
|
||||||
if (!tileGraphicImage.getUrl().contains("blank.png") &&
|
if (!tileGraphicImage.getUrl().contains("blank.png") && !tileGraphicImage.getUrl().contains("flagged.png")) {
|
||||||
!tileGraphicImage.getUrl().contains("flagged.png")) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
boolean flagged = tileGraphicImage.getUrl().contains("flagged.png");
|
boolean flagged = tileGraphicImage.getUrl().contains("flagged.png");
|
||||||
@ -189,22 +588,36 @@ public class Controller {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
bombCount--;
|
bombCount--;
|
||||||
updateBombCounter();
|
if (bombCount > 0)
|
||||||
|
updateBombCounter();
|
||||||
setImage((Button) tileClicked, "img/bomb_flagged.png");
|
setImage((Button) tileClicked, "img/bomb_flagged.png");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* On flag or reinitialization, update the bomb counter to represent the amount of currently flagged tiles
|
||||||
|
*/
|
||||||
private void updateBombCounter() {
|
private void updateBombCounter() {
|
||||||
String bombCountString = String.format("%03d", bombCount);
|
String bombCountString = String.format("%03d", bombCount);
|
||||||
setBombCounterImage(bomb_2, bombCountString.charAt(1));
|
setBombCounterImage(bomb_2, bombCountString.charAt(1));
|
||||||
setBombCounterImage(bomb_3, bombCountString.charAt(2));
|
setBombCounterImage(bomb_3, bombCountString.charAt(2));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used to update the digits of the bomb counter.
|
||||||
|
*
|
||||||
|
* @param imageView The ImageView representing the counter digit to be changed.
|
||||||
|
* @param digit The digit the counter should be changed to.
|
||||||
|
* @see #updateBombCounter()
|
||||||
|
*/
|
||||||
private void setBombCounterImage(ImageView imageView, char digit) {
|
private void setBombCounterImage(ImageView imageView, char digit) {
|
||||||
URL imageURL = getClass().getResource("img/" + digit + "_seconds.png");
|
URL imageURL = getClass().getResource("img/" + digit + "_seconds.png");
|
||||||
imageView.setImage(new Image(String.valueOf(imageURL)));
|
imageView.setImage(new Image(String.valueOf(imageURL)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Starts the timer when the user clicks or flags their first tile.
|
||||||
|
*/
|
||||||
private void scheduleTimer() {
|
private void scheduleTimer() {
|
||||||
startTime = System.currentTimeMillis();
|
startTime = System.currentTimeMillis();
|
||||||
TimerTask task = new TimerTask() {
|
TimerTask task = new TimerTask() {
|
||||||
@ -220,6 +633,11 @@ public class Controller {
|
|||||||
timer.schedule(task, 0, 1000);
|
timer.schedule(task, 0, 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculates the time since the game started, and passes it on.
|
||||||
|
*
|
||||||
|
* @see #setTimerImage(ImageView, char)
|
||||||
|
*/
|
||||||
private void updateTimer() {
|
private void updateTimer() {
|
||||||
long elapsedTimeMillis = System.currentTimeMillis() - startTime;
|
long elapsedTimeMillis = System.currentTimeMillis() - startTime;
|
||||||
time = (int) (elapsedTimeMillis / 1000);
|
time = (int) (elapsedTimeMillis / 1000);
|
||||||
@ -229,47 +647,89 @@ public class Controller {
|
|||||||
setTimerImage(time_3, timeString.charAt(2));
|
setTimerImage(time_3, timeString.charAt(2));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the timer digits individually based on updateTimer()
|
||||||
|
*
|
||||||
|
* @param imageView The ImageView to be updated
|
||||||
|
* @param digit The digit to update the ImageView with
|
||||||
|
* @see #updateTimer()
|
||||||
|
*/
|
||||||
private void setTimerImage(ImageView imageView, char digit) {
|
private void setTimerImage(ImageView imageView, char digit) {
|
||||||
URL imageURL = getClass().getResource("img/" + digit + "_seconds.png");
|
URL imageURL = getClass().getResource("img/" + digit + "_seconds.png");
|
||||||
imageView.setImage(new Image(String.valueOf(imageURL)));
|
imageView.setImage(new Image(String.valueOf(imageURL)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* On game over, show every bomb that was left on the grid, as well as every incorrectly flagged bomb.
|
||||||
|
*
|
||||||
|
* @param clickedColumn The column that caused the game over.
|
||||||
|
* @param clickedRow The row that caused the game over.
|
||||||
|
*/
|
||||||
private void showAllBombs(int clickedColumn, int clickedRow) {
|
private void showAllBombs(int clickedColumn, int clickedRow) {
|
||||||
for (Node node : grid.getChildren()) {
|
for (Node node : grid.getChildren()) {
|
||||||
|
Button b = (Button) node;
|
||||||
|
String buttonURL = ((ImageView) b.getGraphic()).getImage().getUrl();
|
||||||
int column = GridPane.getColumnIndex(node);
|
int column = GridPane.getColumnIndex(node);
|
||||||
int row = GridPane.getRowIndex(node);
|
int row = GridPane.getRowIndex(node);
|
||||||
if (!(column == clickedColumn && row == clickedRow) &&
|
// if the tile isn't the one that was clicked AND the tile is a bomb
|
||||||
wrapper.atColumn(column).atRow(row).isBomb()) {
|
if (!(column == clickedColumn && row == clickedRow) && wrapper.atColumn(column).atRow(row).isBomb()) {
|
||||||
setImage((Button) node, "img/bomb_revealed.png");
|
setImage((Button) node, "img/bomb_revealed.png");
|
||||||
}
|
}
|
||||||
|
if (buttonURL.contains("flagged.png") && !wrapper.atColumn(column).atRow(row).isBomb()) {
|
||||||
|
setImage(b, "img/bomb_wrong.png");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets a button's graphic.
|
||||||
|
*
|
||||||
|
* @param button The button to change.
|
||||||
|
* @param imagePath A path to an image to change the graphic to.
|
||||||
|
*/
|
||||||
private void setImage(Button button, String imagePath) {
|
private void setImage(Button button, String imagePath) {
|
||||||
URL imageURL = getClass().getResource(imagePath);
|
URL imageURL = getClass().getResource(imagePath);
|
||||||
button.setGraphic(new ImageView(new Image(String.valueOf(imageURL), 16, 16, true, false)));
|
button.setGraphic(new ImageView(new Image(String.valueOf(imageURL), 16, 16, true, false)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Replaces an ImageView's graphic with another.
|
||||||
|
*
|
||||||
|
* @param imageView The ImageView to change.
|
||||||
|
* @param imagePath A path to an image to change the graphic to.
|
||||||
|
*/
|
||||||
private void setImage(ImageView imageView, String imagePath) {
|
private void setImage(ImageView imageView, String imagePath) {
|
||||||
URL imageURL = getClass().getResource(imagePath);
|
URL imageURL = getClass().getResource(imagePath);
|
||||||
imageView.setImage(new Image(String.valueOf(imageURL)));
|
imageView.setImage(new Image(String.valueOf(imageURL)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Replaces the smiley with a pressed down variant when it is clicked.
|
||||||
|
*/
|
||||||
@FXML
|
@FXML
|
||||||
private void smileyPressed() {
|
private void smileyPressed() {
|
||||||
setImage(smiley, "img/face_smile_pressed.png");
|
setImage(smiley, "img/face_smile_pressed.png");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Releases the smiley from being pressed down, starts reinitialization.
|
||||||
|
*
|
||||||
|
* @see #reinitialize()
|
||||||
|
*/
|
||||||
@FXML
|
@FXML
|
||||||
private void smileyReleased() {
|
private void smileyReleased() {
|
||||||
gameOver = false;
|
|
||||||
setImage(smiley, "img/face_smile.png");
|
setImage(smiley, "img/face_smile.png");
|
||||||
reinitialize();
|
reinitialize();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the graphic of a tile to indicate how many bombs are adjacent to it.
|
||||||
|
*
|
||||||
|
* @param tileClicked The tile to update.
|
||||||
|
* @param adjacentBombs The number of bombs adjacent to the tile.
|
||||||
|
*/
|
||||||
private void setAdjacentCount(Node tileClicked, int adjacentBombs) {
|
private void setAdjacentCount(Node tileClicked, int adjacentBombs) {
|
||||||
Button button = (Button) tileClicked;
|
Button button = (Button) tileClicked;
|
||||||
URL imageURL = getClass().getResource("img/num_" + adjacentBombs + ".png");
|
setImage(button, "img/num_" + adjacentBombs + ".png");
|
||||||
button.setGraphic(new ImageView(new Image(String.valueOf(imageURL), 16, 16, true, false)));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,18 +1,31 @@
|
|||||||
package com.shr4pnel.minesweeper;
|
package com.shr4pnel.minesweeper;
|
||||||
|
|
||||||
|
|
||||||
import java.util.concurrent.ThreadLocalRandom;
|
import java.util.concurrent.ThreadLocalRandom;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used to fill the GridWrapper with bombs. Planned to merge into GridWrapper.
|
||||||
|
* @since 1.0.0
|
||||||
|
*/
|
||||||
public class Grid {
|
public class Grid {
|
||||||
|
/**
|
||||||
|
* An instance of GridWrapper used to check generation of bombs.
|
||||||
|
*/
|
||||||
final GridWrapper grid = new GridWrapper();
|
final GridWrapper grid = new GridWrapper();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates the bomb-grid structure on instantiation
|
||||||
|
*
|
||||||
|
* @see #generateBombs(int)
|
||||||
|
*/
|
||||||
public Grid() {
|
public Grid() {
|
||||||
// todo fix beginner mode and intermediate!
|
|
||||||
// sorry :3
|
|
||||||
// 99 bombs in expert:
|
|
||||||
generateBombs(99);
|
generateBombs(99);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates a boolean 2D array by randomly selecting a column and row, and setting it to true to represent a bomb.
|
||||||
|
*
|
||||||
|
* @param bombMax The number of bombs to generate.
|
||||||
|
*/
|
||||||
private void generateBombs(int bombMax) {
|
private void generateBombs(int bombMax) {
|
||||||
int i;
|
int i;
|
||||||
boolean success;
|
boolean success;
|
||||||
|
@ -1,37 +1,97 @@
|
|||||||
package com.shr4pnel.minesweeper;
|
package com.shr4pnel.minesweeper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Simplifies operations on the bomb array. Preventing direct access leads to cleaner code.
|
||||||
|
* @since 1.0.0
|
||||||
|
*/
|
||||||
public class GridWrapper {
|
public class GridWrapper {
|
||||||
|
/**
|
||||||
|
* Number of columns.
|
||||||
|
*/
|
||||||
private static final int COLUMNS = 30;
|
private static final int COLUMNS = 30;
|
||||||
|
/**
|
||||||
|
* Number of rows.
|
||||||
|
*/
|
||||||
private static final int ROWS = 16;
|
private static final int ROWS = 16;
|
||||||
|
/**
|
||||||
|
* A low level 2D array representing the position of bombs.
|
||||||
|
*/
|
||||||
final boolean[][] grid = new boolean[COLUMNS][ROWS];
|
final boolean[][] grid = new boolean[COLUMNS][ROWS];
|
||||||
|
/**
|
||||||
|
* Points at a column in grid.
|
||||||
|
*/
|
||||||
private int currentColumn;
|
private int currentColumn;
|
||||||
|
/**
|
||||||
|
* Points at a row in grid.
|
||||||
|
*/
|
||||||
private int currentRow;
|
private int currentRow;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* On instantiation, initialize currentColumn and currentRow to 0
|
||||||
|
*/
|
||||||
public GridWrapper() {
|
public GridWrapper() {
|
||||||
this.currentColumn = 0;
|
this.currentColumn = 0;
|
||||||
this.currentRow = 0;
|
this.currentRow = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets currentColumn to a specified column.
|
||||||
|
*
|
||||||
|
* @param column The column specified.
|
||||||
|
* @return Current GridWrapper instance.
|
||||||
|
*/
|
||||||
public GridWrapper atColumn(int column) {
|
public GridWrapper atColumn(int column) {
|
||||||
this.currentColumn = column;
|
this.currentColumn = column;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets currentColumn to a specified column.
|
||||||
|
*
|
||||||
|
* @param row The row specified.
|
||||||
|
* @return Current GridWrapper instance.
|
||||||
|
*/
|
||||||
public GridWrapper atRow(int row) {
|
public GridWrapper atRow(int row) {
|
||||||
this.currentRow = row;
|
this.currentRow = row;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets a bomb in grid at the position specified by currentColumn and currentRow.
|
||||||
|
*/
|
||||||
public void setBomb() {
|
public void setBomb() {
|
||||||
if (isValid(currentColumn, currentRow)) {
|
if (isValid(currentColumn, currentRow)) {
|
||||||
grid[currentColumn][currentRow] = true;
|
grid[currentColumn][currentRow] = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Switches a bomb from one position to another.
|
||||||
|
*
|
||||||
|
* @param destinationColumn The new column for the bomb.
|
||||||
|
* @param destinationRow The new row for the bomb.
|
||||||
|
*/
|
||||||
|
public void switchBomb(int destinationColumn, int destinationRow) {
|
||||||
|
if (isValid(currentColumn, currentRow) && isValid(destinationColumn, destinationRow)) {
|
||||||
|
grid[destinationColumn][destinationRow] = true;
|
||||||
|
grid[currentColumn][currentRow] = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if there is a bomb at the specified position.
|
||||||
|
*
|
||||||
|
* @return The value in grid specified by currentColumn and currentRow.
|
||||||
|
*/
|
||||||
public boolean isBomb() {
|
public boolean isBomb() {
|
||||||
return isValid(currentColumn, currentRow) && grid[currentColumn][currentRow];
|
return isValid(currentColumn, currentRow) && grid[currentColumn][currentRow];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks for bombs in every direction from the currentColumn and currentRow.
|
||||||
|
*
|
||||||
|
* @return The number of adjacent bombs.
|
||||||
|
*/
|
||||||
public int adjacentBombCount() {
|
public int adjacentBombCount() {
|
||||||
int count = 0;
|
int count = 0;
|
||||||
|
|
||||||
@ -62,11 +122,50 @@ public class GridWrapper {
|
|||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// todo use switchBomb
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Swaps one bomb with another.
|
||||||
|
*
|
||||||
|
* @param oldColumn The original column of the bomb.
|
||||||
|
* @param oldRow The original row of the bomb.
|
||||||
|
* @param newColumn The destination column of the bomb.
|
||||||
|
* @param newRow The destination row of the bomb.
|
||||||
|
*/
|
||||||
|
public void updateGrid(int oldColumn, int oldRow, int newColumn, int newRow) {
|
||||||
|
grid[oldColumn][oldRow] = false;
|
||||||
|
grid[newColumn][newRow] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if a bomb is at a specified position.
|
||||||
|
*
|
||||||
|
* @param column The column specified.
|
||||||
|
* @param row The row specified.
|
||||||
|
* @return A boolean AND representing a valid position and a bomb being present.
|
||||||
|
* @see #isValid(int, int)
|
||||||
|
*/
|
||||||
private boolean isBombAt(int column, int row) {
|
private boolean isBombAt(int column, int row) {
|
||||||
return isValid(column, row) && grid[column][row];
|
return isValid(column, row) && grid[column][row];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if a given column and row is in bounds.
|
||||||
|
*
|
||||||
|
* @param column The column provided.
|
||||||
|
* @param row The row provided.
|
||||||
|
* @return A boolean representing the tile being in bounds.
|
||||||
|
*/
|
||||||
private boolean isValid(int column, int row) {
|
private boolean isValid(int column, int row) {
|
||||||
return column >= 0 && column < COLUMNS && row >= 0 && row < ROWS;
|
return column >= 0 && column < COLUMNS && row >= 0 && row < ROWS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if a given column and row is in bounds using local state
|
||||||
|
*
|
||||||
|
* @return A boolean representing the tile being in bounds.
|
||||||
|
*/
|
||||||
|
public boolean isValid() {
|
||||||
|
return this.currentColumn >= 0 && this.currentColumn < COLUMNS && this.currentRow >= 0 && this.currentRow < ROWS;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package com.shr4pnel.minesweeper;
|
package com.shr4pnel.minesweeper;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
import javafx.application.Application;
|
import javafx.application.Application;
|
||||||
import javafx.fxml.FXML;
|
import javafx.fxml.FXML;
|
||||||
import javafx.fxml.FXMLLoader;
|
import javafx.fxml.FXMLLoader;
|
||||||
@ -8,7 +9,17 @@ import javafx.scene.Scene;
|
|||||||
import javafx.scene.image.Image;
|
import javafx.scene.image.Image;
|
||||||
import javafx.stage.Stage;
|
import javafx.stage.Stage;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The application opening point, used to bootstrap JavaFX and open to the GUI.
|
||||||
|
* @since 1.0.0
|
||||||
|
*/
|
||||||
public class Main extends Application {
|
public class Main extends Application {
|
||||||
|
/**
|
||||||
|
* JavaFX opening method. Creates the stage and bootstraps the application.
|
||||||
|
*
|
||||||
|
* @param stage The stage object passed in by JavaFX.
|
||||||
|
* @throws IOException If the FXML template or app icon are not found in resources.
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void start(Stage stage) throws IOException {
|
public void start(Stage stage) throws IOException {
|
||||||
Image icon = new Image(String.valueOf(getClass().getResource("winmine.png")));
|
Image icon = new Image(String.valueOf(getClass().getResource("winmine.png")));
|
||||||
@ -21,10 +32,19 @@ public class Main extends Application {
|
|||||||
stage.show();
|
stage.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Application opening method. Calls the JavaFX start method.
|
||||||
|
*
|
||||||
|
* @param args Optional commandline parameters, unimplemented.
|
||||||
|
* @see #start(Stage)
|
||||||
|
*/
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
launch();
|
launch();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cancels the timer on application stop.
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
@FXML
|
@FXML
|
||||||
public void stop() {
|
public void stop() {
|
||||||
|
@ -1,3 +1,8 @@
|
|||||||
|
/**
|
||||||
|
* The main module for the program. Required to launch to JavaFX as well as bundle into a native binary.
|
||||||
|
* @author shrapnelnet admin@shr4pnel.com
|
||||||
|
* @since 1.0.0
|
||||||
|
*/
|
||||||
module libremines {
|
module libremines {
|
||||||
requires javafx.controls;
|
requires javafx.controls;
|
||||||
requires javafx.fxml;
|
requires javafx.fxml;
|
||||||
|
31
src/main/resources/com/shr4pnel/minesweeper/about.fxml
Normal file
31
src/main/resources/com/shr4pnel/minesweeper/about.fxml
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
|
||||||
|
<?import javafx.scene.image.*?>
|
||||||
|
<?import javafx.scene.layout.*?>
|
||||||
|
<?import javafx.scene.text.*?>
|
||||||
|
|
||||||
|
<AnchorPane prefHeight="225.0" prefWidth="454.0" xmlns="http://javafx.com/javafx/17.0.2-ea" xmlns:fx="http://javafx.com/fxml/1">
|
||||||
|
<children>
|
||||||
|
<ImageView fitHeight="150.0" fitWidth="200.0" layoutX="146.0" layoutY="31.0" pickOnBounds="true" preserveRatio="true">
|
||||||
|
<image>
|
||||||
|
<Image url="@winmine.png" />
|
||||||
|
</image>
|
||||||
|
</ImageView>
|
||||||
|
<Text layoutY="42.0" strokeType="OUTSIDE" strokeWidth="0.0" text="made with love - shrapnelnet" textAlignment="CENTER" wrappingWidth="454.0">
|
||||||
|
<font>
|
||||||
|
<Font name="Source Code Pro" size="13.0" />
|
||||||
|
</font>
|
||||||
|
</Text>
|
||||||
|
<Text layoutY="183.0" strokeType="OUTSIDE" strokeWidth="0.0" text="greeTz: b4rkod, ping, cockpit, vulon, i330 n' porcupine" textAlignment="CENTER" wrappingWidth="454.0">
|
||||||
|
<font>
|
||||||
|
<Font name="Source Code Pro" size="13.0" />
|
||||||
|
</font>
|
||||||
|
</Text>
|
||||||
|
<Text layoutY="200.0" strokeType="OUTSIDE" strokeWidth="0.0" text="next time make your own!" textAlignment="CENTER" wrappingWidth="454.0">
|
||||||
|
<font>
|
||||||
|
<Font name="Source Code Pro" size="13.0" />
|
||||||
|
</font>
|
||||||
|
</Text>
|
||||||
|
|
||||||
|
</children>
|
||||||
|
</AnchorPane>
|
4
src/main/resources/com/shr4pnel/minesweeper/fix-glow.css
Normal file
4
src/main/resources/com/shr4pnel/minesweeper/fix-glow.css
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
* {
|
||||||
|
-fx-focus-color: transparent;
|
||||||
|
-fx-faint-focus-color: transparent;
|
||||||
|
}
|
BIN
src/main/resources/com/shr4pnel/minesweeper/img/204.jpg
Normal file
BIN
src/main/resources/com/shr4pnel/minesweeper/img/204.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 22 KiB |
@ -6,9 +6,9 @@
|
|||||||
<?import javafx.scene.layout.*?>
|
<?import javafx.scene.layout.*?>
|
||||||
<?import javafx.scene.shape.*?>
|
<?import javafx.scene.shape.*?>
|
||||||
|
|
||||||
<VBox maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="350.0" prefWidth="500.0" style="-fx-border-color: black; -fx-border-width: 1px;" xmlns="http://javafx.com/javafx/11.0.14-internal" xmlns:fx="http://javafx.com/fxml/1" fx:controller="com.shr4pnel.minesweeper.Controller">
|
<VBox maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="350.0" prefWidth="500.0" style="-fx-border-color: black; -fx-border-width: 1px;" stylesheets="@fix-glow.css" xmlns="http://javafx.com/javafx/17.0.2-ea" xmlns:fx="http://javafx.com/fxml/1" fx:controller="com.shr4pnel.minesweeper.Controller">
|
||||||
<children>
|
<children>
|
||||||
<MenuBar style="-fx-background-color: white;">
|
<MenuBar prefWidth="498.0" style="-fx-background-color: white;">
|
||||||
<menus>
|
<menus>
|
||||||
<Menu mnemonicParsing="false" text="Game">
|
<Menu mnemonicParsing="false" text="Game">
|
||||||
<items>
|
<items>
|
||||||
@ -23,11 +23,11 @@
|
|||||||
<ToggleGroup fx:id="difficulty" />
|
<ToggleGroup fx:id="difficulty" />
|
||||||
</toggleGroup>
|
</toggleGroup>
|
||||||
</RadioMenuItem>
|
</RadioMenuItem>
|
||||||
<RadioMenuItem mnemonicParsing="false" text="Internmediate" toggleGroup="$difficulty" />
|
<RadioMenuItem mnemonicParsing="false" text="Intermediate" toggleGroup="$difficulty" />
|
||||||
<RadioMenuItem mnemonicParsing="false" selected="true" text="Expert" toggleGroup="$difficulty" />
|
<RadioMenuItem mnemonicParsing="false" selected="true" text="Expert" toggleGroup="$difficulty" />
|
||||||
<SeparatorMenuItem mnemonicParsing="false" />
|
<SeparatorMenuItem mnemonicParsing="false" />
|
||||||
<RadioMenuItem mnemonicParsing="false" selected="true" text="Marks (?)" />
|
<RadioMenuItem fx:id="marks" mnemonicParsing="false" selected="true" text="Marks (?)" />
|
||||||
<RadioMenuItem mnemonicParsing="false" selected="true" text="Color" />
|
<RadioMenuItem fx:id="color" mnemonicParsing="false" selected="true" text="Color" />
|
||||||
<SeparatorMenuItem mnemonicParsing="false" />
|
<SeparatorMenuItem mnemonicParsing="false" />
|
||||||
<MenuItem mnemonicParsing="false" style="-fx-padding-right: 15; -fx-border-insets: 10px; -fx-background-insets: 10px;" text="Best Times..." />
|
<MenuItem mnemonicParsing="false" style="-fx-padding-right: 15; -fx-border-insets: 10px; -fx-background-insets: 10px;" text="Best Times..." />
|
||||||
<SeparatorMenuItem mnemonicParsing="false" />
|
<SeparatorMenuItem mnemonicParsing="false" />
|
||||||
@ -36,7 +36,7 @@
|
|||||||
</Menu>
|
</Menu>
|
||||||
<Menu mnemonicParsing="false" text="Help">
|
<Menu mnemonicParsing="false" text="Help">
|
||||||
<items>
|
<items>
|
||||||
<MenuItem mnemonicParsing="false" text="About Minesweeper" />
|
<MenuItem fx:id="about" mnemonicParsing="false" text="About Minesweeper" />
|
||||||
</items>
|
</items>
|
||||||
</Menu>
|
</Menu>
|
||||||
</menus>
|
</menus>
|
||||||
|
@ -0,0 +1,15 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
|
||||||
|
<?import javafx.scene.image.*?>
|
||||||
|
<?import javafx.scene.layout.*?>
|
||||||
|
|
||||||
|
|
||||||
|
<Pane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="420.0" prefWidth="525.0" xmlns="http://javafx.com/javafx/17.0.2-ea" xmlns:fx="http://javafx.com/fxml/1">
|
||||||
|
<children>
|
||||||
|
<ImageView fitHeight="420.0" fitWidth="531.0" pickOnBounds="true" preserveRatio="true">
|
||||||
|
<image>
|
||||||
|
<Image url="@img/204.jpg" />
|
||||||
|
</image>
|
||||||
|
</ImageView>
|
||||||
|
</children>
|
||||||
|
</Pane>
|
Loading…
x
Reference in New Issue
Block a user