Final #1

Merged
ppy4sjqvf merged 9 commits from develop into main 2 weeks ago

@ -0,0 +1,8 @@
<component name="ArtifactManager">
<artifact type="jar" name="MathPuzzle:jar">
<output-path>$PROJECT_DIR$/out/artifacts/MathPuzzle_jar</output-path>
<root id="archive" name="MathPuzzle.jar">
<element id="module-output" name="MathPuzzle" />
</root>
</artifact>
</component>

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CheckStyle-IDEA" serialisationVersion="2">
<checkstyleVersion>10.26.1</checkstyleVersion>
<scanScope>JavaOnly</scanScope>
<copyLibs>true</copyLibs>
<option name="thirdPartyClasspath" />
<option name="activeLocationIds">
<option value="bundled-google-checks" />
</option>
<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>

@ -0,0 +1,6 @@
This folder contains libraries copied from the "MathPuzzle" project.
It is managed by the CheckStyle-IDEA IDE plugin.
Do not modify this folder while the IDE is running.
When the IDE is stopped, you may delete this folder at any time. It will be recreated as needed.
In order to prevent the CheckStyle-IDEA IDE plugin from creating this folder,
uncheck the "Copy libraries from project directory" option in the CheckStyle-IDEA settings dialog.

@ -0,0 +1,604 @@
<component name="ProjectCodeStyleConfiguration">
<code_scheme name="Project" version="173">
<option name="OTHER_INDENT_OPTIONS">
<value>
<option name="INDENT_SIZE" value="2" />
<option name="CONTINUATION_INDENT_SIZE" value="4" />
<option name="TAB_SIZE" value="2" />
</value>
</option>
<option name="INSERT_INNER_CLASS_IMPORTS" value="false" />
<option name="CLASS_COUNT_TO_USE_IMPORT_ON_DEMAND" value="5" />
<option name="NAMES_COUNT_TO_USE_IMPORT_ON_DEMAND" value="3" />
<option name="PACKAGES_TO_USE_IMPORT_ON_DEMAND">
<value>
<package name="java.awt" withSubpackages="false" static="false" />
<package name="javax.swing" withSubpackages="false" static="false" />
</value>
</option>
<option name="IMPORT_LAYOUT_TABLE">
<value>
<package name="" withSubpackages="true" static="false" />
<emptyLine />
<package name="javax" withSubpackages="true" static="false" />
<package name="java" withSubpackages="true" static="false" />
<emptyLine />
<package name="" withSubpackages="true" static="true" />
</value>
</option>
<option name="RIGHT_MARGIN" value="100" />
<option name="KEEP_BLANK_LINES_IN_CODE" value="2" />
<option name="KEEP_CONTROL_STATEMENT_IN_ONE_LINE" value="false" />
<option name="KEEP_BLANK_LINES_BEFORE_RBRACE" value="0" />
<option name="BLANK_LINES_AFTER_CLASS_HEADER" value="0" />
<option name="ALIGN_MULTILINE_PARAMETERS" value="false" />
<option name="ALIGN_MULTILINE_FOR" value="false" />
<option name="SPACE_BEFORE_ARRAY_INITIALIZER_LBRACE" value="true" />
<option name="CALL_PARAMETERS_WRAP" value="1" />
<option name="METHOD_PARAMETERS_WRAP" value="1" />
<option name="EXTENDS_LIST_WRAP" value="1" />
<option name="THROWS_KEYWORD_WRAP" value="1" />
<option name="METHOD_CALL_CHAIN_WRAP" value="1" />
<option name="BINARY_OPERATION_WRAP" value="1" />
<option name="BINARY_OPERATION_SIGN_ON_NEXT_LINE" value="true" />
<option name="TERNARY_OPERATION_WRAP" value="1" />
<option name="TERNARY_OPERATION_SIGNS_ON_NEXT_LINE" value="true" />
<option name="FOR_STATEMENT_WRAP" value="1" />
<option name="ARRAY_INITIALIZER_WRAP" value="1" />
<option name="WRAP_COMMENTS" value="true" />
<option name="IF_BRACE_FORCE" value="3" />
<option name="DOWHILE_BRACE_FORCE" value="3" />
<option name="WHILE_BRACE_FORCE" value="3" />
<option name="FOR_BRACE_FORCE" value="3" />
<AndroidXmlCodeStyleSettings>
<option name="USE_CUSTOM_SETTINGS" value="true" />
<option name="LAYOUT_SETTINGS">
<value>
<option name="INSERT_BLANK_LINE_BEFORE_TAG" value="false" />
</value>
</option>
</AndroidXmlCodeStyleSettings>
<JSCodeStyleSettings version="0">
<option name="INDENT_CHAINED_CALLS" value="false" />
</JSCodeStyleSettings>
<JavaCodeStyleSettings>
<option name="INSERT_INNER_CLASS_IMPORTS" value="true" />
<option name="CLASS_COUNT_TO_USE_IMPORT_ON_DEMAND" value="999" />
<option name="NAMES_COUNT_TO_USE_IMPORT_ON_DEMAND" value="999" />
<option name="PACKAGES_TO_USE_IMPORT_ON_DEMAND">
<value />
</option>
<option name="IMPORT_LAYOUT_TABLE">
<value>
<package name="" withSubpackages="true" static="true" />
<emptyLine />
<package name="" withSubpackages="true" static="false" />
</value>
</option>
</JavaCodeStyleSettings>
<Objective-C>
<option name="INDENT_NAMESPACE_MEMBERS" value="0" />
<option name="INDENT_C_STRUCT_MEMBERS" value="2" />
<option name="INDENT_CLASS_MEMBERS" value="2" />
<option name="INDENT_VISIBILITY_KEYWORDS" value="1" />
<option name="INDENT_INSIDE_CODE_BLOCK" value="2" />
<option name="KEEP_STRUCTURES_IN_ONE_LINE" value="true" />
<option name="FUNCTION_PARAMETERS_WRAP" value="5" />
<option name="FUNCTION_CALL_ARGUMENTS_WRAP" value="5" />
<option name="TEMPLATE_CALL_ARGUMENTS_WRAP" value="5" />
<option name="TEMPLATE_CALL_ARGUMENTS_ALIGN_MULTILINE" value="true" />
<option name="ALIGN_INIT_LIST_IN_COLUMNS" value="false" />
<option name="SPACE_BEFORE_SUPERCLASS_COLON" value="false" />
</Objective-C>
<Objective-C-extensions>
<option name="GENERATE_INSTANCE_VARIABLES_FOR_PROPERTIES" value="ASK" />
<option name="RELEASE_STYLE" value="IVAR" />
<option name="TYPE_QUALIFIERS_PLACEMENT" value="BEFORE" />
<file>
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Import" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Macro" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Typedef" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Enum" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Constant" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Global" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Struct" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="FunctionPredecl" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Function" />
</file>
<class>
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Property" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Synthesize" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="InitMethod" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="StaticMethod" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="InstanceMethod" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="DeallocMethod" />
</class>
<extensions>
<pair source="cc" header="h" />
<pair source="c" header="h" />
</extensions>
</Objective-C-extensions>
<Python>
<option name="USE_CONTINUATION_INDENT_FOR_ARGUMENTS" value="true" />
</Python>
<TypeScriptCodeStyleSettings version="0">
<option name="INDENT_CHAINED_CALLS" value="false" />
</TypeScriptCodeStyleSettings>
<XML>
<option name="XML_ALIGN_ATTRIBUTES" value="false" />
</XML>
<codeStyleSettings language="CSS">
<indentOptions>
<option name="INDENT_SIZE" value="2" />
<option name="CONTINUATION_INDENT_SIZE" value="4" />
<option name="TAB_SIZE" value="2" />
</indentOptions>
</codeStyleSettings>
<codeStyleSettings language="ECMA Script Level 4">
<option name="KEEP_BLANK_LINES_IN_CODE" value="1" />
<option name="ALIGN_MULTILINE_PARAMETERS" value="false" />
<option name="ALIGN_MULTILINE_FOR" value="false" />
<option name="CALL_PARAMETERS_WRAP" value="1" />
<option name="METHOD_PARAMETERS_WRAP" value="1" />
<option name="EXTENDS_LIST_WRAP" value="1" />
<option name="BINARY_OPERATION_WRAP" value="1" />
<option name="BINARY_OPERATION_SIGN_ON_NEXT_LINE" value="true" />
<option name="TERNARY_OPERATION_WRAP" value="1" />
<option name="TERNARY_OPERATION_SIGNS_ON_NEXT_LINE" value="true" />
<option name="FOR_STATEMENT_WRAP" value="1" />
<option name="ARRAY_INITIALIZER_WRAP" value="1" />
<option name="IF_BRACE_FORCE" value="3" />
<option name="DOWHILE_BRACE_FORCE" value="3" />
<option name="WHILE_BRACE_FORCE" value="3" />
<option name="FOR_BRACE_FORCE" value="3" />
<option name="PARENT_SETTINGS_INSTALLED" value="true" />
</codeStyleSettings>
<codeStyleSettings language="HTML">
<indentOptions>
<option name="INDENT_SIZE" value="2" />
<option name="CONTINUATION_INDENT_SIZE" value="4" />
<option name="TAB_SIZE" value="2" />
</indentOptions>
</codeStyleSettings>
<codeStyleSettings language="JAVA">
<option name="KEEP_CONTROL_STATEMENT_IN_ONE_LINE" value="false" />
<option name="KEEP_BLANK_LINES_IN_CODE" value="1" />
<option name="BLANK_LINES_AFTER_CLASS_HEADER" value="1" />
<option name="ALIGN_MULTILINE_PARAMETERS" value="false" />
<option name="ALIGN_MULTILINE_RESOURCES" value="false" />
<option name="ALIGN_MULTILINE_FOR" value="false" />
<option name="CALL_PARAMETERS_WRAP" value="1" />
<option name="METHOD_PARAMETERS_WRAP" value="1" />
<option name="EXTENDS_LIST_WRAP" value="1" />
<option name="THROWS_KEYWORD_WRAP" value="1" />
<option name="METHOD_CALL_CHAIN_WRAP" value="1" />
<option name="BINARY_OPERATION_WRAP" value="1" />
<option name="BINARY_OPERATION_SIGN_ON_NEXT_LINE" value="true" />
<option name="TERNARY_OPERATION_WRAP" value="1" />
<option name="TERNARY_OPERATION_SIGNS_ON_NEXT_LINE" value="true" />
<option name="FOR_STATEMENT_WRAP" value="1" />
<option name="ARRAY_INITIALIZER_WRAP" value="1" />
<option name="WRAP_COMMENTS" value="true" />
<option name="IF_BRACE_FORCE" value="3" />
<option name="DOWHILE_BRACE_FORCE" value="3" />
<option name="WHILE_BRACE_FORCE" value="3" />
<option name="FOR_BRACE_FORCE" value="3" />
<indentOptions>
<option name="INDENT_SIZE" value="2" />
<option name="CONTINUATION_INDENT_SIZE" value="4" />
<option name="TAB_SIZE" value="2" />
</indentOptions>
</codeStyleSettings>
<codeStyleSettings language="JSON">
<indentOptions>
<option name="CONTINUATION_INDENT_SIZE" value="4" />
<option name="TAB_SIZE" value="2" />
</indentOptions>
</codeStyleSettings>
<codeStyleSettings language="JavaScript">
<option name="RIGHT_MARGIN" value="80" />
<option name="KEEP_BLANK_LINES_IN_CODE" value="1" />
<option name="ALIGN_MULTILINE_PARAMETERS" value="false" />
<option name="ALIGN_MULTILINE_FOR" value="false" />
<option name="CALL_PARAMETERS_WRAP" value="1" />
<option name="METHOD_PARAMETERS_WRAP" value="1" />
<option name="BINARY_OPERATION_WRAP" value="1" />
<option name="BINARY_OPERATION_SIGN_ON_NEXT_LINE" value="true" />
<option name="TERNARY_OPERATION_WRAP" value="1" />
<option name="TERNARY_OPERATION_SIGNS_ON_NEXT_LINE" value="true" />
<option name="FOR_STATEMENT_WRAP" value="1" />
<option name="ARRAY_INITIALIZER_WRAP" value="1" />
<option name="IF_BRACE_FORCE" value="3" />
<option name="DOWHILE_BRACE_FORCE" value="3" />
<option name="WHILE_BRACE_FORCE" value="3" />
<option name="FOR_BRACE_FORCE" value="3" />
<indentOptions>
<option name="INDENT_SIZE" value="2" />
<option name="TAB_SIZE" value="2" />
</indentOptions>
</codeStyleSettings>
<codeStyleSettings language="ObjectiveC">
<option name="RIGHT_MARGIN" value="80" />
<option name="KEEP_BLANK_LINES_BEFORE_RBRACE" value="1" />
<option name="BLANK_LINES_BEFORE_IMPORTS" value="0" />
<option name="BLANK_LINES_AFTER_IMPORTS" value="0" />
<option name="BLANK_LINES_AROUND_CLASS" value="0" />
<option name="BLANK_LINES_AROUND_METHOD" value="0" />
<option name="BLANK_LINES_AROUND_METHOD_IN_INTERFACE" value="0" />
<option name="ALIGN_MULTILINE_BINARY_OPERATION" value="false" />
<option name="BINARY_OPERATION_SIGN_ON_NEXT_LINE" value="true" />
<option name="FOR_STATEMENT_WRAP" value="1" />
<option name="ASSIGNMENT_WRAP" value="1" />
<indentOptions>
<option name="INDENT_SIZE" value="2" />
<option name="CONTINUATION_INDENT_SIZE" value="4" />
</indentOptions>
</codeStyleSettings>
<codeStyleSettings language="PROTO">
<option name="RIGHT_MARGIN" value="80" />
<indentOptions>
<option name="INDENT_SIZE" value="2" />
<option name="CONTINUATION_INDENT_SIZE" value="2" />
<option name="TAB_SIZE" value="2" />
</indentOptions>
</codeStyleSettings>
<codeStyleSettings language="Python">
<option name="KEEP_BLANK_LINES_IN_CODE" value="1" />
<option name="RIGHT_MARGIN" value="80" />
<option name="ALIGN_MULTILINE_PARAMETERS" value="false" />
<option name="PARENT_SETTINGS_INSTALLED" value="true" />
<indentOptions>
<option name="INDENT_SIZE" value="2" />
<option name="CONTINUATION_INDENT_SIZE" value="4" />
<option name="TAB_SIZE" value="2" />
</indentOptions>
</codeStyleSettings>
<codeStyleSettings language="SASS">
<indentOptions>
<option name="CONTINUATION_INDENT_SIZE" value="4" />
<option name="TAB_SIZE" value="2" />
</indentOptions>
</codeStyleSettings>
<codeStyleSettings language="SCSS">
<indentOptions>
<option name="CONTINUATION_INDENT_SIZE" value="4" />
<option name="TAB_SIZE" value="2" />
</indentOptions>
</codeStyleSettings>
<codeStyleSettings language="TypeScript">
<indentOptions>
<option name="INDENT_SIZE" value="2" />
<option name="TAB_SIZE" value="2" />
</indentOptions>
</codeStyleSettings>
<codeStyleSettings language="XML">
<indentOptions>
<option name="INDENT_SIZE" value="2" />
<option name="CONTINUATION_INDENT_SIZE" value="2" />
<option name="TAB_SIZE" value="2" />
</indentOptions>
<arrangement>
<rules>
<section>
<rule>
<match>
<AND>
<NAME>xmlns:android</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>xmlns:.*</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:id</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>style</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:.*Style</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:layout_width</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:layout_height</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:layout_weight</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:layout_margin</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:layout_marginTop</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:layout_marginBottom</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:layout_marginStart</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:layout_marginEnd</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:layout_marginLeft</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:layout_marginRight</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:layout_.*</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:padding</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:paddingTop</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:paddingBottom</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:paddingStart</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:paddingEnd</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:paddingLeft</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:paddingRight</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*</NAME>
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*</NAME>
<XML_NAMESPACE>http://schemas.android.com/apk/res-auto</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*</NAME>
<XML_NAMESPACE>http://schemas.android.com/tools</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*</NAME>
<XML_NAMESPACE>.*</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
</rules>
</arrangement>
</codeStyleSettings>
<codeStyleSettings language="protobuf">
<option name="RIGHT_MARGIN" value="80" />
<indentOptions>
<option name="CONTINUATION_INDENT_SIZE" value="2" />
</indentOptions>
</codeStyleSettings>
</code_scheme>
</component>

@ -0,0 +1,5 @@
<component name="ProjectCodeStyleConfiguration">
<state>
<option name="PREFERRED_PROJECT_CODE_STYLE" value="GoogleStyle" />
</state>
</component>

@ -1,8 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="MavenRunner">
<option name="jreName" value="17" />
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_17" default="true" project-jdk-name="17" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/out" />
</component>

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

@ -1,5 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="CheckStyle-IDEA-Module" serialisationVersion="2">
<option name="activeLocationsIds" />
</component>
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">

@ -1,2 +0,0 @@
# AutoGeneratePuzzle

@ -0,0 +1,153 @@
# 数学题目生成系统项目说明文档
## 1. 项目概述
### 1.1 项目名称
中小学数学卷子自动生成程序 (Math Puzzle System)
### 1.2 项目简介
数学题目生成系统是一个基于Java开发的教育类应用程序专门用于生成不同教育级别的数学题目。系统支持小学、初中和高中三个级别的题目生成并提供用户管理、题目去重、试卷保存等功能。
### 1.3 项目目标
- 为不同教育级别的学生提供定制化的数学练习题目
- 避免生成重复题目,提高学习效率
- 提供用户管理功能,支持多用户使用
- 生成的题目可保存为文件,便于打印和复习
## 2. 功能特性
### 2.1 用户管理
- **用户注册/登录**:支持现有用户登录系统
- **用户级别切换**:支持在小学、初中、高中三个级别间动态切换
- **个性化存储**:为每个用户创建独立的目录存储历史题目
### 2.2 题目生成
- **小学级别**:生成包含四则运算和括号的简单数学题目,且保证运算结果不会出现负数
- **初中级别**:生成包含四则运算、平方、开根号的数学题目
- **高中级别**生成包含四则运算和三角函数sin、cos、tan的数学题目
### 2.3 题目去重
- **历史题目检查**自动检查用户历史题目避免生成与前述txt文件中的重复题目
- **会话内去重**:防止同一次生成过程中出现重复题目
### 2.4 文件管理
- **自动目录创建**:为每个用户创建专属目录
- **时间戳命名**:生成的试卷以时间戳命名,确保唯一性
- **格式化输出**:题目按照标准格式:前有题号,题干之间添加一行间隔,便于阅读
## 3. 系统架构
### 3.1 核心模块
#### 3.1.1 控制器层 (Controller)
- `StartController`:系统主控制器,处理用户交互和系统流程控制
#### 3.1.2 服务层 (Service)
- `QuestionGenerator`:题目生成器接口
- `PrimarySchoolGenerator`:小学题目生成器
- `JuniorHighGenerator`:初中题目生成器
- `SeniorHighGenerator`:高中题目生成器
- `CaculatePrimary`:小学数学表达式计算器(保证结果不出现负数)
- `FileHandler`:文件处理器
- `QuestionDeduplicator`:题目去重器
#### 3.1.3 实体层 (Entity)
- `User`:用户实体类,包含用户名、密码和级别信息
### 3.2 交互流程
1. 用户启动程序
2. 系统要求用户登录
3. 用户选择题目数量和级别
4. 系统生成相应级别的数学题目
5. 题目去重检查
6. 生成结果展示并保存到文件
## 4. 使用说明
### 4.1 启动程序
```bash
java -jar .\mathpuzzle.jar
```
### 4.2 用户操作
1. **登录**:输入用户名和密码进行登录
2. **输入题目数量**输入10-30之间的数字输入-1退出当前用户
3. **切换级别**:输入"切换为XX"指令切换到相应级别(如"切换为初中"
4. **查看结果**:系统生成题目并显示,同时保存到用户目录
### 4.3 文件结构
```
./
├── [用户名]/
│ ├── 2024-01-01-12-00-00.txt
│ ├── 2024-01-01-12-05-30.txt
│ └── ...
```
## 5. 技术特点
### 5.1 设计模式
- **策略模式**:不同级别的题目生成器实现统一接口
- **工厂模式**:根据用户级别动态创建相应的题目生成器
### 5.2 算法特色
- **双栈算法**:用于计算小学级别的数学表达式
- **随机生成算法**:确保题目多样性和随机性
- **智能去重算法**:避免生成重复题目
### 5.3 代码规范
- 遵循Google Java编码规范
- 完整的Javadoc文档
- 清晰的包结构和类设计
## 6. 系统要求
### 6.1 运行环境
- Java 8或更高版本
- 至少50MB可用磁盘空间用于存储题目文件
### 6.2 权限要求
- 需要文件读写权限(用于创建用户目录和保存题目文件)
## 7. 扩展性说明
### 7.1 可扩展功能
- 支持更多教育级别的题目生成
- 添加更多数学运算符和函数
- 实现题目难度分级
- 增加图形界面支持
### 7.2 代码扩展
- 通过实现`QuestionGenerator`接口添加新的题目生成器
- 通过继承或修改现有生成器类调整题目生成规则
- 扩展用户实体类添加更多用户属性
## 8. 项目维护
### 8.1 代码维护
- 遵循单一职责原则,每个类只负责特定功能
- 使用接口编程,便于功能扩展和替换
- 完整的异常处理机制
### 8.2 版本管理
- 建议使用Git进行版本控制
- 遵循语义化版本控制规范
- 定期备份重要数据文件
## 9. 注意事项
1. 题目数量限制在10-30道之间确保生成效率
2. 系统会自动过滤负数结果,确保题目合理性
3. 生成的题目文件会自动保存,建议定期清理过期文件
4. 初中和高中题目包含高级运算符,需要相应的数学知识
5. 设置循环上限,在无法生成完全不重复的题目时自动退出并给出错误信息
## 10. 联系方式
如需技术支持或功能定制,请联系项目维护者。
---
**版本**1.0
**最后更新**2025年
**文档状态**:正式版

@ -0,0 +1,3 @@
Manifest-Version: 1.0
Main-Class: mathpuzzle.Main

@ -1,5 +0,0 @@
public class Main {
public static void main(String[] args) {
System.out.println("Hello World!");
}
}

@ -0,0 +1,29 @@
package mathpuzzle;
import mathpuzzle.controller.StartController;
/**
*
*
* <p>main
*
*
* @author
* @version 1.0
* @since 2025
*/
public class Main {
/**
*
*
* <p>start
*
*
* @param args 使
*/
public static void main(String[] args) {
StartController startController = new StartController();
startController.start();
}
}

@ -0,0 +1,174 @@
package mathpuzzle.controller;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
import mathpuzzle.entity.User;
import mathpuzzle.service.FileHandler;
import mathpuzzle.service.JuniorHighGenerator;
import mathpuzzle.service.PrimarySchoolGenerator;
import mathpuzzle.service.QuestionDeduplicator;
import mathpuzzle.service.QuestionGenerator;
import mathpuzzle.service.SeniorHighGenerator;
import mathpuzzle.system.LogSystem;
/**
*
*
* <p>
*
* @author
* @version 1.0
* @since 2025
*/
public class StartController {
/**
*
*/
private LogSystem logSystem = new LogSystem();
/**
*
*/
private QuestionDeduplicator deduplicator = new QuestionDeduplicator();
/**
*
*/
private FileHandler fileHandler = new FileHandler();
/**
*
*
* <p>
*
*/
public void start() {
logSystem.userHashMapInit();
Scanner scanner = new Scanner(System.in);
while (true) {
User user = logSystem.login();
if (user == null) {
continue;
}
while (true) {
System.out.println("准备生成" + user.getLevel()
+ "数学题目,请输入生成题目数量(输入-1将退出当前用户重新登录");
String input = scanner.nextLine();
try {
if ("-1".equals(input)) {
System.out.println("退出当前用户");
break;
}
int count = Integer.parseInt(input);
if (count < 10 || count > 30) {
System.out.println("题目数量必须在10-30之间");
continue;
}
handleQuestionGeneration(user, count);
} catch (NumberFormatException e) {
handleLevelSwitch(user, input);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
}
/**
*
*
* <p>"切换为XX"
*
*
* @param user
* @param input
*/
private void handleLevelSwitch(User user, String input) {
if (input.startsWith("切换为")) {
String newLevel = input.substring(3);
if ("小学".equals(newLevel) || "初中".equals(newLevel) || "高中".equals(newLevel)) {
user.setLevel(newLevel);
} else {
System.out.println("请输入小学、初中和高中三个选项中的一个");
}
} else {
System.out.println("无效输入。请输入题目数量或'切换为 XX'指令。");
}
}
/**
*
*
* <p>
*
* @param level "小学""初中""高中"
* @return null
*/
private QuestionGenerator createGenerator(String level) {
switch (level) {
case "小学":
return new PrimarySchoolGenerator();
case "初中":
return new JuniorHighGenerator();
case "高中":
return new SeniorHighGenerator();
default:
return null;
}
}
/**
*
*
* <p>使
*
*
* @param user
* @param count
* @throws IOException
*/
// 处理题目生成,进行去重工作
private void handleQuestionGeneration(User user, int count) throws IOException {
QuestionGenerator generator = createGenerator(user.getLevel());
if (generator == null) {
System.out.println("不支持的题目类型: " + user.getLevel());
return;
}
// 加载该用户所有历史题目用于查重
deduplicator.loadExistingQuestions(user);
List<String> finalQuestions = new ArrayList<>();
int generatedCount = 0;
int maxAttempts = 1000; // 防止因题目空间耗尽而无限循环
int attempts = 0;
while (generatedCount < count && attempts < maxAttempts) {
attempts++;
List<String> tempQuestions = generator.generateQuestions(1);
if (tempQuestions.isEmpty()) {
continue;
}
String newQuestion = tempQuestions.get(0);
String questionForDedup = newQuestion.endsWith(" =")
? newQuestion.substring(0, newQuestion.length() - 2) : newQuestion;
if (!deduplicator.isDuplicate(questionForDedup)) {
// 题目不重复,加入最终列表和查重集
finalQuestions.add(newQuestion);
deduplicator.addQuestion(questionForDedup); // 加入本次会话的查重集,防止本次生成重复
generatedCount++;
}
// 如果重复,则丢弃,循环继续
}
if (generatedCount < count) {
System.out.println(
"警告:在尝试了 " + maxAttempts + " 次后,仅生成了 " + generatedCount + " 道不重复的题目。");
}
for (int i = 0; i < finalQuestions.size(); i++) {
System.out.println((i + 1) + ". " + finalQuestions.get(i));
}
fileHandler.savePaper(user, finalQuestions);
System.out.println("试卷已成功保存!");
}
}

@ -0,0 +1,72 @@
package mathpuzzle.entity;
/**
*
*
* <p>
*
*
* @author
* @version 1.0
* @since 2025
*/
public class User {
/** 用户名,不可修改。 */
private final String name;
/** 用户密码,不可修改。 */
private final String password;
/** 用户当前的学习级别,可以修改。 */
private String level;
/**
*
*
* @param name
* @param password
* @param level "小学""初中""高中"
*/
public User(String name, String password, String level) {
this.name = name;
this.password = password;
this.level = level;
}
/**
*
*
* @return
*/
public String getName() {
return name;
}
/**
*
*
* @return
*/
public String getPassword() {
return password;
}
/**
*
*
* @return
*/
public String getLevel() {
return level;
}
/**
*
*
* @param newLevel "小学""初中""高中"
*/
public void setLevel(String newLevel) {
level = newLevel;
}
}

@ -0,0 +1,95 @@
package mathpuzzle.service;
import static mathpuzzle.service.PrimarySchoolGenerator.isNumeric;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Stack;
/**
*
*
* <p>使
*
*
* @author
* @version 1.0
* @since 2025
*/
public class CaculatePrimary {
/** 数字栈,用于存储操作数。 */
private final Stack<Double> numStack = new Stack<>();
/** 操作符栈,用于存储运算符和括号。 */
private final Stack<String> opStack = new Stack<>();
/** 运算符优先级映射表,数字越大优先级越高。 */
private final Map<String, Integer> precedence = new HashMap<>();
/**
*
*
* <p>使
*
* @param expression
* @return
*/
public double caculate(List<String> expression) {
precedence.put("+", 1);
precedence.put("-", 1);
precedence.put("*", 2);
precedence.put("/", 2);
for (String opOrNum : expression) {
if (isNumeric(opOrNum)) {
numStack.push(Double.parseDouble(opOrNum));
} else if (opOrNum.equals("(")) {
opStack.push(opOrNum);
} else if (opOrNum.equals(")")) {
while (!opStack.peek().equals("(") && !opStack.isEmpty()) {
doCaculte();
}
opStack.pop();
} else if (precedence.containsKey(opOrNum)) {
while (!opStack.isEmpty() && !opStack.peek().equals("(")
&& precedence.get(opOrNum) <= precedence.get(opStack.peek())) {
doCaculte();
}
opStack.push(opOrNum);
}
}
while (!opStack.isEmpty()) {
doCaculte();
}
return numStack.pop();
}
/**
*
*
* <p>
*
*/
public void doCaculte() {
String op = opStack.pop();
double num2 = numStack.pop();
double num1 = numStack.pop();
switch (op) {
case "+":
numStack.push(num1 + num2);
break;
case "-":
numStack.push(num1 - num2);
break;
case "*":
numStack.push(num1 * num2);
break;
case "/":
numStack.push(num1 / num2);
break;
default:
break;
}
}
}

@ -0,0 +1,69 @@
package mathpuzzle.service;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import mathpuzzle.entity.User;
/**
*
*
* <p>
*
*
* @author
* @version 1.0
* @since 2025
*/
public class FileHandler {
/**
*
*
* <p>
*
*
* @param user
* @throws IOException
*/
public void ensureUserDirectory(User user) throws IOException {
String dirPath = "./" + user.getName();
Path path = Paths.get(dirPath);
if (!Files.exists(path)) {
Files.createDirectories(path);
}
}
/**
*
*
* <p>
*
*
* @param user
* @param questions
* @throws IOException
*/
public void savePaper(User user, List<String> questions) throws IOException {
ensureUserDirectory(user);
// 生成文件名:年-月-日-时-分-秒.txt
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd-HH-mm-ss");
String fileName = LocalDateTime.now().format(formatter) + ".txt";
String filePath = "./" + user.getName() + "/" + fileName;
try (BufferedWriter writer = new BufferedWriter(new FileWriter(filePath))) {
for (int i = 0; i < questions.size(); i++) {
writer.write((i + 1) + ". " + questions.get(i)); // 添加题号
writer.newLine();
writer.newLine(); // 每题之间空一行
}
}
}
}

@ -0,0 +1,186 @@
package mathpuzzle.service;
import static mathpuzzle.service.PrimarySchoolGenerator.isNumeric;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
/**
*
*
* <p>
*
*
* @author
* @version 1.0
* @since 2025
*/
public class JuniorHighGenerator implements QuestionGenerator {
/**
* "平方""开根号"
*/
private static final String[] ADVANCED_OPS = {"平方", "开根号"};
/**
*
*/
private static final String[] OPERATORS = {"+", "-", "*", "/"};
/**
*
*/
private final Random random = new Random();
@Override
public List<String> generateQuestions(int count) {
List<String> questions = new ArrayList<>();
for (int i = 0; i < count; i++) {
String question = generateSingleQuestion();
questions.add(question);
}
return questions;
}
/**
*
*
* <p>
*
*
* @return
*/
private String generateSingleQuestion() {
List<String> parts = new ArrayList<>();
int operandCount = random.nextInt(5) + 1;
parts = generateBase(operandCount, parts);
// hasAdvancedOp用以检测下面的循环是否加入了高级运算符如果没有就启动保底
boolean hasAdvancedOp = false;
if (operandCount == 1) {
if ("平方".equals(ADVANCED_OPS[random.nextInt(ADVANCED_OPS.length)])) {
parts.add("平方");
} else {
parts.set(0, "开根号" + parts.get(0));
}
hasAdvancedOp = true;
} else {
// 遍历查找左括号的合理位置
for (int i = 0; i < parts.size() - 2; i++) {
// 该位置要为操作数且随机添加括号
if (isNumeric(parts.get(i)) && random.nextBoolean()) {
// 随机数看取出来的是不是开根号运算符
if ("开根号".equals(ADVANCED_OPS[random.nextInt(ADVANCED_OPS.length)])) {
parts = generateRoot(parts, i);
} else { // 如果不是开根号就是平方运算
parts = generateSquare(parts, i);
}
hasAdvancedOp = true;
break;
}
}
}
// 启动保底强制加入一个高级运算符
if (!hasAdvancedOp) {
parts = forceAddAdvancedOp(parts);
}
return String.join(" ", parts) + " =";
}
/**
*
*
* <p>
*
* @param operandCount
* @param parts
* @return
*/
public List<String> generateBase(int operandCount, List<String> parts) {
for (int i = 0; i < operandCount; i++) {
int num = random.nextInt(100) + 1;
parts.add(String.valueOf(num));
if (i < operandCount - 1) {
parts.add(OPERATORS[random.nextInt(OPERATORS.length)]);
}
}
return parts;
}
/**
*
*
* <p>使
*
*
* @param parts
* @return
*/
public List<String> forceAddAdvancedOp(List<String> parts) {
String advancedOp = ADVANCED_OPS[random.nextInt(ADVANCED_OPS.length)];
if ("平方".equals(advancedOp)) {
parts.add("平方");
} else { // 开根号
parts.set(0, "开根号(" + parts.get(0));
parts.set(parts.size() - 1, parts.get(parts.size() - 1) + ")");
}
return parts;
}
/**
*
*
* <p>
*
*
* @param parts
* @param i
* @return
*/
public List<String> generateRoot(List<String> parts, int i) {
if (random.nextBoolean()) {
parts.set(i, "开根号(" + parts.get(i) + ")");
} else {
parts.set(i, "开根号(" + parts.get(i));
// 为避免随机数上限出现0此处要单独判断一下左括号正好括住倒数第二个操作数的情况
if (i == parts.size() - 3) {
parts.set(parts.size() - 1, parts.get(parts.size() - 1) + ")");
} else {
while (true) {
int i2 = random.nextInt(parts.size() - 3 - i) + 2;
if (isNumeric(parts.get(i + i2))) {
parts.set(i + i2, parts.get(i + i2) + ")");
break;
}
}
}
}
return parts;
}
/**
*
*
* <p>
*
* @param parts
* @param i
* @return
*/
public List<String> generateSquare(List<String> parts, int i) {
parts.set(i, "(" + parts.get(i));
// 为避免随机数上限出现0此处要单独判断一下左括号正好括住倒数第二个操作数的情况
if (i == parts.size() - 3) {
parts.set(parts.size() - 1, parts.get(parts.size() - 1) + ")");
} else {
while (true) {
int i2 = random.nextInt(parts.size() - 3 - i) + 2;
if (isNumeric(parts.get(i + i2))) {
parts.set(i + i2, parts.get(i + i2) + ")平方");
break;
}
}
}
return parts;
}
}

@ -0,0 +1,121 @@
package mathpuzzle.service;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
/**
*
*
* <p>
*
*
* @author
* @version 1.0
* @since 2025
*/
public class PrimarySchoolGenerator implements QuestionGenerator {
/** 运算符数组,包含四则运算符号。 */
private static final String[] OPERATORS = {"+", "-", "*", "/"};
/** 随机数生成器,用于生成随机题目。 */
private final Random random = new Random();
@Override
public List<String> generateQuestions(int count) {
List<String> questions = new ArrayList<>();
for (int i = 0; i < count; i++) {
String question = generateSingleQuestion();
questions.add(question);
}
return questions;
}
/**
* .
*
* <p>2-5
*
*
* @return
*/
private String generateSingleQuestion() {
CaculatePrimary caculatePrimary = new CaculatePrimary();
int operandCount = random.nextInt(4) + 2; // 2-5个操作数
List<String> parts = new ArrayList<>();
while (true) {
// 生成基础操作
parts = generateBase(operandCount, parts);
// 简单添加括号逻辑:随机加一个括号
if (operandCount > 2 && random.nextBoolean()) {
// 遍历查找左括号的合理位置
for (int i = 0; i < parts.size() - 2; i++) {
// 该位置要为操作数且随机添加括号
if (isNumeric(parts.get(i)) && random.nextBoolean()) {
parts.add(i, "(");
i++;
// 为避免随机数上限出现0此处要单独判断一下左括号正好括住倒数第二个操作数的情况
if (i == parts.size() - 3) {
parts.add(")");
} else {
while (true) {
int i2 = random.nextInt(parts.size() - 3 - i) + 2;
if (isNumeric(parts.get(i + i2))) {
parts.add(i + i2 + 1, ")");
break;
}
}
}
break;
}
}
}
if (caculatePrimary.caculate(parts) >= 0) {
return String.join(" ", parts) + " =";
} else {
parts.clear();
}
}
}
/**
*
*
* <p>
*
* @param str
* @return truefalse
*/
public static boolean isNumeric(String str) {
if (str == null || str.isEmpty()) {
return false;
}
try {
Double.parseDouble(str);
return true;
} catch (NumberFormatException e) {
return false;
}
}
/**
*
*
* <p>
*
* @param operandCount
* @param parts
* @return
*/
public List<String> generateBase(int operandCount, List<String> parts) {
for (int i = 0; i < operandCount; i++) {
int num = random.nextInt(100) + 1;
parts.add(String.valueOf(num));
if (i < operandCount - 1) {
parts.add(OPERATORS[random.nextInt(OPERATORS.length)]);
}
}
return parts;
}
}

@ -0,0 +1,91 @@
package mathpuzzle.service;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.HashSet;
import java.util.Set;
import mathpuzzle.entity.User;
/**
*
*
* <p>
*
*
* @author
* @version 1.0
* @since 2025
*/
public class QuestionDeduplicator {
/**
*
*/
private final Set<String> existingQuestions = new HashSet<>();
/**
*
*
* <p>.txt
*
*
* @param user
*/
public void loadExistingQuestions(User user) {
existingQuestions.clear();
String userDir = "./" + user.getName();
File dir = new File(userDir);
if (!dir.exists()) {
return; // 目录不存在,无历史题目
}
File[] files = dir.listFiles((d, name) -> name.endsWith(".txt"));
if (files == null) {
return;
}
for (File file : files) {
try (BufferedReader br = new BufferedReader(new FileReader(file))) {
String line;
while ((line = br.readLine()) != null) {
// 只加载题目行,忽略题号和空行
if (line.trim().isEmpty() || line.matches("\\d+\\. .*")) {
String questionContent = line.replaceFirst("\\d+\\. ", "").trim();
if (!questionContent.isEmpty() && !questionContent.equals("=")) {
existingQuestions.add(questionContent);
}
}
}
} catch (IOException e) {
System.err.println("读取历史文件时出错: " + file.getName());
}
}
}
/**
*
*
* <p>
*
* @param question
* @return truefalse
*/
public boolean isDuplicate(String question) {
return existingQuestions.contains(question);
}
/**
*
*
* <p>
*
*
* @param question
*/
public void addQuestion(String question) {
existingQuestions.add(question);
}
}

@ -0,0 +1,28 @@
package mathpuzzle.service;
import java.util.List;
/**
*
*
* <p>
*
*
*
* @author
* @version 1.0
* @since 2025
*/
public interface QuestionGenerator {
/**
*
*
* <p>
*
*
* @param count
* @return
*/
List<String> generateQuestions(int count);
}

@ -0,0 +1,126 @@
package mathpuzzle.service;
import static mathpuzzle.service.PrimarySchoolGenerator.isNumeric;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
/**
*
*
* <p>sincostan
*
*
* @author
* @version 1.0
* @since 2025
*/
public class SeniorHighGenerator implements QuestionGenerator {
/** 三角函数运算符数组,包含"sin"、"cos"和"tan"。 */
private static final String[] TRIG_FUNCS = {"sin", "cos", "tan"};
/** 基本运算符数组,包含四则运算符号。 */
private static final String[] OPERATORS = {"+", "-", "*", "/"};
/** 随机数生成器,用于生成随机题目。 */
private final Random random = new Random();
@Override
public List<String> generateQuestions(int count) {
List<String> questions = new ArrayList<>();
for (int i = 0; i < count; i++) {
String question = generateSingleQuestion();
questions.add(question);
}
return questions;
}
/**
*
*
* <p>
*
*
* @return
*/
private String generateSingleQuestion() {
List<String> parts = new ArrayList<>();
int operandCount = random.nextInt(5) + 1;
parts = generateBase(operandCount, parts);
String advancedOp;
if (operandCount == 1) {
advancedOp = TRIG_FUNCS[random.nextInt(TRIG_FUNCS.length)];
parts.set(0, advancedOp + parts.get(0));
} else {
// 遍历查找左括号的合理位置
for (int i = 0; i < parts.size(); i++) {
// 最后一次循环保底生成高中三角函数
if (i == parts.size() - 1) {
advancedOp = TRIG_FUNCS[random.nextInt(TRIG_FUNCS.length)];
parts.set(i, advancedOp + parts.get(i));
} else if (isNumeric(parts.get(i)) && random.nextBoolean()) { // 随机数看是否为操作数且随即进入生成程序
// 进入随机生成tan\sin\cos的程序
parts = generateTrig(parts, i);
break;
}
}
}
return String.join(" ", parts) + " =";
}
/**
*
*
* <p>
*
* @param operandCount
* @param parts
* @return
*/
// 产生基本操作
public List<String> generateBase(int operandCount, List<String> parts) {
for (int i = 0; i < operandCount; i++) {
int num = random.nextInt(100) + 1;
parts.add(String.valueOf(num));
if (i < operandCount - 1) {
parts.add(OPERATORS[random.nextInt(OPERATORS.length)]);
}
}
return parts;
}
/**
*
*
* <p>
*
*
* @param parts
* @param i
* @return
*/
// 产生三角函数运算符
public List<String> generateTrig(List<String> parts, int i) {
String trigOp = TRIG_FUNCS[random.nextInt(TRIG_FUNCS.length)];
if (random.nextBoolean()) {
parts.set(i, trigOp + parts.get(i));
} else {
parts.set(i, trigOp + "(" + parts.get(i));
// 为避免随机数上限出现0此处要单独判断一下左括号正好括住倒数第二个操作数的情况
if (i == parts.size() - 3) {
parts.set(parts.size() - 1, parts.get(parts.size() - 1) + ")");
} else {
while (true) {
int i2 = random.nextInt(parts.size() - 3 - i) + 2;
if (isNumeric(parts.get(i + i2))) {
parts.set(i + i2, parts.get(i + i2) + ")");
break;
}
}
}
}
return parts;
}
}

@ -0,0 +1,47 @@
package mathpuzzle.system;
import mathpuzzle.entity.User;
import java.util.HashMap;
import java.util.Scanner;
public class LogSystem {
private final HashMap<String, User> userHashMap = new HashMap<>();
public void userHashMapInit() {
// 小学
userHashMap.put("张三1", new User("张三 1", "123", "小学"));
userHashMap.put("张三2", new User("张三 2", "123", "小学"));
userHashMap.put("张三3", new User("张三 3", "123", "小学"));
// 初中
userHashMap.put("李四1", new User("李四 1", "123", "初中"));
userHashMap.put("李四2", new User("李四 2", "123", "初中"));
userHashMap.put("李四3", new User("李四 3", "123", "初中"));
// 高中
userHashMap.put("王五1", new User("王五 1", "123", "高中"));
userHashMap.put("王五2", new User("王五 2", "123", "高中"));
userHashMap.put("王五3", new User("王五 3", "123", "高中"));
}
public User login() {
System.out.println("请输入用户名和密码,两者之间用空格隔开");
while(true) {
Scanner scanner = new Scanner(System.in);
String[] info = scanner.nextLine().split(" ");
if(info.length != 2) {
System.out.println("请输入正确格式");
} else {
String name = info[0];
String password = info[1];
User user = userHashMap.get(name);
if (user == null) {
System.out.println("请输入正确的用户名、密码");
}
else if (!user.getPassword().equals(password)) {
System.out.println("请输入正确的用户名、密码");
}
else {
System.out.println("当前选择为" + user.getLevel() + "出题");
return user;
}
}
}
}
}
Loading…
Cancel
Save