2503회 채점 중 로직 추가
This commit is contained in:
216
main.py
216
main.py
@@ -1,10 +1,14 @@
|
||||
from jsonpath_ng.ext import parse
|
||||
import json
|
||||
from itertools import chain
|
||||
import os
|
||||
import pandas as pd # 추가된 import
|
||||
import unicodedata # 상단에 import 추가
|
||||
import re # 상단에 추가
|
||||
|
||||
# 파일 경로 설정
|
||||
project_json_path = './sample/제2502회 코딩활용능력 2급 B형 정답/project.json'
|
||||
scoring_json_path = './scoring.json'
|
||||
project_json_path = 'output/2503 CAT 3급 A형'
|
||||
scoring_json_path = './2503 CAT 3급 A형.json'
|
||||
|
||||
# JSON 파일 읽기
|
||||
def read_json(file_path):
|
||||
@@ -36,21 +40,101 @@ def find_list_element(data, jsonpath_expr_list):
|
||||
|
||||
return result
|
||||
|
||||
# 스크립트 채점 진행 전 스크립트 블럭 순서가 when_run_button_click 1번째, when_clone_start 2번째 배열에 없으면
|
||||
# 리스트 순서 스왑해서 각각 0, 1번 순서로 배치될 수 있도록 함
|
||||
# when_scene_start 1번째, when_message_cast 2번째 동일한 순서로 리스트 순서 스왑해서 정렬
|
||||
def swap_script(origin):
|
||||
"""스크립트 블록 순서 정렬 함수"""
|
||||
if not origin or len(origin) == 0:
|
||||
return origin
|
||||
|
||||
# 스크립트 블록 분류를 위한 임시 저장소
|
||||
run_button_block = None
|
||||
key_press_blocks = []
|
||||
clone_start_block = None
|
||||
message_cast_block = None
|
||||
other_blocks = []
|
||||
|
||||
# 각 블록을 타입별로 분류
|
||||
for i, block in enumerate(origin):
|
||||
if not block or len(block) == 0:
|
||||
continue
|
||||
|
||||
block_type = block[0].get("type")
|
||||
|
||||
# 기존 로직: run_button과 scene_start 처리
|
||||
if (block_type == "when_run_button_click" or block_type == "when_scene_start") and i > 0:
|
||||
print(f"swap script run button or scene start")
|
||||
swap = origin[0]
|
||||
origin[0] = origin[i]
|
||||
origin[i] = swap
|
||||
|
||||
# 기존 로직: clone_start와 message_cast 처리
|
||||
elif (block_type == "when_clone_start" or block_type == "when_message_cast") and i > 0:
|
||||
print(f"swap script clone start or msg cast")
|
||||
swap = origin[1]
|
||||
origin[1] = origin[i]
|
||||
origin[i] = swap
|
||||
|
||||
# 새로운 로직: 키 이벤트 처리
|
||||
if block_type == "when_run_button_click":
|
||||
run_button_block = block
|
||||
elif block_type == "when_some_key_pressed":
|
||||
# params[1]에서 키 값 확인 (49, 50, 51) 아스키코드 값이므로 필요하면 추가 가능
|
||||
key_value = block[0].get("params")[1]
|
||||
if key_value in ["49", "50", "51"]:
|
||||
key_press_blocks.append((key_value, block))
|
||||
elif block_type == "when_clone_start":
|
||||
clone_start_block = block
|
||||
elif block_type == "when_message_cast":
|
||||
message_cast_block = block
|
||||
else:
|
||||
other_blocks.append(block)
|
||||
|
||||
# 결과 배열 재구성
|
||||
result = []
|
||||
|
||||
# 1. when_run_button_click 블록을 첫 번째로 추가
|
||||
if run_button_block:
|
||||
result.append(run_button_block)
|
||||
|
||||
# 2. when_some_key_pressed 블록들을 키 값 순서대로 정렬하여 추가
|
||||
key_press_blocks.sort(key=lambda x: int(x[0]) if x[0] else 0)
|
||||
result.extend([block for _, block in key_press_blocks])
|
||||
|
||||
# 3. clone_start와 message_cast 블록 추가
|
||||
if clone_start_block:
|
||||
result.append(clone_start_block)
|
||||
if message_cast_block:
|
||||
result.append(message_cast_block)
|
||||
|
||||
# 4. 나머지 블록 추가
|
||||
result.extend(other_blocks)
|
||||
|
||||
# main 함수
|
||||
def main():
|
||||
project_data = read_json(project_json_path)
|
||||
scoring_data = read_json(scoring_json_path)
|
||||
# 결과가 비어있으면 원본 반환
|
||||
return result if result else origin
|
||||
|
||||
total_points = 0
|
||||
def clean_string(text):
|
||||
"""문자열 끝의 . 또는 ! 제거"""
|
||||
if isinstance(text, str):
|
||||
# 문자열 끝의 . 또는 ! 제거
|
||||
return re.sub(r'', '', text.strip())
|
||||
return text
|
||||
|
||||
def convert_to_str(value):
|
||||
"""값을 문자열로 변환"""
|
||||
if isinstance(value, (list, tuple)):
|
||||
return [convert_to_str(v) for v in value]
|
||||
return str(value)
|
||||
|
||||
def process_project(project_data, scoring_data):
|
||||
total_points = 0
|
||||
points = []
|
||||
|
||||
for key, value in scoring_data.items():
|
||||
ele = value.get('ele')
|
||||
type = value.get('type')
|
||||
blocks = value.get('blocks')
|
||||
# 정답
|
||||
answer = value.get('answer')
|
||||
|
||||
print(f"example: {key}")
|
||||
@@ -58,15 +142,22 @@ def main():
|
||||
exists = find_element(project_data, ele)
|
||||
if exists:
|
||||
print(f"elements found for {ele}")
|
||||
# scene type의 경우 문자열 변환
|
||||
exists = [convert_to_str(x) for x in exists]
|
||||
if exists == answer:
|
||||
total_points += value.get('points')
|
||||
points.append(value.get('points'))
|
||||
|
||||
elif exists and answer == None:
|
||||
total_points += value.get('points')
|
||||
points.append(value.get('points'))
|
||||
print(f"{ele} found ");
|
||||
else :
|
||||
else:
|
||||
points.append(0)
|
||||
print(f"{exists} not found");
|
||||
else:
|
||||
print(f"Element '{ele}' exists in project.json: {exists}")
|
||||
print(f"Element '{ele}' not found")
|
||||
points.append(0)
|
||||
|
||||
if type == "script":
|
||||
exists = find_script_element(project_data, ele)
|
||||
@@ -75,49 +166,118 @@ def main():
|
||||
temp = None
|
||||
else:
|
||||
temp = json.loads(exists)
|
||||
temp = swap_script(temp)
|
||||
|
||||
innerKey= 1;
|
||||
innerKey = 1
|
||||
for block in blocks:
|
||||
innerType = block.get('type')
|
||||
|
||||
if temp == None:
|
||||
print(f"{key}-{innerKey}: Script Not exist")
|
||||
innerKey = innerKey + 1
|
||||
print(f"{key}-{innerKey}: Script Not exist")
|
||||
points.append("확인 필요")
|
||||
continue
|
||||
|
||||
if innerType == "list":
|
||||
elif innerType == "list":
|
||||
block_exists = find_list_element(temp, block.get('ele'))
|
||||
|
||||
else:
|
||||
block_exists = find_element(temp, block.get('ele'))
|
||||
|
||||
# 정답
|
||||
answer = block.get('answer', None)
|
||||
|
||||
if isinstance(answer, list):
|
||||
flat_matches = list(chain.from_iterable(block_exists))
|
||||
|
||||
if block_exists and isinstance(answer, list):
|
||||
# 리스트의 모든 요소를 문자열로 변환
|
||||
flat_matches = [convert_to_str(x) for x in list(chain.from_iterable(block_exists))]
|
||||
else:
|
||||
flat_matches = block_exists[0]
|
||||
if not block_exists:
|
||||
flat_matches = None
|
||||
else:
|
||||
# 단일 값을 문자열로 변환
|
||||
flat_matches = convert_to_str(block_exists[0])
|
||||
|
||||
|
||||
# 블록에 따라 params 값이나 statements 값이 있는 경우 처리 추가 필요
|
||||
if block_exists:
|
||||
if answer is not None and answer != flat_matches:
|
||||
print(f"{key}-{innerKey}: {answer} != {flat_matches}")
|
||||
elif answer is not None and answer == flat_matches:
|
||||
print(f"{key}-{innerKey}: {answer} == {flat_matches}")
|
||||
# answer도 문자열로 변환하여 비교
|
||||
str_answer = convert_to_str(answer) if answer is not None else None
|
||||
if answer is not None and str_answer != flat_matches:
|
||||
print(f"{key}-{innerKey}: {str_answer} != {flat_matches}")
|
||||
points.append(0)
|
||||
elif answer is not None and str_answer == flat_matches:
|
||||
print(f"{key}-{innerKey}: {str_answer} == {flat_matches}")
|
||||
total_points += block.get('points')
|
||||
points.append(block.get('points'))
|
||||
elif answer is None and block_exists:
|
||||
total_points += block.get('points')
|
||||
points.append(block.get('points'))
|
||||
print(f"{key}-{innerKey}: exist ele: {block_exists}")
|
||||
else:
|
||||
print(f"No elements found for {block.get('ele')}")
|
||||
points.append(0)
|
||||
|
||||
innerKey = innerKey + 1
|
||||
|
||||
print(f"Total Points: {total_points}")
|
||||
|
||||
points.append(total_points)
|
||||
return points
|
||||
|
||||
def normalize_path(path):
|
||||
"""한글 경로명을 NFC 방식으로 정규화"""
|
||||
return unicodedata.normalize('NFC', path)
|
||||
|
||||
def main():
|
||||
scoring_data = read_json(scoring_json_path)
|
||||
student_score_list = []
|
||||
|
||||
# 컬럼명 생성
|
||||
columns = ['학생명']
|
||||
idx = 1
|
||||
for key in scoring_data.keys():
|
||||
if scoring_data[key].get('type') == 'scene':
|
||||
columns.append(f'{idx}')
|
||||
idx = idx + 1
|
||||
elif scoring_data[key].get('type') == 'script':
|
||||
for i in range(len(scoring_data[key].get('blocks', []))):
|
||||
columns.append(f'{idx}')
|
||||
idx = idx + 1
|
||||
|
||||
columns.append('총점')
|
||||
|
||||
# os.walk 결과를 리스트로 변환하고 정렬
|
||||
walk_results = []
|
||||
for root, dirs, files in os.walk(project_json_path):
|
||||
# 디렉토리명 정규화
|
||||
normalized_root = normalize_path(root)
|
||||
normalized_dirs = [normalize_path(d) for d in dirs]
|
||||
normalized_files = [normalize_path(f) for f in files]
|
||||
|
||||
normalized_dirs.sort() # 정규화된 디렉토리 정렬
|
||||
walk_results.append((normalized_root, normalized_dirs, normalized_files))
|
||||
|
||||
# 정렬된 결과를 바탕으로 처리
|
||||
for root, dirs, files in sorted(walk_results):
|
||||
for file in sorted(files): # 파일도 정렬
|
||||
if file == 'project.json':
|
||||
full_path = os.path.join(root, file)
|
||||
print(f"\nProcessing: {full_path}")
|
||||
try:
|
||||
# 디렉토리 패스 내에 학생 이름만 뽑아서 엑셀 컬럼 명으로 추가
|
||||
# output/cas-000040-이지원/temp/project.json
|
||||
student_id = normalize_path(full_path.split('/')[2])
|
||||
project_data = read_json(full_path)
|
||||
points = process_project(project_data, scoring_data)
|
||||
points.insert(0, student_id)
|
||||
student_score_list.append(points)
|
||||
print(f"Total Points for {points}")
|
||||
except Exception as e:
|
||||
print(f"Error processing {full_path}: {str(e)}")
|
||||
continue
|
||||
|
||||
# DataFrame 생성 및 엑셀 저장
|
||||
df = pd.DataFrame(student_score_list, columns=columns).transpose()
|
||||
df.columns = df.iloc[0]
|
||||
df = df[1:]
|
||||
|
||||
excel_path = project_json_path + '/' + 'results.xlsx'
|
||||
|
||||
df.to_excel(excel_path, index=False)
|
||||
print(f"\nResults saved to {excel_path}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user