├── .gitignore ├── LICENSE ├── README.md ├── install.sh ├── lint ├── google_checks.xml └── pmd_rules.xml ├── pom.xml └── src ├── main └── java │ └── org │ └── algohub │ └── engine │ ├── JudgeEngine.java │ ├── bo │ ├── InternalTestCase.java │ ├── ProcessResult.java │ └── StatusCode.java │ ├── codegenerator │ ├── CppCodeGenerator.java │ ├── FunctionGenerator.java │ ├── Indentation.java │ ├── JavaCodeGenerator.java │ ├── JavaScriptCodeGenerator.java │ ├── PythonCodeGenerator.java │ ├── RubyCodeGenerator.java │ └── TypeMap.java │ ├── collection │ ├── BinaryTreeNode.java │ └── LinkedListNode.java │ ├── compiler │ └── java │ │ ├── CompileErrorException.java │ │ ├── MemoryClassLoader.java │ │ ├── MemoryJavaCompiler.java │ │ └── MemoryJavaFileManager.java │ ├── judge │ ├── CppJudge.java │ ├── CsharpJudge.java │ ├── JavaJudge.java │ ├── JavaScriptJudge.java │ ├── JudgeInterface.java │ ├── PythonJudge.java │ └── RubyJudge.java │ ├── pojo │ ├── Function.java │ ├── JudgeResult.java │ └── Problem.java │ ├── serde │ ├── Deserializer.java │ └── Serializer.java │ ├── type │ ├── IntermediateType.java │ ├── LanguageType.java │ ├── TypeNode.java │ ├── TypeNodeDeserializer.java │ └── TypeNodeSerializer.java │ └── util │ ├── Equals.java │ └── ObjectMapperInstance.java └── test ├── java └── org │ └── algohub │ └── engine │ ├── codegenerator │ ├── CppCodeGeneratorTest.java │ ├── DataTypes.java │ ├── JavaCodeGeneratorTest.java │ ├── PythonCodeGeneratorTest.java │ └── RubyCodeGeneratorTest.java │ ├── compiler │ └── java │ │ └── MemoryJavaCompilerTest.java │ ├── judge │ ├── CppJudgeTest.java │ ├── JavaJudgeTest.java │ ├── JudgeEngineTestUtil.java │ ├── JudgeOneTest.java │ ├── PythonJudgeTest.java │ └── RubyJudgeTest.java │ ├── serde │ ├── DeserializerTest.java │ ├── SerializerTest.java │ └── SharedData.java │ └── type │ └── TypeNodeTest.java └── resources ├── problems ├── 2sum.json ├── add-two-numbers.json ├── remove-duplicates-from-sorted-list.json ├── reverse-linked-list.json ├── stoi.json ├── valid-sudoku.json └── word-ladder.json └── solutions ├── 2sum ├── TwoSum.java ├── solution.py ├── solution.rb └── two_sum.cpp ├── add-two-numbers ├── Solution.java ├── solution.cpp ├── solution.py └── solution.rb ├── remove-duplicates-from-sorted-list ├── Solution.java ├── solution.cpp ├── solution.py └── solution.rb ├── reverse-linked-list ├── Solution.java ├── solution.cpp ├── solution.py └── solution.rb ├── stoi ├── Solution.java ├── solution.cpp ├── solution.py └── solution.rb ├── valid-sudoku ├── Solution.java ├── solution.cpp ├── solution.py └── solution.rb └── word-ladder ├── WordLadder.java ├── WordLadder.java.bak ├── solution.py ├── solution.rb └── word_ladder.cpp /.gitignore: -------------------------------------------------------------------------------- 1 | # Java 2 | *.class 3 | 4 | # Mobile Tools for Java (J2ME) 5 | .mtj.tmp/ 6 | 7 | # Package Files # 8 | *.jar 9 | *.war 10 | *.ear 11 | 12 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 13 | hs_err_pid* 14 | 15 | # IntelliJ Idea 16 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion 17 | 18 | *.iml 19 | 20 | ## Directory-based project format: 21 | .idea/ 22 | # if you remove the above rule, at least ignore the following: 23 | 24 | # User-specific stuff: 25 | .idea/workspace.xml 26 | .idea/tasks.xml 27 | .idea/dictionaries 28 | 29 | # Sensitive or high-churn files: 30 | .idea/dataSources.ids 31 | .idea/dataSources.xml 32 | .idea/sqlDataSources.xml 33 | .idea/dynamic.xml 34 | .idea/uiDesigner.xml 35 | 36 | # Gradle: 37 | .idea/gradle.xml 38 | .idea/libraries 39 | 40 | # Mongo Explorer plugin: 41 | .idea/mongoSettings.xml 42 | 43 | ## File-based project format: 44 | *.ipr 45 | *.iws 46 | 47 | ## Plugin-specific files: 48 | 49 | # IntelliJ 50 | /out/ 51 | 52 | # mpeltonen/sbt-idea plugin 53 | .idea_modules/ 54 | 55 | # JIRA plugin 56 | atlassian-ide-plugin.xml 57 | 58 | # Crashlytics plugin (for Android Studio and IntelliJ) 59 | com_crashlytics_export_strings.xml 60 | crashlytics.properties 61 | crashlytics-build.properties 62 | 63 | # Maven 64 | target/ 65 | pom.xml.tag 66 | pom.xml.releaseBackup 67 | pom.xml.versionsBackup 68 | pom.xml.next 69 | release.properties 70 | dependency-reduced-pom.xml 71 | buildNumber.properties 72 | .mvn/timing.properties 73 | 74 | .checkstyle 75 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Algohub Judge Engine 2 | 3 | Algohub Judge Engine is a modern online judge engine, which supports most of programming languages. 4 | 5 | Supported OS: Ubuntu 16.04, CentOS 6.7 6 | 7 | 8 | ## Install Dependencies 9 | 10 | ./install.sh 11 | 12 | 13 | ## Compile 14 | 15 | mvn clean package 16 | 17 | 18 | ## Run 19 | 20 | java -jar target/judge-engine-1.0-SNAPSHOT.jar src/test/resources/problems/2-sum/2-sum.json PYTHON src/test/resources/problems/2-sum/solution.py 21 | 22 | 23 | ## Install Dependencies Manually(for advanced users) 24 | 25 | 26 | ### Compilers and Interpreters 27 | 28 | The judge engine uses compilers and interpreters under the hood, so you need to install compilers and interpreters in advance. 29 | 30 | Currently Algohub Judge Engine uses JDK 8, GCC 5, Python3 and Ruby 2. 31 | 32 | The following commands should be available in `$PATH`: 33 | 34 | * `java` 35 | * `javac` 36 | * `g++` 37 | * `python3` 38 | * `ruby` 39 | 40 | 41 | ### Libraries and Pre-defined Modules 42 | 43 | 44 | #### rapidjson 45 | 46 | Algohub Judge Engine relies on the [rapidjson](ihttps://github.com/miloyip/rapidjson) library to support C++ language. So we need to make the rapidjson system wide. 47 | 48 | git clone git@github.com:miloyip/rapidjson.git 49 | sudo cp -r rapidjson/include/rapidjson/ /usr/local/include/ 50 | 51 | 52 | #### Pre-defined C++ Header Files 53 | 54 | First, download the languages support files, 55 | 56 | git clone https://github.com/algohub/judge-engine-languages-support.git 57 | cd judge-engine-languages-support/ 58 | 59 | Algohub Judge Engine has some pre-defined C++ header files which are needed during compilation. 60 | 61 | sudo cp -r judge-engine-cpp-support/include/algohub/ /usr/local/include/ 62 | 63 | 64 | #### Pre-defined Python Module 65 | 66 | The judge engine has a pre-defined python module named `algohub`, which is need during runtime. 67 | 68 | Copy the Python `algohub` module into one of Python's default module paths, i.e., `sys.path` 69 | 70 | python3 -c "import sys;print(sys.path);" 71 | cd judge-engine-languages-support/ 72 | sudo cp -r judge-engine-python-support/algohub/ /usr/local/lib/python3.5/dist-packages/ 73 | 74 | 75 | #### Pre-defined Ruby module 76 | 77 | The judge engine also has a pre-defined ruby module named `algohub`, which is need during runtime. 78 | 79 | Copy the Ruby `algohub` module into one of Ruby's default module search path(run `ruby -e 'puts $:'` to get all paths) 80 | 81 | cd judge-engine-languages-support/ 82 | sudo cp ruby/algohub.rb /usr/local/lib/site_ruby/2.3.0/ 83 | 84 | 85 | ## Acknowledgments 86 | 87 | Special thanks to [@rednaxelafx](https://github.com/rednaxelafx), who is a compiler expert and gave me a lot of vital technical suggestions, this project would not have been possible without his help. 88 | 89 | -------------------------------------------------------------------------------- /install.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | command -v javac >/dev/null 2>&1 || { echo "JDK is no installed, now installing..."; sudo apt -qy install openjdk-8-jdk; } 4 | command -v g++ >/dev/null 2>&1 || { echo "g++ is no installed, now installing..."; sudo apt -qy install build-essential; } 5 | command -v python3 >/dev/null 2>&1 || { echo "Python3 is no installed, now installing..."; sudo apt -qy install python3; } 6 | command -v ruby >/dev/null 2>&1 || { echo "Ruby is no installed, now installing..."; sudo apt -qy install ruby; } 7 | 8 | git config --global http.sslVerify false 9 | 10 | if [[ ! -d "/usr/local/include/rapidjson" ]]; then 11 | git clone https://github.com/miloyip/rapidjson.git 12 | sudo cp -r rapidjson/include/rapidjson/ /usr/local/include/ 13 | rm -rf ./rapidjson 14 | fi 15 | 16 | git clone https://github.com/algohub/judge-engine-languages-support.git /tmp/judge-engine-languages-support 17 | 18 | if [[ ! -d "/usr/local/include/algohub/" ]]; then 19 | sudo cp -r /tmp/judge-engine-languages-support/judge-engine-cpp-support/include/algohub/ /usr/local/include/ 20 | fi 21 | 22 | if [[ ! -d "/usr/local/lib/python3.5/dist-packages/algohub/" ]]; then 23 | sudo cp -r /tmp/judge-engine-languages-support/judge-engine-python-support/algohub/ /usr/local/lib/python3.5/dist-packages/ 24 | fi 25 | 26 | if [[ ! -f "/usr/local/lib/site_ruby/2.3.0/algohub.rb" ]]; then 27 | sudo mkdir -p /usr/local/lib/site_ruby/2.3.0 28 | sudo cp /tmp/judge-engine-languages-support/ruby/algohub.rb /usr/local/lib/site_ruby/2.3.0/ 29 | fi 30 | 31 | command -v mvn >/dev/null 2>&1 || { echo >&2 "Maven is no installed, now start to install..."; sudo apt -y --no-install-recommends install maven; } 32 | 33 | mvn clean package 34 | 35 | if [ "$?" -ne 0 ] 36 | then 37 | echo "mvn clean pacage failed!" >&2 38 | exit 1 39 | else 40 | mvn install -DskipTests 41 | fi 42 | 43 | -------------------------------------------------------------------------------- /lint/pmd_rules.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | Custmized PMD rules 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 4.0.0 7 | 8 | org.algohub.engine 9 | judge-engine 10 | 1.0.1-SNAPSHOT 11 | jar 12 | 13 | Judge Engine 14 | https://github.com/algohub 15 | 16 | 17 | UTF-8 18 | UTF-8 19 | 1.8 20 | 1.8 21 | 23.4-jre 22 | 2.9.2 23 | 3.7.0 24 | 4.12 25 | 3.1.0 26 | 3.0.2 27 | 3.0.1 28 | 2.17 29 | 8.4 30 | 2.5 31 | 3.8 32 | 3.0.5 33 | 34 | 35 | 36 | com.google.guava 37 | guava 38 | ${guava.version} 39 | 40 | 41 | com.fasterxml.jackson.core 42 | jackson-databind 43 | ${jackson.version} 44 | 45 | 46 | com.fasterxml.jackson.core 47 | jackson-core 48 | ${jackson.version} 49 | 50 | 51 | com.fasterxml.jackson.core 52 | jackson-annotations 53 | ${jackson.version} 54 | 55 | 56 | com.fasterxml.jackson.datatype 57 | jackson-datatype-jdk8 58 | ${jackson.version} 59 | 60 | 61 | junit 62 | junit 63 | test 64 | ${junit.version} 65 | 66 | 67 | 68 | 69 | 70 | maven-assembly-plugin 71 | ${maven.assembly.plugin.version} 72 | 73 | false 74 | 75 | jar-with-dependencies 76 | 77 | 78 | 79 | org.algohub.engine.engine.JudgeEngine 80 | 81 | 82 | 83 | 84 | 85 | make-assembly 86 | package 87 | 88 | single 89 | 90 | 91 | 92 | 93 | 94 | org.apache.maven.plugins 95 | maven-source-plugin 96 | ${maven.source.plugin.version} 97 | 98 | 99 | compile 100 | 101 | jar 102 | 103 | 104 | 105 | 106 | 107 | org.apache.maven.plugins 108 | maven-checkstyle-plugin 109 | ${maven.checkstyle.plugin.version} 110 | 111 | 112 | com.puppycrawl.tools 113 | checkstyle 114 | ${checkstyle.version} 115 | 116 | 117 | 118 | 119 | checkstyle 120 | validate 121 | 122 | ${project.basedir}/lint/google_checks.xml 123 | UTF-8 124 | true 125 | true 126 | true 127 | 128 | 129 | checkstyle 130 | 131 | 132 | 133 | 134 | 172 | 173 | 174 | 175 | 176 | 177 | org.apache.maven.plugins 178 | maven-checkstyle-plugin 179 | ${maven.checkstyle.plugin.version} 180 | 181 | google_checks.xml 182 | 183 | 184 | 185 | maven-pmd-plugin 186 | ${maven.pmd.plugin.version} 187 | 188 | 189 | 190 | pmd 191 | cpd 192 | 193 | 194 | 195 | 196 | 197 | org.apache.maven.plugins 198 | maven-jxr-plugin 199 | ${maven.jxr.plugin.version} 200 | 201 | 202 | 203 | 204 | -------------------------------------------------------------------------------- /src/main/java/org/algohub/engine/JudgeEngine.java: -------------------------------------------------------------------------------- 1 | package org.algohub.engine; 2 | 3 | import com.google.common.base.Charsets; 4 | import com.google.common.io.Files; 5 | 6 | import org.algohub.engine.judge.CppJudge; 7 | import org.algohub.engine.judge.RubyJudge; 8 | import org.algohub.engine.pojo.Problem; 9 | import org.algohub.engine.judge.CsharpJudge; 10 | import org.algohub.engine.judge.JavaJudge; 11 | import org.algohub.engine.judge.JavaScriptJudge; 12 | import org.algohub.engine.judge.PythonJudge; 13 | import org.algohub.engine.bo.StatusCode; 14 | import org.algohub.engine.pojo.Function; 15 | import org.algohub.engine.pojo.JudgeResult; 16 | import org.algohub.engine.type.LanguageType; 17 | import org.algohub.engine.util.ObjectMapperInstance; 18 | 19 | import java.io.File; 20 | import java.io.IOException; 21 | 22 | /** 23 | * The final judge compose of multiple languages' judges. 24 | */ 25 | public class JudgeEngine { 26 | /** 27 | * Java judge. 28 | */ 29 | private final transient JavaJudge javaJudge = new JavaJudge(); 30 | /** 31 | * JavaScript judge. 32 | */ 33 | private final transient JavaScriptJudge javaScriptJudge = new JavaScriptJudge(); 34 | /** 35 | * C++ judge. 36 | */ 37 | private final transient CppJudge cppJudge = new CppJudge(); 38 | /** 39 | * C# judge. 40 | */ 41 | private final transient CsharpJudge csharpJudge = new CsharpJudge(); 42 | /** 43 | * Python judge. 44 | */ 45 | private final transient PythonJudge pythonJudge = new PythonJudge(); 46 | /** 47 | * Ruby judge. 48 | */ 49 | private final transient RubyJudge rubyJudge = new RubyJudge(); 50 | 51 | /** 52 | * Entry point main function. 53 | */ 54 | public static void main(final String[] args) throws IOException, InterruptedException { 55 | if (args.length != 3) { 56 | System.err.println("Usage: JudgeEngine problem.json language(PYTHON,RUBY) solution"); 57 | return; 58 | } 59 | 60 | final String problemStr = Files.asCharSource(new File(args[0]), Charsets.UTF_8).read(); 61 | final Problem problem = ObjectMapperInstance.INSTANCE.readValue(problemStr, Problem.class); 62 | final LanguageType languageType = LanguageType.valueOf(args[1]); 63 | final String userCode = Files.asCharSource(new File(args[2]), Charsets.UTF_8).read(); 64 | 65 | final JudgeEngine judgeEngine = new JudgeEngine(); 66 | final JudgeResult result = judgeEngine.judge(problem, userCode, languageType); 67 | 68 | if (result.getStatusCode() == StatusCode.ACCEPTED) { 69 | System.out.println("Accepted!"); 70 | } else { 71 | System.err.println("Wrong Answer!\n" + result); 72 | } 73 | } 74 | 75 | /** 76 | * Judge the code written by a user. 77 | * 78 | * @param function The function prototype declaration 79 | * @param testCases test cases 80 | * @param userCode A function implemented by user 81 | * @param languageType The language that used by the user 82 | * @return If the output is identical with the test case, JudgeResult.succeed will be true, 83 | * otherwise, JudgeResult.succeed will be false and contain both output results. 84 | */ 85 | private JudgeResult judge(final Function function, final Problem.TestCase[] testCases, 86 | final String userCode, final LanguageType languageType) { 87 | switch (languageType) { 88 | case JAVA: 89 | return javaJudge.judge(function, testCases, userCode); 90 | case JAVASCRIPT: 91 | return javaScriptJudge.judge(function, testCases, userCode); 92 | case CPLUSPLUS: 93 | return cppJudge.judge(function, testCases, userCode); 94 | case CSHARP: 95 | return csharpJudge.judge(function, testCases, userCode); 96 | case PYTHON: 97 | return pythonJudge.judge(function, testCases, userCode); 98 | case RUBY: 99 | return rubyJudge.judge(function, testCases, userCode); 100 | default: 101 | throw new IllegalArgumentException("Unsupported language " + languageType.name()); 102 | } 103 | } 104 | 105 | /** 106 | * Judge the code written by a user. 107 | * 108 | * @param problem the problem description and test cases 109 | * @param userCode the function written by user. 110 | * @param languageType the programming language 111 | * @return If the output is identical with the test case, JudgeResult.succeed will be true, 112 | * otherwise, JudgeResult.succeed will be false and contain both output results. 113 | */ 114 | @SuppressWarnings({"PMD.AvoidInstantiatingObjectsInLoops"}) public JudgeResult judge( 115 | final Problem problem, final String userCode, final LanguageType languageType) { 116 | final Problem.TestCase[] testCases = problem.getTestCases(); 117 | return judge(problem.getFunction(), testCases, userCode, languageType); 118 | 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /src/main/java/org/algohub/engine/bo/InternalTestCase.java: -------------------------------------------------------------------------------- 1 | package org.algohub.engine.bo; 2 | 3 | import org.algohub.engine.pojo.Function; 4 | import org.algohub.engine.pojo.Problem; 5 | import org.algohub.engine.serde.Deserializer; 6 | 7 | 8 | /** 9 | * Internal test case, deserialized. 10 | */ 11 | @SuppressWarnings({"PMD.CommentRequired", "PMD.UnusedPrivateField", 12 | "PMD.BeanMembersShouldSerialize", "PMD.SingularField"}) 13 | public class InternalTestCase { 14 | private final Object[] input; 15 | private final Object output; 16 | 17 | /** Constructor. */ 18 | public InternalTestCase(final Object[] input, final Object output) { 19 | this.input = input; 20 | this.output = output; 21 | } 22 | 23 | /** 24 | * Constructor. 25 | */ 26 | public InternalTestCase(final Problem.TestCase testCase, final Function function) { 27 | final Function.Parameter[] parameters = function.getParameters(); 28 | assert (parameters.length == testCase.getInput().size()); 29 | 30 | input = new Object[testCase.getInput().size()]; 31 | for (int i = 0; i < input.length; ++i) { 32 | input[i] = Deserializer.fromJson(parameters[i].getType(), testCase.getInput().get(i)); 33 | } 34 | 35 | this.output = Deserializer.fromJson(function.getReturn_().getType(), testCase.getOutput()); 36 | } 37 | 38 | public Object[] getInput() { 39 | return input; 40 | } 41 | 42 | public Object getOutput() { 43 | return output; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/org/algohub/engine/bo/ProcessResult.java: -------------------------------------------------------------------------------- 1 | package org.algohub.engine.bo; 2 | 3 | /** 4 | * The result of a subprocess. 5 | */ 6 | @SuppressWarnings({"PMD.UnusedPrivateField", "PMD.CommentRequired"}) 7 | public class ProcessResult { 8 | private int exitCode; 9 | private String stdout; 10 | private String stderr; 11 | 12 | public ProcessResult(final int exitCode, final String stdout, final String stderr) { 13 | this.exitCode = exitCode; 14 | this.stdout = stdout; 15 | this.stderr = stderr; 16 | } 17 | 18 | public int getExitCode() { 19 | return exitCode; 20 | } 21 | 22 | public String getStdout() { 23 | return stdout; 24 | } 25 | 26 | public String getStderr() { 27 | return stderr; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/org/algohub/engine/bo/StatusCode.java: -------------------------------------------------------------------------------- 1 | package org.algohub.engine.bo; 2 | 3 | import com.fasterxml.jackson.annotation.JsonCreator; 4 | import com.fasterxml.jackson.annotation.JsonValue; 5 | 6 | /** 7 | * Status code. 8 | */ 9 | public enum StatusCode { 10 | PENDING(0), 11 | RUNNING(1), 12 | 13 | COMPILE_ERROR(2), 14 | RUNTIME_ERROR(3), 15 | 16 | ACCEPTED(4), 17 | WRONG_ANSWER(5), 18 | 19 | TIME_LIMIT_EXCEEDED(6), 20 | MEMORY_LIMIT_EXCEEDED(7), 21 | OUTPUT_LIMIT_EXCEEDED(8), 22 | 23 | RESTRICTED_CALL(9), 24 | TOO_LONG_CODE(10); 25 | 26 | 27 | private final int code; 28 | 29 | StatusCode(int code) { 30 | this.code = code; 31 | } 32 | 33 | @JsonCreator 34 | public static StatusCode fromInt(int code) { 35 | for (final StatusCode v : StatusCode.values()) { 36 | if (code == v.code) { 37 | return v; 38 | } 39 | } 40 | 41 | throw new IllegalArgumentException("Unrecognized status code: " + code); 42 | } 43 | 44 | @JsonValue 45 | public int toInt() { 46 | return this.code; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/org/algohub/engine/codegenerator/CppCodeGenerator.java: -------------------------------------------------------------------------------- 1 | package org.algohub.engine.codegenerator; 2 | 3 | import org.algohub.engine.pojo.Function; 4 | import org.algohub.engine.type.IntermediateType; 5 | import org.algohub.engine.type.LanguageType; 6 | import org.algohub.engine.type.TypeNode; 7 | 8 | /** 9 | * Generate C++ code. 10 | */ 11 | @SuppressWarnings({"PMD.InsufficientStringBufferDeclaration"}) 12 | public final class CppCodeGenerator { 13 | 14 | private CppCodeGenerator() {} 15 | 16 | /** 17 | * Generate a main.cpp to call solution.h. 18 | * 19 | * @param function the function type info 20 | * @param fromFile read testcases from file or stdin 21 | * @return source code of main.cpp 22 | */ 23 | public static String generateMain(final Function function, boolean fromFile) { 24 | final StringBuilder result = new StringBuilder(); 25 | result.append("#include \n#include \n#include " 26 | + "\nusing namespace std;\n#include \"solution.cpp\"\n\n\n"); 27 | 28 | Indentation.append(result, "int main(int argc, char* argv[]) {\n", 0); 29 | Indentation.append(result, "signal(SIGSEGV, sigsegv_handler);\n", 1); 30 | Indentation.append(result, "signal(SIGABRT, sigabrt_handler);\n\n", 1); 31 | if(fromFile) { 32 | Indentation.append(result, "ifstream ifs(\"testcases.json\");\n", 1); 33 | Indentation.append(result, "string testcases_text((istreambuf_iterator(ifs)), (istreambuf_iterator()));\n", 1); 34 | } else { 35 | Indentation.append(result, "string testcases_text;\n", 1); 36 | Indentation.append(result, "getline(cin, testcases_text);\n", 1); 37 | } 38 | Indentation.append(result, "rapidjson::Document testcases_json;\n", 1); 39 | Indentation.append(result, "rapidjson::Document::AllocatorType& allocator = testcases_json.GetAllocator();\n", 1); 40 | Indentation.append(result, "testcases_json.Parse(testcases_text.c_str());\n", 1); 41 | Indentation.append(result, "assert (testcases_json.IsArray());\n\n", 1); 42 | 43 | Indentation 44 | .append(result, "for (rapidjson::SizeType i = 0; i < testcases_json.Size(); i++) {\n", 1); 45 | Indentation.append(result, "const rapidjson::Value& input = testcases_json[i][\"input\"];\n", 2); 46 | Indentation.append(result, "assert (input.IsArray());\n\n", 2); 47 | 48 | // deserialize expected output 49 | Indentation.append(result, 50 | generateTypeDeclaration(function.getReturn_().getType()) + " expected_output;\n", 2); 51 | Indentation.append(result, "from_json(testcases_json[i][\"output\"], expected_output);\n\n", 2); 52 | 53 | // Deserialize arguments 54 | final Function.Parameter[] parameters = function.getParameters(); 55 | for (int i = 0; i < parameters.length; ++i) { 56 | Indentation.append(result, 57 | generateTypeDeclaration(parameters[i].getType()) + " algohub_" + parameters[i].getName() 58 | + ";\n", 2); 59 | Indentation 60 | .append(result, "from_json(input[" + i + "], algohub_" + parameters[i].getName() + ");\n", 61 | 2); 62 | } 63 | result.append('\n'); 64 | 65 | Indentation.append(result, "const auto result = " + function.getName() + "(", 2); 66 | 67 | for (final Function.Parameter parameter : parameters) { 68 | result.append("algohub_").append(parameter.getName()).append(", "); 69 | } 70 | 71 | // delete the last unnecessary " ," 72 | if (parameters.length > 0) { 73 | result.delete(result.length() - 2, result.length()); 74 | } 75 | result.append(");\n\n"); 76 | 77 | Indentation.append(result, "if (expected_output == result) {\n", 2); 78 | Indentation.append(result, "judge_result.testcase_passed_count += 1;\n", 3); 79 | Indentation.append(result, "} else {\n", 2); 80 | Indentation.append(result, "judge_result.input = rapidjson::Value(input, allocator).Move();\n", 3); 81 | Indentation.append(result, "judge_result.expected_output = testcases_json[i][\"output\"];\n", 3); 82 | Indentation.append(result, "judge_result.output = to_json(result, allocator);\n", 3); 83 | Indentation.append(result, "break;\n", 3); 84 | Indentation.append(result, "}\n", 2); 85 | Indentation.append(result, "}\n\n", 1); 86 | 87 | Indentation 88 | .append(result, "if (judge_result.testcase_passed_count < testcases_json.Size()) {\n", 1); 89 | Indentation.append(result, "judge_result.status_code = StatusCode::WRONG_ANSWER;\n", 2); 90 | Indentation.append(result, "} else {\n", 1); 91 | Indentation.append(result, "judge_result.status_code = StatusCode::ACCEPTED;\n", 2); 92 | Indentation.append(result, "}\n\n", 1); 93 | 94 | Indentation.append(result, "std::cout << std::endl << judge_result.to_string();\n", 1); 95 | Indentation.append(result, "return 0;\n}\n", 1); 96 | return result.toString(); 97 | } 98 | 99 | /** 100 | * Generate a type declaration. 101 | * 102 | *

post order, recursive.

103 | * 104 | * @param type the type 105 | * @return type declaration 106 | */ 107 | static String generateTypeDeclaration(final TypeNode type) { 108 | if (!type.isContainer()) { 109 | return TypeMap.TYPE_MAP.get(LanguageType.CPLUSPLUS).get(type.getValue()); 110 | } 111 | 112 | final String containerTypeStr = 113 | TypeMap.TYPE_MAP.get(LanguageType.CPLUSPLUS).get(type.getValue()); 114 | if (type.getKeyType().isPresent()) { 115 | return containerTypeStr + "<" + generateTypeDeclaration(type.getKeyType().get()) + ", " 116 | + generateTypeDeclaration(type.getElementType().get()) + ">"; 117 | } else { 118 | final String typeDeclaration = 119 | containerTypeStr + "<" + generateTypeDeclaration(type.getElementType().get()) + ">"; 120 | return addSharedPtr(type, typeDeclaration); 121 | } 122 | } 123 | 124 | /** 125 | * Generate an empty function with comments. 126 | * @param function Function prototype 127 | * @return source code of a empty function 128 | */ 129 | public static String generateEmptyFunction(final Function function) { 130 | return FunctionGenerator.generateFunction(function, LanguageType.CPLUSPLUS, 0); 131 | } 132 | 133 | private static String addSharedPtr(TypeNode type, String elemType) { 134 | if (type.getValue() == IntermediateType.BINARY_TREE_NODE 135 | || type.getValue() == IntermediateType.LINKED_LIST_NODE) { 136 | return "shared_ptr<" + elemType + ">"; 137 | } else { 138 | return elemType; 139 | } 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /src/main/java/org/algohub/engine/codegenerator/FunctionGenerator.java: -------------------------------------------------------------------------------- 1 | package org.algohub.engine.codegenerator; 2 | 3 | import org.algohub.engine.pojo.Function; 4 | import org.algohub.engine.type.IntermediateType; 5 | import org.algohub.engine.type.LanguageType; 6 | import org.algohub.engine.type.TypeNode; 7 | 8 | import static org.algohub.engine.codegenerator.Indentation.append; 9 | 10 | 11 | /** 12 | * Generate function declaration for display. 13 | */ 14 | @SuppressWarnings({"PMD.InsufficientStringBufferDeclaration", "PMD.ConsecutiveLiteralAppends", 15 | "PMD.InefficientStringBuffering", "PMD.UseUtilityClass", "PMD.ConsecutiveAppendsShouldReuse"}) 16 | public class FunctionGenerator { 17 | 18 | /** 19 | * Generate parameter declaration. 20 | * 21 | * @param type type 22 | * @param languageType programming language 23 | * @param parameterName parameter name 24 | * @return A block of code to declare a parameter 25 | */ 26 | public static String generateParameterDeclaration(final TypeNode type, 27 | final LanguageType languageType, final String parameterName) { 28 | final StringBuilder result = new StringBuilder(); 29 | final String typeDeclaration = generateTypeDeclaration(type, languageType); 30 | 31 | if (languageType == LanguageType.CPLUSPLUS) { 32 | if (type.isContainer() || type.getValue() == IntermediateType.STRING) { 33 | result.append(typeDeclaration).append("& ").append(parameterName); 34 | } else { 35 | result.append(typeDeclaration).append(' ').append(parameterName); 36 | } 37 | 38 | } else { 39 | result.append(typeDeclaration).append(' ').append(parameterName); 40 | } 41 | return result.toString(); 42 | } 43 | 44 | /** 45 | * Convert a TypeNode to a specific language type declaration. 46 | * 47 | *

post order, recursive.

48 | */ 49 | public static String generateTypeDeclaration(final TypeNode type, 50 | final LanguageType languageType) { 51 | switch (languageType) { 52 | case JAVA: 53 | return JavaCodeGenerator.generateTypeDeclaration(type); 54 | case CPLUSPLUS: 55 | return CppCodeGenerator.generateTypeDeclaration(type); 56 | default: 57 | throw new IllegalArgumentException("Unsupported language: " + languageType); 58 | } 59 | } 60 | 61 | /** 62 | * Generate function declaration for Java, C++, C#. 63 | */ 64 | public static String generateFunction(final Function function, final LanguageType languageType, 65 | final int indent) { 66 | final StringBuilder result = new StringBuilder(); 67 | 68 | // function comment 69 | append(result, "/**\n", indent); 70 | for (final Function.Parameter p : function.getParameters()) { 71 | append(result, " * @param " + p.getName() + " " + p.getComment() + "\n", indent); 72 | } 73 | append(result, " * @return " + function.getReturn_().getComment() + "\n", indent); 74 | append(result, " */\n", indent); 75 | 76 | // function body 77 | if (languageType == LanguageType.JAVA) { 78 | append(result, "public ", indent); 79 | result.append(generateTypeDeclaration(function.getReturn_().getType(), languageType)); 80 | } else { 81 | append(result, generateTypeDeclaration(function.getReturn_().getType(), languageType), 82 | indent); 83 | } 84 | result.append(" " + function.getName() + "("); 85 | for (final Function.Parameter p : function.getParameters()) { 86 | result.append(generateParameterDeclaration(p.getType(), languageType, p.getName())) 87 | .append(", "); 88 | } 89 | // delete the last unnecessary " ," 90 | result.delete(result.length() - 2, result.length()); 91 | result.append(") {\n"); 92 | append(result, "// Write your code here\n", indent + 1); 93 | append(result, "}\n", indent); 94 | 95 | return result.toString(); 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /src/main/java/org/algohub/engine/codegenerator/Indentation.java: -------------------------------------------------------------------------------- 1 | package org.algohub.engine.codegenerator; 2 | 3 | /** An interface to hold a function. */ 4 | interface Indentation { 5 | /** 6 | * Append with indentation. 7 | */ 8 | @SuppressWarnings("PMD.ShortVariable") 9 | static void append(final StringBuilder sb, final String content, 10 | final int indent) { 11 | for (int i = 0; i < indent; ++i) { 12 | sb.append(" "); 13 | } 14 | sb.append(content); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/org/algohub/engine/codegenerator/JavaCodeGenerator.java: -------------------------------------------------------------------------------- 1 | package org.algohub.engine.codegenerator; 2 | 3 | import com.google.common.collect.ImmutableMap; 4 | 5 | import org.algohub.engine.pojo.Function; 6 | import org.algohub.engine.type.IntermediateType; 7 | import org.algohub.engine.type.LanguageType; 8 | import org.algohub.engine.type.TypeNode; 9 | 10 | /** 11 | * Generate compilable and runnable Java code. 12 | */ 13 | @SuppressWarnings({"PMD.InsufficientStringBufferDeclaration"}) 14 | public final class JavaCodeGenerator { 15 | /** 16 | * Map intermediate types to real java classes. 17 | */ 18 | public static final ImmutableMap JAVA_CLASS_MAP = 19 | ImmutableMap.builder().put(IntermediateType.BOOL, "Boolean") 20 | .put(IntermediateType.CHAR, "Character") 21 | .put(IntermediateType.STRING, "String") 22 | .put(IntermediateType.DOUBLE, "Double") 23 | .put(IntermediateType.INT, "Integer") 24 | .put(IntermediateType.LONG, "Long").build(); 25 | 26 | private JavaCodeGenerator() {} 27 | 28 | /** 29 | * Convert a TypeNode to a Java type declaration. 30 | * 31 | *

post order, recursive.

32 | */ 33 | private static String generateTypeDeclaration(final TypeNode type, 34 | final IntermediateType parentType) { 35 | if (!type.isContainer()) { 36 | if (parentType == IntermediateType.ARRAY) { 37 | return TypeMap.JAVA_TYPE_MAP.get(type.getValue()); 38 | } else { 39 | return JAVA_CLASS_MAP.get(type.getValue()); 40 | } 41 | } 42 | if (type.getValue() == IntermediateType.ARRAY) { 43 | return generateTypeDeclaration(type.getElementType().get(), type.getValue()) + "[]"; 44 | } else { 45 | final String containerTypeStr = TypeMap.JAVA_TYPE_MAP.get(type.getValue()); 46 | if (type.getKeyType().isPresent()) { 47 | return containerTypeStr + "<" + generateTypeDeclaration(type.getKeyType().get(), 48 | type.getValue()) + ", " + generateTypeDeclaration(type.getElementType().get(), 49 | type.getValue()) + ">"; 50 | } else { 51 | return containerTypeStr + "<" + generateTypeDeclaration(type.getElementType().get(), 52 | type.getValue()) + ">"; 53 | } 54 | } 55 | } 56 | 57 | /** 58 | * Generate a type declaration. 59 | * 60 | *

post order, recursive.

61 | * 62 | * @param type the type 63 | * @return type declaration 64 | */ 65 | static String generateTypeDeclaration(final TypeNode type) { 66 | // the parent type should be ARRAY by default 67 | return generateTypeDeclaration(type, IntermediateType.ARRAY); 68 | } 69 | 70 | /** 71 | * Generate an empty function with comments. 72 | * @param function Function prototype 73 | * @return source code of a empty function 74 | */ 75 | public static String generateEmptyFunction(final Function function) { 76 | return "public class Solution {\n" 77 | + FunctionGenerator.generateFunction(function, LanguageType.JAVA, 1) + "}\n"; 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/main/java/org/algohub/engine/codegenerator/JavaScriptCodeGenerator.java: -------------------------------------------------------------------------------- 1 | package org.algohub.engine.codegenerator; 2 | 3 | import org.algohub.engine.pojo.Function; 4 | 5 | /** 6 | * Generate runnable JavaScript code and call user's function. 7 | */ 8 | @SuppressWarnings({"PMD.InsufficientStringBufferDeclaration"}) 9 | public final class JavaScriptCodeGenerator { 10 | 11 | private JavaScriptCodeGenerator() {} 12 | 13 | /** 14 | * Generate a runnable script for JavaScript. 15 | * 16 | * @param function the function type info 17 | * @return A Compilable and runnable JavaScript script. 18 | */ 19 | public static String generateMain(final Function function) { 20 | final StringBuilder result = new StringBuilder(); 21 | 22 | result.append("input = sys.stdin.read()\njsonValue = json.loads(input)[\"dummy_key\"]\n"); 23 | 24 | final Function.Parameter[] parameters = function.getParameters(); 25 | 26 | for (int i = 0; i < parameters.length; ++i) { 27 | result.append(parameters[i].getName() + " = jsonValue[" + i + "]\n"); 28 | } 29 | 30 | 31 | result.append("result = " + function.getName() + "("); 32 | 33 | 34 | for (final Function.Parameter parameter : parameters) { 35 | result.append(parameter.getName()).append(", "); 36 | } 37 | 38 | // delete the last unnecessary " ," 39 | result.delete(result.length() - 2, result.length()); 40 | result.append(")\nprint(json.dumps(result, separators=(',', ':')))\n"); 41 | 42 | return result.toString(); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/org/algohub/engine/codegenerator/PythonCodeGenerator.java: -------------------------------------------------------------------------------- 1 | package org.algohub.engine.codegenerator; 2 | 3 | import com.fasterxml.jackson.core.JsonProcessingException; 4 | 5 | import org.algohub.engine.pojo.Function; 6 | import org.algohub.engine.type.IntermediateType; 7 | import org.algohub.engine.type.LanguageType; 8 | import org.algohub.engine.type.TypeNode; 9 | import org.algohub.engine.util.ObjectMapperInstance; 10 | 11 | /** 12 | * Generate Python code. 13 | */ 14 | @SuppressWarnings({"PMD.InsufficientStringBufferDeclaration"}) 15 | public final class PythonCodeGenerator { 16 | 17 | private PythonCodeGenerator() {} 18 | 19 | /** 20 | * Generate the main function. 21 | * 22 | * @param function Function type info. 23 | * @param fromFile read testcases from file or stdin 24 | * @return the complete source code 25 | */ 26 | @SuppressWarnings({"PMD.PreserveStackTrace"}) 27 | public static String generateMain(final Function function, boolean fromFile) { 28 | final StringBuilder result = new StringBuilder(); 29 | 30 | result.append("import json\nimport collections\nfrom algohub import *\nimport solution\n\n" 31 | + "if __name__ == '__main__':\n"); 32 | 33 | final Function.Parameter[] parameters = function.getParameters(); 34 | try { 35 | for (final Function.Parameter parameter : parameters) { 36 | Indentation.append(result, 37 | parameter.getName() + "_type = TypeNode.from_json('" + ObjectMapperInstance.INSTANCE 38 | .writeValueAsString(parameter.getType()) + "')\n", 1); 39 | 40 | } 41 | Indentation.append(result, 42 | "output_type = TypeNode.from_json('" + ObjectMapperInstance.INSTANCE 43 | .writeValueAsString(function.getReturn_().getType()) + "')\n\n", 1); 44 | } catch (JsonProcessingException e) { // impossible 45 | throw new IllegalStateException(e.getMessage()); 46 | } 47 | 48 | if(fromFile) { 49 | Indentation.append(result, "with open(\"testcases.json\", \"r\") as f:\n", 1); 50 | Indentation.append(result, "raw_testcases = json.loads(f.read())\n", 2); 51 | } else { 52 | Indentation.append(result, "raw_testcases = json.loads(input())\n", 1); 53 | } 54 | Indentation.append(result, "assert isinstance(raw_testcases, list)\n\n", 1); 55 | 56 | Indentation.append(result, "judge_result = JudgeResult(StatusCode.ACCEPTED)\n\n", 1); 57 | 58 | Indentation.append(result, "for i in range(len(raw_testcases)):\n", 1); 59 | Indentation.append(result, "test_case = raw_testcases[i]\n", 2); 60 | for (int i = 0; i < parameters.length; ++i) { 61 | final Function.Parameter parameter = parameters[i]; 62 | Indentation.append(result, 63 | "algohub_" + parameter.getName() + " = from_json(" + "test_case['input'][" + i + "], " 64 | + parameter.getName() + "_type)\n", 2); 65 | } 66 | 67 | Indentation 68 | .append(result, "expected_output = from_json(" + "test_case['output'], output_type)\n\n", 69 | 2); 70 | 71 | Indentation.append(result, "actual_output = solution." + function.getName() + "(", 2); 72 | for (final Function.Parameter parameter : parameters) { 73 | result.append("algohub_").append(parameter.getName()).append(", "); 74 | } 75 | if (parameters.length > 0) { 76 | result.delete(result.length() - 2, result.length()); 77 | } 78 | result.append(")\n\n"); 79 | 80 | Indentation.append(result, "if actual_output == expected_output:\n", 2); 81 | Indentation.append(result, "judge_result.testcase_passed_count += 1\n", 3); 82 | Indentation.append(result, "else:\n", 2); 83 | Indentation.append(result, "judge_result.input = test_case['input']\n", 3); 84 | Indentation.append(result, "judge_result.expected_output = test_case['output']\n", 3); 85 | Indentation.append(result, "judge_result.output = to_json(actual_output, output_type);\n", 3); 86 | Indentation.append(result, "break\n\n", 3); 87 | 88 | Indentation.append(result, 89 | "if judge_result.testcase_passed_count < len(raw_testcases):\n", 1); 90 | Indentation.append(result, "judge_result.status_code = StatusCode.WRONG_ANSWER\n", 2); 91 | Indentation.append(result, "else:\n", 1); 92 | Indentation.append(result, "judge_result.status_code = StatusCode.ACCEPTED\n\n", 2); 93 | 94 | Indentation.append(result, "print(judge_result)\n", 1); 95 | return result.toString(); 96 | } 97 | 98 | /** 99 | * Generate a type declaration. 100 | * 101 | *

post order, recursive.

102 | * 103 | * @param type the type 104 | * @return type declaration 105 | */ 106 | static String generateTypeDeclaration(final TypeNode type) { 107 | if (!type.isContainer()) { 108 | return TypeMap.PYTHON_TYPE_MAP.get(type.getValue()); 109 | } 110 | 111 | if (type.getValue() == IntermediateType.ARRAY || type.getValue() == IntermediateType.LIST) { 112 | return generateTypeDeclaration(type.getElementType().get()) + "[]"; 113 | } else { 114 | final String containerTypeStr = TypeMap.PYTHON_TYPE_MAP.get(type.getValue()); 115 | if (type.getKeyType().isPresent()) { 116 | return containerTypeStr + "<" + generateTypeDeclaration(type.getKeyType().get()) 117 | + ", " + generateTypeDeclaration(type.getElementType().get()) 118 | + ">"; 119 | } else { 120 | return containerTypeStr + "<" + generateTypeDeclaration(type.getElementType().get()) + ">"; 121 | } 122 | } 123 | } 124 | 125 | /** 126 | * Generate an empty function with comments. 127 | * @param function Function prototype 128 | * @return source code of a empty function 129 | */ 130 | public static String generateEmptyFunction(final Function function) { 131 | return generateEmptyFunction(function, 0); 132 | } 133 | 134 | static String generateEmptyFunction(final Function function, final int indent) { 135 | final StringBuilder result = new StringBuilder(); 136 | 137 | // function comment 138 | for (final Function.Parameter p : function.getParameters()) { 139 | Indentation.append(result, 140 | "# @param {" + generateTypeDeclaration(p.getType()) 141 | + "} " + p.getName() + " " + p.getComment() + "\n", indent); 142 | } 143 | 144 | final Function.Return return_ = function.getReturn_(); 145 | Indentation.append(result, "# @return {" + 146 | generateTypeDeclaration(return_.getType()) + "} " + return_.getComment() + "\n", indent); 147 | 148 | // function body 149 | Indentation.append(result, "def " + function.getName() + "(", indent); 150 | 151 | for (final Function.Parameter p : function.getParameters()) { 152 | result.append(p.getName()).append(", "); 153 | } 154 | // delete the last unnecessary " ," 155 | result.delete(result.length() - 2, result.length()); 156 | result.append("):\n"); 157 | Indentation.append(result, "# Write your code here\n", indent + 1); 158 | 159 | return result.toString(); 160 | } 161 | } 162 | -------------------------------------------------------------------------------- /src/main/java/org/algohub/engine/codegenerator/RubyCodeGenerator.java: -------------------------------------------------------------------------------- 1 | package org.algohub.engine.codegenerator; 2 | 3 | import com.fasterxml.jackson.core.JsonProcessingException; 4 | 5 | import org.algohub.engine.pojo.Function; 6 | import org.algohub.engine.type.IntermediateType; 7 | import org.algohub.engine.type.LanguageType; 8 | import org.algohub.engine.type.TypeNode; 9 | import org.algohub.engine.util.ObjectMapperInstance; 10 | 11 | /** 12 | * Generate runnable Ruby code and call user's function. 13 | */ 14 | @SuppressWarnings({"PMD.InsufficientStringBufferDeclaration"}) 15 | public final class RubyCodeGenerator { 16 | 17 | private RubyCodeGenerator() {} 18 | 19 | /** 20 | * Generate the main function. 21 | * 22 | * @param function Funciton prototype. 23 | * @param fromFile read testcases from file or stdin 24 | * @return the complete source code. 25 | */ 26 | @SuppressWarnings({"PMD.PreserveStackTrace"}) 27 | public static String generateMain(final Function function, boolean fromFile) { 28 | final StringBuilder result = new StringBuilder(); 29 | 30 | result.append("require 'json'\nrequire 'algohub'\nrequire_relative './solution'\n\n\n" 31 | + "if __FILE__ == $0\n"); 32 | 33 | final Function.Parameter[] parameters = function.getParameters(); 34 | try { 35 | for (final Function.Parameter parameter : parameters) { 36 | Indentation.append(result, parameter.getName() + "_type = Algohub::TypeNode.from_json('" 37 | + ObjectMapperInstance.INSTANCE.writeValueAsString(parameter.getType()) + "')\n", 1); 38 | 39 | } 40 | Indentation.append(result, 41 | "output_type = Algohub::TypeNode.from_json('" + ObjectMapperInstance.INSTANCE 42 | .writeValueAsString(function.getReturn_().getType()) + "')\n\n", 1); 43 | } catch (JsonProcessingException e) { // impossible 44 | throw new IllegalStateException(e.getMessage()); 45 | } 46 | 47 | if(fromFile) { 48 | Indentation.append(result, "raw_testcases = JSON.load(IO.read(\"testcases.json\"))\n\n", 1); 49 | } else { 50 | Indentation.append(result, "raw_testcases = JSON.load(STDIN.gets())\n\n", 1); 51 | } 52 | 53 | Indentation.append(result, "judge_result = Algohub::JudgeResult.new(Algohub::StatusCode::ACCEPTED)\n\n", 1); 54 | 55 | Indentation.append(result, "raw_testcases.size.times do |i|\n", 1); 56 | Indentation.append(result, "test_case = raw_testcases[i]\n", 2); 57 | for (int i = 0; i < parameters.length; ++i) { 58 | final Function.Parameter parameter = parameters[i]; 59 | Indentation.append(result, 60 | "algohub_" + parameter.getName() + " = Algohub.from_json(" + "test_case['input'][" + i 61 | + "], " + parameter.getName() + "_type)\n", 2); 62 | } 63 | 64 | Indentation.append(result, 65 | "expected_output = Algohub.from_json(" + "test_case['output'], output_type)\n\n", 2); 66 | 67 | Indentation.append(result, "actual_output = " + function.getName() + "(", 2); 68 | for (final Function.Parameter parameter : parameters) { 69 | result.append("algohub_").append(parameter.getName()).append(", "); 70 | } 71 | if (parameters.length > 0) { 72 | result.delete(result.length() - 2, result.length()); 73 | } 74 | result.append(")\n\n"); 75 | 76 | Indentation.append(result, "if actual_output == expected_output\n", 2); 77 | Indentation.append(result, "judge_result.testcase_passed_count += 1\n", 3); 78 | Indentation.append(result, "else\n", 2); 79 | Indentation.append(result, "judge_result.input = test_case['input']\n", 3); 80 | Indentation.append(result, "judge_result.expected_output = test_case['output']\n", 3); 81 | Indentation.append(result, "judge_result.output = Algohub.to_json(actual_output, output_type)\n", 3); 82 | Indentation.append(result, "break\n", 3); 83 | Indentation.append(result, "end\n", 2); 84 | Indentation.append(result, "end\n\n", 1); 85 | 86 | Indentation.append(result, 87 | "if(judge_result.testcase_passed_count < raw_testcases.size)\n", 1); 88 | Indentation.append(result, "judge_result.status_code = Algohub::StatusCode::WRONG_ANSWER\n", 2); 89 | Indentation.append(result, "else\n", 1); 90 | Indentation.append(result, "judge_result.status_code = Algohub::StatusCode::ACCEPTED\n", 2); 91 | Indentation.append(result, "end\n\n", 1); 92 | 93 | Indentation.append(result, "print(judge_result)\n", 1); 94 | result.append("end\n"); 95 | return result.toString(); 96 | } 97 | 98 | /** 99 | * Generate a type declaration. 100 | * 101 | *

post order, recursive.

102 | * 103 | * @param type the type 104 | * @return type declaration 105 | */ 106 | static String generateTypeDeclaration(final TypeNode type) { 107 | if (!type.isContainer()) { 108 | return TypeMap.RUBY_TYPE_MAP.get(type.getValue()); 109 | } 110 | 111 | if (type.getValue() == IntermediateType.ARRAY || type.getValue() == IntermediateType.LIST) { 112 | return generateTypeDeclaration(type.getElementType().get()) + "[]"; 113 | } else { 114 | final String containerTypeStr = TypeMap.RUBY_TYPE_MAP.get(type.getValue()); 115 | if (type.getKeyType().isPresent()) { 116 | return containerTypeStr + "<" + generateTypeDeclaration(type.getKeyType().get()) 117 | + ", " + generateTypeDeclaration(type.getElementType().get()) 118 | + ">"; 119 | } else { 120 | return containerTypeStr + "<" + generateTypeDeclaration(type.getElementType().get()) + ">"; 121 | } 122 | } 123 | } 124 | 125 | /** 126 | * Generate an empty function with comments. 127 | * @param function Function prototype 128 | * @return source code of a empty function 129 | */ 130 | public static String generateEmptyFunction(final Function function) { 131 | final StringBuilder result = new StringBuilder(); 132 | 133 | // function comment 134 | for (final Function.Parameter p : function.getParameters()) { 135 | result.append("# @param {" + generateTypeDeclaration(p.getType())+ "} " + 136 | p.getName() + " " + p.getComment() + "\n"); 137 | } 138 | 139 | final Function.Return return_ = function.getReturn_(); 140 | result.append("# @return {" + generateTypeDeclaration(return_.getType()) + "} " + 141 | return_.getComment() + "\ndef " + function.getName() + "("); 142 | for (final Function.Parameter p : function.getParameters()) { 143 | result.append(p.getName()).append(", "); 144 | } 145 | // delete the last unnecessary " ," 146 | result.delete(result.length() - 2, result.length()); 147 | result.append(")\n # Write your code here\nend"); 148 | 149 | return result.toString(); 150 | } 151 | } 152 | -------------------------------------------------------------------------------- /src/main/java/org/algohub/engine/codegenerator/TypeMap.java: -------------------------------------------------------------------------------- 1 | package org.algohub.engine.codegenerator; 2 | 3 | import com.google.common.collect.ImmutableMap; 4 | 5 | import org.algohub.engine.type.IntermediateType; 6 | import org.algohub.engine.type.LanguageType; 7 | 8 | /** 9 | * Map intermediate types to language related types. 10 | */ 11 | @SuppressWarnings({"PMD.AvoidDuplicateLiterals"}) 12 | final class TypeMap { 13 | /** 14 | * Map intermediate types to Java types. 15 | */ 16 | public static final ImmutableMap JAVA_TYPE_MAP = 17 | ImmutableMap.builder().put(IntermediateType.BOOL, "boolean") 18 | .put(IntermediateType.CHAR, "char") 19 | .put(IntermediateType.STRING, "String") 20 | .put(IntermediateType.DOUBLE, "double") 21 | .put(IntermediateType.INT, "int") 22 | .put(IntermediateType.LONG, "long") 23 | 24 | //.put(IntermediateType.ARRAY, "[]") 25 | .put(IntermediateType.LIST, "ArrayList") 26 | .put(IntermediateType.SET, "HashSet") 27 | .put(IntermediateType.MAP, "HashMap") 28 | 29 | .put(IntermediateType.LINKED_LIST_NODE, "LinkedListNode") 30 | .put(IntermediateType.BINARY_TREE_NODE, "BinaryTreeNode") 31 | 32 | .build(); 33 | 34 | /** 35 | * Map intermediate types to C++ types. 36 | */ 37 | public static final ImmutableMap CPP_TYPE_MAP = 38 | ImmutableMap.builder().put(IntermediateType.BOOL, "bool") 39 | .put(IntermediateType.CHAR, "char") 40 | .put(IntermediateType.STRING, "string") 41 | .put(IntermediateType.DOUBLE, "double") 42 | .put(IntermediateType.INT, "int") 43 | .put(IntermediateType.LONG, "long long") 44 | 45 | .put(IntermediateType.ARRAY, "vector") 46 | .put(IntermediateType.LIST, "vector") 47 | .put(IntermediateType.SET, "unordered_set") 48 | .put(IntermediateType.MAP, "unordered_map") 49 | 50 | .put(IntermediateType.LINKED_LIST_NODE, "LinkedListNode") 51 | .put(IntermediateType.BINARY_TREE_NODE, "BinaryTreeNode") 52 | 53 | .build(); 54 | 55 | /** 56 | * Map intermediate types to Python types. 57 | */ 58 | public static final ImmutableMap PYTHON_TYPE_MAP = 59 | ImmutableMap.builder().put(IntermediateType.BOOL, "boolean") 60 | .put(IntermediateType.CHAR, "str") 61 | .put(IntermediateType.STRING, "str") 62 | .put(IntermediateType.DOUBLE, "float") 63 | .put(IntermediateType.INT, "int") 64 | .put(IntermediateType.LONG, "int") 65 | 66 | //.put(IntermediateType.ARRAY, "[]") 67 | //.put(IntermediateType.LIST, "[]") 68 | .put(IntermediateType.SET, "set") 69 | .put(IntermediateType.MAP, "dict") 70 | 71 | .put(IntermediateType.LINKED_LIST_NODE, "LinkedListNode") 72 | .put(IntermediateType.BINARY_TREE_NODE, "BinaryTreeNode") 73 | 74 | .build(); 75 | 76 | /** 77 | * Map intermediate types to Ruby types. 78 | */ 79 | public static final ImmutableMap RUBY_TYPE_MAP = 80 | ImmutableMap.builder().put(IntermediateType.BOOL, "Boolean") 81 | .put(IntermediateType.CHAR, "String") 82 | .put(IntermediateType.STRING, "String") 83 | .put(IntermediateType.DOUBLE, "Float") 84 | .put(IntermediateType.INT, "Fixnum") 85 | .put(IntermediateType.LONG, "Fixnum") 86 | 87 | //.put(IntermediateType.ARRAY, "[]") 88 | //.put(IntermediateType.LIST, "[]") 89 | .put(IntermediateType.SET, "Set") 90 | .put(IntermediateType.MAP, "Hash") 91 | 92 | .put(IntermediateType.LINKED_LIST_NODE, "LinkedListNode") 93 | .put(IntermediateType.BINARY_TREE_NODE, "BinaryTreeNode") 94 | 95 | .build(); 96 | 97 | 98 | /** 99 | * LanguageType -> Type -> Specific Type. 100 | */ 101 | public static final ImmutableMap> TYPE_MAP = 102 | ImmutableMap.>builder() 103 | .put(LanguageType.JAVA, JAVA_TYPE_MAP) 104 | .put(LanguageType.CPLUSPLUS, CPP_TYPE_MAP) 105 | .put(LanguageType.PYTHON, PYTHON_TYPE_MAP) 106 | .put(LanguageType.RUBY, RUBY_TYPE_MAP).build(); 107 | 108 | private TypeMap() {} 109 | } 110 | -------------------------------------------------------------------------------- /src/main/java/org/algohub/engine/collection/BinaryTreeNode.java: -------------------------------------------------------------------------------- 1 | package org.algohub.engine.collection; 2 | 3 | import java.util.LinkedList; 4 | import java.util.Queue; 5 | 6 | /** Binary Tree Node. */ 7 | @SuppressWarnings({"PMD.BeanMembersShouldSerialize", "PMD.CommentRequired", "PMD.ShortVariable"}) 8 | public class BinaryTreeNode { 9 | public E value; 10 | public BinaryTreeNode left; 11 | public BinaryTreeNode right; 12 | 13 | /** 14 | * has a left child, but it's a null node. 15 | */ 16 | public transient boolean leftIsNull; 17 | /** 18 | * has a right child, but it's a null node. 19 | */ 20 | public transient boolean rightIsNull; 21 | //public transient BinaryTreeNode next; 22 | 23 | /** 24 | * Constructs an empty binary tree. 25 | */ 26 | public BinaryTreeNode() { 27 | value = null; 28 | left = null; 29 | right = null; 30 | } 31 | 32 | /** 33 | * Constructs an binary tree with one element. 34 | */ 35 | public BinaryTreeNode(final E value) { 36 | this.value = value; 37 | left = null; 38 | right = null; 39 | } 40 | 41 | private static boolean isSameTree(final BinaryTreeNode p, final BinaryTreeNode q) { 42 | if (p == null && q == null) { 43 | return true; 44 | } 45 | if (p == null || q == null) { 46 | return false; 47 | } 48 | 49 | return p.value.equals(q.value) && isSameTree(p.left, q.left) && isSameTree(p.right, q.right); 50 | } 51 | 52 | // get the insertion position 53 | @SuppressWarnings("PMD.AvoidInstantiatingObjectsInLoops") 54 | private NodeAndFather tail() { 55 | final Queue queue = new LinkedList<>(); 56 | if (value != null) { 57 | queue.add(new NodeAndFather(this, null, true)); 58 | } 59 | 60 | while (!queue.isEmpty()) { 61 | final NodeAndFather nodeAndFather = queue.poll(); 62 | 63 | if (nodeAndFather.node != null) { 64 | if (nodeAndFather.node.left != null || nodeAndFather.node.leftIsNull) { 65 | queue.add(new NodeAndFather(nodeAndFather.node.left, nodeAndFather.node, false)); 66 | } else { 67 | return new NodeAndFather(nodeAndFather.node.left, nodeAndFather.node, false); 68 | } 69 | if (nodeAndFather.node.right != null || nodeAndFather.node.rightIsNull) { 70 | queue.add(new NodeAndFather(nodeAndFather.node.right, nodeAndFather.node, true)); 71 | } else { 72 | return new NodeAndFather(nodeAndFather.node.right, nodeAndFather.node, true); 73 | } 74 | } 75 | } 76 | return null; 77 | } 78 | 79 | /** 80 | * return next insert point. 81 | */ 82 | public void add(final E value) { 83 | final NodeAndFather last = tail(); 84 | if (last == null) { 85 | this.value = value; 86 | return; 87 | } 88 | 89 | if (last.isRight) { 90 | if (value == null) { 91 | last.father.rightIsNull = true; 92 | } else { 93 | last.father.right = new BinaryTreeNode<>(value); 94 | } 95 | } else { 96 | if (value == null) { 97 | last.father.leftIsNull = true; 98 | } else { 99 | last.father.left = new BinaryTreeNode<>(value); 100 | } 101 | } 102 | } 103 | 104 | @Override public boolean equals(final Object obj) { 105 | if (obj == this) { 106 | return true; 107 | } 108 | if (!(obj instanceof BinaryTreeNode)) { 109 | return false; 110 | } 111 | 112 | final BinaryTreeNode p = this; 113 | final BinaryTreeNode q = (BinaryTreeNode) obj; 114 | return isSameTree(p, q); 115 | } 116 | 117 | @Override public String toString() { 118 | if (value == null) { 119 | return "[]"; 120 | } 121 | 122 | final StringBuilder sb = new StringBuilder(); 123 | sb.append('['); 124 | final Queue> queue = new LinkedList<>(); 125 | queue.add(this); 126 | while (!queue.isEmpty()) { 127 | final BinaryTreeNode node = queue.poll(); 128 | sb.append(',').append(node.value == null ? "null" : node.value.toString()); 129 | } 130 | 131 | return sb.toString(); 132 | } 133 | 134 | @Override public int hashCode() { 135 | int hashCode = 1; 136 | final Queue> queue = new LinkedList<>(); 137 | queue.add(this); 138 | 139 | while (!queue.isEmpty()) { 140 | final BinaryTreeNode node = queue.poll(); 141 | hashCode = 31 * hashCode + (node.value == null ? 0 : node.value.hashCode()); 142 | 143 | if (node.left != null) { 144 | queue.offer(node.left); 145 | } 146 | if (node.right != null) { 147 | queue.offer(node.right); 148 | } 149 | } 150 | 151 | return hashCode; 152 | } 153 | 154 | 155 | private static class NodeAndFather { 156 | final private BinaryTreeNode node; 157 | final private BinaryTreeNode father; 158 | final private boolean isRight; // node is the right child 159 | 160 | public NodeAndFather(final BinaryTreeNode node, final BinaryTreeNode father, final boolean isRight) { 161 | this.node = node; 162 | this.father = father; 163 | this.isRight = isRight; 164 | } 165 | } 166 | } 167 | -------------------------------------------------------------------------------- /src/main/java/org/algohub/engine/collection/LinkedListNode.java: -------------------------------------------------------------------------------- 1 | package org.algohub.engine.collection; 2 | 3 | /** Singly linked list node. */ 4 | @SuppressWarnings({"PMD.BeanMembersShouldSerialize", "PMD.CommentRequired", "PMD.ShortVariable"}) 5 | public class LinkedListNode { 6 | public E value; 7 | public LinkedListNode next; 8 | 9 | public LinkedListNode(final E value) { 10 | this.value = value; 11 | this.next = null; 12 | } 13 | 14 | public LinkedListNode(final E value, final LinkedListNode next) { 15 | this.value = value; 16 | this.next = next; 17 | } 18 | 19 | @Override public boolean equals(final Object obj) { 20 | if (obj == this) { 21 | return true; 22 | } 23 | if (!(obj instanceof LinkedListNode)) { 24 | return false; 25 | } 26 | 27 | final LinkedListNode other = (LinkedListNode) obj; 28 | 29 | LinkedListNode p = this; 30 | LinkedListNode q = other; 31 | while (p != null && q != null) { 32 | if(p.value == null && q.value == null) return true; 33 | if(p.value == null || q.value == null) return false; 34 | if (!p.value.equals(q.value)) { 35 | return false; 36 | } 37 | p = p.next; 38 | q = q.next; 39 | } 40 | return p == null && q == null; 41 | } 42 | 43 | // just for debug 44 | @Override public String toString() { 45 | final StringBuilder sb = new StringBuilder(); 46 | sb.append('[').append(value == null ? "null" : value); 47 | 48 | for (LinkedListNode p = next; p != null; p = p.next) { 49 | sb.append(", ").append(p.value == null ? "null" : p.value); 50 | } 51 | sb.append(']'); 52 | return sb.toString(); 53 | } 54 | 55 | @Override public int hashCode() { 56 | int hashCode = 1; 57 | for (LinkedListNode p = this; p != null; p = p.next) { 58 | hashCode = 31 * hashCode + (p.value == null ? 0 : p.value.hashCode()); 59 | } 60 | 61 | return hashCode; 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/main/java/org/algohub/engine/compiler/java/CompileErrorException.java: -------------------------------------------------------------------------------- 1 | package org.algohub.engine.compiler.java; 2 | 3 | /** Error compiling. */ 4 | public class CompileErrorException extends Exception { 5 | /** Constructor. */ 6 | public CompileErrorException(final String message) { 7 | super(message); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/org/algohub/engine/compiler/java/MemoryClassLoader.java: -------------------------------------------------------------------------------- 1 | package org.algohub.engine.compiler.java; 2 | 3 | 4 | import java.io.File; 5 | import java.net.MalformedURLException; 6 | import java.net.URL; 7 | import java.net.URLClassLoader; 8 | import java.util.ArrayList; 9 | import java.util.List; 10 | import java.util.Map; 11 | import java.util.StringTokenizer; 12 | 13 | /** 14 | * ClassLoader that loads .class bytes from memory. 15 | */ 16 | @SuppressWarnings({"PMD.ShortVariable"}) 17 | final class MemoryClassLoader extends URLClassLoader { 18 | /** ClassName -> bytecode. */ 19 | private transient Map classBytes; 20 | 21 | /** Constructor. */ 22 | public MemoryClassLoader(final Map classBytes, final String classPath, 23 | final ClassLoader parent) { 24 | super(toUrls(classPath), parent); 25 | this.classBytes = classBytes; 26 | } 27 | 28 | /** Constructor. */ 29 | public MemoryClassLoader(final Map classBytes, final String classPath) { 30 | this(classBytes, classPath, ClassLoader.getSystemClassLoader()); 31 | } 32 | 33 | /** Constructor. */ 34 | public MemoryClassLoader(final Map classBytes) { 35 | this(classBytes, null, ClassLoader.getSystemClassLoader()); 36 | } 37 | 38 | @SuppressWarnings({"PMD.AvoidInstantiatingObjectsInLoops", "PMD.EmptyCatchBlock"}) 39 | private static URL[] toUrls(final String classPath) { 40 | if (classPath == null) { 41 | return new URL[0]; 42 | } 43 | 44 | final List list = new ArrayList(); 45 | final StringTokenizer st = new StringTokenizer(classPath, File.pathSeparator); 46 | while (st.hasMoreTokens()) { 47 | final String token = st.nextToken(); 48 | final File file = new File(token); 49 | try { 50 | if (file.exists()) { 51 | list.add(file.toURI().toURL()); 52 | } else { 53 | list.add(new URL(token)); 54 | } 55 | } catch (MalformedURLException mue) { 56 | } 57 | } 58 | final URL[] res = new URL[list.size()]; 59 | list.toArray(res); 60 | return res; 61 | } 62 | 63 | /** Load one class. */ 64 | public Class load(final String className) throws ClassNotFoundException { 65 | return loadClass(className); 66 | } 67 | 68 | /** Load all classes' bytecode. */ 69 | public Iterable loadAll() throws ClassNotFoundException { 70 | final List classes = new ArrayList(classBytes.size()); 71 | for (final String name : classBytes.keySet()) { 72 | classes.add(loadClass(name)); 73 | } 74 | return classes; 75 | } 76 | 77 | /** @{inheritDoc}. */ 78 | protected Class findClass(final String className) throws ClassNotFoundException { 79 | final byte[] buf = classBytes.get(className); 80 | if (buf == null) { 81 | return super.findClass(className); 82 | } else { 83 | // clear the bytes in map -- we don't need it anymore 84 | classBytes.put(className, null); 85 | return defineClass(className, buf, 0, buf.length); 86 | } 87 | } 88 | } 89 | 90 | 91 | -------------------------------------------------------------------------------- /src/main/java/org/algohub/engine/compiler/java/MemoryJavaCompiler.java: -------------------------------------------------------------------------------- 1 | package org.algohub.engine.compiler.java; 2 | 3 | 4 | import java.io.IOException; 5 | import java.io.PrintWriter; 6 | import java.io.Writer; 7 | import java.lang.invoke.MethodHandle; 8 | import java.lang.invoke.MethodHandles; 9 | import java.lang.invoke.MethodType; 10 | import java.lang.reflect.Method; 11 | import java.util.ArrayList; 12 | import java.util.List; 13 | import java.util.Map; 14 | 15 | import javax.tools.Diagnostic; 16 | import javax.tools.DiagnosticCollector; 17 | import javax.tools.JavaFileObject; 18 | import javax.tools.StandardJavaFileManager; 19 | import javax.tools.ToolProvider; 20 | 21 | /** 22 | * Simple interface to Java compiler using JSR 199 Compiler API. 23 | */ 24 | public final class MemoryJavaCompiler { 25 | public static final MemoryJavaCompiler INSTANCE = new MemoryJavaCompiler(); 26 | private final javax.tools.JavaCompiler tool; 27 | private final StandardJavaFileManager stdManager; 28 | private final MethodHandles.Lookup lookup = MethodHandles.lookup(); 29 | 30 | private MemoryJavaCompiler() { 31 | tool = ToolProvider.getSystemJavaCompiler(); 32 | if (tool == null) { 33 | throw new IllegalStateException( 34 | "Could not get Java compiler. Please, ensure " + "that JDK is used instead of JRE."); 35 | } 36 | stdManager = tool.getStandardFileManager(null, null, null); 37 | } 38 | 39 | private static String getClassName(final String qualifiedClassName) { 40 | final int lastDot = qualifiedClassName.lastIndexOf('.'); 41 | if (lastDot == -1) { 42 | return qualifiedClassName; 43 | } else { 44 | return qualifiedClassName.substring(lastDot + 1); 45 | } 46 | } 47 | 48 | /** 49 | * Compile a single static method. 50 | */ 51 | public Method compileStaticMethod(final String methodName, final String className, 52 | final String source) throws ClassNotFoundException, CompileErrorException { 53 | final Map classBytes = compile(className + ".java", source); 54 | final MemoryClassLoader classLoader = new MemoryClassLoader(classBytes); 55 | final Class clazz = classLoader.loadClass(className); 56 | final Method[] methods = clazz.getDeclaredMethods(); 57 | for (final Method method : methods) { 58 | if (method.getName().equals(methodName)) { 59 | if (!method.isAccessible()) { 60 | method.setAccessible(true); 61 | } 62 | return method; 63 | } 64 | } 65 | throw new NoSuchMethodError(methodName); 66 | } 67 | 68 | /** 69 | * Compile a single static method.

Use MethodHandle instead of reflection to gain better 70 | * performance.

71 | */ 72 | public MethodHandle compileStaticMethod(final String className, final String methodName, 73 | final MethodType type, final String source) 74 | throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, 75 | CompileErrorException { 76 | final Map classBytes = compile(className + ".java", source); 77 | final MemoryClassLoader classLoader = new MemoryClassLoader(classBytes); 78 | //final Class clazz = classLoader.loadClass(className); 79 | final Class clazz = Class.forName(className, true, classLoader); 80 | return lookup.findStatic(clazz, methodName, type); 81 | } 82 | 83 | /** 84 | * Compile a single normal method. 85 | * 86 | * @return [Object, Method], a class instance and the method 87 | */ 88 | public Object[] compileMethod(final String qualifiedClassName, final String methodName, 89 | final String source) throws ClassNotFoundException, CompileErrorException { 90 | final String className = getClassName(qualifiedClassName); 91 | final Map classBytes = compile(className + ".java", source); 92 | final MemoryClassLoader classLoader = new MemoryClassLoader(classBytes); 93 | final Class clazz = Class.forName(qualifiedClassName, true, classLoader); 94 | final Method[] methods = clazz.getDeclaredMethods(); 95 | 96 | for (final Method method : methods) { 97 | if (method.getName().equals(methodName)) { 98 | try { 99 | return new Object[] {clazz.newInstance(), method}; 100 | } catch (InstantiationException | IllegalAccessException e) { 101 | throw new IllegalStateException(e.getMessage()); 102 | } 103 | } 104 | } 105 | throw new NoSuchMethodError(methodName); 106 | } 107 | 108 | /** 109 | * Compile a class. 110 | */ 111 | public Class compileClass(final String qualifiedClassName, final String source) 112 | throws ClassNotFoundException, CompileErrorException { 113 | final String className = getClassName(qualifiedClassName); 114 | final Map classBytes = compile(className + ".java", source); 115 | final MemoryClassLoader classLoader = new MemoryClassLoader(classBytes); 116 | return classLoader.loadClass(qualifiedClassName); 117 | } 118 | 119 | public Map compile(String fileName, String source) throws CompileErrorException { 120 | return compile(fileName, source, new PrintWriter(System.err), null, null); 121 | } 122 | 123 | /** 124 | * compile given String source and return bytecodes as a Map. 125 | * 126 | * @param fileName source fileName to be used for error messages etc. 127 | * @param source Java source as String 128 | * @param err error writer where diagnostic messages are written 129 | * @param sourcePath location of additional .java source files 130 | * @param classPath location of additional .class files 131 | */ 132 | private Map compile(String fileName, String source, Writer err, String sourcePath, 133 | String classPath) throws CompileErrorException { 134 | // create a new memory JavaFileManager 135 | MemoryJavaFileManager fileManager = new MemoryJavaFileManager(stdManager); 136 | 137 | // prepare the compilation unit 138 | List compUnits = new ArrayList(1); 139 | compUnits.add(fileManager.makeStringSource(fileName, source)); 140 | 141 | return compile(compUnits, fileManager, err, sourcePath, classPath); 142 | } 143 | 144 | private Map compile(final List compUnits, 145 | final MemoryJavaFileManager fileManager, Writer err, String sourcePath, String classPath) 146 | throws CompileErrorException { 147 | // javac options 148 | List options = new ArrayList(); 149 | options.add("-Xlint:all"); 150 | // options.add("-g:none"); 151 | options.add("-deprecation"); 152 | if (sourcePath != null) { 153 | options.add("-sourcepath"); 154 | options.add(sourcePath); 155 | } 156 | 157 | if (classPath != null) { 158 | options.add("-classpath"); 159 | options.add(classPath); 160 | } 161 | 162 | // to collect errors, warnings etc. 163 | DiagnosticCollector diagnostics = new DiagnosticCollector(); 164 | // create a compilation task 165 | javax.tools.JavaCompiler.CompilationTask task = 166 | tool.getTask(err, fileManager, diagnostics, options, null, compUnits); 167 | 168 | if (task.call() == false) { 169 | final StringBuilder errorMsg = new StringBuilder(); 170 | final List> diagnostics1 = diagnostics.getDiagnostics(); 171 | for (int i = 1; i < diagnostics1.size(); ++i) { // skipe first one 172 | errorMsg.append(diagnostics1.get(i)); 173 | errorMsg.append('\n'); 174 | } 175 | throw new CompileErrorException(errorMsg.toString()); 176 | } 177 | 178 | Map classBytes = fileManager.getClassBytes(); 179 | try { 180 | fileManager.close(); 181 | } catch (IOException exp) { 182 | } 183 | 184 | return classBytes; 185 | } 186 | } 187 | 188 | -------------------------------------------------------------------------------- /src/main/java/org/algohub/engine/compiler/java/MemoryJavaFileManager.java: -------------------------------------------------------------------------------- 1 | package org.algohub.engine.compiler.java; 2 | 3 | 4 | import java.io.ByteArrayOutputStream; 5 | import java.io.File; 6 | import java.io.FilterOutputStream; 7 | import java.io.IOException; 8 | import java.io.OutputStream; 9 | import java.net.URI; 10 | import java.nio.CharBuffer; 11 | import java.util.HashMap; 12 | import java.util.Map; 13 | 14 | import javax.tools.FileObject; 15 | import javax.tools.ForwardingJavaFileManager; 16 | import javax.tools.JavaFileManager; 17 | import javax.tools.JavaFileObject; 18 | import javax.tools.JavaFileObject.Kind; 19 | import javax.tools.SimpleJavaFileObject; 20 | 21 | /** 22 | * JavaFileManager that keeps compiled .class bytes in memory. 23 | */ 24 | @SuppressWarnings("unchecked") final class MemoryJavaFileManager extends ForwardingJavaFileManager { 25 | 26 | /** 27 | * Java source file extension. 28 | */ 29 | private static final String EXT = ".java"; 30 | 31 | private Map classBytes; 32 | 33 | public MemoryJavaFileManager(JavaFileManager fileManager) { 34 | super(fileManager); 35 | classBytes = new HashMap<>(); 36 | } 37 | 38 | static JavaFileObject makeStringSource(String fileName, String code) { 39 | return new StringInputBuffer(fileName, code); 40 | } 41 | 42 | static URI toUri(String name) { 43 | File file = new File(name); 44 | if (file.exists()) { 45 | return file.toURI(); 46 | } else { 47 | try { 48 | final StringBuilder newUri = new StringBuilder(); 49 | newUri.append("mfm:///"); 50 | newUri.append(name.replace('.', '/')); 51 | if (name.endsWith(EXT)) { 52 | newUri.replace(newUri.length() - EXT.length(), newUri.length(), EXT); 53 | } 54 | return URI.create(newUri.toString()); 55 | } catch (Exception exp) { 56 | return URI.create("mfm:///com/sun/script/java/java_source"); 57 | } 58 | } 59 | } 60 | 61 | public Map getClassBytes() { 62 | return classBytes; 63 | } 64 | 65 | public void close() throws IOException { 66 | classBytes = null; 67 | } 68 | 69 | public void flush() throws IOException { 70 | } 71 | 72 | public JavaFileObject getJavaFileForOutput(JavaFileManager.Location location, String className, 73 | Kind kind, FileObject sibling) throws IOException { 74 | if (kind == Kind.CLASS) { 75 | return new ClassOutputBuffer(className); 76 | } else { 77 | return super.getJavaFileForOutput(location, className, kind, sibling); 78 | } 79 | } 80 | 81 | /** 82 | * A file object used to represent Java source coming from a string. 83 | */ 84 | private static class StringInputBuffer extends SimpleJavaFileObject { 85 | final String code; 86 | 87 | StringInputBuffer(String fileName, String code) { 88 | super(MemoryJavaFileManager.toUri(fileName), Kind.SOURCE); 89 | this.code = code; 90 | } 91 | 92 | public CharBuffer getCharContent(boolean ignoreEncodingErrors) { 93 | return CharBuffer.wrap(code); 94 | } 95 | } 96 | 97 | 98 | /** 99 | * A file object that stores Java bytecode into the classBytes map. 100 | */ 101 | private class ClassOutputBuffer extends SimpleJavaFileObject { 102 | private String name; 103 | 104 | ClassOutputBuffer(String name) { 105 | super(MemoryJavaFileManager.toUri(name), Kind.CLASS); 106 | this.name = name; 107 | } 108 | 109 | public OutputStream openOutputStream() { 110 | return new FilterOutputStream(new ByteArrayOutputStream()) { 111 | public void close() throws IOException { 112 | out.close(); 113 | ByteArrayOutputStream bos = (ByteArrayOutputStream) out; 114 | classBytes.put(name, bos.toByteArray()); 115 | } 116 | }; 117 | } 118 | } 119 | } 120 | 121 | -------------------------------------------------------------------------------- /src/main/java/org/algohub/engine/judge/CppJudge.java: -------------------------------------------------------------------------------- 1 | package org.algohub.engine.judge; 2 | 3 | import java.util.regex.Matcher; 4 | import java.util.regex.Pattern; 5 | import org.algohub.engine.pojo.Function; 6 | import org.algohub.engine.pojo.JudgeResult; 7 | import org.algohub.engine.pojo.Problem; 8 | import org.algohub.engine.type.LanguageType; 9 | 10 | 11 | /** 12 | * C++ language online judge. 13 | */ 14 | public class CppJudge implements JudgeInterface { 15 | /** 16 | * {@inheritDoc}. 17 | */ 18 | public JudgeResult judge(final Function function, final Problem.TestCase[] testCases, 19 | final String userCode) { 20 | return JudgeInterface.judge(function, testCases, userCode, LanguageType.CPLUSPLUS, 21 | CppJudge::createFriendlyMessage); 22 | } 23 | 24 | private static String createFriendlyMessage(final String errorMessage) { 25 | if(errorMessage == null || errorMessage.isEmpty()) return null; 26 | 27 | final StringBuilder sb = new StringBuilder(); 28 | final String[] lines = errorMessage.split("\n"); 29 | final String CPP_SOLUTION_FILE = "solution." + LanguageType.CPLUSPLUS.getFileSuffix(); 30 | final Pattern pattern = Pattern.compile("^solution\\.cpp:(\\d+):\\d+:"); 31 | 32 | for(int i = 0; i < lines.length; i++) { 33 | Matcher matcher = pattern.matcher(lines[i]); 34 | if(matcher.find()) { 35 | String lineNo = matcher.group(1); 36 | sb.append("Line " + lines[i].substring(CPP_SOLUTION_FILE.length() + 1)).append('\n'); 37 | sb.append(lines[i+1]).append('\n'); 38 | sb.append(lines[i+2]).append('\n'); 39 | i += 2; 40 | } else if(lines[i].startsWith("main.cpp: In function") && lines[i+1].contains("was not declared in this scope") ) { 41 | int pos = lines[i+1].indexOf("error:"); 42 | sb.append(lines[i+1].substring(pos)).append('\n'); 43 | i+= 1; 44 | } 45 | } 46 | return sb.toString(); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/org/algohub/engine/judge/CsharpJudge.java: -------------------------------------------------------------------------------- 1 | package org.algohub.engine.judge; 2 | 3 | import org.algohub.engine.pojo.JudgeResult; 4 | import org.algohub.engine.pojo.Problem; 5 | import org.algohub.engine.pojo.Function; 6 | import org.algohub.engine.bo.StatusCode; 7 | 8 | /** 9 | * C# language online judge. 10 | */ 11 | public class CsharpJudge implements JudgeInterface { 12 | //TODO: 13 | 14 | /** 15 | * {@inheritDoc}. 16 | */ 17 | public JudgeResult judge(final Function function, final Problem.TestCase[] testCases, 18 | final String userCode) { 19 | return new JudgeResult(StatusCode.ACCEPTED, null, null, null, null, 0, 0, 0, 0); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/org/algohub/engine/judge/JavaJudge.java: -------------------------------------------------------------------------------- 1 | package org.algohub.engine.judge; 2 | 3 | import com.fasterxml.jackson.databind.JsonNode; 4 | import org.algohub.engine.bo.InternalTestCase; 5 | import org.algohub.engine.compiler.java.CompileErrorException; 6 | import org.algohub.engine.compiler.java.MemoryJavaCompiler; 7 | import org.algohub.engine.pojo.JudgeResult; 8 | import org.algohub.engine.pojo.Problem; 9 | import org.algohub.engine.serde.Serializer; 10 | import org.algohub.engine.type.TypeNode; 11 | import org.algohub.engine.util.Equals; 12 | import org.algohub.engine.pojo.Function; 13 | import org.algohub.engine.bo.StatusCode; 14 | 15 | import java.lang.reflect.InvocationTargetException; 16 | import java.lang.reflect.Method; 17 | import java.util.Optional; 18 | import java.util.regex.Matcher; 19 | import java.util.regex.Pattern; 20 | 21 | /** 22 | * Java language online judge. 23 | */ 24 | public class JavaJudge implements JudgeInterface { 25 | // for finding class name 26 | private static final Pattern[] PATTERNS = 27 | new Pattern[] {Pattern.compile("public\\s+class\\s+(\\w+)\\s+"), 28 | Pattern.compile("final\\s+public\\s+class\\s+(\\w+)\\s+"), 29 | Pattern.compile("public\\s+final\\s+class\\s+(\\w+)\\s+"),}; 30 | 31 | private static final String PACKAGE_NAME = "org.algohub"; 32 | private static final String IMPORTS = 33 | "package " + PACKAGE_NAME + ";\n" + "import java.util.*;\n" + 34 | "import org.algohub.engine.collection.*;\n\n\n"; 35 | private static final int IMPORTS_LINES = 5; 36 | 37 | private static JudgeResult judge(final Object clazz, final Method method, 38 | final InternalTestCase[] testCases, final Problem.TestCase[] testCasesJson, 39 | final TypeNode returnType) { 40 | final long start = System.currentTimeMillis(); 41 | for (int i = 0; i < testCases.length; ++i) { 42 | final InternalTestCase testCase = testCases[i]; 43 | final JudgeOneCaseResult oneResult = judge(clazz, method, testCase, returnType); 44 | if (!oneResult.correct) { 45 | final long time = System.currentTimeMillis() - start; 46 | return new JudgeResult(StatusCode.WRONG_ANSWER, null, 47 | testCasesJson[i].getInput(), oneResult.wrongOutput, 48 | testCasesJson[i].getOutput(), i, 49 | testCases.length, time, 0L); 50 | } 51 | } 52 | final long time = System.currentTimeMillis() - start; 53 | return new JudgeResult(StatusCode.ACCEPTED, null, null, null, 54 | null, testCases.length, testCases.length, time, 0); 55 | } 56 | 57 | private static JudgeOneCaseResult judge(final Object clazz, final Method method, 58 | final InternalTestCase testCase, final TypeNode returnType) { 59 | final Object output; 60 | try { 61 | output = method.invoke(clazz, testCase.getInput()); 62 | } catch (IllegalAccessException | InvocationTargetException e) { 63 | throw new IllegalStateException(e.getMessage()); 64 | } 65 | final JudgeOneCaseResult result = new JudgeOneCaseResult(); 66 | if (Equals.equal(testCase.getOutput(), output)) { 67 | result.correct = true; 68 | } else { 69 | result.wrongOutput = Serializer.toJson(output, returnType); 70 | } 71 | return result; 72 | } 73 | 74 | private static Optional getClassName(final String javaCode) { 75 | for (final Pattern pattern : PATTERNS) { 76 | final Matcher matcher = pattern.matcher(javaCode); 77 | if (matcher.find()) { 78 | return Optional.of(matcher.group(1)); 79 | } 80 | } 81 | return Optional.empty(); 82 | } 83 | 84 | /** 85 | * {@inheritDoc}. 86 | */ 87 | public JudgeResult judge(final Function function, final Problem.TestCase[] testCases, 88 | final String userCode) { 89 | final InternalTestCase[] internalTestCases = new InternalTestCase[testCases.length]; 90 | for (int i = 0; i < testCases.length; ++i) { 91 | internalTestCases[i] = new InternalTestCase(testCases[i], function); 92 | } 93 | try { 94 | return judge(function, internalTestCases, userCode, testCases); 95 | } catch (NoSuchMethodError ex) { 96 | return new JudgeResult(ex.getClass().getCanonicalName() + ": " + ex.getMessage()); 97 | } 98 | } 99 | 100 | /** 101 | * Judge a user's code. 102 | * 103 | * @param function Function prototype 104 | * @param testCases test cases 105 | * @param userCode user code 106 | * @param testCasesJson test cases in JSON format 107 | * @return JudgeResult 108 | */ 109 | public JudgeResult judge(final Function function, final InternalTestCase[] testCases, 110 | final String userCode, final Problem.TestCase[] testCasesJson) { 111 | final Object clazz; 112 | final Method method; 113 | try { 114 | final String completeUserCode = IMPORTS + userCode; 115 | final Optional className = getClassName(completeUserCode); 116 | if (!className.isPresent()) { 117 | return new JudgeResult("ClassNotFoundException: No public class found"); 118 | } 119 | final Object[] tmp = MemoryJavaCompiler.INSTANCE 120 | .compileMethod("org.algohub." + className.get(), function.getName(), completeUserCode); 121 | clazz = tmp[0]; 122 | method = (Method) tmp[1]; 123 | } catch (ClassNotFoundException e) { 124 | return new JudgeResult(e.getClass() + " : " + e.getMessage()); 125 | } catch (CompileErrorException e) { 126 | return new JudgeResult(createFriendlyMessage(e.getMessage())); 127 | } 128 | 129 | return judge(clazz, method, testCases, testCasesJson, function.getReturn_().getType()); 130 | } 131 | 132 | private String createFriendlyMessage(final String errorMessage) { 133 | if(errorMessage == null || errorMessage.isEmpty()) return null; 134 | 135 | final StringBuilder sb = new StringBuilder(); 136 | final String[] lines = errorMessage.split("\n"); 137 | for (final String line : lines) { 138 | final int pos = line.indexOf(".java:"); 139 | if (pos > 0) { 140 | // get the line number 141 | final int pos2 = line.indexOf(':', pos + ".java:".length()); 142 | final int lineNumber; 143 | { 144 | final String numberStr = line.substring(pos + ".java:".length(), pos2); 145 | lineNumber = Integer.valueOf(numberStr) - IMPORTS_LINES; 146 | } 147 | final String friendlyMessage = "Line:" + lineNumber + line.substring(pos2); 148 | sb.append(friendlyMessage).append('\n'); 149 | } else { 150 | sb.append(line).append('\n'); 151 | } 152 | } 153 | return sb.toString(); 154 | } 155 | 156 | private static class JudgeOneCaseResult { 157 | boolean correct; 158 | JsonNode wrongOutput; 159 | } 160 | } 161 | -------------------------------------------------------------------------------- /src/main/java/org/algohub/engine/judge/JavaScriptJudge.java: -------------------------------------------------------------------------------- 1 | package org.algohub.engine.judge; 2 | 3 | import org.algohub.engine.pojo.Function; 4 | import org.algohub.engine.pojo.JudgeResult; 5 | import org.algohub.engine.pojo.Problem; 6 | import org.algohub.engine.bo.StatusCode; 7 | 8 | /** 9 | * JavaScript language online judge. 10 | */ 11 | public class JavaScriptJudge implements JudgeInterface { 12 | //TODO: 13 | 14 | /** 15 | * {@inheritDoc}. 16 | */ 17 | public JudgeResult judge(final Function function, final Problem.TestCase[] testCases, 18 | final String userCode) { 19 | return new JudgeResult(StatusCode.ACCEPTED, null, null, null, null, 0, 0, 0, 0); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/org/algohub/engine/judge/PythonJudge.java: -------------------------------------------------------------------------------- 1 | package org.algohub.engine.judge; 2 | 3 | import org.algohub.engine.pojo.Function; 4 | import org.algohub.engine.pojo.JudgeResult; 5 | import org.algohub.engine.pojo.Problem; 6 | import org.algohub.engine.type.LanguageType; 7 | 8 | 9 | public class PythonJudge implements JudgeInterface { 10 | private static final String IMPORTS = "import collections\nimport math\nfrom algohub import *\n\n\n"; 11 | private static final int IMPORTS_LINES = 5; 12 | 13 | /** 14 | * @{inhericDoc}. 15 | */ 16 | public JudgeResult judge(final Function function, final Problem.TestCase[] testCases, 17 | final String userCode) { 18 | return JudgeInterface.judge(function, testCases, IMPORTS + userCode, LanguageType.PYTHON, 19 | PythonJudge::createFriendlyMessage); 20 | } 21 | 22 | private static String createFriendlyMessage(final String errorMessage) { 23 | if(errorMessage == null || errorMessage.isEmpty()) return null; 24 | 25 | final StringBuilder sb = new StringBuilder(); 26 | final String[] lines = errorMessage.split("\n"); 27 | 28 | if(errorMessage.contains("AttributeError: module 'solution' has no attribute")) { 29 | return lines[3]; 30 | } else if(lines[0].startsWith("Traceback (most recent call last):") && lines[3].startsWith("TypeError:") && lines[3].contains("required positional argument")) { 31 | return lines[3]; 32 | } 33 | 34 | int startLine = 0; 35 | for (final String line : lines) { 36 | final int pos = line.indexOf("solution.py"); 37 | if (pos > 0) { 38 | break; 39 | } 40 | startLine++; 41 | } 42 | for (int i = startLine; i < lines.length; ++i) { 43 | final String line = lines[i]; 44 | final String uniqueStr = "solution.py\", line "; 45 | final int pos = line.indexOf(uniqueStr); 46 | if (pos > 0) { 47 | final int pos2 = line.indexOf(", ", pos + uniqueStr.length()); 48 | final int lineNumber = 49 | Integer.parseInt(line.substring(pos + uniqueStr.length(), pos2)) - IMPORTS_LINES; 50 | final String friendlyMessage = "Line " + lineNumber + ":" + line.substring(pos2 + 1); 51 | 52 | sb.append(friendlyMessage).append('\n'); 53 | } else { 54 | sb.append(line).append('\n'); 55 | } 56 | } 57 | 58 | return sb.toString(); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/main/java/org/algohub/engine/judge/RubyJudge.java: -------------------------------------------------------------------------------- 1 | package org.algohub.engine.judge; 2 | 3 | import org.algohub.engine.pojo.Function; 4 | import org.algohub.engine.pojo.JudgeResult; 5 | import org.algohub.engine.pojo.Problem; 6 | import org.algohub.engine.type.LanguageType; 7 | 8 | 9 | public class RubyJudge implements JudgeInterface { 10 | private static final String IMPORTS = "require 'set'\nrequire 'algohub'\nLinkedListNode = Algohub::LinkedListNode\nBinaryTreeNode = Algohub::BinaryTreeNode\n\n\n"; 11 | private static final int IMPORTS_LINES = 6; 12 | 13 | /** 14 | * @{inhericDoc}. 15 | */ 16 | public JudgeResult judge(final Function function, final Problem.TestCase[] testCases, 17 | final String userCode) { 18 | return JudgeInterface.judge(function, testCases, IMPORTS + userCode, LanguageType.RUBY, 19 | RubyJudge::createFriendlyMessage); 20 | } 21 | 22 | private static String createFriendlyMessage(final String errorMessage) { 23 | if(errorMessage == null || errorMessage.isEmpty()) return null; 24 | 25 | final StringBuilder sb = new StringBuilder(); 26 | final String[] lines = errorMessage.split("\n"); 27 | 28 | if (errorMessage.contains("for main:Object (NoMethodError)")) { 29 | final int pos = lines[0].indexOf("undefined method"); 30 | return lines[0].substring(pos); 31 | } 32 | 33 | for (final String line : lines) { 34 | final int pos = line.indexOf("/solution.rb:"); 35 | if (pos == -1) { 36 | continue; 37 | } 38 | 39 | final int numberStart = pos + "/solution.rb:".length(); 40 | final int pos2 = line.indexOf(":in `", numberStart); 41 | if (pos2 == -1) { // default to original 42 | sb.append(line).append('\n'); 43 | } else { 44 | final int lineNumber = Integer.valueOf(line.substring(numberStart, pos2)) - IMPORTS_LINES; 45 | sb.append("Line " + lineNumber + ": " + line.substring(pos2 + 1)).append('\n'); 46 | } 47 | } 48 | 49 | return sb.toString(); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/main/java/org/algohub/engine/pojo/Function.java: -------------------------------------------------------------------------------- 1 | package org.algohub.engine.pojo; 2 | 3 | import com.fasterxml.jackson.annotation.JsonCreator; 4 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties; 5 | import com.fasterxml.jackson.annotation.JsonProperty; 6 | import org.algohub.engine.type.TypeNode; 7 | 8 | 9 | /** 10 | * Function metadata. 11 | */ 12 | @SuppressWarnings({"PMD.BeanMembersShouldSerialize", "PMD.UnusedPrivateField", "PMD.SingularField", 13 | "PMD.ArrayIsStoredDirectly"}) @JsonIgnoreProperties(ignoreUnknown = true) public 14 | class Function { 15 | 16 | /** 17 | * Function name. 18 | */ 19 | private final String name; 20 | /** 21 | * Return metadata. 22 | */ 23 | @JsonProperty("return") private final Return return_; 24 | /** 25 | * Parameters' metadata. 26 | */ 27 | private final Parameter[] parameters; 28 | 29 | /** 30 | * Since this class is immutable, need to provide a method for Jackson. 31 | */ 32 | @JsonCreator public Function(@JsonProperty("name") final String name, 33 | @JsonProperty("return") final Return return_, 34 | @JsonProperty("parameters") final Parameter[] parameters) { 35 | this.name = name; 36 | this.return_ = return_; 37 | this.parameters = parameters; 38 | } 39 | 40 | 41 | /** 42 | * Return type. 43 | */ 44 | @JsonIgnoreProperties(ignoreUnknown = true) public static class Return { 45 | /** 46 | * Return data type. 47 | */ 48 | private final TypeNode type; 49 | /** 50 | * Comment of returned value. 51 | */ 52 | private final String comment; 53 | 54 | /** 55 | * Since this class is immutable, need to provide a method for Jackson. 56 | */ 57 | @JsonCreator public Return(@JsonProperty("type") final TypeNode type, 58 | @JsonProperty("comment") final String comment) { 59 | this.type = type; 60 | this.comment = comment; 61 | } 62 | 63 | public TypeNode getType() { 64 | return type; 65 | } 66 | 67 | public String getComment() { 68 | return comment; 69 | } 70 | } 71 | 72 | 73 | /** 74 | * Function parameters' metadata. 75 | */ 76 | @JsonIgnoreProperties(ignoreUnknown = true) public static class Parameter { 77 | /** 78 | * Parameter name. 79 | */ 80 | private final String name; 81 | /** 82 | * Parameter type. 83 | */ 84 | private final TypeNode type; 85 | /** 86 | * Parameter comment. 87 | */ 88 | private final String comment; 89 | 90 | /** 91 | * Since this class is immutable, need to provide a method for Jackson. 92 | */ 93 | @JsonCreator public Parameter(@JsonProperty("name") final String name, 94 | @JsonProperty("type") final TypeNode type, @JsonProperty("comment") final String comment) { 95 | this.name = name; 96 | this.type = type; 97 | this.comment = comment; 98 | } 99 | 100 | public String getName() { 101 | return name; 102 | } 103 | 104 | public TypeNode getType() { 105 | return type; 106 | } 107 | 108 | public String getComment() { 109 | return comment; 110 | } 111 | } 112 | 113 | public String getName() { 114 | return name; 115 | } 116 | 117 | public Return getReturn_() { 118 | return return_; 119 | } 120 | 121 | public Parameter[] getParameters() { 122 | return parameters; 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /src/main/java/org/algohub/engine/pojo/JudgeResult.java: -------------------------------------------------------------------------------- 1 | package org.algohub.engine.pojo; 2 | 3 | import com.fasterxml.jackson.annotation.JsonCreator; 4 | import com.fasterxml.jackson.annotation.JsonProperty; 5 | 6 | import com.fasterxml.jackson.databind.JsonNode; 7 | import com.fasterxml.jackson.databind.node.ArrayNode; 8 | import org.algohub.engine.bo.StatusCode; 9 | 10 | 11 | /** 12 | * Judge result. 13 | */ 14 | @SuppressWarnings("PMD.CommentRequired") 15 | public final class JudgeResult { 16 | @JsonProperty(value = "status_code", required = true) private StatusCode statusCode; 17 | @JsonProperty("error_message") private String errorMessage; 18 | private ArrayNode input; 19 | private JsonNode output; 20 | @JsonProperty("expected_output") private JsonNode expectedOutput; 21 | @JsonProperty("testcase_passed_count") private int testcasePassedCount; 22 | @JsonProperty("testcase_total_count") private int testcaseTotalCount; 23 | @JsonProperty("elapsed_time") private long elapsedTime; // milliseconds 24 | @JsonProperty("consumed_memory") private long consumedMemory; // bytes 25 | 26 | /** 27 | * Since some fields are immutable, need to provide a method for Jackson. 28 | */ 29 | @JsonCreator public JudgeResult(@JsonProperty(value = "status_code", required = true) final StatusCode statusCode, 30 | @JsonProperty("error_message") final String errorMessage, 31 | @JsonProperty("input") final ArrayNode input, @JsonProperty("output") final JsonNode output, 32 | @JsonProperty("expected_output") final JsonNode expectedOutput, 33 | @JsonProperty("testcase_passed_count") final int testcasePassedCount, 34 | @JsonProperty("testcase_total_count") final int testcaseTotalCount, 35 | @JsonProperty("elapsed_time") final long elapsedTime, 36 | @JsonProperty("consumed_memory") final long consumedMemory) { 37 | this.statusCode = statusCode; 38 | this.errorMessage = errorMessage; 39 | this.input = input; 40 | this.output = output; 41 | this.expectedOutput = expectedOutput; 42 | this.testcasePassedCount = testcasePassedCount; 43 | this.testcaseTotalCount = testcaseTotalCount; 44 | this.elapsedTime = elapsedTime; 45 | this.consumedMemory = consumedMemory; 46 | } 47 | 48 | /** 49 | * Constructor. 50 | */ 51 | public JudgeResult(final String compileErrorMsg) { 52 | this.statusCode = StatusCode.COMPILE_ERROR; 53 | this.errorMessage = compileErrorMsg; 54 | } 55 | 56 | // PENDING or RUNNING 57 | public JudgeResult(final StatusCode statusCode) { 58 | this.statusCode = statusCode; 59 | } 60 | 61 | public StatusCode getStatusCode() { 62 | return statusCode; 63 | } 64 | 65 | public String getErrorMessage() { 66 | return errorMessage; 67 | } 68 | 69 | public void setErrorMessage(String errorMessage) { 70 | this.errorMessage = errorMessage; 71 | } 72 | 73 | public ArrayNode getInput() { 74 | return input; 75 | } 76 | 77 | public JsonNode getOutput() { 78 | return output; 79 | } 80 | 81 | public JsonNode getExpectedOutput() { 82 | return expectedOutput; 83 | } 84 | 85 | public int getTestcasePassedCount() { 86 | return testcasePassedCount; 87 | } 88 | 89 | public int getTestcaseTotalCount() { 90 | return testcaseTotalCount; 91 | } 92 | 93 | public void setTestcaseTotalCount(int n) { 94 | this.testcaseTotalCount = n; 95 | } 96 | 97 | public long getElapsedTime() { 98 | return elapsedTime; 99 | } 100 | 101 | public long getConsumedMemory() { 102 | return consumedMemory; 103 | } 104 | 105 | public void setElapsedTime(long elapsedTime) { 106 | this.elapsedTime = elapsedTime; 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /src/main/java/org/algohub/engine/pojo/Problem.java: -------------------------------------------------------------------------------- 1 | package org.algohub.engine.pojo; 2 | 3 | import com.fasterxml.jackson.annotation.JsonCreator; 4 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties; 5 | import com.fasterxml.jackson.annotation.JsonProperty; 6 | import com.fasterxml.jackson.databind.JsonNode; 7 | import com.fasterxml.jackson.databind.node.ArrayNode; 8 | 9 | import java.util.Map; 10 | import org.algohub.engine.type.LanguageType; 11 | 12 | 13 | /** 14 | * Problem Java Object, corresponds to the problem JSON string. 15 | */ 16 | @SuppressWarnings({"PMD.BeanMembersShouldSerialize", "PMD.UnusedPrivateField", "PMD.SingularField", 17 | "PMD.ArrayIsStoredDirectly", "PMD.CommentRequired"}) 18 | @JsonIgnoreProperties(ignoreUnknown = true) 19 | public class Problem { 20 | @JsonProperty(required = true) private final Map title; 21 | @JsonProperty(required = true) private final Map description; 22 | @JsonProperty(required = true) private final Function function; 23 | @JsonProperty(value = "test_cases", required = true) private final TestCase[] testCases; 24 | private final String category; 25 | private final String[] tags; 26 | private final int difficulty; 27 | @JsonProperty("time_limit") private final int timeLimit; 28 | @JsonProperty("memory_limit") private final int memoryLimit; 29 | @JsonProperty("related_problems") private final String[] relatedProblems; 30 | private final Map author; 31 | @JsonProperty("test_cases_generator") private final String testCasesGenerator; 32 | 33 | /** 34 | * Since some fields are immutable, need to provide a method for Jackson. 35 | */ 36 | @SuppressWarnings({"PMD.ExcessiveParameterList", "PMD.ShortVariable"}) @JsonCreator 37 | public Problem( 38 | @JsonProperty(value = "title", required = true) final Map title, 39 | @JsonProperty(value = "description", required = true) final Map description, 40 | @JsonProperty(value = "function", required = true) final Function function, 41 | @JsonProperty(value = "test_cases", required = true) final TestCase[] testCases, 42 | @JsonProperty("category") final String category, 43 | @JsonProperty("tags") final String[] tags, 44 | @JsonProperty("difficulty") final int difficulty, 45 | @JsonProperty("time_limit") final int timeLimit, 46 | @JsonProperty("memory_limit") final int memoryLimit, 47 | @JsonProperty("related_problems") final String[] relatedProblems, 48 | @JsonProperty("author") final Map author, 49 | @JsonProperty("test_cases_generator") final String testCasesGenerator) { 50 | this.title = title; 51 | this.description = description; 52 | this.category = category; 53 | this.tags = tags; 54 | this.difficulty = difficulty; 55 | this.timeLimit = timeLimit; 56 | this.memoryLimit = memoryLimit; 57 | this.relatedProblems = relatedProblems; 58 | this.function = function; 59 | this.author = author; 60 | this.testCases = testCases; 61 | this.testCasesGenerator = testCasesGenerator; 62 | } 63 | 64 | /** 65 | * Test cases. 66 | */ 67 | @JsonIgnoreProperties(ignoreUnknown = true) public static class TestCase { 68 | @JsonProperty(required = true) private final ArrayNode input; 69 | @JsonProperty(required = true) private final JsonNode output; 70 | 71 | @JsonCreator public TestCase( 72 | @JsonProperty(value = "input", required = true) final ArrayNode input, 73 | @JsonProperty(value = "output", required = true) final JsonNode output) { 74 | this.input = input; 75 | this.output = output; 76 | } 77 | 78 | public ArrayNode getInput() { 79 | return input; 80 | } 81 | 82 | public JsonNode getOutput() { 83 | return output; 84 | } 85 | } 86 | 87 | public String getId() { 88 | return this.title.get("en").replaceAll("\\s+", "-").replaceAll("['\\(\\),]+", "").toLowerCase(); 89 | } 90 | 91 | public Map getTitle() { 92 | return title; 93 | } 94 | 95 | public Map getDescription() { 96 | return description; 97 | } 98 | 99 | public String getCategory() { 100 | return category; 101 | } 102 | 103 | public String[] getTags() { 104 | return tags; 105 | } 106 | 107 | public int getDifficulty() { 108 | return difficulty; 109 | } 110 | 111 | public int getTimeLimit() { 112 | return timeLimit; 113 | } 114 | 115 | public int getMemoryLimit() { 116 | return memoryLimit; 117 | } 118 | 119 | public String[] getRelatedProblems() { 120 | return relatedProblems; 121 | } 122 | 123 | public Function getFunction() { 124 | return function; 125 | } 126 | 127 | public Map getAuthor() { 128 | return author; 129 | } 130 | 131 | public TestCase[] getTestCases() { 132 | return testCases; 133 | } 134 | 135 | public String getTestCasesGenerator() { 136 | return testCasesGenerator; 137 | } 138 | } 139 | -------------------------------------------------------------------------------- /src/main/java/org/algohub/engine/serde/Deserializer.java: -------------------------------------------------------------------------------- 1 | package org.algohub.engine.serde; 2 | 3 | import com.google.common.collect.ImmutableMap; 4 | import com.google.common.primitives.Ints; 5 | 6 | import com.fasterxml.jackson.databind.JsonNode; 7 | import com.fasterxml.jackson.databind.node.ArrayNode; 8 | 9 | import org.algohub.engine.collection.BinaryTreeNode; 10 | import org.algohub.engine.collection.LinkedListNode; 11 | import org.algohub.engine.pojo.Function; 12 | import org.algohub.engine.type.IntermediateType; 13 | import org.algohub.engine.type.TypeNode; 14 | 15 | import java.lang.reflect.Array; 16 | import java.util.ArrayList; 17 | import java.util.HashMap; 18 | import java.util.HashSet; 19 | import java.util.Iterator; 20 | import java.util.List; 21 | import java.util.Map; 22 | import java.util.Set; 23 | 24 | /** 25 | * Convert JSON to Java Object. 26 | */ 27 | @SuppressWarnings({"PMD.CommentRequired"}) public interface Deserializer { 28 | ImmutableMap JAVA_CLASS_MAP = 29 | ImmutableMap.builder() 30 | .put(IntermediateType.STRING, String.class) 31 | .put(IntermediateType.LIST, ArrayList.class) 32 | .put(IntermediateType.SET, HashSet.class) 33 | .put(IntermediateType.MAP, HashMap.class) 34 | .put(IntermediateType.LINKED_LIST_NODE, LinkedListNode.class) 35 | .put(IntermediateType.BINARY_TREE_NODE, BinaryTreeNode.class).build(); 36 | 37 | /** 38 | * Get type of array element. 39 | */ 40 | static IntermediateType getArrayElementType(final TypeNode typeNode) { 41 | TypeNode node = typeNode; 42 | while (node.getValue() == IntermediateType.ARRAY) { 43 | node = node.getElementType().get(); 44 | } 45 | return node.getValue(); 46 | } 47 | 48 | /** 49 | * Get all dimensions. 50 | */ 51 | static int[] getDimensions(final ArrayNode arrayNode, final TypeNode typeNode) { 52 | final ArrayList list = new ArrayList<>(); 53 | 54 | JsonNode cur = arrayNode; 55 | TypeNode node = typeNode; 56 | while (node.getValue() == IntermediateType.ARRAY) { 57 | if (cur != null) { 58 | assert cur.isArray(); 59 | list.add(cur.size()); 60 | cur = cur.get(0); 61 | } else { 62 | list.add(0); 63 | } 64 | node = node.getElementType().get(); 65 | } 66 | return Ints.toArray(list); 67 | } 68 | 69 | 70 | /** 71 | * Convert primitive values to JsonNode. 72 | */ 73 | static Object jsonToJavaPrimitive(final TypeNode type, final JsonNode jsonNode) { 74 | if (jsonNode.isNull()) { 75 | return null; 76 | } 77 | final Object object; 78 | 79 | switch (type.getValue()) { 80 | case BOOL: 81 | object = jsonNode.asBoolean(); 82 | break; 83 | case CHAR: 84 | object = jsonNode.asText().charAt(0); 85 | break; 86 | case STRING: 87 | object = jsonNode.asText(); 88 | break; 89 | case DOUBLE: 90 | object = jsonNode.asDouble(); 91 | break; 92 | case INT: 93 | object = jsonNode.asInt(); 94 | break; 95 | case LONG: 96 | object = jsonNode.asLong(); 97 | break; 98 | default: 99 | throw new IllegalArgumentException("Unrecognized primitive type: " + type); 100 | } 101 | return object; 102 | } 103 | 104 | /** 105 | * Deserialize an object using JSON. 106 | */ 107 | // Post order 108 | static Object fromJson(final TypeNode type, final JsonNode jsonNode) { 109 | if (!type.isContainer()) { 110 | return jsonToJavaPrimitive(type, jsonNode); 111 | } 112 | 113 | final Object javaNode; 114 | switch (type.getValue()) { 115 | case ARRAY: { 116 | final ArrayNode elements = (ArrayNode) jsonNode; 117 | final int[] dimensions = getDimensions(elements, type); 118 | final IntermediateType innerestType = getArrayElementType(type); 119 | final TypeNode elementType = type.getElementType().get(); 120 | 121 | switch (innerestType) { 122 | case BOOL: 123 | javaNode = Array.newInstance(boolean.class, dimensions); 124 | break; 125 | case CHAR: 126 | javaNode = Array.newInstance(char.class, dimensions); 127 | break; 128 | case INT: 129 | javaNode = Array.newInstance(int.class, dimensions); 130 | break; 131 | case LONG: 132 | javaNode = Array.newInstance(long.class, dimensions); 133 | break; 134 | case DOUBLE: 135 | javaNode = Array.newInstance(double.class, dimensions); 136 | break; 137 | default: // LIST, LinkedListNode, SET, MAP, BinaryTreeNode 138 | javaNode = Array.newInstance(JAVA_CLASS_MAP.get(innerestType), dimensions); 139 | } 140 | for (int i = 0; i < elements.size(); ++i) { 141 | Array.set(javaNode, i, fromJson(elementType, elements.get(i))); 142 | } 143 | break; 144 | } 145 | case LIST: { 146 | final ArrayNode elements = (ArrayNode) jsonNode; 147 | 148 | final List javaList = new ArrayList<>(); 149 | for (final JsonNode e : elements) { 150 | javaList.add(fromJson(type.getElementType().get(), e)); 151 | } 152 | javaNode = javaList; 153 | break; 154 | } 155 | case SET: { 156 | final ArrayNode elements = (ArrayNode) jsonNode; 157 | 158 | final Set javaSet = new HashSet<>(); 159 | for (final JsonNode e : elements) { 160 | javaSet.add(fromJson(type.getElementType().get(), e)); 161 | } 162 | javaNode = javaSet; 163 | break; 164 | } 165 | case MAP: { 166 | final Iterator> iterator = jsonNode.fields(); 167 | final Map javaMap = new HashMap<>(); 168 | 169 | while (iterator.hasNext()) { 170 | final Map.Entry entry = iterator.next(); 171 | //NOTE: Since JSON only allows string as key, so all hashmap's key has a 172 | // single level 173 | final String keyStr = entry.getKey(); 174 | final Object key; 175 | switch (type.getKeyType().get().getValue()) { 176 | case BOOL: 177 | key = Boolean.valueOf(keyStr); 178 | break; 179 | case CHAR: 180 | key = Character.valueOf(keyStr.charAt(0)); 181 | break; 182 | case STRING: 183 | key = keyStr; 184 | break; 185 | case DOUBLE: 186 | key = Double.valueOf(keyStr); 187 | break; 188 | case INT: 189 | key = Integer.valueOf(keyStr); 190 | break; 191 | case LONG: 192 | key = Long.valueOf(keyStr); 193 | break; 194 | default: 195 | throw new IllegalArgumentException("map keys can only be primitive type: " + type); 196 | } 197 | final Object value = fromJson(type.getElementType().get(), entry.getValue()); 198 | javaMap.put(key, value); 199 | } 200 | javaNode = javaMap; 201 | break; 202 | } 203 | case LINKED_LIST_NODE: { 204 | final ArrayNode elements = (ArrayNode) jsonNode; 205 | final LinkedListNode dummy = new LinkedListNode<>(null); 206 | LinkedListNode tail = dummy; 207 | for (final JsonNode e : elements) { 208 | tail.next = new LinkedListNode<>(fromJson(type.getElementType().get(), e)); 209 | tail = tail.next; 210 | } 211 | javaNode = dummy.next; 212 | break; 213 | } 214 | case BINARY_TREE_NODE: { 215 | final ArrayNode elements = (ArrayNode) jsonNode; 216 | if(elements.size() > 0) { 217 | final BinaryTreeNode javaBinaryTree = new BinaryTreeNode<>(); 218 | for (final JsonNode e : elements) { 219 | javaBinaryTree.add(fromJson(type.getElementType().get(), e)); 220 | } 221 | javaNode = javaBinaryTree; 222 | } else { 223 | javaNode = null; 224 | } 225 | break; 226 | } 227 | default: 228 | throw new IllegalArgumentException("Unrecognized collection type: " + type.getValue()); 229 | } 230 | 231 | return javaNode; 232 | } 233 | 234 | /** 235 | * Convert input to array. 236 | */ 237 | static Object[] inputToJavaArray(ArrayNode input, Function.Parameter[] parameters) { 238 | final Object[] arguments = new Object[parameters.length]; 239 | 240 | for (int i = 0; i < parameters.length; i++) { 241 | arguments[i] = fromJson(parameters[i].getType(), input.get(i)); 242 | } 243 | return arguments; 244 | } 245 | } 246 | -------------------------------------------------------------------------------- /src/main/java/org/algohub/engine/serde/Serializer.java: -------------------------------------------------------------------------------- 1 | package org.algohub.engine.serde; 2 | 3 | import java.util.ArrayList; 4 | import java.util.HashMap; 5 | import java.util.HashSet; 6 | import java.util.LinkedList; 7 | import java.util.Map; 8 | import java.util.Queue; 9 | 10 | import org.algohub.engine.collection.BinaryTreeNode; 11 | import org.algohub.engine.collection.LinkedListNode; 12 | import org.algohub.engine.type.TypeNode; 13 | import org.algohub.engine.util.ObjectMapperInstance; 14 | 15 | import com.fasterxml.jackson.databind.JsonNode; 16 | import com.fasterxml.jackson.databind.node.ArrayNode; 17 | import com.fasterxml.jackson.databind.node.BooleanNode; 18 | import com.fasterxml.jackson.databind.node.DoubleNode; 19 | import com.fasterxml.jackson.databind.node.IntNode; 20 | import com.fasterxml.jackson.databind.node.LongNode; 21 | import com.fasterxml.jackson.databind.node.NullNode; 22 | import com.fasterxml.jackson.databind.node.ObjectNode; 23 | import com.fasterxml.jackson.databind.node.TextNode; 24 | 25 | public interface Serializer { 26 | /** 27 | * Serialize primtive values to JSON . 28 | */ 29 | static JsonNode primitiveToJson(final T value, final TypeNode type) { 30 | final JsonNode result; 31 | // for BinaryTreeNode 32 | if (value == null) { 33 | return NullNode.instance; 34 | } 35 | 36 | switch (type.getValue()) { 37 | case BOOL: 38 | result = BooleanNode.valueOf((Boolean) value); 39 | break; 40 | case CHAR: 41 | result = TextNode.valueOf(value.toString()); 42 | break; 43 | case STRING: 44 | result = TextNode.valueOf((String) value); 45 | break; 46 | case DOUBLE: 47 | result = DoubleNode.valueOf((Double) value); 48 | break; 49 | case INT: 50 | result = IntNode.valueOf((Integer) value); 51 | break; 52 | case LONG: 53 | result = LongNode.valueOf((Long) value); 54 | break; 55 | default: 56 | throw new IllegalArgumentException("Unrecognized primitive type: " + type); 57 | } 58 | return result; 59 | } 60 | 61 | /** 62 | * Convert objects to JSON serializable objects. 63 | */ 64 | static JsonNode toJson(final T value, final TypeNode type) { 65 | if (!type.isContainer()) { 66 | return primitiveToJson(value, type); 67 | } 68 | 69 | // Deal with two children first 70 | final JsonNode result; 71 | switch (type.getValue()) { 72 | case ARRAY: { 73 | final ArrayNode arrayNode = ObjectMapperInstance.INSTANCE.createArrayNode(); 74 | final TypeNode elementType = type.getElementType().get(); 75 | switch (elementType.getValue()) { 76 | case BOOL: { 77 | final boolean[] array = (boolean[]) value; 78 | for (final boolean e : array) { 79 | arrayNode.add(primitiveToJson(e, elementType)); 80 | } 81 | break; 82 | } 83 | case CHAR: { 84 | final char[] array = (char[]) value; 85 | for (final char e : array) { 86 | arrayNode.add(primitiveToJson(e, elementType)); 87 | } 88 | break; 89 | } 90 | case INT: { 91 | final int[] array = (int[]) value; 92 | for (final int e : array) { 93 | arrayNode.add(primitiveToJson(e, elementType)); 94 | } 95 | break; 96 | } 97 | case LONG: { 98 | final long[] array = (long[]) value; 99 | for (final long e : array) { 100 | arrayNode.add(primitiveToJson(e, elementType)); 101 | } 102 | break; 103 | } 104 | case DOUBLE: { 105 | final double[] array = (double[]) value; 106 | for (final double e : array) { 107 | arrayNode.add(primitiveToJson(e, elementType)); 108 | } 109 | break; 110 | } 111 | default: { 112 | final Object[] array = (Object[]) value; 113 | for (final Object e : array) { 114 | arrayNode.add(toJson(e, type.getElementType().get())); 115 | } 116 | } 117 | } 118 | result = arrayNode; 119 | break; 120 | } 121 | case LIST: { 122 | final ArrayList arrayList = (ArrayList) value; 123 | final ArrayNode arrayNode = ObjectMapperInstance.INSTANCE.createArrayNode(); 124 | 125 | for (final Object e : arrayList) { 126 | arrayNode.add(toJson(e, type.getElementType().get())); 127 | } 128 | result = arrayNode; 129 | break; 130 | } 131 | case SET: { 132 | final HashSet hashSet = (HashSet) value; 133 | final ArrayNode arrayNode = ObjectMapperInstance.INSTANCE.createArrayNode(); 134 | 135 | for (final Object e : hashSet) { 136 | arrayNode.add(toJson(e, type.getElementType().get())); 137 | } 138 | result = arrayNode; 139 | break; 140 | } 141 | case MAP: { 142 | final HashMap hashMap = (HashMap) value; 143 | final ObjectNode objectNode = ObjectMapperInstance.INSTANCE.createObjectNode(); 144 | 145 | for (Map.Entry entry : hashMap.entrySet()) { 146 | final JsonNode keyNode = toJson(entry.getKey(), type.getKeyType().get()); 147 | final JsonNode valueNode = toJson(entry.getValue(), type.getElementType().get()); 148 | objectNode.set(keyNode.asText(), valueNode); 149 | } 150 | ; 151 | 152 | result = objectNode; 153 | break; 154 | } 155 | case LINKED_LIST_NODE: { 156 | final LinkedListNode linkedList = (LinkedListNode) value; 157 | final ArrayNode arrayNode = ObjectMapperInstance.INSTANCE.createArrayNode(); 158 | 159 | for (LinkedListNode i = linkedList; i != null; i = i.next) { 160 | arrayNode.add(toJson(i.value, type.getElementType().get())); 161 | } 162 | 163 | result = arrayNode; 164 | break; 165 | } 166 | case BINARY_TREE_NODE: { 167 | final BinaryTreeNode root = (BinaryTreeNode) value; 168 | final ArrayNode arrayNode = ObjectMapperInstance.INSTANCE.createArrayNode(); 169 | 170 | Queue current = new LinkedList<>(); 171 | Queue next = new LinkedList<>(); 172 | if (root != null) { 173 | current.offer(root); 174 | } 175 | 176 | while (!current.isEmpty()) { 177 | final ArrayList level = new ArrayList<>(); 178 | while (!current.isEmpty()) { 179 | level.add(current.poll()); 180 | } 181 | 182 | int lastNotNullIndex = -1; 183 | for (int i = level.size() - 1; i >= 0; i--) { 184 | if (level.get(i) != null) { 185 | lastNotNullIndex = i; 186 | break; 187 | } 188 | } 189 | 190 | for (int i = 0; i <= lastNotNullIndex; ++i) { 191 | final BinaryTreeNode node = level.get(i); 192 | if (node != null) { 193 | arrayNode.add(toJson(node.value, type.getElementType().get())); 194 | } else { 195 | arrayNode.add(NullNode.instance); 196 | } 197 | 198 | if (node != null) { 199 | next.offer(node.left); 200 | next.offer(node.right); 201 | } 202 | } 203 | // swap current and next 204 | final Queue tmp = current; 205 | current = next; 206 | next = tmp; 207 | } 208 | 209 | result = arrayNode; 210 | break; 211 | } 212 | default: 213 | throw new IllegalArgumentException("Unrecognized collection type: " + type.getValue()); 214 | } 215 | 216 | return result; 217 | } 218 | } 219 | -------------------------------------------------------------------------------- /src/main/java/org/algohub/engine/type/IntermediateType.java: -------------------------------------------------------------------------------- 1 | package org.algohub.engine.type; 2 | 3 | import com.fasterxml.jackson.annotation.JsonCreator; 4 | import com.fasterxml.jackson.annotation.JsonValue; 5 | 6 | /** 7 | * Supported intermediate types. 8 | */ 9 | public enum IntermediateType { 10 | BOOL("bool"), 11 | CHAR("char"), 12 | STRING("string"), 13 | DOUBLE("double"), 14 | INT("int"), 15 | LONG("long"), 16 | ARRAY("array"), 17 | LIST("list"), 18 | SET("set"), 19 | MAP("map"), 20 | LINKED_LIST_NODE("LinkedListNode"), 21 | BINARY_TREE_NODE("BinaryTreeNode"); 22 | 23 | /** 24 | * Text for display. 25 | */ 26 | private final String text; 27 | 28 | IntermediateType(final String text) { 29 | this.text = text; 30 | } 31 | 32 | /** 33 | * Return real Enum from string. 34 | */ 35 | @JsonCreator 36 | public static IntermediateType fromString(final String text) { 37 | if (text != null) { 38 | for (final IntermediateType v : IntermediateType.values()) { 39 | if (text.equalsIgnoreCase(v.text)) { 40 | return v; 41 | } 42 | } 43 | } 44 | throw new IllegalArgumentException("Unrecognized type: " + text); 45 | } 46 | 47 | /** 48 | * {@inheritDoc}. 49 | */ 50 | @JsonValue 51 | @Override public String toString() { 52 | return text; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/main/java/org/algohub/engine/type/LanguageType.java: -------------------------------------------------------------------------------- 1 | package org.algohub.engine.type; 2 | 3 | import com.fasterxml.jackson.annotation.JsonCreator; 4 | import com.fasterxml.jackson.annotation.JsonValue; 5 | 6 | import java.util.HashMap; 7 | import java.util.Map; 8 | 9 | /** 10 | * Supported Languages. 11 | */ 12 | public enum LanguageType { 13 | JAVA("Java"), 14 | PYTHON("Python"), 15 | CPLUSPLUS("C++"), 16 | 17 | CLOJURE("Clojure"), 18 | CSHARP("C#"), 19 | FSHARP("F#"), 20 | GO("Go"), 21 | HASKELL("Haskell"), 22 | JAVASCRIPT("JavaScript"), 23 | LUA("Lua"), 24 | OCAML("Ocaml"), 25 | RACKET("Racket"), 26 | RUBY("Ruby"), 27 | RUST("Rust"), 28 | SCALA("Scala"), 29 | SWIFT("Swift"); 30 | 31 | /** 32 | * Text for display. 33 | */ 34 | private final String text; 35 | 36 | LanguageType(final String text) { 37 | this.text = text; 38 | } 39 | 40 | /** 41 | * Return real Enum from string. 42 | */ 43 | @JsonCreator 44 | public static LanguageType fromString(String text) { 45 | if (text != null) { 46 | for (final LanguageType v : LanguageType.values()) { 47 | if (text.equalsIgnoreCase(v.text)) { 48 | return v; 49 | } 50 | } 51 | } 52 | throw new IllegalArgumentException("Unrecognized language: " + text); 53 | } 54 | 55 | /** 56 | * {@inheritDoc}. 57 | */ 58 | @JsonValue 59 | @Override public String toString() { 60 | return text; 61 | } 62 | 63 | public String getFileSuffix() { 64 | switch (this) { 65 | case CPLUSPLUS: 66 | return "cpp"; 67 | case PYTHON: 68 | return "py"; 69 | case CLOJURE: 70 | return "clj"; 71 | case CSHARP: 72 | return "cs"; 73 | case FSHARP: 74 | return "fs"; 75 | case HASKELL: 76 | return "hs"; 77 | case JAVASCRIPT: 78 | return "js"; 79 | case OCAML: 80 | return "ml"; 81 | case RACKET: 82 | return "rkt"; 83 | case RUBY: 84 | return "rb"; 85 | case RUST: 86 | return "rs"; 87 | default: 88 | return text.toLowerCase(); 89 | } 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /src/main/java/org/algohub/engine/type/TypeNode.java: -------------------------------------------------------------------------------- 1 | package org.algohub.engine.type; 2 | 3 | import com.fasterxml.jackson.annotation.JsonIgnore; 4 | import com.fasterxml.jackson.annotation.JsonProperty; 5 | import com.fasterxml.jackson.databind.annotation.JsonDeserialize; 6 | import com.fasterxml.jackson.databind.annotation.JsonSerialize; 7 | 8 | import java.util.Optional; 9 | 10 | 11 | /** 12 | * Represent a type. 13 | * 14 | *

Actually you can view it as a binary tree.

15 | * 16 | *

keyType only has meaning when parent is a HashMap.

17 | * 18 | *

elementType will be empty if value is not a container type.

19 | */ 20 | @SuppressWarnings({"PMD.UnusedPrivateField", "PMD.BeanMembersShouldSerialize", "PMD.SingularField", 21 | "PMD.ShortVariable"}) 22 | // @JsonSerialize(using = TypeNodeSerializer.class) Do NOT use it !!! 23 | @JsonDeserialize(using = TypeNodeDeserializer.class) 24 | public class TypeNode { 25 | /** 26 | * type. 27 | */ 28 | private final IntermediateType value; 29 | /** 30 | * if parent is hashmap, keyType won't be empty. 31 | */ 32 | @JsonProperty("key_type") private final Optional keyType; // left child 33 | /** 34 | * if parent is container, this is its element type. 35 | */ 36 | @JsonProperty("element_type") private final Optional elementType; // right child 37 | /** 38 | * point to parent contaier. 39 | */ 40 | @JsonIgnore @SuppressWarnings("PMD.ImmutableField") private Optional parent; 41 | 42 | /** 43 | * Constructor. 44 | */ 45 | public TypeNode(final IntermediateType value, final Optional keyType, 46 | final Optional elementType) { 47 | this.value = value; 48 | this.elementType = elementType; 49 | this.keyType = keyType; 50 | this.parent = Optional.empty(); 51 | } 52 | 53 | /** 54 | * Create a TypeNode from a string. 55 | */ 56 | public static TypeNode fromString(final String typeStr) { 57 | if (!checkAngleBrackets(typeStr)) { 58 | throw new IllegalArgumentException("Illegal type: " + typeStr); 59 | } 60 | 61 | // remove all whitespaces 62 | final String typeString = typeStr.replaceAll("\\s+", ""); 63 | final Optional result = fromStringRecursive(typeString); 64 | if (result.isPresent()) { 65 | initializeParent(result, Optional.empty()); 66 | return result.get(); 67 | } else { 68 | throw new IllegalArgumentException("Type can not be empty!"); 69 | } 70 | } 71 | 72 | @Override 73 | public String toString() { 74 | return toString(this); 75 | } 76 | 77 | private static String toString(TypeNode typeNode) { 78 | if(!typeNode.isContainer()) { 79 | return typeNode.value.toString(); 80 | } 81 | final StringBuilder result = new StringBuilder(typeNode.value.toString() + "<"); 82 | if(typeNode.keyType.isPresent()) { 83 | result.append(toString(typeNode.keyType.get())); 84 | result.append(", "); 85 | } 86 | if(typeNode.elementType.isPresent()) { 87 | result.append(toString(typeNode.elementType.get())); 88 | } 89 | return result + ">"; 90 | } 91 | 92 | // construct a binary tre in post-order 93 | // A node has three conditions, type, type or type 94 | private static Optional fromStringRecursive(final String typeStr) { 95 | final int firstLeftBracket = typeStr.indexOf('<'); 96 | 97 | if (firstLeftBracket == -1) { // Not a container 98 | if (typeStr.isEmpty()) { 99 | return Optional.empty(); 100 | } 101 | final IntermediateType currentValue = IntermediateType.fromString(typeStr); 102 | final TypeNode currentNode = new TypeNode(currentValue, Optional.empty(), Optional.empty()); 103 | return Optional.of(currentNode); 104 | } else { // is a container 105 | final IntermediateType containerType = 106 | IntermediateType.fromString(typeStr.substring(0, firstLeftBracket)); 107 | final String childStr = typeStr.substring(firstLeftBracket + 1, typeStr.length() - 1); 108 | 109 | if (containerType == IntermediateType.MAP) { 110 | final int firstCommaOrBracket; 111 | if (childStr.indexOf('<') == -1 && childStr.indexOf(',') == -1) { 112 | throw new IllegalArgumentException("Illegal type: " + childStr); 113 | } else if (childStr.indexOf('<') == -1) { 114 | firstCommaOrBracket = childStr.indexOf(','); 115 | } else if (childStr.indexOf(',') == -1) { 116 | firstCommaOrBracket = childStr.indexOf('<'); 117 | } else { 118 | firstCommaOrBracket = Math.min(childStr.indexOf('<'), childStr.indexOf(',')); 119 | } 120 | 121 | final int commaPos; 122 | if (childStr.charAt(firstCommaOrBracket) == ',') { // primitive, type 123 | commaPos = firstCommaOrBracket; 124 | } else { 125 | final int rightBracket = findRightBracket(childStr, firstCommaOrBracket); 126 | commaPos = rightBracket + 1; 127 | } 128 | final Optional keyType = fromStringRecursive(childStr.substring(0, commaPos)); 129 | final Optional child = fromStringRecursive(childStr.substring(commaPos + 1)); 130 | final TypeNode currentNode = new TypeNode(containerType, keyType, child); 131 | return Optional.of(currentNode); 132 | } else { 133 | final TypeNode currentNode = 134 | new TypeNode(containerType, Optional.empty(), fromStringRecursive(childStr)); 135 | return Optional.of(currentNode); 136 | } 137 | } 138 | } 139 | 140 | /** 141 | * Check if the brackets match with each other. 142 | */ 143 | public static boolean checkAngleBrackets(final String typeStr) { 144 | return checkAngleBrackets(typeStr, 0, 0); 145 | } 146 | 147 | private static boolean checkAngleBrackets(final String typeStr, final int cur, final int count) { 148 | if (typeStr.length() == cur) { 149 | return count == 0; 150 | } else { 151 | if (count >= 0) { 152 | final char ch = typeStr.charAt(cur); 153 | if (ch == '<') { 154 | return checkAngleBrackets(typeStr, cur + 1, count + 1); 155 | } else if (ch == '>') { 156 | return checkAngleBrackets(typeStr, cur + 1, count - 1); 157 | } else { 158 | return checkAngleBrackets(typeStr, cur + 1, count); 159 | } 160 | } else { 161 | return false; 162 | } 163 | } 164 | } 165 | 166 | /** 167 | * Find the right matched bracket. 168 | * 169 | * @param typeStr the string 170 | * @param leftBracket a left bracket in the string 171 | * @return the index of right matched bracket, otherwise return -1 172 | */ 173 | static int findRightBracket(final String typeStr, final int leftBracket) { 174 | if (!checkAngleBrackets(typeStr)) { 175 | throw new IllegalArgumentException("Found unmatched brackets!"); 176 | } 177 | 178 | return findRightBracket(typeStr, leftBracket + 1, 1); 179 | } 180 | 181 | private static int findRightBracket(final String typeStr, final int cur, final int count) { 182 | if (count == 0) { 183 | return cur - 1; 184 | } 185 | 186 | final char ch = typeStr.charAt(cur); 187 | if (ch == '<') { 188 | return findRightBracket(typeStr, cur + 1, count + 1); 189 | } else if (ch == '>') { 190 | return findRightBracket(typeStr, cur + 1, count - 1); 191 | } else { 192 | return findRightBracket(typeStr, cur + 1, count); 193 | } 194 | } 195 | 196 | /** 197 | * Initialize all parent, pre-order. 198 | */ 199 | private static void initializeParent(final Optional node, 200 | final Optional parent) { 201 | if (!node.isPresent()) { 202 | return; 203 | } 204 | final TypeNode realNode = node.get(); 205 | realNode.setParent(parent); 206 | initializeParent(realNode.getKeyType(), node); 207 | initializeParent(realNode.getElementType(), node); 208 | } 209 | 210 | /** 211 | * if the elementType is not empty, which means it's a container. 212 | */ 213 | @JsonIgnore public boolean isContainer() { 214 | return elementType.isPresent(); 215 | } 216 | 217 | /** Singly linked list and binary tree are user-defined class. */ 218 | @JsonIgnore public boolean isCustomizedType() { 219 | return value == IntermediateType.LINKED_LIST_NODE || value == IntermediateType.BINARY_TREE_NODE; 220 | } 221 | 222 | public boolean hasCustomizedType() { 223 | return hasCustomizedType(this); 224 | } 225 | 226 | private static boolean hasCustomizedType(final TypeNode type) { 227 | if (type.getValue() == IntermediateType.LINKED_LIST_NODE 228 | || type.getValue() == IntermediateType.BINARY_TREE_NODE) { 229 | return true; 230 | } else { 231 | if (type.getElementType().isPresent()) { 232 | return hasCustomizedType(type.getElementType().get()); 233 | } else { 234 | return false; 235 | } 236 | } 237 | } 238 | 239 | // Generated automatically 240 | 241 | public IntermediateType getValue() { 242 | return value; 243 | } 244 | 245 | public Optional getKeyType() { 246 | return keyType; 247 | } 248 | 249 | public Optional getElementType() { 250 | return elementType; 251 | } 252 | 253 | public Optional getParent() { 254 | return parent; 255 | } 256 | 257 | public void setParent(final Optional parent) { 258 | this.parent = parent; 259 | } 260 | } 261 | -------------------------------------------------------------------------------- /src/main/java/org/algohub/engine/type/TypeNodeDeserializer.java: -------------------------------------------------------------------------------- 1 | package org.algohub.engine.type; 2 | 3 | import com.fasterxml.jackson.core.JsonParser; 4 | import com.fasterxml.jackson.databind.DeserializationContext; 5 | import com.fasterxml.jackson.databind.JsonDeserializer; 6 | import com.fasterxml.jackson.databind.JsonNode; 7 | 8 | import java.io.IOException; 9 | 10 | 11 | /** 12 | * TypeNode JSON deserializer. 13 | */ 14 | @SuppressWarnings({"PMD.ShortVariable"}) public class TypeNodeDeserializer 15 | extends JsonDeserializer { 16 | /** 17 | * {@inheritDoc}. 18 | */ 19 | public TypeNode deserialize(final JsonParser p, final DeserializationContext ctxt) 20 | throws IOException { 21 | final JsonNode jsonNode = p.readValueAsTree(); 22 | return TypeNode.fromString(jsonNode.asText()); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/org/algohub/engine/type/TypeNodeSerializer.java: -------------------------------------------------------------------------------- 1 | package org.algohub.engine.type; 2 | 3 | import com.fasterxml.jackson.core.JsonGenerator; 4 | import com.fasterxml.jackson.core.JsonProcessingException; 5 | import com.fasterxml.jackson.databind.SerializerProvider; 6 | import com.fasterxml.jackson.databind.ser.std.StdSerializer; 7 | 8 | import java.io.IOException; 9 | 10 | public class TypeNodeSerializer extends StdSerializer { 11 | public TypeNodeSerializer() { 12 | this(null); 13 | } 14 | 15 | public TypeNodeSerializer(Class t) { 16 | super(t); 17 | } 18 | 19 | @Override 20 | public void serialize( 21 | TypeNode value, JsonGenerator jgen, SerializerProvider provider) 22 | throws IOException, JsonProcessingException { 23 | jgen.writeString(value.toString()); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/org/algohub/engine/util/Equals.java: -------------------------------------------------------------------------------- 1 | package org.algohub.engine.util; 2 | 3 | import java.util.Arrays; 4 | 5 | public interface Equals { 6 | /** 7 | * More powerful than java.util.Objects.equals(). 8 | */ 9 | static boolean equal(Object a, Object b) { 10 | if (a == b) { 11 | return true; 12 | } else if (a == null || b == null) { 13 | return false; 14 | } 15 | 16 | boolean eq; 17 | if (a instanceof Object[] && b instanceof Object[]) { 18 | eq = Arrays.deepEquals((Object[]) a, (Object[]) b); 19 | } else if (a instanceof byte[] && b instanceof byte[]) { 20 | eq = Arrays.equals((byte[]) a, (byte[]) b); 21 | } else if (a instanceof short[] && b instanceof short[]) { 22 | eq = Arrays.equals((short[]) a, (short[]) b); 23 | } else if (a instanceof int[] && b instanceof int[]) { 24 | eq = Arrays.equals((int[]) a, (int[]) b); 25 | } else if (a instanceof long[] && b instanceof long[]) { 26 | eq = Arrays.equals((long[]) a, (long[]) b); 27 | } else if (a instanceof char[] && b instanceof char[]) { 28 | eq = Arrays.equals((char[]) a, (char[]) b); 29 | } else if (a instanceof float[] && b instanceof float[]) { 30 | eq = Arrays.equals((float[]) a, (float[]) b); 31 | } else if (a instanceof double[] && b instanceof double[]) { 32 | eq = Arrays.equals((double[]) a, (double[]) b); 33 | } else if (a instanceof boolean[] && b instanceof boolean[]) { 34 | eq = Arrays.equals((boolean[]) a, (boolean[]) b); 35 | } else { 36 | eq = a.equals(b); 37 | } 38 | return eq; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/org/algohub/engine/util/ObjectMapperInstance.java: -------------------------------------------------------------------------------- 1 | package org.algohub.engine.util; 2 | 3 | import com.fasterxml.jackson.annotation.JsonInclude; 4 | import com.fasterxml.jackson.databind.ObjectMapper; 5 | import com.fasterxml.jackson.datatype.jdk8.Jdk8Module; 6 | 7 | public final class ObjectMapperInstance { 8 | public static final ObjectMapper INSTANCE = new ObjectMapper(); 9 | private ObjectMapperInstance() {} 10 | 11 | static { 12 | INSTANCE.registerModule(new Jdk8Module()); 13 | INSTANCE.setSerializationInclusion(JsonInclude.Include.NON_NULL); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/test/java/org/algohub/engine/codegenerator/DataTypes.java: -------------------------------------------------------------------------------- 1 | package org.algohub.engine.codegenerator; 2 | 3 | import org.algohub.engine.pojo.Function; 4 | import org.algohub.engine.type.TypeNode; 5 | 6 | 7 | public interface DataTypes { 8 | TypeNode ARRAY_INT = TypeNode.fromString("array"); 9 | TypeNode LIST_INT = TypeNode.fromString("list"); 10 | TypeNode SET_INT = TypeNode.fromString("set"); 11 | TypeNode LINKED_LIST_INT = TypeNode.fromString("LinkedListNode"); 12 | 13 | TypeNode MAP_STRING_INT = TypeNode.fromString("map"); 14 | TypeNode MAP_INT_DOUBLE = TypeNode.fromString("map"); 15 | 16 | TypeNode BINARY_TREE_INT = TypeNode.fromString("BinaryTreeNode"); 17 | 18 | TypeNode ARRAY_ARRAY_INT = TypeNode.fromString("array>"); 19 | TypeNode ARRAY_LIST_INT = TypeNode.fromString("array>"); 20 | TypeNode ARRAY_SET_INT = TypeNode.fromString("array>"); 21 | TypeNode ARRAY_LINKED_LIST_INT = TypeNode.fromString("array>"); 22 | TypeNode ARRAY_MAP_STRING_INT = TypeNode.fromString("array>"); 23 | TypeNode ARRAY_MAP_INT_DOUBLE = TypeNode.fromString("array>"); 24 | 25 | TypeNode LIST_ARRAY_INT = TypeNode.fromString("list>"); 26 | TypeNode LIST_LIST_INT = TypeNode.fromString("list>"); 27 | TypeNode LIST_SET_INT = TypeNode.fromString("list>"); 28 | TypeNode LIST_LINKED_LIST_INT = TypeNode.fromString("list>"); 29 | TypeNode LIST_MAP_STRING_INT = TypeNode.fromString("list>"); 30 | TypeNode LIST_MAP_INT_DOUBLE = TypeNode.fromString("list>"); 31 | 32 | TypeNode SET_ARRAY_INT = TypeNode.fromString("set>"); 33 | TypeNode SET_LIST_INT = TypeNode.fromString("set>"); 34 | TypeNode SET_LINKED_LIST_INT = TypeNode.fromString("set>"); 35 | TypeNode SET_SET_INT = TypeNode.fromString("set>"); 36 | TypeNode SET_MAP_STRING_INT = TypeNode.fromString("set>"); 37 | TypeNode SET_MAP_INT_DOUBLE = TypeNode.fromString("set>"); 38 | 39 | TypeNode LINKED_LIST_ARRAY_INT = TypeNode.fromString("LinkedListNode>"); 40 | TypeNode LINKED_LIST_LIST_INT = TypeNode.fromString("LinkedListNode>"); 41 | TypeNode LINKED_LIST_SET_INT = TypeNode.fromString("LinkedListNode>"); 42 | TypeNode LINKED_LIST_LINKED_LIST_INT = TypeNode.fromString("LinkedListNode>"); 43 | TypeNode LINKED_LIST_MAP_STRING_INT = TypeNode.fromString("LinkedListNode>"); 44 | TypeNode LINKED_LIST_MAP_INT_DOUBLE = TypeNode.fromString("LinkedListNode>"); 45 | 46 | TypeNode BINARY_TREE_ARRAY_INT = TypeNode.fromString("BinaryTreeNode>"); 47 | TypeNode BINARY_TREE_LIST_INT = TypeNode.fromString("BinaryTreeNode>"); 48 | TypeNode BINARY_TREE_SET_INT = TypeNode.fromString("BinaryTreeNode>"); 49 | TypeNode BINARY_TREE_LINKED_LIST_INT = TypeNode.fromString("BinaryTreeNode>"); 50 | TypeNode BINARY_TREE_MAP_STRING_INT = TypeNode.fromString("BinaryTreeNode>"); 51 | TypeNode BINARY_TREE_MAP_INT_DOUBLE = TypeNode.fromString("BinaryTreeNode>"); 52 | 53 | TypeNode MAP_STRING_LINKED_LIST_INT = TypeNode.fromString("map>"); 54 | TypeNode ARRAY_LIST_SET_MAP_STRING_LINKED_LIST_INT = TypeNode.fromString( 55 | "array>>>>"); 56 | TypeNode BINARY_TREE_MAP_STRING_SET_LIST_DOUBLE = TypeNode.fromString( 57 | "BinaryTreeNode>>>"); 58 | 59 | // two functions 60 | Function TWO_SUM = new Function("twoSum", 61 | new Function.Return(TypeNode.fromString("array"), 62 | "[index1 + 1, index2 + 1] (index1 < index2)"), new Function.Parameter[] { 63 | new Function.Parameter("numbers", TypeNode.fromString("array"), "An array of Integers"), 64 | new Function.Parameter("target", TypeNode.fromString("int"), 65 | "target = numbers[index1] + numbers[index2]")}); 66 | 67 | Function WORD_LADDER = new Function("ladderLength", 68 | new Function.Return(TypeNode.fromString("int"), "The shortest length"), 69 | new Function.Parameter[] { 70 | new Function.Parameter("begin_word", TypeNode.fromString("string"), "the begin word"), 71 | new Function.Parameter("end_word", TypeNode.fromString("string"), "the end word"), 72 | new Function.Parameter("dict", TypeNode.fromString("set"), "the dictionary")}); 73 | } 74 | -------------------------------------------------------------------------------- /src/test/java/org/algohub/engine/codegenerator/JavaCodeGeneratorTest.java: -------------------------------------------------------------------------------- 1 | package org.algohub.engine.codegenerator; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.algohub.engine.codegenerator.DataTypes.*; 6 | import static org.junit.Assert.assertEquals; 7 | 8 | 9 | @SuppressWarnings({"PMD.CommentRequired"}) 10 | public class JavaCodeGeneratorTest { 11 | 12 | @Test public void generateJavaFunctionTest() { 13 | final String twoSumGenerated = JavaCodeGenerator.generateEmptyFunction(TWO_SUM); 14 | final String twoSumExpected = 15 | "public class Solution {\n" + " /**\n" + " * @param numbers An array of Integers\n" 16 | + " * @param target target = numbers[index1] + numbers[index2]\n" 17 | + " * @return [index1 + 1, index2 + 1] (index1 < index2)\n" + " */\n" 18 | + " public int[] twoSum(int[] numbers, int target) {\n" 19 | + " // Write your code here\n" + " }\n" + "}\n"; 20 | assertEquals(twoSumExpected, twoSumGenerated); 21 | 22 | final String wordLadderGenerated = JavaCodeGenerator.generateEmptyFunction(WORD_LADDER); 23 | final String wordLadderExpected = 24 | "public class Solution {\n" + " /**\n" + " * @param begin_word the begin word\n" 25 | + " * @param end_word the end word\n" + " * @param dict the dictionary\n" 26 | + " * @return The shortest length\n" + " */\n" 27 | + " public int ladderLength(String begin_word, String end_word, HashSet " 28 | + "dict) {\n" 29 | + " // Write your code here\n" + " }\n" + "}\n"; 30 | assertEquals(wordLadderExpected, wordLadderGenerated); 31 | } 32 | 33 | @Test public void generateTypeDeclarationTest() { 34 | assertEquals("int[]", JavaCodeGenerator.generateTypeDeclaration(ARRAY_INT)); 35 | assertEquals("ArrayList", JavaCodeGenerator.generateTypeDeclaration(LIST_INT)); 36 | assertEquals("HashSet", JavaCodeGenerator.generateTypeDeclaration(SET_INT)); 37 | assertEquals("LinkedListNode", 38 | JavaCodeGenerator.generateTypeDeclaration(LINKED_LIST_INT)); 39 | 40 | assertEquals("HashMap", 41 | JavaCodeGenerator.generateTypeDeclaration(MAP_STRING_INT)); 42 | assertEquals("HashMap", 43 | JavaCodeGenerator.generateTypeDeclaration(MAP_INT_DOUBLE)); 44 | 45 | assertEquals("BinaryTreeNode", 46 | JavaCodeGenerator.generateTypeDeclaration(BINARY_TREE_INT)); 47 | 48 | assertEquals("int[][]", JavaCodeGenerator.generateTypeDeclaration( 49 | ARRAY_ARRAY_INT)); 50 | assertEquals("ArrayList[]", JavaCodeGenerator.generateTypeDeclaration( 51 | ARRAY_LIST_INT)); 52 | assertEquals("HashSet[]", JavaCodeGenerator.generateTypeDeclaration( 53 | ARRAY_SET_INT)); 54 | assertEquals("LinkedListNode[]", 55 | JavaCodeGenerator.generateTypeDeclaration(ARRAY_LINKED_LIST_INT)); 56 | assertEquals("HashMap[]", 57 | JavaCodeGenerator.generateTypeDeclaration(ARRAY_MAP_STRING_INT)); 58 | assertEquals("HashMap[]", 59 | JavaCodeGenerator.generateTypeDeclaration(ARRAY_MAP_INT_DOUBLE)); 60 | 61 | assertEquals("ArrayList", JavaCodeGenerator.generateTypeDeclaration( 62 | LIST_ARRAY_INT)); 63 | assertEquals("ArrayList>", JavaCodeGenerator.generateTypeDeclaration( 64 | LIST_LIST_INT)); 65 | assertEquals("ArrayList>", JavaCodeGenerator.generateTypeDeclaration( 66 | LIST_SET_INT)); 67 | assertEquals("ArrayList>", 68 | JavaCodeGenerator.generateTypeDeclaration(LIST_LINKED_LIST_INT)); 69 | assertEquals("ArrayList>", 70 | JavaCodeGenerator.generateTypeDeclaration(LIST_MAP_STRING_INT)); 71 | assertEquals("ArrayList>", 72 | JavaCodeGenerator.generateTypeDeclaration(LIST_MAP_INT_DOUBLE)); 73 | 74 | assertEquals("HashSet", 75 | JavaCodeGenerator.generateTypeDeclaration(SET_ARRAY_INT)); 76 | assertEquals("HashSet>", 77 | JavaCodeGenerator.generateTypeDeclaration(SET_LIST_INT)); 78 | assertEquals("HashSet>", 79 | JavaCodeGenerator.generateTypeDeclaration(SET_SET_INT)); 80 | assertEquals("HashSet>", 81 | JavaCodeGenerator.generateTypeDeclaration(SET_LINKED_LIST_INT)); 82 | assertEquals("HashSet>", 83 | JavaCodeGenerator.generateTypeDeclaration(SET_MAP_STRING_INT)); 84 | assertEquals("HashSet>", 85 | JavaCodeGenerator.generateTypeDeclaration(SET_MAP_INT_DOUBLE)); 86 | 87 | assertEquals("LinkedListNode", 88 | JavaCodeGenerator.generateTypeDeclaration(LINKED_LIST_ARRAY_INT)); 89 | assertEquals("LinkedListNode>", 90 | JavaCodeGenerator.generateTypeDeclaration(LINKED_LIST_LIST_INT)); 91 | assertEquals("LinkedListNode>", 92 | JavaCodeGenerator.generateTypeDeclaration(LINKED_LIST_SET_INT)); 93 | assertEquals("LinkedListNode>", 94 | JavaCodeGenerator.generateTypeDeclaration(LINKED_LIST_LINKED_LIST_INT)); 95 | assertEquals("LinkedListNode>", 96 | JavaCodeGenerator.generateTypeDeclaration(LINKED_LIST_MAP_STRING_INT)); 97 | assertEquals("LinkedListNode>", 98 | JavaCodeGenerator.generateTypeDeclaration(LINKED_LIST_MAP_INT_DOUBLE)); 99 | 100 | assertEquals("BinaryTreeNode", 101 | JavaCodeGenerator.generateTypeDeclaration(BINARY_TREE_ARRAY_INT)); 102 | assertEquals("BinaryTreeNode>", 103 | JavaCodeGenerator.generateTypeDeclaration(BINARY_TREE_LIST_INT)); 104 | assertEquals("BinaryTreeNode>", 105 | JavaCodeGenerator.generateTypeDeclaration(BINARY_TREE_SET_INT)); 106 | assertEquals("BinaryTreeNode>", 107 | JavaCodeGenerator.generateTypeDeclaration(BINARY_TREE_LINKED_LIST_INT)); 108 | assertEquals("BinaryTreeNode>", 109 | JavaCodeGenerator.generateTypeDeclaration(BINARY_TREE_MAP_STRING_INT)); 110 | assertEquals("BinaryTreeNode>", 111 | JavaCodeGenerator.generateTypeDeclaration(BINARY_TREE_MAP_INT_DOUBLE)); 112 | 113 | assertEquals("ArrayList>>>[]", 114 | JavaCodeGenerator.generateTypeDeclaration(ARRAY_LIST_SET_MAP_STRING_LINKED_LIST_INT)); 115 | 116 | assertEquals("BinaryTreeNode>>>", 117 | JavaCodeGenerator.generateTypeDeclaration(BINARY_TREE_MAP_STRING_SET_LIST_DOUBLE)); 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /src/test/java/org/algohub/engine/codegenerator/PythonCodeGeneratorTest.java: -------------------------------------------------------------------------------- 1 | package org.algohub.engine.codegenerator; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.algohub.engine.codegenerator.DataTypes.*; 6 | import static org.junit.Assert.assertEquals; 7 | 8 | 9 | @SuppressWarnings({"PMD.CommentRequired"}) 10 | public class PythonCodeGeneratorTest { 11 | 12 | @Test public void generatePythonFunctiontTest() { 13 | final String twoSumExpected = "# @param {int[]} numbers An array of Integers\n" 14 | + "# @param {int} target target = numbers[index1] + numbers[index2]\n" 15 | + "# @return {int[]} [index1 + 1, index2 + 1] (index1 < index2)\n" 16 | + "def twoSum(numbers, target):\n # Write your code here\n"; 17 | final String twoSumGenerated = PythonCodeGenerator.generateEmptyFunction(TWO_SUM); 18 | assertEquals(twoSumExpected, twoSumGenerated); 19 | 20 | final String wordLadderExpected = "# @param {str} begin_word the begin word\n" 21 | + "# @param {str} end_word the end word\n" 22 | + "# @param {set} dict the dictionary\n" + "# @return {int} The shortest length\n" 23 | + "def ladderLength(begin_word, end_word, dict):\n # Write your code here\n"; 24 | final String wordLadderGenerated = PythonCodeGenerator.generateEmptyFunction(WORD_LADDER); 25 | assertEquals(wordLadderExpected, wordLadderGenerated); 26 | } 27 | 28 | @Test public void generateTypeDeclarationTest() { 29 | assertEquals("int[]", PythonCodeGenerator.generateTypeDeclaration(ARRAY_INT)); 30 | assertEquals("int[]", PythonCodeGenerator.generateTypeDeclaration(LIST_INT)); 31 | assertEquals("set", PythonCodeGenerator.generateTypeDeclaration(SET_INT)); 32 | assertEquals("LinkedListNode", 33 | PythonCodeGenerator.generateTypeDeclaration(LINKED_LIST_INT)); 34 | 35 | assertEquals("dict", 36 | PythonCodeGenerator.generateTypeDeclaration(MAP_STRING_INT)); 37 | assertEquals("dict", 38 | PythonCodeGenerator.generateTypeDeclaration(MAP_INT_DOUBLE)); 39 | 40 | assertEquals("BinaryTreeNode", 41 | PythonCodeGenerator.generateTypeDeclaration(BINARY_TREE_INT)); 42 | 43 | assertEquals("int[][]", PythonCodeGenerator.generateTypeDeclaration( 44 | ARRAY_ARRAY_INT)); 45 | assertEquals("int[][]", PythonCodeGenerator.generateTypeDeclaration( 46 | ARRAY_LIST_INT)); 47 | assertEquals("set[]", PythonCodeGenerator.generateTypeDeclaration( 48 | ARRAY_SET_INT)); 49 | assertEquals("LinkedListNode[]", 50 | PythonCodeGenerator.generateTypeDeclaration(ARRAY_LINKED_LIST_INT)); 51 | assertEquals("dict[]", 52 | PythonCodeGenerator.generateTypeDeclaration(ARRAY_MAP_STRING_INT)); 53 | assertEquals("dict[]", 54 | PythonCodeGenerator.generateTypeDeclaration(ARRAY_MAP_INT_DOUBLE)); 55 | 56 | assertEquals("int[][]", PythonCodeGenerator.generateTypeDeclaration( 57 | LIST_ARRAY_INT)); 58 | assertEquals("int[][]", PythonCodeGenerator.generateTypeDeclaration( 59 | LIST_LIST_INT)); 60 | assertEquals("set[]", PythonCodeGenerator.generateTypeDeclaration( 61 | LIST_SET_INT)); 62 | assertEquals("LinkedListNode[]", 63 | PythonCodeGenerator.generateTypeDeclaration(LIST_LINKED_LIST_INT)); 64 | assertEquals("dict[]", 65 | PythonCodeGenerator.generateTypeDeclaration(LIST_MAP_STRING_INT)); 66 | assertEquals("dict[]", 67 | PythonCodeGenerator.generateTypeDeclaration(LIST_MAP_INT_DOUBLE)); 68 | 69 | assertEquals("set", 70 | PythonCodeGenerator.generateTypeDeclaration(SET_ARRAY_INT)); 71 | assertEquals("set", 72 | PythonCodeGenerator.generateTypeDeclaration(SET_LIST_INT)); 73 | assertEquals("set>", 74 | PythonCodeGenerator.generateTypeDeclaration(SET_SET_INT)); 75 | assertEquals("set>", 76 | PythonCodeGenerator.generateTypeDeclaration(SET_LINKED_LIST_INT)); 77 | assertEquals("set>", 78 | PythonCodeGenerator.generateTypeDeclaration(SET_MAP_STRING_INT)); 79 | assertEquals("set>", 80 | PythonCodeGenerator.generateTypeDeclaration(SET_MAP_INT_DOUBLE)); 81 | 82 | assertEquals("LinkedListNode", 83 | PythonCodeGenerator.generateTypeDeclaration(LINKED_LIST_ARRAY_INT)); 84 | assertEquals("LinkedListNode", 85 | PythonCodeGenerator.generateTypeDeclaration(LINKED_LIST_LIST_INT)); 86 | assertEquals("LinkedListNode>", 87 | PythonCodeGenerator.generateTypeDeclaration(LINKED_LIST_SET_INT)); 88 | assertEquals("LinkedListNode>", 89 | PythonCodeGenerator.generateTypeDeclaration(LINKED_LIST_LINKED_LIST_INT)); 90 | assertEquals("LinkedListNode>", 91 | PythonCodeGenerator.generateTypeDeclaration(LINKED_LIST_MAP_STRING_INT)); 92 | assertEquals("LinkedListNode>", 93 | PythonCodeGenerator.generateTypeDeclaration(LINKED_LIST_MAP_INT_DOUBLE)); 94 | 95 | assertEquals("BinaryTreeNode", 96 | PythonCodeGenerator.generateTypeDeclaration(BINARY_TREE_ARRAY_INT)); 97 | assertEquals("BinaryTreeNode", 98 | PythonCodeGenerator.generateTypeDeclaration(BINARY_TREE_LIST_INT)); 99 | assertEquals("BinaryTreeNode>", 100 | PythonCodeGenerator.generateTypeDeclaration(BINARY_TREE_SET_INT)); 101 | assertEquals("BinaryTreeNode>", 102 | PythonCodeGenerator.generateTypeDeclaration(BINARY_TREE_LINKED_LIST_INT)); 103 | assertEquals("BinaryTreeNode>", 104 | PythonCodeGenerator.generateTypeDeclaration(BINARY_TREE_MAP_STRING_INT)); 105 | assertEquals("BinaryTreeNode>", 106 | PythonCodeGenerator.generateTypeDeclaration(BINARY_TREE_MAP_INT_DOUBLE)); 107 | 108 | assertEquals("set>>[][]", 109 | PythonCodeGenerator.generateTypeDeclaration(ARRAY_LIST_SET_MAP_STRING_LINKED_LIST_INT)); 110 | 111 | assertEquals("BinaryTreeNode>>", 112 | PythonCodeGenerator.generateTypeDeclaration(BINARY_TREE_MAP_STRING_SET_LIST_DOUBLE)); 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /src/test/java/org/algohub/engine/codegenerator/RubyCodeGeneratorTest.java: -------------------------------------------------------------------------------- 1 | package org.algohub.engine.codegenerator; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.algohub.engine.codegenerator.DataTypes.*; 6 | import static org.junit.Assert.assertEquals; 7 | 8 | 9 | @SuppressWarnings({"PMD.CommentRequired"}) 10 | public class RubyCodeGeneratorTest { 11 | 12 | @Test public void generateRubyFunctionTest() { 13 | 14 | final String twoSumExpected = "# @param {Fixnum[]} numbers An array of Integers\n" 15 | + "# @param {Fixnum} target target = numbers[index1] + numbers[index2]\n" 16 | + "# @return {Fixnum[]} [index1 + 1, index2 + 1] (index1 < index2)\n" 17 | + "def twoSum(numbers, target)\n" + " # Write your code here\n" + "end"; 18 | final String twoSumGenerated = RubyCodeGenerator.generateEmptyFunction(TWO_SUM); 19 | assertEquals(twoSumExpected, twoSumGenerated); 20 | 21 | final String wordLadderExpected = "# @param {String} begin_word the begin word\n" 22 | + "# @param {String} end_word the end word\n" 23 | + "# @param {Set} dict the dictionary\n" 24 | + "# @return {Fixnum} The shortest length\n" 25 | + "def ladderLength(begin_word, end_word, dict)\n" + " # Write your code here\n" + "end"; 26 | final String wordLadderGenerated = RubyCodeGenerator.generateEmptyFunction(WORD_LADDER); 27 | assertEquals(wordLadderExpected, wordLadderGenerated); 28 | } 29 | 30 | @Test public void generateTypeDeclarationTest() { 31 | assertEquals("Fixnum[]", RubyCodeGenerator.generateTypeDeclaration(ARRAY_INT)); 32 | assertEquals("Fixnum[]", RubyCodeGenerator.generateTypeDeclaration(LIST_INT)); 33 | assertEquals("Set", RubyCodeGenerator.generateTypeDeclaration(SET_INT)); 34 | assertEquals("LinkedListNode", 35 | RubyCodeGenerator.generateTypeDeclaration(LINKED_LIST_INT)); 36 | 37 | assertEquals("Hash", 38 | RubyCodeGenerator.generateTypeDeclaration(MAP_STRING_INT)); 39 | assertEquals("Hash", 40 | RubyCodeGenerator.generateTypeDeclaration(MAP_INT_DOUBLE)); 41 | 42 | assertEquals("BinaryTreeNode", 43 | RubyCodeGenerator.generateTypeDeclaration(BINARY_TREE_INT)); 44 | 45 | assertEquals("Fixnum[][]", RubyCodeGenerator.generateTypeDeclaration( 46 | ARRAY_ARRAY_INT)); 47 | assertEquals("Fixnum[][]", RubyCodeGenerator.generateTypeDeclaration( 48 | ARRAY_LIST_INT)); 49 | assertEquals("Set[]", RubyCodeGenerator.generateTypeDeclaration( 50 | ARRAY_SET_INT)); 51 | assertEquals("LinkedListNode[]", 52 | RubyCodeGenerator.generateTypeDeclaration(ARRAY_LINKED_LIST_INT)); 53 | assertEquals("Hash[]", 54 | RubyCodeGenerator.generateTypeDeclaration(ARRAY_MAP_STRING_INT)); 55 | assertEquals("Hash[]", 56 | RubyCodeGenerator.generateTypeDeclaration(ARRAY_MAP_INT_DOUBLE)); 57 | 58 | assertEquals("Fixnum[][]", RubyCodeGenerator.generateTypeDeclaration( 59 | LIST_ARRAY_INT)); 60 | assertEquals("Fixnum[][]", RubyCodeGenerator.generateTypeDeclaration( 61 | LIST_LIST_INT)); 62 | assertEquals("Set[]", RubyCodeGenerator.generateTypeDeclaration( 63 | LIST_SET_INT)); 64 | assertEquals("LinkedListNode[]", 65 | RubyCodeGenerator.generateTypeDeclaration(LIST_LINKED_LIST_INT)); 66 | assertEquals("Hash[]", 67 | RubyCodeGenerator.generateTypeDeclaration(LIST_MAP_STRING_INT)); 68 | assertEquals("Hash[]", 69 | RubyCodeGenerator.generateTypeDeclaration(LIST_MAP_INT_DOUBLE)); 70 | 71 | assertEquals("Set", 72 | RubyCodeGenerator.generateTypeDeclaration(SET_ARRAY_INT)); 73 | assertEquals("Set", 74 | RubyCodeGenerator.generateTypeDeclaration(SET_LIST_INT)); 75 | assertEquals("Set>", 76 | RubyCodeGenerator.generateTypeDeclaration(SET_SET_INT)); 77 | assertEquals("Set>", 78 | RubyCodeGenerator.generateTypeDeclaration(SET_LINKED_LIST_INT)); 79 | assertEquals("Set>", 80 | RubyCodeGenerator.generateTypeDeclaration(SET_MAP_STRING_INT)); 81 | assertEquals("Set>", 82 | RubyCodeGenerator.generateTypeDeclaration(SET_MAP_INT_DOUBLE)); 83 | 84 | assertEquals("LinkedListNode", 85 | RubyCodeGenerator.generateTypeDeclaration(LINKED_LIST_ARRAY_INT)); 86 | assertEquals("LinkedListNode", 87 | RubyCodeGenerator.generateTypeDeclaration(LINKED_LIST_LIST_INT)); 88 | assertEquals("LinkedListNode>", 89 | RubyCodeGenerator.generateTypeDeclaration(LINKED_LIST_SET_INT)); 90 | assertEquals("LinkedListNode>", 91 | RubyCodeGenerator.generateTypeDeclaration(LINKED_LIST_LINKED_LIST_INT)); 92 | assertEquals("LinkedListNode>", 93 | RubyCodeGenerator.generateTypeDeclaration(LINKED_LIST_MAP_STRING_INT)); 94 | assertEquals("LinkedListNode>", 95 | RubyCodeGenerator.generateTypeDeclaration(LINKED_LIST_MAP_INT_DOUBLE)); 96 | 97 | assertEquals("BinaryTreeNode", 98 | RubyCodeGenerator.generateTypeDeclaration(BINARY_TREE_ARRAY_INT)); 99 | assertEquals("BinaryTreeNode", 100 | RubyCodeGenerator.generateTypeDeclaration(BINARY_TREE_LIST_INT)); 101 | assertEquals("BinaryTreeNode>", 102 | RubyCodeGenerator.generateTypeDeclaration(BINARY_TREE_SET_INT)); 103 | assertEquals("BinaryTreeNode>", 104 | RubyCodeGenerator.generateTypeDeclaration(BINARY_TREE_LINKED_LIST_INT)); 105 | assertEquals("BinaryTreeNode>", 106 | RubyCodeGenerator.generateTypeDeclaration(BINARY_TREE_MAP_STRING_INT)); 107 | assertEquals("BinaryTreeNode>", 108 | RubyCodeGenerator.generateTypeDeclaration(BINARY_TREE_MAP_INT_DOUBLE)); 109 | 110 | assertEquals("Set>>[][]", 111 | RubyCodeGenerator.generateTypeDeclaration(ARRAY_LIST_SET_MAP_STRING_LINKED_LIST_INT)); 112 | 113 | assertEquals("BinaryTreeNode>>", 114 | RubyCodeGenerator.generateTypeDeclaration(BINARY_TREE_MAP_STRING_SET_LIST_DOUBLE)); 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /src/test/java/org/algohub/engine/compiler/java/MemoryJavaCompilerTest.java: -------------------------------------------------------------------------------- 1 | package org.algohub.engine.compiler.java; 2 | 3 | 4 | import org.junit.Test; 5 | 6 | import java.lang.invoke.MethodHandle; 7 | import java.lang.invoke.MethodType; 8 | import java.lang.reflect.Method; 9 | 10 | import static org.junit.Assert.assertEquals; 11 | 12 | @SuppressWarnings({"PMD.CommentRequired"}) 13 | public class MemoryJavaCompilerTest { 14 | 15 | @Test public void compileStaticMethodTest() throws Throwable { 16 | final String source = 17 | "public final class Solution {\n" + "public static String greeting(String name) {\n" 18 | + "\treturn \"Hello \" + name;\n" + "}\n}\n"; 19 | final Method greeting = MemoryJavaCompiler.INSTANCE.compileStaticMethod("greeting", "Solution", source); 20 | final Object result = greeting.invoke(null, "soulmachine"); 21 | assertEquals("Hello soulmachine", result); 22 | 23 | final MethodHandle methodHandle = MemoryJavaCompiler.INSTANCE.compileStaticMethod("Solution", "greeting", 24 | MethodType.methodType(String.class, new Class[] {String.class}), source); 25 | final String result1 = (String) methodHandle.invokeExact("soulmachine"); 26 | assertEquals("Hello soulmachine", result1); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/test/java/org/algohub/engine/judge/CppJudgeTest.java: -------------------------------------------------------------------------------- 1 | package org.algohub.engine.judge; 2 | 3 | import org.algohub.engine.type.LanguageType; 4 | import org.junit.Test; 5 | 6 | @SuppressWarnings({"PMD.CommentRequired"}) 7 | public class CppJudgeTest { 8 | 9 | @Test public void judgeTest() { 10 | JudgeEngineTestUtil.batchJudge(LanguageType.CPLUSPLUS); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /src/test/java/org/algohub/engine/judge/JavaJudgeTest.java: -------------------------------------------------------------------------------- 1 | package org.algohub.engine.judge; 2 | 3 | import org.algohub.engine.type.LanguageType; 4 | import org.junit.Test; 5 | 6 | @SuppressWarnings({"PMD.CommentRequired"}) 7 | public class JavaJudgeTest { 8 | 9 | @Test public void judgeTest() { 10 | JudgeEngineTestUtil.batchJudge(LanguageType.JAVA); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/test/java/org/algohub/engine/judge/JudgeEngineTestUtil.java: -------------------------------------------------------------------------------- 1 | package org.algohub.engine.judge; 2 | 3 | import com.fasterxml.jackson.core.JsonProcessingException; 4 | 5 | import org.algohub.engine.JudgeEngine; 6 | import org.algohub.engine.bo.StatusCode; 7 | import org.algohub.engine.pojo.JudgeResult; 8 | import org.algohub.engine.pojo.Problem; 9 | import org.algohub.engine.type.LanguageType; 10 | import org.algohub.engine.util.ObjectMapperInstance; 11 | 12 | import java.io.File; 13 | import java.io.IOException; 14 | import java.nio.charset.StandardCharsets; 15 | import java.nio.file.Paths; 16 | 17 | import static org.junit.Assert.assertEquals; 18 | import static org.junit.Assert.fail; 19 | 20 | final class JudgeEngineTestUtil { 21 | private static final JudgeEngine JUDGE_ENGINE = new JudgeEngine(); 22 | 23 | static void batchJudge(final LanguageType languageType) { 24 | final File rootDir = new File("src/test/resources/solutions/"); 25 | final File problemDir = new File("src/test/resources/problems/"); 26 | 27 | try { 28 | for (final File solutionDir : rootDir.listFiles()) { 29 | final String problemId = solutionDir.getName(); 30 | final String problemJson = new String(java.nio.file.Files.readAllBytes( 31 | Paths.get(problemDir.getAbsolutePath(), problemId + ".json")), 32 | StandardCharsets.UTF_8); 33 | final Problem problem = ObjectMapperInstance.INSTANCE.readValue(problemJson, Problem.class); 34 | 35 | for (final File solutionFile : solutionDir.listFiles( 36 | (dir, name) -> name.toLowerCase().endsWith("." + languageType.getFileSuffix()))) { 37 | final String userCode = 38 | new String(java.nio.file.Files.readAllBytes(solutionFile.toPath()), 39 | StandardCharsets.UTF_8); 40 | 41 | judgeOne(problem, userCode, languageType); 42 | } 43 | } 44 | } catch (IOException ex) { 45 | fail(ex.getMessage()); 46 | } 47 | } 48 | 49 | static void judgeOne(final Problem problem, final String userCode, 50 | LanguageType languageType) { 51 | final JudgeResult result = JUDGE_ENGINE.judge(problem, userCode, languageType); 52 | if(StatusCode.ACCEPTED != result.getStatusCode()) { 53 | try { 54 | System.err.println(ObjectMapperInstance.INSTANCE.writeValueAsString(result)); 55 | } catch (JsonProcessingException e) { 56 | e.printStackTrace(); 57 | } 58 | } 59 | assertEquals(StatusCode.ACCEPTED, result.getStatusCode()); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/test/java/org/algohub/engine/judge/JudgeOneTest.java: -------------------------------------------------------------------------------- 1 | package org.algohub.engine.judge; 2 | 3 | import java.io.File; 4 | import java.io.IOException; 5 | import java.nio.charset.StandardCharsets; 6 | import java.nio.file.Paths; 7 | import org.algohub.engine.pojo.Problem; 8 | import org.algohub.engine.type.LanguageType; 9 | import org.algohub.engine.util.ObjectMapperInstance; 10 | import org.junit.Test; 11 | 12 | 13 | // for debug only 14 | public class JudgeOneTest { 15 | 16 | // only for debug 17 | @Test 18 | public void judgeOne() { 19 | // judgeOne("partition-list", LanguageType.JAVA); 20 | } 21 | 22 | private static void judgeOne(final String problemId, LanguageType languageType) { 23 | final File solutionDir = new File("src/test/resources/solutions/"); 24 | final File problemDir = new File("src/test/resources/problems/"); 25 | 26 | try { 27 | final String problemJson = new String(java.nio.file.Files.readAllBytes( 28 | Paths.get(problemDir.getAbsolutePath(), problemId + ".json")), 29 | StandardCharsets.UTF_8); 30 | final Problem problem = ObjectMapperInstance.INSTANCE.readValue(problemJson, Problem.class); 31 | final File solutionFile = Paths.get(solutionDir.getAbsolutePath(), problemId).toFile().listFiles( 32 | (dir, name) -> name.toLowerCase().endsWith("." + languageType.getFileSuffix()))[0]; 33 | final String userCode = new String(java.nio.file.Files.readAllBytes(solutionFile.toPath()), 34 | StandardCharsets.UTF_8); 35 | JudgeEngineTestUtil.judgeOne(problem, userCode, languageType); 36 | } catch (IOException e) { 37 | e.printStackTrace(); 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/test/java/org/algohub/engine/judge/PythonJudgeTest.java: -------------------------------------------------------------------------------- 1 | package org.algohub.engine.judge; 2 | 3 | import org.algohub.engine.type.LanguageType; 4 | import org.junit.Test; 5 | 6 | @SuppressWarnings({"PMD.CommentRequired"}) 7 | public class PythonJudgeTest { 8 | 9 | @Test public void judgeTest() { 10 | JudgeEngineTestUtil.batchJudge(LanguageType.PYTHON); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/test/java/org/algohub/engine/judge/RubyJudgeTest.java: -------------------------------------------------------------------------------- 1 | package org.algohub.engine.judge; 2 | 3 | import org.algohub.engine.type.LanguageType; 4 | import org.junit.Test; 5 | 6 | @SuppressWarnings({"PMD.CommentRequired"}) 7 | public class RubyJudgeTest { 8 | @Test public void judgeTest() { 9 | JudgeEngineTestUtil.batchJudge(LanguageType.RUBY); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/test/java/org/algohub/engine/serde/DeserializerTest.java: -------------------------------------------------------------------------------- 1 | package org.algohub.engine.serde; 2 | 3 | import com.fasterxml.jackson.databind.node.BooleanNode; 4 | import com.fasterxml.jackson.databind.node.DoubleNode; 5 | import com.fasterxml.jackson.databind.node.IntNode; 6 | import com.fasterxml.jackson.databind.node.TextNode; 7 | 8 | import java.util.ArrayList; 9 | import org.algohub.engine.collection.LinkedListNode; 10 | import org.algohub.engine.type.TypeNode; 11 | import org.junit.Test; 12 | 13 | import java.util.HashMap; 14 | import java.util.HashSet; 15 | 16 | import static org.algohub.engine.codegenerator.DataTypes.*; 17 | import static org.algohub.engine.serde.SharedData.*; 18 | import static org.junit.Assert.assertArrayEquals; 19 | import static org.junit.Assert.assertEquals; 20 | 21 | 22 | @SuppressWarnings({"PMD.CommentRequired"}) 23 | public class DeserializerTest { 24 | 25 | @Test public void deserializePrimitiveTest() { 26 | assertEquals(Boolean.TRUE, 27 | Deserializer.fromJson(TypeNode.fromString("bool"), BooleanNode.TRUE)); 28 | assertEquals(Boolean.FALSE, 29 | Deserializer.fromJson(TypeNode.fromString("bool"), BooleanNode.FALSE)); 30 | 31 | assertEquals('a', 32 | Deserializer.fromJson(TypeNode.fromString("char"), TextNode.valueOf("a"))); 33 | 34 | assertEquals(Integer.valueOf(123), 35 | Deserializer.fromJson(TypeNode.fromString("int"), IntNode.valueOf(123))); 36 | 37 | assertEquals(Long.valueOf(123), 38 | Deserializer.fromJson(TypeNode.fromString("long"), IntNode.valueOf(123))); 39 | 40 | assertEquals(Double.valueOf(123.0), 41 | Deserializer.fromJson(TypeNode.fromString("double"), DoubleNode.valueOf(123.0))); 42 | 43 | assertEquals("algohub", 44 | Deserializer.fromJson(TypeNode.fromString("string"), TextNode.valueOf("algohub"))); 45 | } 46 | 47 | @Test public void deserializeCollectionTest() { 48 | assertArrayEquals(arrayInt, (int[]) Deserializer.fromJson(ARRAY_INT, arrayIntJson)); 49 | assertEquals(listInt, Deserializer.fromJson(LIST_INT, arrayIntJson)); 50 | assertEquals(setInt, Deserializer.fromJson(SET_INT, arrayIntJson)); 51 | assertEquals(linkedListInt, Deserializer.fromJson(LINKED_LIST_INT, arrayIntJson)); 52 | 53 | // empty linked list 54 | assertEquals(null, Deserializer.fromJson(LINKED_LIST_INT, emptyArrayJson)); 55 | 56 | assertEquals(mapStringInt, Deserializer.fromJson(MAP_STRING_INT, mapStringIntJson)); 57 | assertEquals(mapIntDouble, Deserializer.fromJson(MAP_INT_DOUBLE, mapIntDoubleJson)); 58 | 59 | // empty binary tree 60 | assertEquals(null, Deserializer.fromJson(BINARY_TREE_INT, emptyArrayJson)); 61 | assertEquals(binaryTree, Deserializer.fromJson(BINARY_TREE_INT, binaryTreeJson)); 62 | 63 | final int[][] arrayArrayIntActual = (int[][]) Deserializer.fromJson( 64 | ARRAY_ARRAY_INT, arrayArrayIntJson); 65 | assertArrayEquals(arrayArrayInt[0], arrayArrayIntActual[0]); 66 | assertArrayEquals(arrayArrayInt[1], arrayArrayIntActual[1]); 67 | 68 | final ArrayList> listListIntActual = 69 | (ArrayList>) Deserializer.fromJson(LIST_LIST_INT, arrayArrayIntJson); 70 | assertEquals(listListInt, listListIntActual); 71 | 72 | final LinkedListNode> linkedListLinkedListIntActual = 73 | (LinkedListNode) Deserializer.fromJson(LINKED_LIST_LINKED_LIST_INT, arrayArrayIntJson); 74 | assertEquals(linkedListLinkedListInt, linkedListLinkedListIntActual); 75 | 76 | final LinkedListNode[] arrayLinkedListIntActual = (LinkedListNode[]) Deserializer 77 | .fromJson(ARRAY_LINKED_LIST_INT, arrayArrayIntJson); 78 | assertArrayEquals(arrayLinkedListInt, arrayLinkedListIntActual); 79 | 80 | final HashSet> setLinkedListIntActual = (HashSet) Deserializer.fromJson( 81 | SET_LINKED_LIST_INT, arrayArrayIntJson); 82 | assertEquals(setLinkedListInt, setLinkedListIntActual); 83 | 84 | final HashMap> mapStringLinkedListIntActual = 85 | (HashMap>) Deserializer.fromJson( 86 | MAP_STRING_LINKED_LIST_INT, mapStringLinkedListIntJson); 87 | assertEquals(mapStringLinkedListInt, mapStringLinkedListIntActual); 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /src/test/java/org/algohub/engine/serde/SerializerTest.java: -------------------------------------------------------------------------------- 1 | package org.algohub.engine.serde; 2 | 3 | import com.fasterxml.jackson.databind.node.BooleanNode; 4 | import com.fasterxml.jackson.databind.node.DoubleNode; 5 | import com.fasterxml.jackson.databind.node.IntNode; 6 | import com.fasterxml.jackson.databind.node.LongNode; 7 | import com.fasterxml.jackson.databind.node.ObjectNode; 8 | import com.fasterxml.jackson.databind.node.TextNode; 9 | 10 | import org.algohub.engine.type.TypeNode; 11 | import org.junit.Test; 12 | 13 | import static org.algohub.engine.codegenerator.DataTypes.*; 14 | import static org.algohub.engine.serde.SharedData.*; 15 | import static org.junit.Assert.assertEquals; 16 | 17 | 18 | @SuppressWarnings({"PMD.CommentRequired"}) 19 | public class SerializerTest { 20 | 21 | @Test public void primitiveToJsonTest() { 22 | assertEquals(BooleanNode.TRUE, Serializer.toJson(true, TypeNode.fromString("bool"))); 23 | assertEquals(BooleanNode.FALSE, Serializer.toJson(false, TypeNode.fromString("bool"))); 24 | 25 | assertEquals(TextNode.valueOf("a"), 26 | Serializer.toJson('a', TypeNode.fromString("char"))); 27 | 28 | assertEquals(IntNode.valueOf(123), Serializer.toJson(123, TypeNode.fromString("int"))); 29 | 30 | assertEquals(LongNode.valueOf(123), Serializer.toJson(123L, TypeNode.fromString("long"))); 31 | 32 | assertEquals(DoubleNode.valueOf(123.0), 33 | Serializer.toJson(123.0, TypeNode.fromString("double"))); 34 | 35 | assertEquals(TextNode.valueOf("123"), 36 | Serializer.toJson("123", TypeNode.fromString("string"))); 37 | } 38 | 39 | @Test public void collectionToJsonTest() { 40 | assertEquals(arrayIntJson, Serializer.toJson(arrayInt, ARRAY_INT)); 41 | assertEquals(arrayIntJson, Serializer.toJson(listInt, LIST_INT)); 42 | assertEquals(arrayIntJson, Serializer.toJson(setInt, SET_INT)); 43 | assertEquals(arrayIntJson, Serializer.toJson(linkedListInt, LINKED_LIST_INT)); 44 | // empty linked list 45 | assertEquals(emptyArrayJson, Serializer.toJson(null, LINKED_LIST_INT)); 46 | 47 | final ObjectNode mapStringIntActual = 48 | (ObjectNode) Serializer.toJson(mapStringInt, MAP_STRING_INT); 49 | assertEquals(mapStringIntJson, mapStringIntActual); 50 | final ObjectNode mapIntDoubleActual = 51 | (ObjectNode) Serializer.toJson(mapIntDouble, MAP_INT_DOUBLE); 52 | assertEquals(mapIntDoubleJson, mapIntDoubleActual); 53 | 54 | // empty binary tree 55 | assertEquals(emptyArrayJson, Serializer.toJson(null, BINARY_TREE_INT)); 56 | assertEquals(binaryTreeJson, Serializer.toJson(binaryTree, BINARY_TREE_INT)); 57 | 58 | assertEquals(arrayArrayIntJson, Serializer.toJson(arrayArrayInt, ARRAY_ARRAY_INT)); 59 | assertEquals(arrayArrayIntJson, Serializer.toJson(listListInt, LIST_LIST_INT)); 60 | assertEquals(arrayArrayIntJson, Serializer.toJson(linkedListLinkedListInt, 61 | LINKED_LIST_LINKED_LIST_INT)); 62 | assertEquals(arrayArrayIntJson, Serializer.toJson(arrayLinkedListInt, ARRAY_LINKED_LIST_INT)); 63 | assertEquals(arrayArrayIntJson, Serializer.toJson(setLinkedListInt, SET_LINKED_LIST_INT)); 64 | 65 | final ObjectNode mapStringLinkedListJsonActual = (ObjectNode) Serializer.toJson( 66 | mapStringLinkedListInt, MAP_STRING_LINKED_LIST_INT); 67 | assertEquals(mapStringLinkedListIntJson, mapStringLinkedListJsonActual); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/test/java/org/algohub/engine/serde/SharedData.java: -------------------------------------------------------------------------------- 1 | package org.algohub.engine.serde; 2 | 3 | import com.fasterxml.jackson.databind.node.ArrayNode; 4 | import com.fasterxml.jackson.databind.node.DoubleNode; 5 | import com.fasterxml.jackson.databind.node.IntNode; 6 | import com.fasterxml.jackson.databind.node.NullNode; 7 | import com.fasterxml.jackson.databind.node.ObjectNode; 8 | import java.util.ArrayList; 9 | import java.util.Arrays; 10 | import java.util.HashMap; 11 | import java.util.HashSet; 12 | import org.algohub.engine.collection.BinaryTreeNode; 13 | import org.algohub.engine.collection.LinkedListNode; 14 | import org.algohub.engine.util.ObjectMapperInstance; 15 | 16 | final class SharedData { 17 | static final ArrayNode arrayIntJson = ObjectMapperInstance.INSTANCE.createArrayNode(); 18 | static final int[] arrayInt = {1, 2, 3, 4, 5}; 19 | static final ArrayList listInt = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5)); 20 | static final HashSet setInt = new HashSet<>(Arrays.asList(1, 2, 3, 4, 5)); 21 | static final LinkedListNode linkedListInt = new LinkedListNode<>(1, 22 | new LinkedListNode<>(2, 23 | new LinkedListNode<>(3, 24 | new LinkedListNode<>(4, 25 | new LinkedListNode<>(5))))); 26 | 27 | static final HashMap mapStringInt = new HashMap<>(); 28 | static final ObjectNode mapStringIntJson = ObjectMapperInstance.INSTANCE.createObjectNode(); 29 | 30 | static final HashMap mapIntDouble = new HashMap<>(); 31 | static final ObjectNode mapIntDoubleJson = ObjectMapperInstance.INSTANCE.createObjectNode(); 32 | 33 | static final BinaryTreeNode binaryTree = new BinaryTreeNode<>(2); 34 | static final ArrayNode binaryTreeJson = ObjectMapperInstance.INSTANCE.createArrayNode(); 35 | 36 | private static final ArrayNode arrayIntJson2 = ObjectMapperInstance.INSTANCE.createArrayNode(); 37 | private static final int[] arrayInt2 = {6, 7, 8, 9, 10}; 38 | private static final ArrayList listInt2 = new ArrayList<>(Arrays.asList(6, 7, 8, 9, 10)); 39 | private static final LinkedListNode linkedListInt2 = new LinkedListNode<>(6, 40 | new LinkedListNode<>(7, 41 | new LinkedListNode<>(8, 42 | new LinkedListNode<>(9, 43 | new LinkedListNode<>(10))))); 44 | 45 | static final ArrayNode arrayArrayIntJson = ObjectMapperInstance.INSTANCE.createArrayNode(); 46 | static final int[][] arrayArrayInt = new int[][] {arrayInt, arrayInt2}; 47 | static final ArrayList> listListInt = new ArrayList<>(); 48 | static final LinkedListNode> linkedListLinkedListInt = 49 | new LinkedListNode<>(linkedListInt, new LinkedListNode<>(linkedListInt2)); 50 | static final LinkedListNode[] arrayLinkedListInt = 51 | new LinkedListNode[] {linkedListInt, linkedListInt2}; 52 | static final HashSet> setLinkedListInt = 53 | new HashSet<>(Arrays.asList(linkedListInt, linkedListInt2)); 54 | 55 | static final HashMap> mapStringLinkedListInt = new HashMap<>(); 56 | static final ObjectNode mapStringLinkedListIntJson = 57 | ObjectMapperInstance.INSTANCE.createObjectNode(); 58 | 59 | // for empty linked list and empty binary tree 60 | static final ArrayNode emptyArrayJson = ObjectMapperInstance.INSTANCE.createArrayNode(); 61 | 62 | 63 | 64 | static { 65 | arrayIntJson.addAll(Arrays.asList(IntNode.valueOf(1), IntNode.valueOf(2), IntNode.valueOf(3), 66 | IntNode.valueOf(4), IntNode.valueOf(5))); 67 | arrayIntJson2.addAll(Arrays.asList(IntNode.valueOf(6), IntNode.valueOf(7), IntNode.valueOf(8), 68 | IntNode.valueOf(9), IntNode.valueOf(10))); 69 | 70 | mapStringInt.put("hello", 1); 71 | mapStringInt.put("world", 2); 72 | mapStringIntJson.set("hello", IntNode.valueOf(1)); 73 | mapStringIntJson.set("world", IntNode.valueOf(2)); 74 | 75 | mapIntDouble.put(1, 1.0); 76 | mapIntDouble.put(2, 2.0); 77 | mapIntDoubleJson.set("1", DoubleNode.valueOf(1.0)); 78 | mapIntDoubleJson.set("2", DoubleNode.valueOf(2.0)); 79 | 80 | binaryTree.left = new BinaryTreeNode<>(1); 81 | binaryTree.right = new BinaryTreeNode<>(10); 82 | binaryTree.left.leftIsNull = true; 83 | binaryTree.left.rightIsNull = true; 84 | binaryTree.right.left = new BinaryTreeNode<>(5); 85 | binaryTreeJson.addAll(Arrays.asList(IntNode.valueOf(2), IntNode.valueOf(1), IntNode.valueOf(10), 86 | NullNode.getInstance(), NullNode.getInstance(), IntNode.valueOf(5))); 87 | 88 | arrayArrayIntJson.add(arrayIntJson); 89 | arrayArrayIntJson.add(arrayIntJson2); 90 | listListInt.add(listInt); 91 | listListInt.add(listInt2); 92 | 93 | mapStringLinkedListInt.put("hello", linkedListInt); 94 | mapStringLinkedListInt.put("world", linkedListInt2); 95 | mapStringLinkedListIntJson.set("hello", arrayIntJson); 96 | mapStringLinkedListIntJson.set("world", arrayIntJson2); 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /src/test/java/org/algohub/engine/type/TypeNodeTest.java: -------------------------------------------------------------------------------- 1 | package org.algohub.engine.type; 2 | 3 | import com.fasterxml.jackson.core.JsonProcessingException; 4 | import org.algohub.engine.util.ObjectMapperInstance; 5 | import org.junit.Test; 6 | 7 | import static org.junit.Assert.assertEquals; 8 | import static org.junit.Assert.assertFalse; 9 | import static org.junit.Assert.assertTrue; 10 | 11 | @SuppressWarnings({"PMD.CommentRequired"}) 12 | public class TypeNodeTest { 13 | 14 | @Test public void checkAngleBracketsTest() { 15 | assertFalse(TypeNode.checkAngleBrackets("<")); 16 | assertTrue(TypeNode.checkAngleBrackets("<>")); 17 | assertFalse(TypeNode.checkAngleBrackets("><")); 18 | assertFalse(TypeNode.checkAngleBrackets("")); 19 | assertTrue(TypeNode.checkAngleBrackets("")); 20 | } 21 | 22 | @Test public void findRightBracketTest() { 23 | assertEquals(10, TypeNode.findRightBracket("vector", 6)); 24 | assertEquals(22, TypeNode.findRightBracket("map>", 3)); 25 | assertEquals(21, TypeNode.findRightBracket("map>", 17)); 26 | } 27 | 28 | @Test public void fromStringTest() { 29 | final TypeNode node1 = TypeNode.fromString("int"); 30 | assertEquals(IntermediateType.INT, node1.getValue()); 31 | assertFalse(node1.getElementType().isPresent()); 32 | assertFalse(node1.getKeyType().isPresent()); 33 | assertFalse(node1.getParent().isPresent()); 34 | assertEquals("int", node1.toString()); 35 | 36 | final TypeNode node2 = TypeNode.fromString("list"); 37 | assertEquals(IntermediateType.LIST, node2.getValue()); 38 | assertTrue(node2.getElementType().isPresent()); 39 | assertFalse(node2.getKeyType().isPresent()); 40 | assertFalse(node2.getParent().isPresent()); 41 | assertEquals("list", node2.toString()); 42 | 43 | final TypeNode node2Child = node2.getElementType().get(); 44 | assertEquals(IntermediateType.INT, node2Child.getValue()); 45 | assertFalse(node2Child.getElementType().isPresent()); 46 | assertFalse(node2Child.getKeyType().isPresent()); 47 | assertTrue(node2Child.getParent().isPresent()); 48 | assertEquals(IntermediateType.LIST, node2Child.getParent().get().getValue()); 49 | 50 | final TypeNode mapNode = TypeNode.fromString("map>"); 51 | assertEquals(IntermediateType.MAP, mapNode.getValue()); 52 | assertTrue(mapNode.getElementType().isPresent()); 53 | assertTrue(mapNode.getKeyType().isPresent()); 54 | assertEquals(IntermediateType.STRING, mapNode.getKeyType().get().getValue()); 55 | assertEquals(IntermediateType.LIST, mapNode.getElementType().get().getValue()); 56 | assertEquals(IntermediateType.INT, 57 | mapNode.getElementType().get().getElementType().get().getValue()); 58 | assertEquals("map>", mapNode.toString()); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/test/resources/problems/word-ladder.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": { 3 | "de": "", 4 | "en": "Word Ladder", 5 | "es": "", 6 | "fr": "", 7 | "ja": "", 8 | "pt-BR": "", 9 | "ru": "", 10 | "zh-CN": "" 11 | }, 12 | "description": { 13 | "en": "Given two words (start and end), and a dictionary, find the length of shortest transformation sequence from start to end, such that:\n\n1. Only one letter can be changed at a time\n2. Each intermediate word must exist in the dictionary" 14 | }, 15 | "category": "algorithm", 16 | "tags": [ 17 | "BFS" 18 | ], 19 | "difficulty": 4, 20 | "time_limit": 10, 21 | "memory_limit": 32, 22 | "related_problems": [ 23 | "word-ladder-ii" 24 | ], 25 | "function": { 26 | "name": "ladderLength", 27 | "return": { 28 | "type": "int", 29 | "comment": "The shortest length" 30 | }, 31 | "parameters": [ 32 | { 33 | "name": "begin", 34 | "type": "string", 35 | "comment": "the begin word" 36 | }, 37 | { 38 | "name": "end", 39 | "type": "string", 40 | "comment": "the end word" 41 | }, 42 | { 43 | "name": "dict", 44 | "type": "set", 45 | "comment": "the dictionary" 46 | } 47 | ] 48 | }, 49 | "author": { 50 | "name": "soulmachine", 51 | "email": "soulmachine@gmail.com", 52 | "website": "http://www.soulmachine.me", 53 | "github": "https://github.com/soulmachine", 54 | "facebook": "https://www.facebook.com/soulmachine", 55 | "linkedin": "http://www.linkedin.com/in/soulmachine", 56 | "twitter": "https://twitter.com/soulmachine" 57 | }, 58 | "test_cases": [ 59 | {"input": ["a", "c", ["a","b","c"]], "output": 2}, 60 | {"input": ["hot", "dog", ["hot","cog","dog","tot","hog","hop","pot","dot"]], "output": 3}, 61 | {"input": ["game", "thee", ["frye","heat","tree","thee","game","free","hell","fame","faye"]], "output": 7}, 62 | {"input": ["kiss", "tusk", ["miss","dusk","kiss","musk","tusk","diss","disk","sang","ties","muss"]], "output": 5}, 63 | {"input": ["teach", "place", ["peale","wilts","place","fetch","purer","pooch","peace","poach","berra","teach","rheum","peach"]], "output": 4}, 64 | {"input": ["ta", "if", ["ts","sc","ph","ca","jr","hf","to","if","ha","is","io","cf","ta"]], "output": 4}, 65 | {"input": ["qa", "sq", ["si","go","se","cm","so","ph","mt","db","mb","sb","kr","ln","tm","le","av","sm","ar","ci","ca","br","ti","ba","to","ra","fa","yo","ow","sn","ya","cr","po","fe","ho","ma","re","or","rn","au","ur","rh","sr","tc","lt","lo","as","fr","nb","yb","if","pb","ge","th","pm","rb","sh","co","ga","li","ha","hz","no","bi","di","hi","qa","pi","os","uh","wm","an","me","mo","na","la","st","er","sc","ne","mn","mi","am","ex","pt","io","be","fm","ta","tb","ni","mr","pa","he","lr","sq","ye"]], "output": 5}, 66 | {"input": ["cet", "ism", ["kid","tag","pup","ail","tun","woo","erg","luz","brr","gay","sip","kay","per","val","mes","ohs","now","boa","cet","pal","bar","die","war","hay","eco","pub","lob","rue","fry","lit","rex","jan","cot","bid","ali","pay","col","gum","ger","row","won","dan","rum","fad","tut","sag","yip","sui","ark","has","zip","fez","own","ump","dis","ads","max","jaw","out","btu","ana","gap","cry","led","abe","box","ore","pig","fie","toy","fat","cal","lie","noh","sew","ono","tam","flu","mgm","ply","awe","pry","tit","tie","yet","too","tax","jim","san","pan","map","ski","ova","wed","non","wac","nut","why","bye","lye","oct","old","fin","feb","chi","sap","owl","log","tod","dot","bow","fob","for","joe","ivy","fan","age","fax","hip","jib","mel","hus","sob","ifs","tab","ara","dab","jag","jar","arm","lot","tom","sax","tex","yum","pei","wen","wry","ire","irk","far","mew","wit","doe","gas","rte","ian","pot","ask","wag","hag","amy","nag","ron","soy","gin","don","tug","fay","vic","boo","nam","ave","buy","sop","but","orb","fen","paw","his","sub","bob","yea","oft","inn","rod","yam","pew","web","hod","hun","gyp","wei","wis","rob","gad","pie","mon","dog","bib","rub","ere","dig","era","cat","fox","bee","mod","day","apr","vie","nev","jam","pam","new","aye","ani","and","ibm","yap","can","pyx","tar","kin","fog","hum","pip","cup","dye","lyx","jog","nun","par","wan","fey","bus","oak","bad","ats","set","qom","vat","eat","pus","rev","axe","ion","six","ila","lao","mom","mas","pro","few","opt","poe","art","ash","oar","cap","lop","may","shy","rid","bat","sum","rim","fee","bmw","sky","maj","hue","thy","ava","rap","den","fla","auk","cox","ibo","hey","saw","vim","sec","ltd","you","its","tat","dew","eva","tog","ram","let","see","zit","maw","nix","ate","gig","rep","owe","ind","hog","eve","sam","zoo","any","dow","cod","bed","vet","ham","sis","hex","via","fir","nod","mao","aug","mum","hoe","bah","hal","keg","hew","zed","tow","gog","ass","dem","who","bet","gos","son","ear","spy","kit","boy","due","sen","oaf","mix","hep","fur","ada","bin","nil","mia","ewe","hit","fix","sad","rib","eye","hop","haw","wax","mid","tad","ken","wad","rye","pap","bog","gut","ito","woe","our","ado","sin","mad","ray","hon","roy","dip","hen","iva","lug","asp","hui","yak","bay","poi","yep","bun","try","lad","elm","nat","wyo","gym","dug","toe","dee","wig","sly","rip","geo","cog","pas","zen","odd","nan","lay","pod","fit","hem","joy","bum","rio","yon","dec","leg","put","sue","dim","pet","yaw","nub","bit","bur","sid","sun","oil","red","doc","moe","caw","eel","dix","cub","end","gem","off","yew","hug","pop","tub","sgt","lid","pun","ton","sol","din","yup","jab","pea","bug","gag","mil","jig","hub","low","did","tin","get","gte","sox","lei","mig","fig","lon","use","ban","flo","nov","jut","bag","mir","sty","lap","two","ins","con","ant","net","tux","ode","stu","mug","cad","nap","gun","fop","tot","sow","sal","sic","ted","wot","del","imp","cob","way","ann","tan","mci","job","wet","ism","err","him","all","pad","hah","hie","aim","ike","jed","ego","mac","baa","min","com","ill","was","cab","ago","ina","big","ilk","gal","tap","duh","ola","ran","lab","top","gob","hot","ora","tia","kip","han","met","hut","she","sac","fed","goo","tee","ell","not","act","gil","rut","ala","ape","rig","cid","god","duo","lin","aid","gel","awl","lag","elf","liz","ref","aha","fib","oho","tho","her","nor","ace","adz","fun","ned","coo","win","tao","coy","van","man","pit","guy","foe","hid","mai","sup","jay","hob","mow","jot","are","pol","arc","lax","aft","alb","len","air","pug","pox","vow","got","meg","zoe","amp","ale","bud","gee","pin","dun","pat","ten","mob"]], "output": 11} 67 | ] 68 | } 69 | -------------------------------------------------------------------------------- /src/test/resources/solutions/2sum/TwoSum.java: -------------------------------------------------------------------------------- 1 | public class TwoSum { 2 | public int[] twoSum(int[] numbers, int target) { 3 | HashMap map = new HashMap(); 4 | int[] result = new int[2]; 5 | 6 | for (int i = 0; i < numbers.length; i++) { 7 | if (map.containsKey(numbers[i])) { 8 | int index = map.get(numbers[i]); 9 | result[0] = index + 1; 10 | result[1] = i + 1; 11 | break; 12 | } else { 13 | map.put(target - numbers[i], i); 14 | } 15 | } 16 | 17 | return result; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/test/resources/solutions/2sum/solution.py: -------------------------------------------------------------------------------- 1 | def twoSum(num, target): 2 | d = {} 3 | for i in range(len(num)): 4 | d.setdefault(num[i], []).append(i+1) 5 | for x in d: 6 | rest = target - x 7 | if rest == x: 8 | if len(d[x]) >= 2: 9 | return [min(d[x]), max(d[x])] 10 | else: 11 | if rest in d: 12 | return [min(d[x][0], d[rest][0]), max(d[x][0], d[rest][0])] 13 | -------------------------------------------------------------------------------- /src/test/resources/solutions/2sum/solution.rb: -------------------------------------------------------------------------------- 1 | # return a array, [index1, index2] 2 | def twoSum(numbers, target) 3 | # brute_force(numbers, target) 4 | hash_table(numbers, target).sort 5 | end 6 | 7 | def brute_force(numbers, target) 8 | [].tap do |result| 9 | numbers.each_with_index do |n, i| 10 | numbers[i+1..-1].each_with_index do |m, j| 11 | result << i + 1 << i + 1 + j + 1 if target - n == m 12 | end 13 | end 14 | end 15 | end 16 | 17 | def hash_table(numbers, target) 18 | [].tap do |result| 19 | hash = {} 20 | numbers.each_with_index do |n, i| 21 | if j = hash[target - n] 22 | return result << j + 1 << i + 1 23 | end 24 | hash[n] = i 25 | end 26 | end 27 | end 28 | 29 | -------------------------------------------------------------------------------- /src/test/resources/solutions/2sum/two_sum.cpp: -------------------------------------------------------------------------------- 1 | vector twoSum(vector &num, int target) { 2 | unordered_map mapping; 3 | vector result; 4 | for (int i = 0; i < num.size(); i++) { 5 | mapping[num[i]] = i; 6 | } 7 | for (int i = 0; i < num.size(); i++) { 8 | const int gap = target - num[i]; 9 | if (mapping.find(gap) != mapping.end() && mapping[gap] > i) { 10 | result.push_back(i + 1); 11 | result.push_back(mapping[gap] + 1); 12 | break; 13 | } 14 | } 15 | return result; 16 | } 17 | -------------------------------------------------------------------------------- /src/test/resources/solutions/add-two-numbers/Solution.java: -------------------------------------------------------------------------------- 1 | public class Solution { 2 | public LinkedListNode addTwoNumbers(LinkedListNode l1, LinkedListNode l2) { 3 | LinkedListNode dummy = new LinkedListNode(-1); // 头节点 4 | int carry = 0; 5 | LinkedListNode prev = dummy; 6 | for (LinkedListNode pa = l1, pb = l2; 7 | pa != null || pb != null; 8 | pa = pa == null ? null : pa.next, 9 | pb = pb == null ? null : pb.next, 10 | prev = prev.next) { 11 | final int ai = pa == null ? 0 : pa.value; 12 | final int bi = pb == null ? 0 : pb.value; 13 | final int value = (ai + bi + carry) % 10; 14 | carry = (ai + bi + carry) / 10; 15 | prev.next = new LinkedListNode(value); // 尾插法 16 | } 17 | if (carry > 0) 18 | prev.next = new LinkedListNode(carry); 19 | return dummy.next; 20 | } 21 | }; 22 | 23 | -------------------------------------------------------------------------------- /src/test/resources/solutions/add-two-numbers/solution.cpp: -------------------------------------------------------------------------------- 1 | shared_ptr> addTwoNumbers(shared_ptr> l1, shared_ptr> l2) { 2 | auto dummy = make_shared>(-1); // 头节点 3 | int carry = 0; 4 | auto prev = dummy; 5 | for (auto pa = l1, pb = l2; 6 | pa != nullptr || pb != nullptr; 7 | pa = pa == nullptr ? nullptr : pa->next, 8 | pb = pb == nullptr ? nullptr : pb->next, 9 | prev = prev->next) { 10 | const int ai = pa == nullptr ? 0 : pa->value; 11 | const int bi = pb == nullptr ? 0 : pb->value; 12 | const int value = (ai + bi + carry) % 10; 13 | carry = (ai + bi + carry) / 10; 14 | prev->next = make_shared>(value); // 尾插法 15 | } 16 | if (carry > 0) 17 | prev->next = make_shared>(carry); 18 | return dummy->next; 19 | } 20 | 21 | -------------------------------------------------------------------------------- /src/test/resources/solutions/add-two-numbers/solution.py: -------------------------------------------------------------------------------- 1 | def addTwoNumbers(l1, l2): 2 | carry = 0 3 | root = n = LinkedListNode(0) 4 | while l1 or l2 or carry: 5 | v1 = v2 = 0 6 | if l1: 7 | v1 = l1.value 8 | l1 = l1.next 9 | if l2: 10 | v2 = l2.value 11 | l2 = l2.next 12 | carry, value = divmod(v1+v2+carry, 10) 13 | n.next = LinkedListNode(value) 14 | n = n.next 15 | return root.next 16 | 17 | -------------------------------------------------------------------------------- /src/test/resources/solutions/add-two-numbers/solution.rb: -------------------------------------------------------------------------------- 1 | def addTwoNumbers(l1, l2) 2 | list = LinkedListNode.new(0) 3 | feed = 0 4 | pin = list 5 | until l1.nil? && l2.nil? && feed == 0 6 | if l1.nil? 7 | v1 = 0 8 | else 9 | v1 = l1.value 10 | end 11 | 12 | if l2.nil? 13 | v2 = 0 14 | else 15 | v2 = l2.value 16 | end 17 | 18 | list.value = v1 + v2 + feed 19 | feed = 0 20 | if list.value >= 10 21 | list.value = list.value - 10 22 | feed = 1 23 | end 24 | unless l1.nil? 25 | l1 = l1.next 26 | end 27 | 28 | unless l2.nil? 29 | l2 = l2.next 30 | end 31 | unless l1.nil? && l2.nil? && feed == 0 32 | list.next = LinkedListNode.new(0) 33 | list = list.next 34 | end 35 | end 36 | pin 37 | end 38 | 39 | -------------------------------------------------------------------------------- /src/test/resources/solutions/remove-duplicates-from-sorted-list/Solution.java: -------------------------------------------------------------------------------- 1 | public class Solution { 2 | public LinkedListNode deleteDuplicates(LinkedListNode head) { 3 | if (head == null) return null; 4 | 5 | for (LinkedListNode prev = head, cur = head.next; cur != null; cur = prev.next) { 6 | if (prev.value == cur.value) { 7 | prev.next = cur.next; 8 | } else { 9 | prev = cur; 10 | } 11 | } 12 | return head; 13 | } 14 | }; 15 | 16 | -------------------------------------------------------------------------------- /src/test/resources/solutions/remove-duplicates-from-sorted-list/solution.cpp: -------------------------------------------------------------------------------- 1 | shared_ptr> deleteDuplicates(shared_ptr> head) { 2 | if (head == nullptr) return nullptr; 3 | 4 | for (shared_ptr> prev = head, cur = head->next; cur != nullptr; cur = prev->next) { 5 | if (prev->value == cur->value) { 6 | prev->next = cur->next; 7 | } else { 8 | prev = cur; 9 | } 10 | } 11 | return head; 12 | } 13 | 14 | -------------------------------------------------------------------------------- /src/test/resources/solutions/remove-duplicates-from-sorted-list/solution.py: -------------------------------------------------------------------------------- 1 | def deleteDuplicates(head): 2 | if head == None: 3 | return None 4 | node1 = head 5 | while node1.next != None: 6 | node2 = node1.next 7 | if node2.value == node1.value: 8 | node1.next = node2.next 9 | else: 10 | node1 = node1.next 11 | return head 12 | 13 | -------------------------------------------------------------------------------- /src/test/resources/solutions/remove-duplicates-from-sorted-list/solution.rb: -------------------------------------------------------------------------------- 1 | def deleteDuplicates(head) 2 | return head if head.nil? || head.next.nil? 3 | prev = head 4 | current = head.next 5 | 6 | until current.nil? 7 | if current.value == prev.value 8 | prev.next = current.next 9 | else 10 | prev = prev.next 11 | end 12 | current = current.next 13 | end 14 | head 15 | end 16 | 17 | -------------------------------------------------------------------------------- /src/test/resources/solutions/reverse-linked-list/Solution.java: -------------------------------------------------------------------------------- 1 | public class Solution { 2 | public LinkedListNode reverseLinkedList(LinkedListNode head) { 3 | if (head == null || head.next == null) return head; 4 | 5 | LinkedListNode tail = null; 6 | LinkedListNode p = head; 7 | LinkedListNode q = p.next; 8 | 9 | while (q != null) { 10 | LinkedListNode old = q.next; 11 | p.next = tail; 12 | q.next = p; 13 | 14 | tail = p; 15 | p = q; 16 | q = old; 17 | } 18 | return p; 19 | } 20 | } 21 | 22 | -------------------------------------------------------------------------------- /src/test/resources/solutions/reverse-linked-list/solution.cpp: -------------------------------------------------------------------------------- 1 | std::shared_ptr> reverseLinkedList(std::shared_ptr> head) { 2 | if (!head || !(head -> next)) return head; 3 | std::shared_ptr> node = reverseLinkedList(head -> next); 4 | head -> next -> next = head; 5 | head -> next = NULL; 6 | return node; 7 | } 8 | 9 | -------------------------------------------------------------------------------- /src/test/resources/solutions/reverse-linked-list/solution.py: -------------------------------------------------------------------------------- 1 | def reverseLinkedList(head): 2 | prev = None 3 | while head: 4 | curr = head 5 | head = head.next 6 | curr.next = prev 7 | prev = curr 8 | return prev 9 | 10 | -------------------------------------------------------------------------------- /src/test/resources/solutions/reverse-linked-list/solution.rb: -------------------------------------------------------------------------------- 1 | def reverseLinkedList(head) 2 | # no node or only one node 3 | return head if head.nil? || head.next.nil? 4 | 5 | current_n = head 6 | prev_n = nil 7 | next_n = current_n.next 8 | 9 | # only two node 10 | if current_n.next.next.nil? 11 | current_n.next.next = current_n 12 | current_n = current_n.next 13 | current_n.next.next = nil 14 | return current_n 15 | end 16 | 17 | # more than two node 18 | while !current_n.next.nil? 19 | current_n.next = prev_n 20 | prev_n = current_n 21 | current_n = next_n 22 | next_n = next_n.next 23 | end 24 | 25 | current_n.next=prev_n 26 | return current_n 27 | 28 | end 29 | 30 | -------------------------------------------------------------------------------- /src/test/resources/solutions/stoi/Solution.java: -------------------------------------------------------------------------------- 1 | public class Solution { 2 | public int myStoi(final String str) { 3 | int num = 0; 4 | int sign = 1; 5 | final int n = str.length(); 6 | if (n == 0) return 0; 7 | 8 | int i = 0; 9 | while (i < n && str.charAt(i) == ' ') i++; 10 | 11 | if (str.charAt(i) == '+') { 12 | i++; 13 | } else if (str.charAt(i) == '-') { 14 | sign = -1; 15 | i++; 16 | } 17 | 18 | for (; i < n; i++) { 19 | if (str.charAt(i) < '0' || str.charAt(i) > '9') 20 | break; 21 | if (num > Integer.MAX_VALUE / 10 || 22 | (num == Integer.MAX_VALUE / 10 && 23 | (str.charAt(i) - '0') > Integer.MAX_VALUE % 10)) { 24 | return sign == -1 ? Integer.MIN_VALUE : Integer.MAX_VALUE; 25 | } 26 | num = num * 10 + str.charAt(i) - '0'; 27 | } 28 | return num * sign; 29 | } 30 | } 31 | 32 | -------------------------------------------------------------------------------- /src/test/resources/solutions/stoi/solution.cpp: -------------------------------------------------------------------------------- 1 | int myStoi(const string &str) { 2 | int num = 0; 3 | int sign = 1; 4 | const int n = str.length(); 5 | if (n == 0) return 0; 6 | 7 | int i = 0; 8 | while (str[i] == ' ' && i < n) i++; 9 | 10 | if (str[i] == '+') { 11 | i++; 12 | } else if (str[i] == '-') { 13 | sign = -1; 14 | i++; 15 | } 16 | 17 | for (; i < n; i++) { 18 | if (str[i] < '0' || str[i] > '9') 19 | break; 20 | if (num > INT_MAX / 10 || 21 | (num == INT_MAX / 10 && 22 | (str[i] - '0') > INT_MAX % 10)) { 23 | return sign == -1 ? INT_MIN : INT_MAX; 24 | } 25 | num = num * 10 + str[i] - '0'; 26 | } 27 | return num * sign; 28 | } 29 | 30 | -------------------------------------------------------------------------------- /src/test/resources/solutions/stoi/solution.py: -------------------------------------------------------------------------------- 1 | def myStoi(s): 2 | ###better to do strip before sanity check (although 8ms slower): 3 | #ls = list(s.strip()) 4 | #if len(ls) == 0 : return 0 5 | if len(s) == 0 : return 0 6 | ls = list(s.strip()) 7 | 8 | sign = -1 if ls[0] == '-' else 1 9 | if ls[0] in ['-','+'] : del ls[0] 10 | ret, i = 0, 0 11 | while i < len(ls) and ls[i].isdigit() : 12 | ret = ret*10 + ord(ls[i]) - ord('0') 13 | i += 1 14 | return max(-2**31, min(sign * ret,2**31-1)) 15 | 16 | -------------------------------------------------------------------------------- /src/test/resources/solutions/stoi/solution.rb: -------------------------------------------------------------------------------- 1 | def myStoi(str) 2 | arr = str.strip.split(/\s+/) 3 | if arr[0] =~ /^([+-]?[0-9]+)/ 4 | i = $1.to_i 5 | return i >= 0 ? [2147483647, i].min : [-2147483648, i].max 6 | end 7 | 0 8 | end 9 | 10 | -------------------------------------------------------------------------------- /src/test/resources/solutions/valid-sudoku/Solution.java: -------------------------------------------------------------------------------- 1 | public class Solution { 2 | public boolean isValidSudoku(char[][] board) { 3 | boolean[] used = new boolean[9]; 4 | 5 | for (int i = 0; i < 9; ++i) { 6 | Arrays.fill(used, false); 7 | 8 | for (int j = 0; j < 9; ++j) // 检查行 9 | if (!check(board[i][j], used)) 10 | return false; 11 | 12 | Arrays.fill(used, false); 13 | 14 | for (int j = 0; j < 9; ++j) // 检查列 15 | if (!check(board[j][i], used)) 16 | return false; 17 | } 18 | 19 | for (int r = 0; r < 3; ++r) // 检查 9 个子格子 20 | for (int c = 0; c < 3; ++c) { 21 | Arrays.fill(used, false); 22 | 23 | for (int i = r * 3; i < r * 3 + 3; ++i) 24 | for (int j = c * 3; j < c * 3 + 3; ++j) 25 | if (!check(board[i][j], used)) 26 | return false; 27 | } 28 | 29 | return true; 30 | } 31 | 32 | private static boolean check(char ch, boolean[] used) { 33 | if (ch == '.') return true; 34 | 35 | if (used[ch - '1']) return false; 36 | 37 | return used[ch - '1'] = true; 38 | } 39 | }; 40 | 41 | -------------------------------------------------------------------------------- /src/test/resources/solutions/valid-sudoku/solution.cpp: -------------------------------------------------------------------------------- 1 | bool check(char ch, bool used[9]) { 2 | if (ch == '.') return true; 3 | 4 | if (used[ch - '1']) return false; 5 | 6 | return used[ch - '1'] = true; 7 | } 8 | 9 | bool isValidSudoku(const vector>& board) { 10 | bool used[9]; 11 | 12 | for (int i = 0; i < 9; ++i) { 13 | fill(used, used + 9, false); 14 | 15 | for (int j = 0; j < 9; ++j) // 检查行 16 | if (!check(board[i][j], used)) 17 | return false; 18 | 19 | fill(used, used + 9, false); 20 | 21 | for (int j = 0; j < 9; ++j) // 检查列 22 | if (!check(board[j][i], used)) 23 | return false; 24 | } 25 | 26 | for (int r = 0; r < 3; ++r) // 检查 9 个子格子 27 | for (int c = 0; c < 3; ++c) { 28 | fill(used, used + 9, false); 29 | 30 | for (int i = r * 3; i < r * 3 + 3; ++i) 31 | for (int j = c * 3; j < c * 3 + 3; ++j) 32 | if (!check(board[i][j], used)) 33 | return false; 34 | } 35 | 36 | return true; 37 | } 38 | 39 | -------------------------------------------------------------------------------- /src/test/resources/solutions/valid-sudoku/solution.py: -------------------------------------------------------------------------------- 1 | def isValidSudoku(board): 2 | row = [set([]) for i in range(9)] 3 | col = [set([]) for i in range(9)] 4 | grid = [set([]) for i in range(9)] 5 | 6 | for r in range(9): 7 | for c in range(9): 8 | if board[r][c] == '.': 9 | continue 10 | if board[r][c] in row[r]: 11 | return False 12 | if board[r][c] in col[c]: 13 | return False 14 | 15 | g = r // 3 * 3 + c // 3 16 | if board[r][c] in grid[g]: 17 | return False 18 | grid[g].add(board[r][c]) 19 | row[r].add(board[r][c]) 20 | col[c].add(board[r][c]) 21 | 22 | return True 23 | 24 | -------------------------------------------------------------------------------- /src/test/resources/solutions/valid-sudoku/solution.rb: -------------------------------------------------------------------------------- 1 | def isValidSudoku(board) 2 | rowbuckets = Array.new(9) { Hash.new } 3 | colbuckets = Array.new(9) { Hash.new } 4 | boxbuckets = Array.new(9) { Hash.new } 5 | 6 | 0.upto(8) do |i| 7 | 0.upto(8) do |j| 8 | char = board[i][j] 9 | next if char == '.' 10 | 11 | return false if rowbuckets[i][char] 12 | rowbuckets[i][char] = true 13 | 14 | return false if colbuckets[j][char] 15 | colbuckets[j][char] = true 16 | 17 | k = (i / 3) * 3 + (j / 3) 18 | return false if boxbuckets[k][char] 19 | boxbuckets[k][char] = true 20 | end 21 | end 22 | return true 23 | end 24 | 25 | -------------------------------------------------------------------------------- /src/test/resources/solutions/word-ladder/WordLadder.java: -------------------------------------------------------------------------------- 1 | public class WordLadder { 2 | public static int ladderLength(String start, String end, 3 | HashSet dict) { 4 | int result = 0; 5 | if (dict.size() == 0) { 6 | return result; 7 | } 8 | 9 | dict.add(start); 10 | dict.add(end); 11 | 12 | result = BFS(start, end, dict); 13 | 14 | return result; 15 | } 16 | 17 | private static int BFS(String start, String end, HashSet dict) { 18 | Queue queue = new LinkedList(); 19 | Queue length = new LinkedList(); 20 | queue.add(start); 21 | length.add(1); 22 | 23 | while (!queue.isEmpty()) { 24 | String word = queue.poll(); 25 | int len = length.poll(); 26 | 27 | if (match(word, end)) { 28 | return len; 29 | } 30 | 31 | for (int i = 0; i < word.length(); i++) { 32 | char[] arr = word.toCharArray(); 33 | for (char c = 'a'; c <= 'z'; c++) { 34 | if (c == arr[i]) 35 | continue; 36 | 37 | arr[i] = c; 38 | String str = String.valueOf(arr); 39 | if (dict.contains(str)) { 40 | queue.add(str); 41 | length.add(len + 1); 42 | dict.remove(str); 43 | } 44 | } 45 | } 46 | } 47 | 48 | return 0; 49 | } 50 | 51 | private static boolean match(String word, String end) { 52 | if (word.equals(end)) { 53 | return true; 54 | } 55 | return false; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/test/resources/solutions/word-ladder/WordLadder.java.bak: -------------------------------------------------------------------------------- 1 | class WordNode{ 2 | String word; 3 | int numSteps; 4 | 5 | public WordNode(String word, int numSteps){ 6 | this.word = word; 7 | this.numSteps = numSteps; 8 | } 9 | } 10 | 11 | public class Solution { 12 | public int ladderLength(String beginWord, String endWord, Set wordDict) { 13 | LinkedList queue = new LinkedList(); 14 | queue.add(new WordNode(beginWord, 1)); 15 | 16 | wordDict.add(endWord); 17 | 18 | while(!queue.isEmpty()){ 19 | WordNode top = queue.remove(); 20 | String word = top.word; 21 | 22 | if(word.equals(endWord)){ 23 | return top.numSteps; 24 | } 25 | 26 | char[] arr = word.toCharArray(); 27 | for(int i=0; i &dict) { 4 | queue current, next; 5 | unordered_set visited; 6 | 7 | int level = 0; 8 | bool found = false; 9 | 10 | auto state_is_target = [&](const string &s) {return s == end;}; 11 | auto state_extend = [&](const string &s) { 12 | vector result; 13 | 14 | for (size_t i = 0; i < s.size(); ++i) { 15 | string new_word(s); 16 | for (char c = 'a'; c <= 'z'; c++) { 17 | if (c == new_word[i]) continue; 18 | 19 | swap(c, new_word[i]); 20 | 21 | if ((dict.count(new_word) > 0 || new_word == end) && 22 | !visited.count(new_word)) { 23 | result.push_back(new_word); 24 | visited.insert(new_word); 25 | } 26 | swap(c, new_word[i]); 27 | } 28 | } 29 | 30 | return result; 31 | }; 32 | 33 | current.push(start); 34 | while (!current.empty() && !found) { 35 | ++level; 36 | while (!current.empty() && !found) { 37 | const string str = current.front(); 38 | current.pop(); 39 | 40 | const auto& new_states = state_extend(str); 41 | for (const auto& state : new_states) { 42 | next.push(state); 43 | if (state_is_target(state)) { 44 | found = true; 45 | break; 46 | } 47 | } 48 | } 49 | swap(next, current); 50 | } 51 | if (found) return level + 1; 52 | else return 0; 53 | } 54 | 55 | --------------------------------------------------------------------------------