Compare commits
	
		
			27 Commits
		
	
	
		
			1.0.1
			...
			d681f20b90
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 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 | 
							
								
								
									
										34
									
								
								.github/workflows/maven-publish.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										34
									
								
								.github/workflows/maven-publish.yml
									
									
									
									
										vendored
									
									
								
							@@ -1,34 +0,0 @@
 | 
			
		||||
# This workflow will build a package using Maven and then publish it to GitHub packages when a release is created
 | 
			
		||||
# For more information see: https://github.com/actions/setup-java/blob/main/docs/advanced-usage.md#apache-maven-with-a-settings-path
 | 
			
		||||
 | 
			
		||||
name: Maven Package
 | 
			
		||||
 | 
			
		||||
on:
 | 
			
		||||
  release:
 | 
			
		||||
    types: [created]
 | 
			
		||||
 | 
			
		||||
jobs:
 | 
			
		||||
  build:
 | 
			
		||||
 | 
			
		||||
    runs-on: ubuntu-latest
 | 
			
		||||
    permissions:
 | 
			
		||||
      contents: read
 | 
			
		||||
      packages: write
 | 
			
		||||
 | 
			
		||||
    steps:
 | 
			
		||||
    - uses: actions/checkout@v4
 | 
			
		||||
    - name: Set up JDK 21
 | 
			
		||||
      uses: actions/setup-java@v3
 | 
			
		||||
      with:
 | 
			
		||||
        java-version: '21'
 | 
			
		||||
        distribution: 'temurin'
 | 
			
		||||
        server-id: github # Value of the distributionManagement/repository/id field of the pom.xml
 | 
			
		||||
        settings-path: ${{ github.workspace }} # location for the settings.xml file
 | 
			
		||||
 | 
			
		||||
    - name: Build with Maven
 | 
			
		||||
      run: mvn -B package --file pom.xml
 | 
			
		||||
 | 
			
		||||
    - name: Publish to GitHub Packages Apache Maven
 | 
			
		||||
      run: mvn deploy -s $GITHUB_WORKSPACE/settings.xml
 | 
			
		||||
      env:
 | 
			
		||||
        GITHUB_TOKEN: ${{ github.token }}
 | 
			
		||||
							
								
								
									
										5
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										5
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@@ -42,3 +42,8 @@ bin/
 | 
			
		||||
.DS_Store
 | 
			
		||||
.idea
 | 
			
		||||
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>
 | 
			
		||||
							
								
								
									
										35
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										35
									
								
								README.md
									
									
									
									
									
								
							@@ -1 +1,34 @@
 | 
			
		||||
[](https://github.com/shrapnelnet/libremines/actions/workflows/maven-publish.yml)
 | 
			
		||||
# Libremines
 | 
			
		||||
 | 
			
		||||
"named this way because i didn't realise there was another libremines!"
 | 
			
		||||
 | 
			
		||||

 | 
			
		||||
 | 
			
		||||
## Building
 | 
			
		||||
 | 
			
		||||
### Requirements:
 | 
			
		||||
- Java 21
 | 
			
		||||
- Maven 3.8.8 or lower
 | 
			
		||||
- GraalVM 21
 | 
			
		||||
 | 
			
		||||
### Instructions:
 | 
			
		||||
 | 
			
		||||
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`
 | 
			
		||||
 | 
			
		||||
Alternatively, to run using the JVM, use:
 | 
			
		||||
 | 
			
		||||
```shell
 | 
			
		||||
./mvnw javafx:run
 | 
			
		||||
```
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										9
									
								
								pom.xml
									
									
									
									
									
								
							
							
						
						
									
										9
									
								
								pom.xml
									
									
									
									
									
								
							@@ -6,7 +6,7 @@
 | 
			
		||||
 | 
			
		||||
    <groupId>com.shr4pnel.minesweeper</groupId>
 | 
			
		||||
    <artifactId>libremines</artifactId>
 | 
			
		||||
    <version>1.0-SNAPSHOT</version>
 | 
			
		||||
    <version>1.0</version>
 | 
			
		||||
 | 
			
		||||
    <properties>
 | 
			
		||||
        <maven.compiler.source>21</maven.compiler.source>
 | 
			
		||||
@@ -17,12 +17,12 @@
 | 
			
		||||
        <dependency>
 | 
			
		||||
            <groupId>org.openjfx</groupId>
 | 
			
		||||
            <artifactId>javafx-controls</artifactId>
 | 
			
		||||
            <version>21.0.3</version>
 | 
			
		||||
            <version>21.0.4</version>
 | 
			
		||||
        </dependency>
 | 
			
		||||
        <dependency>
 | 
			
		||||
            <groupId>org.openjfx</groupId>
 | 
			
		||||
            <artifactId>javafx-fxml</artifactId>
 | 
			
		||||
            <version>21.0.3</version>
 | 
			
		||||
            <version>21.0.4</version>
 | 
			
		||||
        </dependency>
 | 
			
		||||
    </dependencies>
 | 
			
		||||
    <build>
 | 
			
		||||
@@ -46,6 +46,9 @@
 | 
			
		||||
                <version>1.0.22</version>
 | 
			
		||||
                <configuration>
 | 
			
		||||
                    <mainClass>com.shr4pnel.minesweeper.Main</mainClass>
 | 
			
		||||
                    <reflectionList>
 | 
			
		||||
                        com.shr4pnel.minesweeper.Controller
 | 
			
		||||
                    </reflectionList>
 | 
			
		||||
                </configuration>
 | 
			
		||||
            </plugin>
 | 
			
		||||
            <plugin>
 | 
			
		||||
 
 | 
			
		||||
@@ -1,43 +1,167 @@
 | 
			
		||||
package com.shr4pnel.minesweeper;
 | 
			
		||||
 | 
			
		||||
import java.io.IOException;
 | 
			
		||||
import java.net.URL;
 | 
			
		||||
import java.util.Timer;
 | 
			
		||||
import java.util.TimerTask;
 | 
			
		||||
 | 
			
		||||
import javafx.event.ActionEvent;
 | 
			
		||||
import javafx.event.EventHandler;
 | 
			
		||||
import javafx.fxml.FXML;
 | 
			
		||||
import javafx.fxml.FXMLLoader;
 | 
			
		||||
import javafx.scene.Node;
 | 
			
		||||
import javafx.scene.Parent;
 | 
			
		||||
import javafx.scene.Scene;
 | 
			
		||||
import javafx.scene.control.Button;
 | 
			
		||||
import javafx.scene.control.MenuItem;
 | 
			
		||||
import javafx.scene.control.RadioMenuItem;
 | 
			
		||||
import javafx.scene.image.Image;
 | 
			
		||||
import javafx.scene.image.ImageView;
 | 
			
		||||
import javafx.scene.input.MouseButton;
 | 
			
		||||
import javafx.scene.input.MouseEvent;
 | 
			
		||||
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 {
 | 
			
		||||
    /**
 | 
			
		||||
     * The grid within the FXML holding all the tiles.
 | 
			
		||||
     */
 | 
			
		||||
    @FXML
 | 
			
		||||
    private GridPane grid;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Images within the FXML structure.
 | 
			
		||||
     */
 | 
			
		||||
    @FXML
 | 
			
		||||
    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;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * A wrapper to make operations on the underlying grid easier.
 | 
			
		||||
     */
 | 
			
		||||
    private GridWrapper wrapper;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Handles the grid during a game over state preventing further clicking of the grid.
 | 
			
		||||
     */
 | 
			
		||||
    private boolean gameOver = false;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * A variable specifying if the game has been loaded for the first time.
 | 
			
		||||
     */
 | 
			
		||||
    private boolean isFirstLoad = true;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * The game timer.
 | 
			
		||||
     */
 | 
			
		||||
    static Timer timer = new Timer();
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * The time that has elapsed since the game started.
 | 
			
		||||
     */
 | 
			
		||||
    private int time = 0;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * The time the game was started at.
 | 
			
		||||
     */
 | 
			
		||||
    private long startTime;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * The number of bombs on the grid.
 | 
			
		||||
     */
 | 
			
		||||
    private int bombCount = 99;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * A 2D array holding all tiles that have previously recursively been expanded.
 | 
			
		||||
     */
 | 
			
		||||
    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
 | 
			
		||||
    private void initialize() {
 | 
			
		||||
        setNotYetImplemented(color);
 | 
			
		||||
        setNotYetImplemented(marks);
 | 
			
		||||
        about.setOnAction(this::openAbout);
 | 
			
		||||
        setupGrid();
 | 
			
		||||
        gridHandler = new Grid();
 | 
			
		||||
        wrapper = gridHandler.grid;
 | 
			
		||||
        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() {
 | 
			
		||||
        for (int column = 0; column < 30; ++column) {
 | 
			
		||||
            for (int row = 0; row < 16; ++row) {
 | 
			
		||||
@@ -47,17 +171,51 @@ public class Controller {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Used during initialization to fill the board
 | 
			
		||||
     *
 | 
			
		||||
     * @return A blank button
 | 
			
		||||
     */
 | 
			
		||||
    private Button createBlankButton() {
 | 
			
		||||
        Image blank =
 | 
			
		||||
            new Image(String.valueOf(getClass().getResource("img/blank.png")), 16, 16, true, true);
 | 
			
		||||
        Image blank = new Image(String.valueOf(getClass().getResource("img/blank.png")), 16, 16, true, false);
 | 
			
		||||
        ImageView blankImage = new ImageView(blank);
 | 
			
		||||
        Button blankButton = new Button();
 | 
			
		||||
        blankButton.setGraphic(blankImage);
 | 
			
		||||
        blankButton.setMinSize(16, 16);
 | 
			
		||||
        blankButton.setOnMouseClicked(this::buttonClicked);
 | 
			
		||||
        blankButton.setOnMousePressed(this::mouseHeld);
 | 
			
		||||
        blankButton.setOnMouseReleased(this::mouseReleased);
 | 
			
		||||
        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) {
 | 
			
		||||
        if (gameOver) {
 | 
			
		||||
            return;
 | 
			
		||||
@@ -78,25 +236,135 @@ public class Controller {
 | 
			
		||||
        if (buttonImage.getUrl().contains("flagged.png")) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
//        if (buttonImage.getUrl().contains("num") && !buttonImage.getUrl().contains("num_0.png")) {
 | 
			
		||||
//            chord(clicked, buttonImage.getUrl());
 | 
			
		||||
//            return;
 | 
			
		||||
//        }
 | 
			
		||||
        handlePrimaryClick(clicked, column, row);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
//    private void chord(Button clicked, String clickedURL) {
 | 
			
		||||
//        int column = GridPane.getColumnIndex(clicked);
 | 
			
		||||
//        int row = GridPane.getRowIndex(clicked);
 | 
			
		||||
//        int urlLength = clickedURL.length();
 | 
			
		||||
//        char expectedAdjacentChar = clickedURL.charAt(urlLength-5);
 | 
			
		||||
//        int expectedAdjacent = Integer.parseInt(Character.toString(expectedAdjacentChar));
 | 
			
		||||
//        int actualAdjacent = wrapper.atColumn(column).atRow(row).adjacentBombCount();
 | 
			
		||||
//        if (expectedAdjacent != actualAdjacent) {
 | 
			
		||||
//            return;
 | 
			
		||||
//        }
 | 
			
		||||
//        // chord logic
 | 
			
		||||
//    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 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};
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        // this realistically should never happen... sorry!
 | 
			
		||||
        return null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 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
 | 
			
		||||
     *
 | 
			
		||||
     * @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) getNodeByRowColumnIndex(row, column);
 | 
			
		||||
                assert current != null;
 | 
			
		||||
                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) {
 | 
			
		||||
        if (wrapper.atColumn(column).atRow(row).isBomb()) {
 | 
			
		||||
        if (wrapper.atColumn(column).atRow(row).isBomb() && !isFirstClick) {
 | 
			
		||||
            gameOver(clicked);
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        if (wrapper.isBomb() && isFirstClick) {
 | 
			
		||||
            int[] chosenColumnAndRow = setBombIfFirstTileIsBomb(column, row);
 | 
			
		||||
            // assertions are evil but i dont care
 | 
			
		||||
            assert chosenColumnAndRow != null;
 | 
			
		||||
            int columnMovedTo = chosenColumnAndRow[0];
 | 
			
		||||
            int rowMovedTo = chosenColumnAndRow[1];
 | 
			
		||||
            wrapper.atColumn(column).atRow(row).switchBomb(columnMovedTo, rowMovedTo);
 | 
			
		||||
            recursiveExpandTiles(column, row);
 | 
			
		||||
            clicked = (Button) getNodeByRowColumnIndex(row, column);
 | 
			
		||||
        }
 | 
			
		||||
        isFirstClick = false;
 | 
			
		||||
        int adjacentBombs = wrapper.adjacentBombCount();
 | 
			
		||||
        setAdjacentCount(clicked, adjacentBombs);
 | 
			
		||||
        if (adjacentBombs == 0) {
 | 
			
		||||
            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) {
 | 
			
		||||
        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;
 | 
			
		||||
        }
 | 
			
		||||
        expandTile(column, row);
 | 
			
		||||
@@ -112,6 +380,12 @@ 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) {
 | 
			
		||||
        Node tile = getNodeByRowColumnIndex(row, column);
 | 
			
		||||
        if (tile != null) {
 | 
			
		||||
@@ -127,6 +401,13 @@ public class Controller {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 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 getNodeByRowColumnIndex(int row, int column) {
 | 
			
		||||
        for (Node node : grid.getChildren()) {
 | 
			
		||||
            if (GridPane.getRowIndex(node) == row && GridPane.getColumnIndex(node) == column) {
 | 
			
		||||
@@ -136,8 +417,12 @@ public class Controller {
 | 
			
		||||
        return null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Resets important state variables on restart
 | 
			
		||||
     */
 | 
			
		||||
    @FXML
 | 
			
		||||
    private void reinitialize() {
 | 
			
		||||
        gameOver = false;
 | 
			
		||||
        bombCount = 99;
 | 
			
		||||
        updateBombCounter();
 | 
			
		||||
        resetTimer();
 | 
			
		||||
@@ -145,8 +430,14 @@ public class Controller {
 | 
			
		||||
        gridHandler = new Grid();
 | 
			
		||||
        wrapper = gridHandler.grid;
 | 
			
		||||
        expandedTiles = new boolean[30][16];
 | 
			
		||||
        isFirstClick = true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Resets the timer to 0
 | 
			
		||||
     *
 | 
			
		||||
     * @see #reinitialize()
 | 
			
		||||
     */
 | 
			
		||||
    private void resetTimer() {
 | 
			
		||||
        URL zeroSecondURL = getClass().getResource("img/0_seconds.png");
 | 
			
		||||
        time_1.setImage(new Image(String.valueOf(zeroSecondURL)));
 | 
			
		||||
@@ -157,6 +448,11 @@ public class Controller {
 | 
			
		||||
        timer = new Timer();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // todo figure out why createBlankButton errors here
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Refills the grid with new blank buttons
 | 
			
		||||
     */
 | 
			
		||||
    private void resetGrid() {
 | 
			
		||||
        URL blank = getClass().getResource("img/blank.png");
 | 
			
		||||
        for (Node node : grid.getChildren()) {
 | 
			
		||||
@@ -165,6 +461,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) {
 | 
			
		||||
        gameOver = true;
 | 
			
		||||
        timer.cancel();
 | 
			
		||||
@@ -173,12 +474,45 @@ public class Controller {
 | 
			
		||||
        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) getNodeByRowColumnIndex(row, column);
 | 
			
		||||
                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) {
 | 
			
		||||
        Button tileAsButton = (Button) tileClicked;
 | 
			
		||||
        ImageView tileGraphic = (ImageView) tileAsButton.getGraphic();
 | 
			
		||||
        Image tileGraphicImage = tileGraphic.getImage();
 | 
			
		||||
        if (!tileGraphicImage.getUrl().contains("blank.png") &&
 | 
			
		||||
            !tileGraphicImage.getUrl().contains("flagged.png")) {
 | 
			
		||||
        if (!tileGraphicImage.getUrl().contains("blank.png") && !tileGraphicImage.getUrl().contains("flagged.png")) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        boolean flagged = tileGraphicImage.getUrl().contains("flagged.png");
 | 
			
		||||
@@ -189,22 +523,36 @@ public class Controller {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        bombCount--;
 | 
			
		||||
        updateBombCounter();
 | 
			
		||||
        if (bombCount > 0)
 | 
			
		||||
            updateBombCounter();
 | 
			
		||||
        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() {
 | 
			
		||||
        String bombCountString = String.format("%03d", bombCount);
 | 
			
		||||
        setBombCounterImage(bomb_2, bombCountString.charAt(1));
 | 
			
		||||
        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) {
 | 
			
		||||
        URL imageURL = getClass().getResource("img/" + digit + "_seconds.png");
 | 
			
		||||
        imageView.setImage(new Image(String.valueOf(imageURL)));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Starts the timer when the user clicks or flags their first tile.
 | 
			
		||||
     */
 | 
			
		||||
    private void scheduleTimer() {
 | 
			
		||||
        startTime = System.currentTimeMillis();
 | 
			
		||||
        TimerTask task = new TimerTask() {
 | 
			
		||||
@@ -220,6 +568,11 @@ public class Controller {
 | 
			
		||||
        timer.schedule(task, 0, 1000);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Calculates the time since the game started, and passes it on.
 | 
			
		||||
     *
 | 
			
		||||
     * @see #setTimerImage(ImageView, char)
 | 
			
		||||
     */
 | 
			
		||||
    private void updateTimer() {
 | 
			
		||||
        long elapsedTimeMillis = System.currentTimeMillis() - startTime;
 | 
			
		||||
        time = (int) (elapsedTimeMillis / 1000);
 | 
			
		||||
@@ -229,19 +582,32 @@ public class Controller {
 | 
			
		||||
        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) {
 | 
			
		||||
        URL imageURL = getClass().getResource("img/" + digit + "_seconds.png");
 | 
			
		||||
        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) {
 | 
			
		||||
        for (Node node : grid.getChildren()) {
 | 
			
		||||
            Button b = (Button) node;
 | 
			
		||||
            String buttonURL = ((ImageView) b.getGraphic()).getImage().getUrl();
 | 
			
		||||
            int column = GridPane.getColumnIndex(node);
 | 
			
		||||
            int row = GridPane.getRowIndex(node);
 | 
			
		||||
            if (!(column == clickedColumn && row == clickedRow) &&
 | 
			
		||||
                wrapper.atColumn(column).atRow(row).isBomb()) {
 | 
			
		||||
            // if the tile isn't the one that was clicked AND the tile is a bomb
 | 
			
		||||
            if (!(column == clickedColumn && row == clickedRow) && wrapper.atColumn(column).atRow(row).isBomb()) {
 | 
			
		||||
                setImage((Button) node, "img/bomb_revealed.png");
 | 
			
		||||
            }
 | 
			
		||||
            if (buttonURL.contains("flagged.png") && !wrapper.atColumn(column).atRow(row).isBomb()) {
 | 
			
		||||
@@ -250,28 +616,53 @@ public class Controller {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 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) {
 | 
			
		||||
        URL imageURL = getClass().getResource(imagePath);
 | 
			
		||||
        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) {
 | 
			
		||||
        URL imageURL = getClass().getResource(imagePath);
 | 
			
		||||
        imageView.setImage(new Image(String.valueOf(imageURL)));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Replaces the smiley with a pressed down variant when it is clicked.
 | 
			
		||||
     */
 | 
			
		||||
    @FXML
 | 
			
		||||
    private void smileyPressed() {
 | 
			
		||||
        setImage(smiley, "img/face_smile_pressed.png");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Releases the smiley from being pressed down, starts reinitialization.
 | 
			
		||||
     *
 | 
			
		||||
     * @see #reinitialize()
 | 
			
		||||
     */
 | 
			
		||||
    @FXML
 | 
			
		||||
    private void smileyReleased() {
 | 
			
		||||
        gameOver = false;
 | 
			
		||||
        setImage(smiley, "img/face_smile.png");
 | 
			
		||||
        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) {
 | 
			
		||||
        Button button = (Button) tileClicked;
 | 
			
		||||
        setImage(button, "img/num_" + adjacentBombs + ".png");
 | 
			
		||||
 
 | 
			
		||||
@@ -1,18 +1,31 @@
 | 
			
		||||
package com.shr4pnel.minesweeper;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
import java.util.concurrent.ThreadLocalRandom;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Used to fill the GridWrapper with bombs. Planned to merge into GridWrapper.
 | 
			
		||||
 * @since 1.0.0
 | 
			
		||||
 */
 | 
			
		||||
public class Grid {
 | 
			
		||||
    /**
 | 
			
		||||
     * An instance of GridWrapper used to check generation of bombs.
 | 
			
		||||
     */
 | 
			
		||||
    final GridWrapper grid = new GridWrapper();
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Generates the bomb-grid structure on instantiation
 | 
			
		||||
     *
 | 
			
		||||
     * @see #generateBombs(int)
 | 
			
		||||
     */
 | 
			
		||||
    public Grid() {
 | 
			
		||||
        // todo fix beginner mode and intermediate!
 | 
			
		||||
        // sorry :3
 | 
			
		||||
        // 99 bombs in expert:
 | 
			
		||||
        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) {
 | 
			
		||||
        int i;
 | 
			
		||||
        boolean success;
 | 
			
		||||
 
 | 
			
		||||
@@ -1,37 +1,97 @@
 | 
			
		||||
package com.shr4pnel.minesweeper;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Simplifies operations on the bomb array. Preventing direct access leads to cleaner code.
 | 
			
		||||
 * @since 1.0.0
 | 
			
		||||
 */
 | 
			
		||||
public class GridWrapper {
 | 
			
		||||
    /**
 | 
			
		||||
     * Number of columns.
 | 
			
		||||
     */
 | 
			
		||||
    private static final int COLUMNS = 30;
 | 
			
		||||
    /**
 | 
			
		||||
     * Number of rows.
 | 
			
		||||
     */
 | 
			
		||||
    private static final int ROWS = 16;
 | 
			
		||||
    /**
 | 
			
		||||
     * A low level 2D array representing the position of bombs.
 | 
			
		||||
     */
 | 
			
		||||
    final boolean[][] grid = new boolean[COLUMNS][ROWS];
 | 
			
		||||
    /**
 | 
			
		||||
     * Points at a column in grid.
 | 
			
		||||
     */
 | 
			
		||||
    private int currentColumn;
 | 
			
		||||
    /**
 | 
			
		||||
     * Points at a row in grid.
 | 
			
		||||
     */
 | 
			
		||||
    private int currentRow;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * On instantiation, initialize currentColumn and currentRow to 0
 | 
			
		||||
     */
 | 
			
		||||
    public GridWrapper() {
 | 
			
		||||
        this.currentColumn = 0;
 | 
			
		||||
        this.currentRow = 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Sets currentColumn to a specified column.
 | 
			
		||||
     *
 | 
			
		||||
     * @param column The column specified.
 | 
			
		||||
     * @return Current GridWrapper instance.
 | 
			
		||||
     */
 | 
			
		||||
    public GridWrapper atColumn(int column) {
 | 
			
		||||
        this.currentColumn = column;
 | 
			
		||||
        return this;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Sets currentColumn to a specified column.
 | 
			
		||||
     *
 | 
			
		||||
     * @param row The row specified.
 | 
			
		||||
     * @return Current GridWrapper instance.
 | 
			
		||||
     */
 | 
			
		||||
    public GridWrapper atRow(int row) {
 | 
			
		||||
        this.currentRow = row;
 | 
			
		||||
        return this;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Sets a bomb in grid at the position specified by currentColumn and currentRow.
 | 
			
		||||
     */
 | 
			
		||||
    public void setBomb() {
 | 
			
		||||
        if (isValid(currentColumn, currentRow)) {
 | 
			
		||||
            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() {
 | 
			
		||||
        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() {
 | 
			
		||||
        int count = 0;
 | 
			
		||||
 | 
			
		||||
@@ -62,10 +122,40 @@ public class GridWrapper {
 | 
			
		||||
        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) {
 | 
			
		||||
        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) {
 | 
			
		||||
        return column >= 0 && column < COLUMNS && row >= 0 && row < ROWS;
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,7 @@
 | 
			
		||||
package com.shr4pnel.minesweeper;
 | 
			
		||||
 | 
			
		||||
import java.io.IOException;
 | 
			
		||||
 | 
			
		||||
import javafx.application.Application;
 | 
			
		||||
import javafx.fxml.FXML;
 | 
			
		||||
import javafx.fxml.FXMLLoader;
 | 
			
		||||
@@ -8,7 +9,17 @@ import javafx.scene.Scene;
 | 
			
		||||
import javafx.scene.image.Image;
 | 
			
		||||
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 {
 | 
			
		||||
    /**
 | 
			
		||||
     * 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
 | 
			
		||||
    public void start(Stage stage) throws IOException {
 | 
			
		||||
        Image icon = new Image(String.valueOf(getClass().getResource("winmine.png")));
 | 
			
		||||
@@ -21,10 +32,19 @@ public class Main extends Application {
 | 
			
		||||
        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) {
 | 
			
		||||
        launch();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Cancels the timer on application stop.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    @FXML
 | 
			
		||||
    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 {
 | 
			
		||||
    requires javafx.controls;
 | 
			
		||||
    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.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>
 | 
			
		||||
        <MenuBar style="-fx-background-color: white;">
 | 
			
		||||
        <MenuBar prefWidth="498.0" style="-fx-background-color: white;">
 | 
			
		||||
            <menus>
 | 
			
		||||
                <Menu mnemonicParsing="false" text="Game">
 | 
			
		||||
                    <items>
 | 
			
		||||
@@ -23,11 +23,11 @@
 | 
			
		||||
                                <ToggleGroup fx:id="difficulty" />
 | 
			
		||||
                            </toggleGroup>
 | 
			
		||||
                        </RadioMenuItem>
 | 
			
		||||
                        <RadioMenuItem mnemonicParsing="false" text="Internmediate" toggleGroup="$difficulty" />
 | 
			
		||||
                        <RadioMenuItem mnemonicParsing="false" text="Intermediate" toggleGroup="$difficulty" />
 | 
			
		||||
                        <RadioMenuItem mnemonicParsing="false" selected="true" text="Expert" toggleGroup="$difficulty" />
 | 
			
		||||
                        <SeparatorMenuItem mnemonicParsing="false" />
 | 
			
		||||
                        <RadioMenuItem mnemonicParsing="false" selected="true" text="Marks (?)" />
 | 
			
		||||
                        <RadioMenuItem mnemonicParsing="false" selected="true" text="Color" />
 | 
			
		||||
                        <RadioMenuItem fx:id="marks" mnemonicParsing="false" selected="true" text="Marks (?)" />
 | 
			
		||||
                        <RadioMenuItem fx:id="color" mnemonicParsing="false" selected="true" text="Color" />
 | 
			
		||||
                        <SeparatorMenuItem mnemonicParsing="false" />
 | 
			
		||||
                        <MenuItem mnemonicParsing="false" style="-fx-padding-right: 15; -fx-border-insets: 10px; -fx-background-insets: 10px;" text="Best Times..." />
 | 
			
		||||
                        <SeparatorMenuItem mnemonicParsing="false" />
 | 
			
		||||
@@ -36,7 +36,7 @@
 | 
			
		||||
                </Menu>
 | 
			
		||||
                <Menu mnemonicParsing="false" text="Help">
 | 
			
		||||
                    <items>
 | 
			
		||||
                        <MenuItem mnemonicParsing="false" text="About Minesweeper" />
 | 
			
		||||
                        <MenuItem fx:id="about" mnemonicParsing="false" text="About Minesweeper" />
 | 
			
		||||
                    </items>
 | 
			
		||||
                </Menu>
 | 
			
		||||
            </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>
 | 
			
		||||
		Reference in New Issue
	
	Block a user