ACC-IDE Code Judge #130
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: ACC-IDE Code Judge | |
| on: | |
| workflow_dispatch: | |
| inputs: | |
| # 从App接收要评测的代码 | |
| source_code: | |
| description: 'The source code to be judged' | |
| required: true | |
| # 从App接收标准输入 | |
| std_input: | |
| description: 'Standard input for the code' | |
| required: false | |
| default: '' | |
| # 从App接收预期输出 | |
| expected_output: | |
| description: 'Expected output for comparison' | |
| required: false | |
| default: '' | |
| # App传来的语言类型,用于选择编译器 | |
| language: | |
| description: 'The programming language (cpp, python, java)' | |
| required: true | |
| default: 'cpp' | |
| jobs: | |
| build-and-run: | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 1 | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v4 | |
| # 根据语言,将接收到的代码和输入写入文件 | |
| - name: Prepare execution files | |
| run: | | |
| set +e | |
| mkdir -p results || true | |
| export LC_ALL=C.UTF-8 || true | |
| export LANG=C.UTF-8 || true | |
| echo -e "${{ github.event.inputs.std_input }}" > input.txt || true | |
| echo -e "${{ github.event.inputs.expected_output }}" > expected.txt || true | |
| if [ ! -s expected.txt ] || [ "$(cat expected.txt | tr -d '[:space:]')" = "" ]; then | |
| echo "EXPECTED_EMPTY=true" >> $GITHUB_ENV || true | |
| echo "预期输出为空,设置 EXPECTED_EMPTY=true" || true | |
| else | |
| echo "EXPECTED_EMPTY=false" >> $GITHUB_ENV || true | |
| echo "预期输出不为空,设置 EXPECTED_EMPTY=false" || true | |
| fi | |
| echo "=== Expected Output Content ===" || true | |
| cat expected.txt || true | |
| echo "===============================" || true | |
| if [ "${{ github.event.inputs.language }}" = "java" ]; then | |
| SOURCE_FILE="Main.java" | |
| elif [ "${{ github.event.inputs.language }}" = "python" ] || [ "${{ github.event.inputs.language }}" = "py" ]; then | |
| SOURCE_FILE="main.py" | |
| else | |
| SOURCE_FILE="main.${{ github.event.inputs.language }}" | |
| fi | |
| # 使用 base64 解码确保源代码中的空格和特殊字符被正确保留 | |
| echo "=== Decoding Base64 Source Code ===" || true | |
| echo "${{ github.event.inputs.source_code }}" | base64 -d > $SOURCE_FILE || true | |
| echo "===================================" || true | |
| # 确保源代码文件是 UTF-8 编码 | |
| echo "=== Converting to UTF-8 ===" || true | |
| iconv -f UTF-8 -t UTF-8 $SOURCE_FILE -o $SOURCE_FILE.utf8 2>/dev/null || cp $SOURCE_FILE $SOURCE_FILE.utf8 | |
| mv $SOURCE_FILE.utf8 $SOURCE_FILE || true | |
| echo "=========================" || true | |
| echo "SOURCE_FILE=$SOURCE_FILE" >> $GITHUB_ENV || true | |
| echo "=== Final Source Code ===" || true | |
| cat $SOURCE_FILE || true | |
| echo "========================" || true | |
| echo "=== File Encoding ===" || true | |
| file -i $SOURCE_FILE || true | |
| echo "====================" || true | |
| - name: Compile C++ Code | |
| if: github.event.inputs.language == 'cpp' | |
| id: compile_cpp | |
| run: | | |
| set +e | |
| g++ --version || true | |
| mkdir -p ./results || true | |
| g++ main.cpp -o main_exec -O2 -std=c++17 -Wall -Wextra -fdiagnostics-color=always > ./results/compile.log 2>&1 | |
| COMPILE_RESULT=$? | |
| echo "=== Compilation Log ===" || true | |
| cat ./results/compile.log || true | |
| echo "=======================" || true | |
| if [ $COMPILE_RESULT -ne 0 ]; then | |
| echo "Compilation failed with exit code: $COMPILE_RESULT" || true | |
| echo '{"status": "CE", "message": "Compilation Error", "execution_time": 0}' > ./results/result.json || true | |
| echo "JUDGE_STATUS=CE" >> $GITHUB_ENV || true | |
| else | |
| echo "Compilation successful" || true | |
| fi | |
| - name: Run and Judge C++ Code | |
| if: success() && env.JUDGE_STATUS != 'CE' && github.event.inputs.language == 'cpp' | |
| run: | | |
| set +e | |
| # 检查预期输出是否为空 | |
| if [ ! -s expected.txt ] || [ "$(cat expected.txt | tr -d '[:space:]')" = "" ]; then | |
| EXPECTED_EMPTY=true | |
| else | |
| EXPECTED_EMPTY=false | |
| fi | |
| # 计时脚本 | |
| cat > time_wrapper.sh << 'EOF' | |
| #!/bin/bash | |
| start_time=$(date +%s%N) | |
| "$@" | |
| exit_code=$? | |
| end_time=$(date +%s%N) | |
| execution_time=$((($end_time - $start_time) / 1000000)) | |
| echo $execution_time > execution_time.txt | |
| exit $exit_code | |
| EOF | |
| chmod +x time_wrapper.sh | |
| # TLE: 2 seconds, MLE: 256 MB | |
| timeout 2s ./time_wrapper.sh ./main_exec < input.txt > ./results/actual.txt 2> ./results/stderr.log || true | |
| EXIT_CODE=$? | |
| # 获取执行时间 | |
| EXECUTION_TIME=0 | |
| if [ -f execution_time.txt ]; then | |
| EXECUTION_TIME=$(cat execution_time.txt) | |
| fi | |
| if [ $EXIT_CODE -eq 124 ]; then | |
| STATUS="TLE" | |
| MESSAGE="Time Limit Exceeded" | |
| elif [ $EXIT_CODE -ne 0 ]; then | |
| STATUS="RE" | |
| MESSAGE="Runtime Error (Exit Code: $EXIT_CODE)" | |
| else | |
| # 检查预期是否为空,空则"RS"(Run Successful) | |
| if [ "$EXPECTED_EMPTY" = "true" ]; then | |
| STATUS="RS" | |
| MESSAGE="Run Successful" | |
| else | |
| # 使用 diff 命令比较输出。 | |
| # -i 忽略大小写, -w 忽略所有空格, -B 忽略空行 | |
| diff -i -w -B ./results/actual.txt expected.txt > /dev/null | |
| DIFF_RESULT=$? | |
| if [ $DIFF_RESULT -ne 0 ]; then | |
| STATUS="WA" | |
| MESSAGE="Wrong Answer" | |
| echo "=== Expected Output ===" > ./results/diff.txt | |
| cat expected.txt >> ./results/diff.txt | |
| echo -e "\n=== Actual Output ===" >> ./results/diff.txt | |
| cat ./results/actual.txt >> ./results/diff.txt | |
| else | |
| STATUS="AC" | |
| MESSAGE="Accepted" | |
| fi | |
| fi | |
| fi | |
| echo "{\"status\": \"$STATUS\", \"message\": \"$MESSAGE\", \"execution_time\": $EXECUTION_TIME}" > ./results/result.json | |
| # 输出调试信息 | |
| echo "=== DEBUG INFO (C++) ===" || true | |
| echo "Input:" || true | |
| cat input.txt || true | |
| echo -e "\nExpected Output:" || true | |
| cat expected.txt || true | |
| echo -e "\nActual Output:" || true | |
| cat ./results/actual.txt || true | |
| echo -e "\nStatus: $STATUS (EXPECTED_EMPTY=$EXPECTED_EMPTY)" || true | |
| echo "===========================" || true | |
| - name: Run Python Code | |
| if: github.event.inputs.language == 'python' || github.event.inputs.language == 'py' | |
| run: | | |
| set +e | |
| mkdir -p ./results || true | |
| if [ ! -s expected.txt ] || [ "$(cat expected.txt | tr -d '[:space:]')" = "" ]; then | |
| EXPECTED_EMPTY=true | |
| else | |
| EXPECTED_EMPTY=false | |
| fi | |
| cat > time_wrapper.sh << 'EOF' | |
| #!/bin/bash | |
| start_time=$(date +%s%N) | |
| "$@" | |
| exit_code=$? | |
| end_time=$(date +%s%N) | |
| execution_time=$((($end_time - $start_time) / 1000000)) | |
| echo $execution_time > execution_time.txt | |
| exit $exit_code | |
| EOF | |
| chmod +x time_wrapper.sh | |
| timeout 2s ./time_wrapper.sh python3 main.py < input.txt > ./results/actual.txt 2> ./results/stderr.log || true | |
| EXIT_CODE=$? | |
| EXECUTION_TIME=0 | |
| if [ -f execution_time.txt ]; then | |
| EXECUTION_TIME=$(cat execution_time.txt) | |
| fi | |
| if [ $EXIT_CODE -eq 124 ]; then | |
| STATUS="TLE" | |
| MESSAGE="Time Limit Exceeded" | |
| elif [ $EXIT_CODE -ne 0 ]; then | |
| STATUS="RE" | |
| MESSAGE="Runtime Error (Exit Code: $EXIT_CODE)" | |
| else | |
| if [ "$EXPECTED_EMPTY" = "true" ]; then | |
| STATUS="RS" | |
| MESSAGE="Run Successful" | |
| else | |
| diff -i -w -B ./results/actual.txt expected.txt > /dev/null | |
| DIFF_RESULT=$? | |
| if [ $DIFF_RESULT -ne 0 ]; then | |
| STATUS="WA" | |
| MESSAGE="Wrong Answer" | |
| echo "=== Expected Output ===" > ./results/diff.txt | |
| cat expected.txt >> ./results/diff.txt | |
| echo -e "\n=== Actual Output ===" >> ./results/diff.txt | |
| cat ./results/actual.txt >> ./results/diff.txt | |
| else | |
| STATUS="AC" | |
| MESSAGE="Accepted" | |
| fi | |
| fi | |
| fi | |
| echo "{\"status\": \"$STATUS\", \"message\": \"$MESSAGE\", \"execution_time\": $EXECUTION_TIME}" > ./results/result.json | |
| echo "=== DEBUG INFO (Python) ===" || true | |
| echo "Input:" || true | |
| cat input.txt || true | |
| echo -e "\nExpected Output:" || true | |
| cat expected.txt || true | |
| echo -e "\nActual Output:" || true | |
| cat ./results/actual.txt || true | |
| echo -e "\nStatus: $STATUS (EXPECTED_EMPTY=$EXPECTED_EMPTY)" || true | |
| echo "===========================" || true | |
| - name: Compile Java Code | |
| if: github.event.inputs.language == 'java' | |
| id: compile_java | |
| run: | | |
| set +e | |
| javac Main.java -d . &> ./results/compile.log || true | |
| COMPILE_RESULT=$? | |
| echo "=== Compilation Log ===" || true | |
| cat ./results/compile.log || true | |
| echo "=======================" || true | |
| if [ $COMPILE_RESULT -ne 0 ]; then | |
| echo "Compilation failed with exit code: $COMPILE_RESULT" || true | |
| echo '{"status": "CE", "message": "Compilation Error", "execution_time": 0}' > ./results/result.json || true | |
| echo "JUDGE_STATUS=CE" >> $GITHUB_ENV || true | |
| else | |
| echo "Compilation successful" || true | |
| fi | |
| - name: Run Java Code | |
| if: success() && env.JUDGE_STATUS != 'CE' && github.event.inputs.language == 'java' | |
| run: | | |
| set +e | |
| if [ ! -s expected.txt ] || [ "$(cat expected.txt | tr -d '[:space:]')" = "" ]; then | |
| EXPECTED_EMPTY=true | |
| else | |
| EXPECTED_EMPTY=false | |
| fi | |
| cat > time_wrapper.sh << 'EOF' | |
| #!/bin/bash | |
| start_time=$(date +%s%N) | |
| "$@" | |
| exit_code=$? | |
| end_time=$(date +%s%N) | |
| execution_time=$((($end_time - $start_time) / 1000000)) | |
| echo $execution_time > execution_time.txt | |
| exit $exit_code | |
| EOF | |
| chmod +x time_wrapper.sh | |
| timeout 2s ./time_wrapper.sh java Main < input.txt > ./results/actual.txt 2> ./results/stderr.log || true | |
| EXIT_CODE=$? | |
| EXECUTION_TIME=0 | |
| if [ -f execution_time.txt ]; then | |
| EXECUTION_TIME=$(cat execution_time.txt) | |
| fi | |
| if [ $EXIT_CODE -eq 124 ]; then | |
| STATUS="TLE" | |
| MESSAGE="Time Limit Exceeded" | |
| elif [ $EXIT_CODE -ne 0 ]; then | |
| STATUS="RE" | |
| MESSAGE="Runtime Error (Exit Code: $EXIT_CODE)" | |
| else | |
| if [ "$EXPECTED_EMPTY" = "true" ]; then | |
| STATUS="RS" | |
| MESSAGE="Run Successful" | |
| else | |
| diff -i -w -B ./results/actual.txt expected.txt > /dev/null | |
| DIFF_RESULT=$? | |
| if [ $DIFF_RESULT -ne 0 ]; then | |
| STATUS="WA" | |
| MESSAGE="Wrong Answer" | |
| echo "=== Expected Output ===" > ./results/diff.txt | |
| cat expected.txt >> ./results/diff.txt | |
| echo -e "\n=== Actual Output ===" >> ./results/diff.txt | |
| cat ./results/actual.txt >> ./results/diff.txt | |
| else | |
| STATUS="AC" | |
| MESSAGE="Accepted" | |
| fi | |
| fi | |
| fi | |
| echo "{\"status\": \"$STATUS\", \"message\": \"$MESSAGE\", \"execution_time\": $EXECUTION_TIME}" > ./results/result.json | |
| echo "=== DEBUG INFO (Java) ===" || true | |
| echo "Input:" || true | |
| cat input.txt || true | |
| echo -e "\nExpected Output:" || true | |
| cat expected.txt || true | |
| echo -e "\nActual Output:" || true | |
| cat ./results/actual.txt || true | |
| echo -e "\nStatus: $STATUS (EXPECTED_EMPTY=$EXPECTED_EMPTY)" || true | |
| echo "===========================" || true | |
| # 上传结果文件 | |
| - name: Upload judgment result | |
| uses: actions/upload-artifact@v4 | |
| continue-on-error: true | |
| with: | |
| name: judge-result | |
| path: ./results/ | |
| if-no-files-found: warn |