diff --git "a/app.py" "b/app.py" --- "a/app.py" +++ "b/app.py" @@ -8,7 +8,7 @@ from openai import OpenAI import json # --- 페이지 설정 (스크립트 최상단) --- -st.set_page_config(layout="wide", page_title="진실을 찾아서: 현대사 취재기록") +st.set_page_config(layout="wide", page_title="진실을 찾아서: 우리 역사 이야기") # --- OpenAI API 키 설정 --- if "OPENAI_API_KEY" not in os.environ: @@ -25,239 +25,339 @@ SCENARIOS = { "4.19_revolution": { "display_name": "4.19 혁명 취재 (1960)", "start_year": 1960, - "player_role": "신입 기자 (자유일보)", + "player_role": "새내기 기자 (자유일보)", "initial_press_freedom": 40, "initial_reporter_safety": 70, "initial_public_trust": 50, - "vocab_level": "보통", + "vocab_level": "초등", "max_turns": 8, }, "5.18_gwangju": { "display_name": "5.18 광주 현장 취재 (1980)", "start_year": 1980, - "player_role": "지방 주재 기자 (민주신문)", + "player_role": "지방 기자 (민주신문)", "initial_press_freedom": 20, "initial_reporter_safety": 50, "initial_public_trust": 40, - "vocab_level": "보통", + "vocab_level": "초등", "max_turns": 8, }, "june_struggle": { - "display_name": "6월 항쟁 동행 취재 (1987)", + "display_name": "6월 항쟁 함께 취재 (1987)", "start_year": 1987, "player_role": "사회부 기자 (시민일보)", "initial_press_freedom": 30, "initial_reporter_safety": 60, "initial_public_trust": 45, - "vocab_level": "보통", + "vocab_level": "초등", "max_turns": 7, } } -# --- 텍스트 저장소 --- +# --- 텍스트 저장소 (모든 텍스트 초등 수준으로 변경) --- ALL_TEXTS = { # --- 공통 UI --- - "game_title": {"보통": "🎙️ 진실을 찾아서: 현대사 취재기록"}, - "scenario_select_title": {"보통": "📰 취재할 시대를 선택하세요"}, - "scenario_select_button": {"보통": "취재 시작"}, - "dashboard_title": {"보통": "📊 기자 상황판"}, - "dashboard_term": {"보통": "{year}년 {turn}번째 취재일"}, - "term_press_freedom": {"보통": "취재 자유도"}, - "term_article_score_avg": {"보통": "평균 기사 점수"}, - "term_reporter_safety": {"보통": "기자 안전도"}, - "term_public_trust": {"보통": "대중 신뢰도"}, - "current_assignment_title": {"보통": "📋 오늘의 취재 지시"}, - "reporter_actions_title": {"보통": "🎤 취재 활동 선택"}, - "action_button_label": {"보통": "{action} (위험도: {risk_str})"}, - "action_success_message": {"보통": "'{action}' 취재 완료."}, - "button_next_day": {"보통": "➡️ 다음 날로"}, - "button_restart_assignment": {"보통": "이번 취재 다시 시작"}, - "button_back_to_scenario_select": {"보통": "다른 시대 취재"}, - "assignment_over_title": {"보통": "취재 기간 종료"}, - "assignment_over_subtitle": {"보통": "최종 취재 결과 및 평가"}, - "term_event_log": {"보통": "취재 일지"}, - "historical_source_title": {"보통": "참고 자료"}, - "reporter_notebook_title": {"보통": "📝 나의 취재 노트"}, - "article_writing_title": {"보통": "🖋️ 기사 작성"}, - "desk_feedback_title": {"보통": "📢 AI 편집장 평가"}, - "status_loading_assignment": {"보통": "{year}년 {turn}번째 취재일 준비 중..."}, - "status_actions_taken": {"보통": "오늘의 주요 취재 활동을 마쳤습니다. 기사를 정리하거나 다음 날로 진행하세요."}, - "sidebar_title": {"보통": "메뉴"}, - "sidebar_glossary_title": {"보통": "📰 관련 용어/인물"}, - "sidebar_current_source_title": {"보통": "📎 현재 참고 자료"}, - "sidebar_no_source": {"보통": "현재 참고할 만한 특별 자료가 없습니다."}, - "button_submit_article": {"보통": "기사 송고 (AI 평가)"}, - "article_headline_label": {"보통": "기사 제목:"}, - "article_body_label": {"보통": "기사 본문 핵심 (3-5문장 요약):"}, - "article_tone_label": {"보통": "기사 논조 선택:"}, - "warning_empty_article": {"보통": "기사 제목과 핵심 내용을 모두 작성해주세요."}, - "info_no_special_info": {"보통": "특별한 정보는 얻지 못했습니다."}, - "log_freedom_loss": {"보통": " - 취재 중 제약 발생, 취재 자유도 {loss} 감소."}, - "log_safety_loss": {"보통": " - 취재 중 신변 위협 감지, 기자 안전도 {loss} 감소."}, - "log_info_acquired": {"보통": " - 정보 획득: {info}"}, - "log_no_info_acquired": {"보통": " - 특별한 정보는 얻지 못함."}, - "log_article_submitted": {"보통": "기사 송고: '{headline}' (논조: {tone}) - AI 평가 점수: {score}점"}, - "log_desk_feedback": {"보통": " - AI 편집장 코멘트: {feedback}"}, - "log_trust_change": {"보통": " - 대중 신뢰도 {change:+} 변동."}, - "log_freedom_change_article": {"보통": " - 취재 자유도 {change:+} 변동."}, - "log_safety_change_article": {"보통": " - 기자 안전도 {change:+} 변동."}, - "log_assignment_over": {"보통": "--- {scenario_name} 취재 기간 종료 ---"}, - "log_next_day_start": {"보통": "--- {year}년 {turn}번째 취재일 시작 ---"}, - "button_go_to_article_writing": {"보통": "기사 작성하기"}, - "error_openai_api": {"보통": "OpenAI API 호출 중 오류가 발생했습니다: {error}"}, + "game_title": "🎙️ 진실을 찾아서: 우리 역사 이야기", + "scenario_select_title": "📰 어떤 시대로 가볼까요?", + "scenario_select_button": "이 시대로 출발!", + "dashboard_title": "📊 기자님 현재 상황", + "dashboard_term": "{year}년 {turn}번째 날", + "term_press_freedom": "기사 쓰는 자유", + "term_article_score_avg": "평균 기사 점수", + "term_reporter_safety": "기자님 안전", + "term_public_trust": "사람들의 믿음", + "current_assignment_title": "📋 오늘 할 일", + "reporter_actions_title": "🎤 무엇을 할까요?", + "action_button_label": "{action} (이걸 하면? {risk_str})", + "action_success_message": "'{action}' 취재 끝!", + "button_next_day": "➡️ 다음 날로 가기", + "button_restart_assignment": "이번 취재 다시 하기", + "button_back_to_scenario_select": "다른 시대로 가기", + "assignment_over_title": "취재 끝!", + "assignment_over_subtitle": "마지막 취재 결과와 점수", + "term_event_log": "오늘 있었던 일", + "historical_source_title": "도움되는 이야기", + "reporter_notebook_title": "📝 내가 적은 내용", + "article_writing_title": "🖋️ 기사 쓰기", + "desk_feedback_title": "📢 AI 편집장님의 한마디", + "status_loading_assignment": "{year}년 {turn}번째 날, 무슨 일이 있을까? 기다려주세요...", + "status_actions_taken": "오늘 할 일을 다 했어요. 기사를 쓰거나 다음 날로 넘어가세요.", + "sidebar_title": "메뉴", + "sidebar_glossary_title": "📰 어려운 말/사람 이야기", + "sidebar_current_source_title": "📎 지금 보는 도움 자료", + "sidebar_no_source": "지금은 특별히 볼 만한 자료가 없어요.", + "button_submit_article": "기사 보내기 (AI 편집장님께)", + "article_headline_label": "기사 제목:", + "article_body_label": "기사 내용 요약 (짧게 3~5줄):", + "article_tone_label": "기사 분위기 선택:", + "warning_empty_article": "기사 제목과 내용을 모두 써 주세요.", + "info_no_special_info": "특별한 건 알아내지 못했어요.", + "log_freedom_loss": " - 취재가 힘들어졌어요. 기사 쓰는 자유가 {loss}만큼 줄었어요.", + "log_safety_loss": " - 취재하다 위험했어요. 기자님 안전이 {loss}만큼 줄었어요.", + "log_info_acquired": " - 새로운 사실 발견: {info}", + "log_no_info_acquired": " - 특별히 알아낸 건 없어요.", + "log_article_submitted": "기사 보냄: '{headline}' (분위기: {tone}) - AI 편집장님 점수: {score}점", + "log_desk_feedback": " - AI 편집장님 한마디: {feedback}", + "log_trust_change": " - 사람들이 나를 {change:+}만큼 더 믿거나 덜 믿게 됐어요.", + "log_freedom_change_article": " - 기사 쓰는 자유가 {change:+}만큼 바뀌었어요.", + "log_safety_change_article": " - 기자님 안전이 {change:+}만큼 바뀌었어요.", + "log_assignment_over": "--- {scenario_name} 취재 끝 ---", + "log_next_day_start": "--- {year}년 {turn}번째 날 시작 ---", + "button_go_to_article_writing": "기사 쓰러 가기", + "error_openai_api": "AI 편집장님 연결에 문제가 생겼어요: {error}", # --- 4.19 혁명 취재 시나리오 --- - "scenario_419_revolution_name": {"보통": "4.19 혁명 취재 (1960)"}, + "scenario_419_revolution_name": "4.19 혁명 이야기 (1960년)", # Turn 1 (3.15 부정선거) - "event_419_t1_assignment": {"보통": "3.15 정부통령 선거일입니다. 전국 투표소 상황 및 개표 과정에서 예상되는 부정행위 정황을 포착하고, 관련자(참관인, 유권자, 선관위 관계자 등)의 증언을 확보하는 것이 오늘의 주요 임무입니다. 특히 야당 참관인들의 활동과 여당 측의 조직적인 움직임을 면밀히 관찰하십시오."}, - "event_419_t1_source": {"보통": "[배경 정보] 현재 자유당 정권의 장기집권에 대한 국민적 불만이 높은 상황입니다. 이번 선거에서 이승만 대통령의 4선과 이기붕 부통령의 당선을 위해 정부와 여당이 조직적으로 선거에 개입할 것이라는 예측이 지배적입니다. 사전투표함 바꿔치기, 유령 유권자 동원, 3인조 및 5인조 공개투표 강요, 야당 참관인 축출 등의 소문이 이미 파다하게 퍼져 있습니다."}, - "action_419_t1_opt1_text": {"보��": "서울 시내 주요 투표소 잠입 및 비밀 촬영 시도"}, - "action_419_t1_opt2_text": {"보통": "야당 선거 감시단과 동행하며 부정 사례 공동 취재"}, - "action_419_t1_opt3_text": {"보통": "선관위 내부 고발자로 추정되는 인물과 비밀 접선 시도"}, - "info_419_t1_opt1_got": {"보통": "정보: 종로구 A투표소에서 자유당 완장을 찬 청년들이 투표함에 다량의 투표용지를 추가로 넣는 장면을 멀리서 목격함. 접근하려 하자 위협적인 눈초리를 보냄. (키워드: 투표함 추가 투입, 자유당 완장, 위협)"}, - "info_419_t1_opt2_got": {"보통": "정보: 민주당 참관인 박씨, '성북구 B투표소에서 경찰이 특정 유권자들에게 기표소까지 동행하며 기표 내용을 확인하는 것을 목격했다. 항의했으나 묵살당했다'고 격앙된 목소리로 증언. 관련 사진 일부 확보. (키워드: 경찰 동행 기표, 참관인 항의 묵살, 민주당)"}, - "info_419_t1_opt3_got": {"보통": "정보: 익명을 요구한 선관위 하급 직원, '오늘 새벽, 일부 지역 투표소로 향하는 사전투표함 중 몇 개가 정체불명의 차량으로 옮겨지는 것을 보았다. 매우 불안하다'고 떨리는 목소리로 제보. (키워드: 사전투표함 교체 의혹, 선관위 내부 제보, 불안감)"}, + "event_419_t1_assignment": "오늘은 3월 15일, 대통령과 부통령을 뽑는 날이에요. 투표하는 곳에서 나쁜 사람들이 규칙을 어기고 자기편만 뽑으려고 할지도 몰라요. 그런 이상한 점을 찾아내고, 투표를 지켜보는 사람, 투표하는 사람, 선거를 관리하는 사람들에게 이야기를 들어보는 것이 오늘 할 일이에요. 특히 반대편 사람들이 잘 감시하는지, 힘 있는 쪽 사람들이 몰래 나쁜 일을 꾸미는지 잘 살펴보세요.", + "event_419_t1_source": "[알아두면 좋아요] 지금 자유당이라는 당이 오랫동안 나라를 다스려서 사람들이 불만이 많아요. 이번 선거에서 이승만 대통령이 또 대통령이 되고, 이기붕 아저씨가 부통령이 되려고 자유당이 나쁜 방법을 쓸 거라는 소문이 많아요. 미리 투표한 표를 몰래 바꾸거나, 없는 사람 표를 넣거나, 여럿이 같이 보면서 투표하게 만들거나, 반대편 감시하는 사람들을 쫓아낸다는 이야기가 돌고 있어요.", + "action_419_t1_opt1_text": "서울 투표하는 곳에 몰래 들어가서 사진 찍어보기", + "action_419_t1_opt2_text": "선거 감시하는 사람들과 함께 나쁜 일 찾아보기", + "action_419_t1_opt3_text": "선거 관리하는 곳 사람 중 몰래 알려줄 사람 만나보기", + "info_419_t1_opt1_got": "새로운 사실: 종로 A투표소에서 자유당 표시를 한 사람들이 투표함에 표를 많이 넣는 걸 멀리서 봤어요. 가까이 가려니까 무섭게 쳐다봤어요. (힌트: 표 몰래 넣기, 자유당 표시, 무서움)", + "info_419_t1_opt2_got": "새로운 사실: 민주당 쪽 감시원 박 아저씨가 화나서 말했어요. '성북 B투표소에서 경찰이 어떤 사람들 투표하는 곳까지 따라가서 누굴 찍는지 봤어요! 안 된다고 했는데 내 말을 안 들었어요!' 사진도 조금 찍었대요. (힌트: 경찰이 투표 방해, 감시원 말 무시, 민주당)", + "info_419_t1_opt3_got": "새로운 사실: 이름을 밝히기 싫어하는 선거 관리 직원이 떨면서 말했어요. '오늘 새벽에 어떤 투표함들을 이상한 차가 가져가는 걸 봤어요. 너무 무서워요.' (힌트: 투표함 몰래 바꾼 듯, 선거 관리 직원 제보, 무서움)", # Turn 2 (김주열 열사 발견) - "event_419_t2_assignment": {"보통": "마산에서 3.15 부정선거에 항의하던 시위 중 실종된 김주열 학생의 시신이 참혹한 모습으로 발견되었습니다. 이 사건의 정확한 사망 원인, 경찰의 초기 대응 과정에서의 문제점, 그리고 마산 시민과 학생들의 격앙된 반응을 심층 취재하십시오."}, - "event_419_t2_source": {"보통": "[배경 정보] 4월 11일, 마산 중앙부두 앞바다에서 오른쪽 눈에 최루탄이 박힌 채 떠오른 김주열 군의 시신은 전국민에게 엄청난 충격을 주었습니다. 경찰은 초기 사인을 단순 익사로 발표하려 했으나, 시신 상태가 공개되면서 은폐 의혹이 커지고 있습니다. 마산 지역은 이미 3.15 시위 이후 긴장 상태가 지속되고 있었습니다."}, - "action_419_t2_opt1_text": {"보통": "김주열 군 시신 안치 병원을 찾아 부검의 또는 의료진 접촉 시도"}, - "action_419_t2_opt2_text": {"보통": "마산 시내 학생 시위 현장(마산상고, 북마산파출소 등) 직접 취재"}, - "action_419_t2_opt3_text": {"보통": "최초 시신 발견 어민 및 김주열 군 가족 인터뷰"}, - "info_419_t2_opt1_got": {"보통": "정보: 병원 관계자(익명), '부검 결과 김 군의 사인은 최루탄 파편에 의한 두개골 골절 및 뇌손상으로 잠정 결론났다. 경찰이 부검 결과 발표를 미루고 있다'고 전함. (키워드: 최루탄 사인, 두개골 골절, 경찰 발표 지연)"}, - "info_419_t2_opt2_got": {"보통": "정보: 마산상고 학생들이 '학우를 살려내라!', '살인경찰 처단하라!' 등의 구호를 외치며 경찰과 격렬하게 대치 중. 돌과 화염병이 등장했으며, 경찰은 최루탄을 난사하며 강경 진압. 부상 학생 속출. (키워드: 마산 학생시위, 경찰과격진압, 부상자)"}, - "info_419_t2_opt3_got": {"보통": "정보: 김주열 군 어머니, '내 아들은 시위 나간다고 말하고 나갔다. 경찰이 죽인 것이 틀림없다. 이 원통함을 어떻게 풀어야 할지 모르겠다'며 오열. (키워드: 김주열 가족, 경찰 책임 주장, 원통함)"}, + "event_419_t2_assignment": "마산에서 나쁜 선거에 반대하며 시위하던 김주열 학생이 사라졌는데, 바다에서 슬픈 모습으로 발견됐어요. 왜 김주열 학생이 죽었는지, 경찰은 처음에 어떻게 했는지, 마산 사람들이 얼마나 화가 났는지 자세히 알아보세요.", + "event_419_t2_source": "[알아두면 좋아요] 4월 11일, 마산 앞바다에서 눈에 최루탄이 박힌 김주열 학생의 모습은 사람들에게 큰 충격을 줬어요. 경찰은 처음엔 그냥 물에 빠져 죽었다고 하려 했지만, 모습이 알려지면서 거짓말 아니냐는 말이 많아졌어요. 마산은 이미 시위 때문에 분위기가 안 좋았어요.", + "action_419_t2_opt1_text": "김주열 학생이 있는 병원에 가서 의사 선생님 만나보기", + "action_419_t2_opt2_text": "마산 학생들이 시위하는 곳(마산상고 등)에 직접 가보기", + "action_419_t2_opt3_text": "김주열 학생을 처음 본 어부 아저씨와 가족들 이야기 듣기", + "info_419_t2_opt1_got": "새로운 사실: 병원 관계자가 몰래 말해줬어요. '김주열 학생은 최루탄 때문에 머리를 다쳐서 죽은 것 같아요. 경찰이 이걸 알리지 말라고 하고 있어요.' (힌트: 최루탄 때문에 죽음, 머리 다침, 경찰이 숨김)", + "info_419_t2_opt2_got": "새로운 사실: 마산상고 학생들이 '친구를 살려내라!', '나쁜 경찰 혼내주자!' 외치며 경찰과 싸우고 있어요. 돌멩이랑 불도 던지고, 경찰은 최루탄을 마구 쏴요. 다친 학생들이 많아요. (힌트: 마산 학생 시위, 경찰이 심하게 막음, 다친 사람 많음)", + "info_419_t2_opt3_got": "새로운 사실: 김주열 학생 어머니가 울면서 말했어요. '우리 아들은 시위하러 간다고 하고 나갔어요. 경찰이 죽인 게 틀림없어요. 너무 억울해요.' (힌트: 김주열 가족, 경찰이 죽였다고 생각, 억울함)", # Turn 3 (고려대생 피습) - "event_419_t3_assignment": {"보통": "4월 18일, 부정선거 규탄 시위를 마치고 귀교하던 고려대학교 학생들이 정치깡패들에게 피습당하는 사건이 발생했습니다. 사건의 전모, 경찰의 대응, 학생 및 시민 사회의 반응을 취재하십시오."}, - "event_419_t3_source": {"보통": "[배경 정보] 김주열 열사 사건 이후 학생 시위가 전국적으로 확산되는 가운데, 조직폭력배(정치깡패)가 동원되어 시위 학생들을 폭행하는 사건이 발생하여 국민적 분노가 더욱 커지고 있습니다. 경찰의 묵인 또는 방조 의혹도 제기되고 있습니다."}, - "action_419_t3_opt1_text": {"보통": "피습 현장(종로4가) 및 피해 학생 입원 병원 방문 취재"}, - "action_419_t3_opt2_text": {"보통": "경찰서 방문, 사건 수사 진행 상황 및 정치깡패 배후설 관련 질의"}, - "action_419_t3_opt3_text": {"보통": "고려대학교 총학생회 및 다른 대학 학생 대표 인터뷰"}, - "info_419_t3_opt1_got": {"보통": "정보: 피해 학생 증언, '시위 후 평화롭게 돌아가는데 갑자기 쇠파이프와 각목을 든 수십 명의 괴한이 덮쳤다. 살려달라고 외쳤지만 무자비하게 폭행했다.' 병원 복도에는 부상당한 학생들로 가득. (키워드: 고려대생 피습, 정치깡패, 쇠파이프, 집단폭행)"}, - "info_419_t3_opt2_got": {"보통": "정보: 경찰 관계자, '우발적인 학생 간 충돌로 파악하고 있다. 정치깡패 배후설은 낭설이다'라며 수사 확대에 소극적인 태도. (키워드: 경찰 축소수사, 우발적 충돌 주장, 배후부인)"}, - "info_419_t3_opt3_got": {"보통": "정보: 서울대 총학생회장, '이는 명백한 야만적 테러 행위이며, 정권의 비호 없이는 불가능한 일이다. 모든 학생이 연대하여 투쟁할 것'이라고 강력 규탄. (키워드: 학생사회 규탄, 정권 배후 의혹, 연대투쟁)"}, + "event_419_t3_assignment": "4월 18일, 나쁜 선거를 반대하는 시위를 마치고 학교로 돌아가던 고려대학교 학생들�� 나쁜 아저씨들에게 맞았어요. 무슨 일이 있었는지, 경찰은 뭘 했는지, 다른 사람들은 어떻게 생각하는지 알아보세요.", + "event_419_t3_source": "[알아두면 좋아요] 김주열 학생 일 때문에 학생들이 더 많이 시위하고 있는데, 이번엔 깡패 아저씨들이 나타나서 학생들을 때렸어요. 사람들이 더 화가 났어요. 경찰이 이걸 보고도 못 본 척한 거 아니냐는 말도 나와요.", + "action_419_t3_opt1_text": "학생들이 맞은 곳과 다친 학생들이 있는 병원에 가보기", + "action_419_t3_opt2_text": "경찰서에 가서 어떻게 조사하고 있는지, 깡패들 뒤에 누가 있는지 물어보기", + "action_419_t3_opt3_text": "고려대학교 학생 대표와 다른 대학교 학생 대표들 이야기 듣기", + "info_419_t3_opt1_got": "새로운 사실: 다친 학생이 말했어요. '시위 끝나고 조용히 가는데 갑자기 쇠파이프 든 아저씨들이 때렸어요. 살려달라고 해도 마구 때렸어요.' 병원에는 다친 학생들이 많았어요. (힌트: 고려대생 맞음, 깡패, 쇠파이프, 단체로 때림)", + "info_419_t3_opt2_got": "새로운 사실: 경찰 아저씨가 말했어요. '학생들끼리 싸운 것 같아요. 깡패가 있다는 건 그냥 소문이에요.' 더 조사할 생각은 없어 보였어요. (힌트: 경찰이 대충 조사, 그냥 싸웠다고 함, 뒤에 누가 있는지 모른 척)", + "info_419_t3_opt3_got": "새로운 사실: 서울대 학생 대표가 말했어요. '이건 나쁜 테러예요! 나라에서 도와주지 않으면 불가능한 일이에요. 모든 학생이 힘을 합쳐 싸울 거예요!' (힌트: 다른 학생들도 화남, 나라가 뒤에 있다고 의심, 같이 싸우자)", # Turn 4 (4.19 당일, 경무대 앞 발포) - "event_419_t4_assignment": {"보통": "4월 19일, 서울 시내에서 대규모 시위가 발생하여 경무대로 향하고 있습니다. 시위대의 규모와 요구사항, 경찰의 대응(발포 여부 포함), 사상자 발생 현황을 긴급 타전해야 합니다. 극도로 위험한 상황이니 신변 안전에 각별히 유의하십시오."}, - "event_419_t4_source": {"보통": "[배경 정보] 고려대생 피습 사건에 분노한 서울 시내 대학생과 중고생, 시민들이 거리로 쏟아져 나와 '이승만 하야', '부정선거 다시 하라' 등을 외치며 경무대로 향하고 있습니다. 경찰은 최루탄과 소방차를 동원해 저지하고 있으나 역부족인 상황입니다."}, - "action_419_t4_opt1_text": {"보통": "경무대 인근 시위대 선두 합류, 현장 상황 실시간 취재 (매우 위험)"}, - "action_419_t4_opt2_text": {"보통": "안전한 건물 옥상 등에서 시위 전체 규모 및 경찰 대응 관찰"}, - "action_419_t4_opt3_text": {"보통": "병원 응급실 방문, 부상자 및 사망자 현황 파악"}, - "info_419_t4_opt1_got": {"보통": "정보: 시위대, 경찰 저지선 뚫고 경무대 진입 시도. 경찰, 시위대를 향해 무차별 발포 시작. 눈앞에서 학생들이 피를 흘리며 쓰러지는 아비규환의 현장. (키워드: 경무대 발포, 무차별 사격, 학생 희생, 아비규환)"}, - "info_419_t4_opt2_got": {"보통": "정보: 수만 명의 시위대가 태평로와 광화문 일대를 가득 메움. 경찰, 최루탄과 함께 실탄 발포 확인. 시가지는 전쟁터 방불. (키워드: 대규모 시위, 경찰 실탄 발포, 시가전 양상)"}, - "info_419_t4_opt3_got": {"보통": "정보: 세브란스 병원 응급실, 총상 환자로 가득. 사망자 다수 발생. 의료진은 쉴 새 없이 움직이지만 역부족. '학생들이 죽어가고 있다'는 절규. (키워드: 총상환자, 다수 사망, 병원 참상, 의료진 부족)"}, + "event_419_t4_assignment": "4월 19일, 서울에서 아주 큰 시위가 일어나서 대통령이 사는 경무대로 가고 있어요. 얼마나 많은 사람들이 모였는지, 뭘 원하는지, 경찰은 어떻게 하는지(총을 쏘는지 포함), 다치거나 죽은 사람은 없는지 빨리 알려야 해요. 아주 위험하니까 조심 또 조심하세요!", + "event_419_t4_source": "[알아두면 좋아요] 고려대 학생들이 맞은 일 때문에 서울에 있는 대학생, 중고등학생, 어른들까지 거리로 나와서 '이승만 대통령 물러나라!', '나쁜 선거 다시 하자!' 외치면서 경무대로 가고 있어요. 경찰은 최루탄이랑 소방차로 막고 있지만 사람들이 너무 많아요.", + "action_419_t4_opt1_text": "경무대 근처 시위대 맨 앞에 가서 직접 보기 (아주 위험!)", + "action_419_t4_opt2_text": "안전한 건물 위에서 시위 전체 모습과 경찰 행동 살피기", + "action_419_t4_opt3_text": "병원 응급실에 가서 다치거나 죽은 사람 있는지 알아보기", + "info_419_t4_opt1_got": "새로운 사실: 시위대가 경찰 막는 걸 뚫고 경무대로 가려고 해요. 경찰이 시위대���테 마구 총을 쏘기 시작했어요! 눈앞에서 학생들이 피 흘리며 쓰러져요. 너무 무서운 현장이에요. (힌트: 경무대에서 총쏨, 마구 쏨, 학생들 죽음, 끔찍함)", + "info_419_t4_opt2_got": "새로운 사실: 수만 명의 사람들이 태평로와 광화문을 꽉 채웠어요. 경찰이 최루탄이랑 진짜 총알을 쏘는 걸 봤어요. 길거리가 전쟁터 같아요. (힌트: 아주 큰 시위, 경찰이 진짜 총쏨, 전쟁터 같음)", + "info_419_t4_opt3_got": "새로운 사실: 세브란스 병원 응급실에 총 맞은 사람들로 가득해요. 죽은 사람도 많아요. 의사 선생님들이 바쁘게 움직이지만 사람이 너무 많아요. '학생들이 죽어가고 있어요!' 하고 소리쳐요. (힌트: 총 맞은 환자, 많이 죽음, 병원도 힘듦, 의사 부족)", # Turn 5 (계엄령 선포) - "event_419_t5_assignment": {"보통": "정부가 서울 등 주요 도시에 비상계엄을 선포했습니다. 계엄군의 배치 상황, 시민들의 반응, 그리고 계엄 하에서의 언론 통제 실태를 취재하십시오."}, - "event_419_t5_source": {"보통": "[배경 정보] 4.19 시위가 격화되자 정부는 4월 19일 오후 5시를 기해 서울 지역에 비상계엄을 선포하고 군 병력을 투입했습니다. 이후 부산, 대구, 광주 등 주요 도시로 계엄이 확대되었습니다. 계엄사령부는 집회 및 시위 금지, 언론 검열 등을 포고했습니다."}, - "action_419_t5_opt1_text": {"보통": "시내 주요 지점 계엄군 배치 및 검문검색 현황 취재"}, - "action_419_t5_opt2_text": {"보통": "계엄 하 시민 인터뷰 (두려움 속에서도 저항 의지 확인)"}, - "action_419_t5_opt3_text": {"보통": "계엄사령부 방문, 언론 검열 지침 및 협조 요청 내용 파악"}, - "info_419_t5_opt1_got": {"보통": "정보: 탱크와 장갑차를 앞세운 계엄군이 시내 주요 도로와 관공서를 장악. 시민들의 통행을 엄격히 통제하며, 일부 지역에서는 학생들을 강제 연행하는 모습 목격. (키워드: 계엄군 시내 장악, 탱크 장갑차, 통행금지, 강제연행)"}, - "info_419_t5_opt2_got": {"보통": "정보: 시민 A씨, '군인들이 총칼을 들고 거리를 활보하니 무섭지만, 이대로 독재를 용납할 수는 없다. 기회가 되면 다시 거리로 나갈 것'이라고 다짐. (키워드: 계엄하 시민반응, 공포와 저항, 독재타도 의지)"}, - "info_419_t5_opt3_got": {"보통": "정보: 계엄사 공보실, '국가 안정을 위해 보도 내용을 사전 검열하며, 유언비어 유포 시 엄단할 것'이라는 내용의 보도지침 전달. 사실상 정부 발표 외 보도 금지. (키워드: 언론검열, 보도지침, 계엄사령부, 정보통제)"}, + "event_419_t5_assignment": "정부가 서울이랑 다른 큰 도시에 '비상계엄'을 내렸어요. 군인들이 어디에 있는지, 사람들은 어떻게 생각하는지, 계엄령 아래서 신문이나 방송은 어떻게 되는지 알아보세요.", + "event_419_t5_source": "[알아두면 좋아요] 4.19 시위가 너무 커지니까 정부가 4월 19일 오후 5시에 서울에 비상계엄을 내리고 군인들을 보냈어요. 그 후 부산, 대구, 광주 같은 큰 도시에도 계엄령이 내려졌어요. 계엄사령부는 모이거나 시위하는 걸 금지하고, 신문 기사도 미리 검사한다고 했어요.", + "action_419_t5_opt1_text": "시내 중요 장소에 군인들이 있는지, 사람들 지나가는 거 검사하는지 보기", + "action_419_t5_opt2_text": "계엄령 아래 있는 사람들 이야기 듣기 (무서워도 싸우고 싶은 마음)", + "action_419_t5_opt3_text": "계엄사령부에 가서 신문 기사 어떻게 검사하는지 알아보기", + "info_419_t5_opt1_got": "새로운 사실: 탱크랑 장갑차를 탄 군인들이 길이랑 중요한 건물들을 지키고 있어요. 사람들이 마음대로 못 다니게 하고, 어떤 곳에서는 학생들을 막 잡아갔어요. (힌트: 군인이 도시 장악, 탱크 장갑차, 못 다니게 함, 강제로 잡아감)", + "info_419_t5_opt2_got": "새로운 사실: 어떤 아저씨가 말했어요. '군인들이 총 들고 다니니까 무섭지만, 이렇게 나쁜 정치를 그냥 둘 수는 없어요. 기회가 되면 다시 시위할 거예요.' (힌트: 계엄령 속 사람들 마음, 무섭지만 싸우고 싶음, 나쁜 정치 싫음)", + "info_419_t5_opt3_got": "새로운 사실: 계엄사령부에서 말했어요. '나라를 안전하게 하려고 신문 내용을 미리 검사할 거예요. 거짓 소문 퍼뜨리면 혼내줄 거예요.' 사실상 정부가 시키는 대로만 써야 해요. (힌트: 신문 검사, 정부 말만 쓰게 함, 계엄사령부, 정보 막음)", # Turn 6 (대학교수단 시위) - "event_419_t6_assignment": {"보통": "4월 25일, 전국 대학교수단이 시국선언문을 발표하고 거리 시위에 나섰습니다. 교수단의 요��사항, 시위 규모 및 양상, 이에 대한 정부와 시민들의 반응을 취재하십시오."}, - "event_419_t6_source": {"보통": "[배경 정보] 학생들의 피에 지식인 사회도 분노했습니다. 서울대 문리대 교수들을 시작으로 전국 27개 대학 258명의 교수들이 '학생들의 피에 보답하라'며 이승만 대통령의 하야와 정부 총사퇴를 요구하는 시국선언을 하고 거리로 나섰습니다. 이는 정권에 큰 도덕적 타격을 주었습니다."}, - "action_419_t6_opt1_text": {"보통": "교수단 시위 현장(국회의사당 앞 등) 동행 취재"}, - "action_419_t6_opt2_text": {"보통": "시국선언 주도 교수 인터뷰 (요구사항 및 결의)"}, - "action_419_t6_opt3_text": {"보통": "시민들의 교수단 시위 지지 및 환호 반응 취재"}, - "info_419_t6_opt1_got": {"보통": "정보: 수백 명의 교수들이 '이승만은 하야하라', '민주주의 수호하자' 등의 플래카드를 들고 질서정연하게 행진. 시민들은 박수와 환호로 지지. 경찰도 이전보다 소극적 대응. (키워드: 교수단 시위, 이승만 하야 요구, 시민 지지, 평화 행진)"}, - "info_419_t6_opt2_got": {"보통": "정보: 서울대 K교수, '더 이상 지식인으로서 불의를 외면할 수 없었다. 이 대통령은 즉각 물러나고, 민주 질서를 회복해야 한다'고 단호히 발언. (키워드: 교수 시국선언, 불의 항거, 민주질서 회복)"}, - "info_419_t6_opt3_got": {"보통": "정보: 시위 지켜보던 시민 L씨, '교수님들까지 나서주시니 이제 정말 이 정권 끝났다. 우리 학생들, 시민들 힘내자!'며 눈시울을 붉힘. (키워드: 시민 감격, 교수 지지, 정권 종말 예감)"}, + "event_419_t6_assignment": "4월 25일, 전국 대학교수님들이 '우리도 할 말이 있다!' 하면서 거리로 나왔어요. 교수님들이 뭘 원하는지, 얼마나 많이 모였는지, 정부랑 사람들은 어떻게 생각하는지 알아보세요.", + "event_419_t6_source": "[알아두면 좋아요] 학생들이 피 흘리는 걸 보고 똑똑한 어른들도 화가 났어요. 서울대학교 교수님들을 시작으로 전국 27개 대학교 258명의 교수님들이 '학생들의 피에 보답하라!' 하면서 이승만 대통령 물러나고 정부도 다 그만두라고 외치며 거리로 나왔어요. 이건 정부에게 큰 충격이었어요.", + "action_419_t6_opt1_text": "교수님들 시위하는 곳(국회의사당 앞 등)에 같이 가보기", + "action_419_t6_opt2_text": "시위 이끄는 교수님 만나서 왜 하는지, 뭘 원하는지 듣기", + "action_419_t6_opt3_text": "사람들이 교수님들 시위 응원하는 모습 보기", + "info_419_t6_opt1_got": "새로운 사실: 수백 명의 교수님들이 '이승만 물러나라', '민주주의 지키자' 같은 글을 들고 조용히 걸었어요. 사람들은 박수치고 응원했어요. 경찰도 전보다 덜 막았어요. (힌트: 교수님들 시위, 이승만 물러나라고 함, 사람들 응원, 조용한 시위)", + "info_419_t6_opt2_got": "새로운 사실: 서울대 K교수님이 말했어요. '더 이상 나쁜 일을 보고만 있을 수 없었어요. 이 대통령은 빨리 물러나고, 민주주의를 다시 찾아야 해요.' (힌트: 교수님들 생각, 나쁜 일 못 참음, 민주주의 되찾자)", + "info_419_t6_opt3_got": "새로운 사실: 시위 보던 어떤 아줌마가 울면서 말했어요. '교수님들까지 나오시니 이제 정말 이 정권 끝났어요. 우리 학생들, 사람들 힘내요!' (힌트: 사람들 감동, 교수님들 응원, 정권 끝날 것 같음)", # Turn 7 (미국의 압력과 이승만 하야 결심) - "event_419_t7_assignment": {"보통": "미국 정부가 현 사태에 대한 우려와 함께 이승만 대통령의 결단을 촉구하는 메시지를 전달한 것으로 알려졌습니다. 이승만 대통령의 심경 변화와 하야 가능성, 그리고 자유당 내부의 움직임을 긴급 취재하십시오."}, - "event_419_t7_source": {"보통": "[배경 정보] 4.19 혁명이 격화되자 미국 정부는 월터 매카나기 주한미국대사를 통해 이승만 대통령에게 사실상의 하야를 권고했습니다. 국제적인 고립과 내부의 거센 저항에 직면한 이 대통령은 중대한 결심을 앞두고 있습니다."}, - "action_419_t7_opt1_text": {"보통": "경무대 주변 취재, 이 대통령 측근 동향 파악"}, - "action_419_t7_opt2_text": {"보통": "자유당 고위 관계자 접촉, 당내 분위기 및 수습책 논의 내용 취재"}, - "action_419_t7_opt3_text": {"보통": "주한미국대사관 주변 취재, 미국의 입장 변화 확인"}, - "info_419_t7_opt1_got": {"보통": "정보: 경무대 관계자(익명), '대통령께서 며칠 밤잠을 못 이루시고 깊은 고뇌에 빠져 계신다. 곧 중대 발표가 있을 것이라는 소문이 파다하다.' (키워드: 이승만 고뇌, 중대발표 임박, 경무대 분위기)"}, - "info_419_t7_opt2_got": {"보통": "정보: 자유당 중진 의원 M씨, '이미 대세는 기울었다. 대통령께서 명예롭게 퇴진하시는 것만이 유일한 수습책이다. 당내에서도 하야를 건의해야 한다는 목소리가 커지고 있다.' (키워드: 자유당 하야 건의, 명예퇴진, 당내 분열)"}, - "info_419_t7_opt3_got": {"보통": "정보: 미 대사관 관계자(비공식), '미국 정부는 한국의 민주주의 회복과 안정적인 정권 이양을 강력히 희망한다. 현 상황이 지속되는 것은 바람직하지 않다.' (키워드: 미국 정부 입장, 민주주의 회복 촉구, 정권이양 희망)"}, + "event_419_t7_assignment": "미국 정부가 지금 우리나라 상황이 걱정된다면서 이승만 대통령에게 중요한 결정을 하라고 했다는 소문이 있어요. 이승만 대통령 마음이 어떻게 변했는지, 정말 물러날 건지, 자유당 사람들은 어떻게 움직이는지 빨리 알아보세요.", + "event_419_t7_source": "[알아두면 좋아요] 4.19 혁명이 커지니까 미국 정부가 우리나라에 있는 미국 대사를 통해 이승만 대통령에게 사실상 물러나라고 했어요. 외국에서도 외면받고, 나라 안에서도 사람들이 계속 반대하니까 이 대통령은 아주 중요한 결정을 해야 해요.", + "action_419_t7_opt1_text": "경무대 근처에서 대통령 주변 사람들 어떻게 하는지 보기", + "action_419_t7_opt2_text": "자유당 높은 사람들 만나서 당 분위기랑 앞으로 어떻게 할 건지 듣기", + "action_419_t7_opt3_text": "미국 대사관 근처에서 미국 생각이 바뀌었는지 알아보기", + "info_419_t7_opt1_got": "새로운 사실: 경무대에서 일하는 사람이 몰래 말해줬어요. '대통령님이 며칠 동안 잠도 못 자고 깊이 고민하고 계세요. 곧 아주 중요한 발표가 있을 거라는 소문이 많아요.' (힌트: 이승만 대통령 고민, 중요한 발표 곧 할 듯, 경무대 분위기 심각)", + "info_419_t7_opt2_got": "새로운 사실: 자유당 국회의원 M아저씨가 말했어요. '이미 끝났어요. 대통령님이 멋있게 물러나시는 게 유일한 방법이에요. 우리 당 안에서도 물러나시라고 말해야 한다는 목소리가 커지고 있어요.' (힌트: 자유당도 물러나라고 함, 멋있게 그만두길 바람, 당 안에서도 의견 갈림)", + "info_419_t7_opt3_got": "새로운 사실: 미국 대사관 사람이 몰래 말해줬어요. '미국 정부는 한국이 다시 민주주의를 찾고, 평화롭게 정권이 바뀌길 바라요. 지금 상황이 계속되는 건 좋지 않아요.' (힌트: 미국 정부 생각, 민주주의 되찾길 바람, 평화롭게 바뀌길 바람)", # Turn 8 (이승만 대통령 하야 발표) - "event_419_t8_assignment": {"보통": "4월 26일, 이승만 대통령이 하야를 발표했습니다. 하야 성명 내용, 시민들의 반응, 그리고 향후 정국 전망을 종합적으로 취재하여 특별 기사를 작성해야 합니다. (이번 턴은 취재 활동 없이 바로 기사 작성으로 이어집니다.)"}, - "event_419_t8_source": {"보통": "[속보] 이승만 대통령, 국민의 요구에 따라 대통령직에서 물러나겠다고 발표. 라디오를 통해 하야 성명 발표. 시민들 거리로 쏟아져 나와 환호. 12년간의 자유당 정권 종식."}, - "action_419_t8_opt1_text": {"보통": "하야 성명 전문 및 주요 내용 분석"}, # 정보 획득용 선택지 (실제로는 자동 획득) - "action_419_t8_opt2_text": {"보통": "시민 환호 현장 및 인터뷰"}, - "action_419_t8_opt3_text": {"보통": "정치권 및 학계 향후 정국 전망 분석"}, - "info_419_t8_opt1_got": {"보통": "정보: 이승만 대통령 하야 성명 전문 입수. '국민이 원한다면 대통령직을 사임하겠다', '3.15 선거는 부정이 있었으니 다시 하도록 지시', '내각책임제 개헌도 할 것' 등 내용 포함. (키워드: 이승만 하야 성명, 국민의 뜻, 부정선거 인정, 내각제 개헌)"}, - "info_419_t8_opt2_got": {"보통": "정보: 서울 시내, 시민들 거리로 뛰쳐나와 '독재 타도, 민주 승리' 외치며 서로 부둥켜안고 눈물. 자동차 경적 울리며 축제 분위기. (키워드: 시민 환호, 민주승리, 축제분위기, 독재종식)"}, - "info_419_t8_opt3_got": {"보통": "정보: 정치학자 P교수, '허정 과도정부 수립 후 조속한 시일 내에 총선거 실시 예상. 민주당 중심의 내각책임제 정부 출범 가능성 높다. 다만, 정치적 혼란과 사회적 요구 분출 우려.' (키워드: 허정과도정부, 총선거, 내각책임제, 정치혼란 우려)"}, + "event_419_t8_assignment": "4월 26일, 이승만 대통령이 물러나겠다고 발표했어요! 대통령이 뭐라고 말했는지, 사람들은 어떤 반응인지, 앞으로 나라는 어떻게 될지 다 합쳐서 특별 기사를 ��야 해요. (이번엔 취재 활동 없이 바로 기사 쓰기로 가요.)", + "event_419_t8_source": "[긴급 뉴스] 이승만 대통령, 국민들이 원해서 대통령 자리에서 물러나겠다고 발표. 라디오로 이야기했어요. 사람들이 거리로 나와서 기뻐하고 있어요. 12년 동안 계속된 자유당 정치가 끝났어요.", + "action_419_t8_opt1_text": "대통령이 물러나면서 한 말 자세히 보기", + "action_419_t8_opt2_text": "사람들이 기뻐하는 모습과 이야기 듣기", + "action_419_t8_opt3_text": "정치인들과 똑똑한 사람들이 앞으로 어떻게 될지 이야기하는 것 듣기", + "info_419_t8_opt1_got": "새로운 사실: 이승만 대통령이 물러나면서 한 말 전문을 구했어요. '국민이 원하면 대통령 그만두겠다', '3.15 선거는 잘못됐으니 다시 하라고 했다', '나라 다스리는 방법도 바꾸겠다' 같은 내용이 있었어요. (힌트: 이승만 대통령 물러남, 국민 뜻 따름, 나쁜 선거 인정, 정치 방식 바꿈)", + "info_419_t8_opt2_got": "새로운 사실: 서울 길거리에 사람들이 뛰쳐나와 '나쁜 정치 끝났다, 민주주의 이겼다!' 외치면서 서로 껴안고 울었어요. 자동차들이 빵빵거리며 축제 분위기였어요. (힌트: 사람들 기뻐함, 민주주의 승리, 축제 분위기, 나쁜 정치 끝)", + "info_419_t8_opt3_got": "새로운 사실: 정치학자 P교수님이 말했어요. '허정 아저씨가 잠깐 나라를 맡고, 곧 국회의원 선거를 다시 할 것 같아요. 민주당이 중심이 돼서 나라를 다스릴 가능성이 높아요. 하지만 좀 시끄럽고 사람들이 원하는 게 많아질 수도 있어요.' (힌트: 허정 아저씨가 임시로 맡음, 다시 선거, 민주당 중심 정치, 좀 시끄러울 수도 있음)", # --- 5.18 광주 취재 시나리오 --- - "scenario_518_gwangju_name": {"보통": "5.18 광주 현장 취재 (1980)"}, + "scenario_518_gwangju_name": "5.18 광주 이야기 (1980년)", # Turn 1 (5.17 비상계엄 전국 확대) - "event_518_t1_assignment": {"보통": "5월 17일 24시를 기해 비상계엄이 전국으로 확대되었습니다. 광주 지역의 분위기, 주요 인사(학생운동 지도부, 재야인사)들의 동향, 그리고 계엄군의 움직임을 파악하여 보고하십시오. 언론 통제가 심하니 보안에 각별히 유의해야 합니다."}, - "event_518_t1_source": {"보통": "[배경 정보] 10.26 사건 이후 '서울의 봄'이 찾아왔으나, 신군부가 12.12 군사반란으로 실권을 장악하면서 정국은 다시 경색되고 있습니다. 신군부는 사회 혼란을 빌미로 비상계엄을 전국으로 확대하고, 김대중, 김영삼 등 주요 정치인들을 체포/연금했습니다. 광주 지역 대학가에서는 학생들의 시위 움직임이 감지되고 있습니다."}, - "action_518_t1_opt1_text": {"보통": "전남대학교 등 주요 대학가 학생회관 주변 탐문"}, - "action_518_t1_opt2_text": {"보통": "광주 시내 주요 도로 및 공공기관 계엄군 배치 상황 확인"}, - "action_518_t1_opt3_text": {"보통": "지역 재야인사 또는 종교 지도자 비밀 인터뷰 시도"}, - "info_518_t1_opt1_got": {"보통": "정보: 전남대 학생회 간부들, '계엄 확대는 민주화 열망을 짓밟는 폭거'라며 내일(18일) 오전 교내 시위 계획 중. '휴교령 반대, 계엄 철폐' 구호 준비. (키워드: 전남대 학생시위 예고, 계엄반대, 휴교령 철회 요구)"}, - "info_518_t1_opt2_got": {"보통": "정보: 광주역, 버스터미널, 도청 등 주요 지점에 중무장한 공수부대원들이 배치되기 시작. 시민들은 불안감과 공포감을 느끼고 있음. (키워드: 공수부대 배치, 삼엄한 경계, 시민 불안)"}, - "info_518_t1_opt3_got": {"보통": "정보: 익명의 종교 지도자, '신군부가 정권 장악을 위해 무자비한 탄압을 자행할 가능성이 크다. 광주가 희생양이 될까 우려된다'며 깊은 한숨. (키워드: 신군부 탄압 우려, 광주 희생양, 종교계 시국관)"}, + "event_518_t1_assignment": "5월 17일 밤부터 '비상계엄'이 전국으로 커졌어요. 광주 분위기는 어떤지, 중요한 사람들(학생 대표, 숨어있는 어른들)은 어떻게 움직이는지, 군인들은 뭘 하는지 알아보고 알려주세요. 신문이나 방송을 못 믿게 하니까 몰래 조심해서 취재해야 해요.", + "event_518_t1_source": "[알아두면 좋아요] 10.26 사건 뒤에 '서울의 봄'이라고 해서 좋은 세상이 올 것 같았지만, 새로운 군인 아저씨들이 12.12 군사반란으로 힘을 잡으면서 다시 무서워졌어요. 새 군인들은 나라가 시끄럽다면서 비상계엄을 전국으로 넓히고, 김대중, 김영삼 같은 유명한 정치인들을 잡아가거나 못 나오게 했어요. 광주 대학교에서는 학생들이 시위하려는 움직임이 보여요.", + "action_518_t1_opt1_text": "전남대학교 같은 대학교 학생회관 근처에서 이야기 들어보기", + "action_518_t1_opt2_text": "광주 시내 큰 길이나 중요한 건물에 군인들이 있는지 확인하기", + "action_518_t1_opt3_text": "광주에 사는 숨어있는 어른이나 종교 지도자 몰래 만나보기", + "info_518_t1_opt1_got": "새로운 사실: 전남대 학생 대표들이 '계엄 확대는 나쁜 짓이다!' 하면서 내일(18일) 아침에 학교에서 시위할 계획이래요. '학교 문 닫지 마라, 계엄령 없애라!' 외칠 준비를 하고 있어요. (힌트: 전남대 학생 시위 예고, 계엄 반대, 학교 문 열라고 함)", + "info_518_t1_opt2_got": "새로운 사실: 광주역, 버스터미널, 도청 같은 중요한 곳에 무서운 무기를 든 공수부대 군인들이 나타나기 시작했어요. 사람들은 무서워하고 불안해해요. (힌트: 공수부대 나타남, 무섭게 지킴, 사람들 불안)", + "info_518_t1_opt3_got": "새로운 사실: 이름을 밝히기 싫어하는 종교 지도자가 한숨 쉬며 말했어요. '새 군인들이 자기들 마음대로 하려고 사람들을 아주 심하게 혼내줄 것 같아요. 광주가 큰일 날까 봐 걱정돼요.' (힌트: 새 군인들 무섭게 할 듯, 광주 걱정, 종교 어른 생각)", # Turn 2 (5.18 첫날, 전남대 앞 충돌) - "event_518_t2_assignment": {"보통": "5월 18일 오전, 전남대학교 앞에서 학생들과 계엄군 간의 첫 충돌이 발생했습니다. 충돌의 원인과 과정, 학생 및 계엄군의 피해 상황, 그리고 시민들의 반응을 긴급히 취재하십시오. 현장 접근 시 신변 안전에 극히 유의해야 합니다."}, - "event_518_t2_source": {"보통": "[배경 정보] 어제(17일) 비상계엄 전국 확대 조치에 따라 대학 휴교령이 내려졌으나, 전남대 학생들은 이에 항의하며 교문 앞에서 시위를 벌였습니다. 계엄군(공수부대)은 이를 강경 진압하기 시작했습니다."}, - "action_518_t2_opt1_text": {"보통": "전남대학교 정문 앞 시위 현장 직접 취재 (매우 위험)"}, - "action_518_t2_opt2_text": {"보통": "부상 학생 후송된 인근 병원 방문, 피해 상황 파악"}, - "action_518_t2_opt3_text": {"보통": "현장 주변 상인 및 주민 목격담 청취"}, - "info_518_t2_opt1_got": {"보통": "정보: 공수부대원들이 교문으로 진입하려는 학생들을 향해 무차별적으로 곤봉을 휘두르고 군홧발로 폭행. 여학생, 남학생 가리지 않고 구타. 학생들이 피를 흘리며 쓰러지고 끌려가는 모습 목격. (키워드: 공수부대 과잉진압, 무차별 폭행, 학생 부상, 전남대 정문)"}, - "info_518_t2_opt2_got": {"보통": "정보: 병원 응급실, 두부 외상 및 골절상 입은 학생들로 가득. 한 학생은 '단지 학교에 들어가려 했을 뿐인데, 군인들이 갑자기 몽둥이로 때렸다'며 울분 토로. (키워드: 학생 중상, 병원 응급실, 군인 폭력 증언)"}, - "info_518_t2_opt3_got": {"보통": "정보: 인근 상인, '학생들이 무슨 큰 죄를 지었다고 저렇게까지 때리나. 이건 너무 심하다. 군인들이 아니라 깡패 같다'며 분개. (키워드: 시민 분노, 계엄군 만행 비판, 과잉진압 목격)"}, - # (이하 5.18 턴들 생략) + "event_518_t2_assignment": "5월 18일 아침, 전남대학교 앞에서 학생들과 군인들이 처음으로 싸웠어요. 왜 싸움이 났는지, 어떻게 싸웠는지, 학생들과 군인들은 얼마나 다쳤는지, 다른 사람들은 어떻게 생각하는지 빨리 알아보세요. 현장에 갈 땐 아주 조심해야 해요!", + "event_518_t2_source": "[알아두면 좋아요] 어제(17일) 비상계엄이 전국으로 커지면서 대학교 문을 닫으라고 했지만, 전남대 학생들은 반대하면서 학교 문 앞에서 시위를 했어요. 계엄군(공수부대)은 이걸 아주 세게 막기 시작했어요.", + "action_518_t2_opt1_text": "전남대학교 정문 앞 시위 현장에 직접 가보기 (아주 위험!)", + "action_518_t2_opt2_text": "다친 학생들이 간 근처 병원에 가서 얼마나 다쳤는지 알아보기", + "action_518_t2_opt3_text": "현장 근처 가게 주인이나 동네 사람들한테 본 이야기 듣기", + "info_518_t2_opt1_got": "새로운 사실: 공수부대 군인들이 학교 문으로 들어가려는 학생들을 몽둥이로 마구 때리고 군홧발로 찼어요. 여자든 남자든 가리지 않고 때렸어요. 학생들이 피 흘리며 쓰러지고 끌려가는 걸 봤어요. (힌트: 공수부대 너무 심하게 때림, 마구 때림, 학생들 다침, 전남대 정문)", + "info_518_t2_opt2_got": "새로운 사실: 병원 응급실에 머리나 뼈를 다친 학생들로 가득해요. 한 학생은 '그냥 학교에 들어가려고 했는데, 군인들이 갑자기 몽둥이로 때렸어요!' 하면서 울었어요. (힌트: 학생들 많이 다침, 병원 응급실, 군인이 때렸다고 함)", + "info_518_t2_opt3_got": "새로운 사실: 근처 가게 주인이 화내면서 말했어요. '학생들이 뭘 그렇게 잘못했다고 저렇게까지 때리나. 이건 너무 심해요. 군인이 아니라 깡패 같아요!' (힌트: 사람들 화남, 군인들 나쁘다고 함, 너무 심하게 막는 거 봄)", + # Turn 3 (시위 확산과 계엄군의 잔혹한 진압) + "event_518_t3_assignment": "학생들 시위가 광주 시내 전체로 퍼지고 있어요. 일반 시민들도 함께하고 있어요. 하지만 공수부대 군인들이 더 잔인하게 사람들을 때리고 잡아가고 있다는 소문이 들려요. 이 상황을 자세히 취재해주세요. 정말 위험하니 몸조심하세요!", + "event_518_t3_source": "[알아두면 좋아요] 전남대 앞에서 시작된 군인들의 폭력은 오히려 시민들의 분노를 키웠어요. 학생들뿐만 아니라 일반 시민들도 거리로 나와 '계엄 철폐', '살인마 전두환 물러가라' 등을 외치고 있어요. 공수부대는 시위대뿐 아니라 길 가던 사람들에게도 폭력을 행사하고 있다는 목격담이 나오고 있어요.", + "action_518_t3_opt1_text": "금남로 등 시위가 격렬한 곳으로 가서 상황 보기 (매우 위험!)", + "action_518_t3_opt2_text": "시위에 참여한 시민들 이야기 들어보기 (왜 나왔는지, 뭘 봤는지)", + "action_518_t3_opt3_text": "군인들에게 맞거나 끌려간 사람들의 가족 만나보기", + "info_518_t3_opt1_got": "새로운 사실: 금남로에서 군인들이 곤봉과 대검으로 사람들을 마구 찌르고 때리고 있어요. 길바닥에 피가 흥건하고, 비명소리가 끊이지 않아요. 젊은이, 노인 가리지 않아요. (힌트: 금남로, 군인들 잔인함, 피, 비명)", + "info_518_t3_opt2_got": "새로운 사실: 한 아주머니가 울면서 말했어요. '내 아들이 학생도 아닌데 길 가다가 군인들에게 끌려갔어요! 살려주세요!' 많은 시민들이 군인들의 만행에 치를 떨고 있어요. (힌트: 시민들 분노, 아무나 잡아감, 군인 만행)", + "info_518_t3_opt3_got": "새로운 사실: 군인에게 맞아서 다리가 부러진 아저씨를 만났어요. '그냥 집에 가던 길이었는데, 갑자기 군인 서너 명이 달려들어 때렸어요. 이유도 없었어요.' (힌트: 무차별 폭행, 이유 없는 폭력, 시민 피해)", + # Turn 4 (시민들의 자체 무장과 항쟁 시작) + "event_518_t4_assignment": "군인들의 폭력이 너무 심해지자, 일부 시민들이 스스로를 지키기 위해 무기를 들기 시작했다는 소식이 있어요. '시민군'이 만들어졌다는 말도 들려요. 광주 상황이 어떻게 변하고 있는지, 시민들은 왜 무기를 들었는지 알아보세요.", + "event_518_t4_source": "[알아두면 좋아요] 계엄군의 무자비한 살상 행위에 맞서 시민들은 더 이상 맨손으로 저항할 수 없다고 판단하기 시작했어요. 경찰서나 예비군 무기고에서 총기 등을 확보하고, 스스로를 '시민군'이라 부르며 조직적으로 저항하려는 움직임이 나타나고 있어요. 광주는 외부와 완전히 차단된 상태예요.", + "action_518_t4_opt1_text": "시민군이 모여 있다는 곳(도청 주변 등)에 조심스럽게 접근해보기", + "action_518_t4_opt2_text": "무기를 든 시민에게 왜 그랬는지, 앞으로 뭘 할 건지 물어보기", + "action_518_t4_opt3_text": "광주 시내 병원에 가서 총상 환자가 있는지, 의료 상황은 어떤지 확인하기", + "info_518_t4_opt1_got": "새로운 사실: 도청 주변에 젊은이들이 총을 들고 모여 있어요. 스스로를 '시민군'이라고 부르며, '계엄군으로부터 광주를 지키겠다'고 외치고 있어요. 분위기가 아주 긴장돼요. (힌트: 시민군 등장, 도청, 총 든 시민, 광주 지키기)", + "info_518_t4_opt2_got": "새로운 사실: 총을 든 한 청년이 말했어요. '우리 가족과 친구들이 군인들에게 맞아 죽는 걸 더는 볼 수 없었어요. 우리도 살기 위해 싸우는 거예요!' (힌트: 시민군 된 이유, 가족 보호, 살기 위한 싸움)", + "info_518_t4_opt3_got": "새로운 사실: 병원에 총 맞은 사람들이 계속 실려오고 있어요. 의사, 간호사, 약품 모두 부족해요. '제발 도와주세요!' 하는 소리가 들려요. (힌트: 총상 환자 많음, 병원 부족, 도움 필요)", + # Turn 5 (해방 광주와 시민 자치) + "event_518_t5_assignment": "계엄군이 잠시 광주 외곽으로 물러나고, 시민들이 광주를 스스로 다스리고 있다는 소식이 있어요. 이 짧은 '해방 광주' 기간 동안 시민들은 어떻게 지내고 있는지, 질서는 잘 지켜지는지, 앞으로 뭘 걱정하는지 취재해주세요.", + "event_518_t5_source": "[알아두면 좋아요] 시민들의 거센 저항에 밀려 계엄군이 5월 21일 광주 시내에서 철수했어요. 이후 며칠간 시민들은 스스로 질서를 유지하며 식량과 생필품을 나누고, 부상자를 돌봤어요. 하지만 계엄군이 다시 공격해올 거라는 불안감도 컸어요.", + "action_518_t5_opt1_text": "시민들이 모여 회의하는 곳(도청 광장 등)에 가보기", + "action_518_t5_opt2_text": "시민들에게 지금 생활이 어떤지, 뭘 가장 바라는지 물어보기", + "action_518_t5_opt3_text": "식량이나 물건을 나눠주는 곳에 가서 시민들 돕는 모습 보기", + "info_518_t5_opt1_got": "새로운 사실: 도청 광장에서 시민들이 모여 앞으로 어떻게 할지 이야기하고 있어요. '우리의 요구를 정부에 알려야 한다', '끝까지 싸우자' 같은 목소리가 나와요. (힌트: 시민 회의, 도청 광장, 요구 전달, 계속 싸우자)", + "info_518_t5_opt2_got": "새로운 사실: 한 상인이 말했어요. '군인들이 없으니 잠시 평화롭지만, 언제 다시 쳐들어올지 몰라 무서워요. 제발 이 일이 빨리 해결됐으면 좋겠어요.' (힌트: 잠시 평화, 다시 공격 걱정, 빨리 해결되길 바람)", + "info_518_t5_opt3_got": "새로운 사실: 아주머니들이 주먹밥을 만들어서 시민군과 배고픈 사람들에게 나눠주고 있어요. 서로 돕고 아끼는 모습이 감동적이에요. (힌트: 시민들 서로 도움, 주먹밥 나눔, 감동적)", + # Turn 6 (계엄군의 재진입 임박과 마지막 저항 준비) + "event_518_t6_assignment": "계엄군이 다시 광주로 쳐들어올 거라는 소문이 파다해요. 시민들은 마지막까지 싸울 준비를 하고 있는 것 같아요. 도청을 중심으로 한 시민군의 상황과 광주 전체의 긴장된 분위기를 전해주세요. 매우 위험한 상황입니다.", + "event_518_t6_source": "[알아두면 좋아요] '해방 광주'는 오래가지 못했어요. 신군부는 대규모 병력을 동원해 광주를 다시 점령할 계획을 세웠어요. 시민들은 이 사실을 알고 있었지만, 많은 이들이 끝까지 남아 광주를 지키려 했어요. 외부와의 통신은 거의 끊긴 상태예요.", + "action_518_t6_opt1_text": "도청 주변 시민군들의 마지막 방어 준비 모습 살펴보기 (극도로 위험!)", + "action_518_t6_opt2_text": "남아있는 시민들에게 왜 떠나지 않았는지, 심정이 어떤지 듣기", + "action_518_t6_opt3_text": "외신기자나 외부와 연락하려는 사람들을 찾아보기", + "info_518_t6_opt1_got": "새로운 사실: 도청 주변에 시민군들이 바리케이드를 쌓고 무기를 점검하고 있어요. 표정은 굳어있지만, 눈빛은 결연해요. '광주는 우리가 지킨다!'는 말이 들려요. (힌트: 도청 방어 준비, 시민군 결의, 마지막 저항)", + "info_518_t6_opt2_got": "새로운 사실: 어린 학생 시민군이 말했어요. '무섭지만 도망가지 않을 거예요. 여기서 죽더라도 광주를 지키고 싶어요.' 많은 사람들이 비장한 각오를 하고 있어요. (힌트: 남은 시민들 각오, 두려움과 용기, 광주 지키기)", + "info_518_t6_opt3_got": "새로운 사실: 광주의 진실을 알리려는 일부 시민들이 몰래 외부로 편지나 사진을 보내려고 애쓰고 있어요. 하지만 군인들이 철저히 막고 있어서 쉽지 않아 보여요. (힌트: 진실 알리기 노력, 외부 연락 시도, 군인 통제)", + # Turn 7 (5.27 새벽, 계엄군 도청 진압 작전) + "event_518_t7_assignment": "5월 27일 새벽, 결국 계엄군이 탱크를 앞세우고 도청으로 쳐들어왔어요. 마지막까지 저항하던 시민군과 계엄군 사이에 큰 전투가 벌어지고 있어요. 이 비극적인 상황을 기록해야 합니다. 안전을 최우선으로 하세요.", + "event_518_t7_source": "[알아두면 좋아요] 5월 27일 새벽, 계엄군은 '상무충정작전'이라는 이름으로 전남도청을 무력으로 점령했어요. 도청을 사수하던 많은 시민군이 이 과정에서 희생되었어요. 이로써 열흘간의 광주민주화운동은 비극적으로 막을 내리게 됩니다.", + "action_518_t7_opt1_text": "도청 근처 안전한 곳에서 총소리와 상황 파악하기 (매우 위험!)", + "action_518_t7_opt2_text": "진압 작전 후 거리 모습과 시민들 반응 살피기", + "action_518_t7_opt3_text": "병원으로 실려 오는 부상자나 사망자 상황 확인하기", + "info_518_t7_opt1_got": "새로운 사실: 새벽부터 도청 쪽에서 총소리가 쉴 새 없이 들려요. 탱크 소리도 들리고, 하늘에는 헬리콥터가 날아다녀요. 마치 전쟁터 같아요. (힌트: 도청 진압, 총소리, 탱크, 전쟁터)", + "info_518_t7_opt2_got": "새로운 사실: 날이 밝자 군인들이 도청을 완전히 장악했어요. 거리에는 군인들만 보이고, 시민들은 두려움에 떨며 숨어있어요. 광주 전체가 슬픔과 절망에 빠졌어요. (힌트: 군인들 도청 장악, 시민들 공포, 슬픔과 절망)", + "info_518_t7_opt3_got": "새로운 사실: 병원에는 새벽 전투로 다치거나 죽은 시민군들이 계속 들어오고 있어요. 가족들의 울음소리가 끊이지 않아요. 너무나 많은 희생자가 나왔어요. (힌트: 많은 사상자, 병원 비상, 가족들 슬픔)", + # Turn 8 (항쟁 이후, 남겨진 이야기들) + "event_518_t8_assignment": "광주에서의 큰 싸움은 끝났지만, 슬픔과 아픔은 계속되고 있어요. 살아남은 사람들의 이야기, 숨겨진 진실, 그리고 앞으로 광주가 어떻게 될지 마지막으로 취재해서 알려주세요.", + "event_518_t8_source": "[알아두면 좋아요] 5.18 광주민주화운동은 비록 군인들에게 진압되었지만, 이후 한국 민주주의 발전에 큰 영향을 주었어요. 하지만 오랫동안 진실이 제대로 알려지지 않아 많은 사람들이 아픔을 겪었어요.", + "action_518_t8_opt1_text": "희생자 가족이나 살아남은 시민군을 만나 이야기 듣기", + "action_518_t8_opt2_text": "군인들이 숨기려는 이야기나 증거 찾아보기", + "info_518_t8_opt1_got": "새로운 사실: 아들을 잃은 어머니가 말했어요. '내 아들은 나쁜 사람이 아니었어요. 옳은 일을 하다가 죽었어요. 제발 잊지 말아 주세요.' 많은 사람들이 억울함과 슬픔을 안고 살아가고 있어요. (힌트: 남은 가족들 슬픔, 억울함, 잊지 말아달라는 부탁)", + "info_518_t8_opt2_got": "새로운 사실: 군인들이 시민들을 몰래 묻었다는 소문이 있어요. 정부는 사망자 수를 줄여서 발표하고, 진실을 숨기려고 해요. 사람들은 언젠가 모든 것이 밝혀지길 바라고 있어요. (힌트: 숨겨진 진실, 정부의 은폐, 진실 규명 바람)", # --- 6월 항쟁 취재 시나리오 --- - "scenario_june_struggle_name": {"보통": "6월 항쟁 동행 취재 (1987)"}, + "scenario_june_struggle_name": "6월 항쟁 이야기 (1987년)", # Turn 1 (박종철 고문치사 사건) - "event_june_t1_assignment": {"보통": "서울대생 박종철 군이 경찰 조사 중 사망하는 사건이 발생했습니다. 경찰은 '책상을 탁 치니 억 하고 죽었다'고 발표했으나, 고문 의혹이 강하게 제기되고 있습니다. 사건의 진실을 규명할 단서와 주변 반응을 취재하십시오."}, - "event_june_t1_source": {"보통": "[배경 정보] 1987년 1월 14일, 박종철 군은 치안본부 남영동 대공분실에서 조사를 받던 중 사망했습니다. 경찰의 석연치 않은 사인 발표는 국민적 공분을 사고 있으며, 재야단체와 종교계를 중심으로 진상 규명 요구가 확산되고 있습니다. 전두환 정권의 도덕성에 큰 타격이 예상됩니다."}, - "action_june_t1_opt1_text": {"보통": "사건 담당 경찰서 및 치안본부 주변 취재, 관계자 비공식 접촉 시도"}, - "action_june_t1_opt2_text": {"보통": "박종철 군 유족 및 서울대 동료 학생 인터뷰"}, - "action_june_t1_opt3_text": {"보통": "부검 참관 의사 또는 의료계 전문가 익명 인터뷰 (사인 규명)"}, - "info_june_t1_opt1_got": {"보통": "정보: 치안본부 관계자(익명), '윗선에서 사건을 빨리 덮으라는 지시가 있었다. 단순 쇼크사로 처리하라는 압력이 상당하다'고 귀띔. (키워드: 경찰 윗선 압력, 사건은폐 지시, 쇼크사 조작)"}, - "info_june_t1_opt2_got": {"보통": "정보: 박종철 군 아버지는 '철아, 잘 가그래이... 아부지는 할 말이 없데이...'라며 오열. 동료 학생들은 '고문살인 책임자를 처벌하라'며 분노. (키워드: 박종철유족 슬픔, 고문살인 규탄, 학생 분노)"}, - "info_june_t1_opt3_got": {"보통": "정보: 부검의 황적준 박사(실명 언급 가능성 낮으나 게임적 허용), '부검 결과 목 부위 압박 흔적과 폐에서 수포음이 들리는 등 단순 쇼크사와는 거리가 멀다. 물고문 가능성을 배제할 수 없다'고 조심스럽게 언급. (키워드: 부검의 증언, 물고문 의혹, 경찰발표 반박)"}, - # (이하 6월 항쟁 턴들 생략) - - "article_tone_fact_based": {"보통": "객관적 사실 전달 위주"}, - "article_tone_critical": {"보통": "정부/기관 비판적 논조"}, - "article_tone_sympathetic": {"보통": "피해자/시위대 동정적 논조"}, - "article_tone_cautious": {"보통": "신중하고 유보적인 논조"}, - - "glossary_419_revolution_free_party": {"보통": "**자유당 (自由黨):** 1951년 이승만 대통령을 중심으로 창당된 정당. 1960년 4.19 혁명으로 이승만 대통령이 하야하면서 사실상 해체되었다."}, - "glossary_419_revolution_315_election": {"보통": "**3.15 부정선거:** 1960년 3월 15일 실시된 제4대 대통령 및 제5대 부통령 선거에서 자유당 정권이 이승만-이기붕 후보를 당선시키기 위해 자행��� 대규모 부정선거. 4.19 혁명의 직접적인 도화선이 되었다."}, - "glossary_419_revolution_kimjuyeol": {"보통": "**김주열 (金朱烈):** 1943~1960. 마산상업고등학교 학생. 3.15 마산 시위 중 실종되었다가 4월 11일 눈에 최루탄이 박힌 시신으로 발견되어 4.19 혁명을 격화시키는 계기가 되었다."}, - "glossary_419_revolution_gyeongmudae": {"보통": "**경무대 (景武臺):** 현재 청와대 자리에 있던 조선시대 건물로, 대한민국 정부 수립 후 대통령 관저 및 집무실로 사용되었다. 4.19 혁명 당시 시위대가 경무대로 향하자 경찰이 발포하여 많은 사상자가 발생했다."}, - "glossary_419_revolution_martial_law": {"보통": "**계엄령 (戒嚴令):** 전시, 사변 또는 이에 준하는 국가비상사태 시 법률이 정하는 바에 따라 군사권을 발동하여 치안을 유지할 수 있는 국가긴급권의 하나. 4.19 혁명 당시 정부는 주요 도시에 계엄령을 선포했다."}, - - "glossary_518_gwangju_new_military": {"보통": "**신군부 (新軍部):** 1979년 10.26 사건 이후 12.12 군사반란을 통해 권력을 장악한 전두환, 노태우 등 하나회 중심의 군부 세력."}, - "glossary_518_gwangju_517_measure": {"보통": "**5.17 비상계엄 전국 확대 조치:** 1980년 5월 17일 신군부가 비상계엄을 전국으로 확대하고 정치활동 금지, 대학 휴교, 언론 검열 강화 등을 단행한 조치. 5.18 광주 민주화운동의 직접적인 배경이 되었다."}, - "glossary_518_gwangju_paratroopers": {"보통": "**공수부대 (공수특전여단):** 5.18 광주 민주화운동 당시 광주에 투입되어 학생과 시민들을 과잉 진압한 부대. 잔혹한 진압 방식으로 많은 사상자를 발생시켰다."}, - "glossary_518_gwangju_geumnamno": {"보통": "**금남로 (錦南路):** 광주광역시의 중심 도로. 5.18 광주 민주화운동 기간 동안 대규모 시위와 계엄군과의 충돌이 벌어진 핵심 장소였다."}, - "glossary_518_gwangju_citizens_army": {"보통": "**시민군 (市民軍):** 5.18 광주 민주화운동 당시 계엄군의 폭력적인 진압에 맞서 스스로 무장한 광주 시민들. 도청을 중심으로 항쟁을 벌였다."}, - "glossary_518_gwangju_sangmuchungjeong": {"보통": "**상무충정작전 (尙武忠正作戰):** 1980년 5월 27일 새벽 계엄군이 광주 시내로 재진입하여 전남도청 등을 장악한 군사작전명. 이 작전으로 5.18 광주 민주화운동은 비극적으로 진압되었다."}, - - "glossary_june_struggle_parkjongchul": {"보통": "**박종철 (朴鍾哲):** 1965~1987. 서울대학교 언어학과 학생. 1987년 1월 경찰의 고문으로 사망하여 6월 민주 항쟁의 도화선이 되었다."}, - "glossary_june_struggle_413_measure": {"보통": "**4.13 호헌 조치 (四一三護憲措置):** 1987년 4월 13일 전두환 대통령이 대통령 직선제 개헌 요구를 거부하고 현행 헌법(간선제)을 고수하겠다고 발표한 조치. 국민적 저항을 불러일으켰다."}, - "glossary_june_struggle_leehanyeol": {"보통": "**이한열 (李韓烈):** 1966~1987. 연세대학교 경영학과 학생. 1987년 6월 9일 시위 중 경찰이 쏜 최루탄에 맞아 중태에 빠졌다가 7월 5일 사망했다. 그의 죽음은 6월 항쟁을 더욱 확산시키는 계기가 되었다."}, - "glossary_june_struggle_610_rally": {"보통": "**6.10 국민대회:** 1987년 6월 10일 '박종철군 고문살인 은폐 규탄 및 민주헌법 쟁취 범국민대회'라는 이름으로 전국적으로 열린 대규모 시위. 6월 항쟁의 본격적인 시작을 알렸다."}, - "glossary_june_struggle_myeongdong_cathedral": {"보통": "**명동성당 (明洞聖堂):** 서울 명동에 위치한 천주교 서울대교구 주교좌 성당. 6월 항쟁 당시 시위대의 주요 농성 장소이자 민주화 운동의 상징적 공간이 되었다."}, - "glossary_june_struggle_necktie_brigade": {"보통": "**넥타이 부대:** 6월 항쟁 당시 시위에 참여한 일반 사무직 회사원들을 일컫는 말. 중산층의 시위 참여를 상징하며 항쟁의 대중적 확산을 보여주었다."}, - "glossary_june_struggle_629_declaration": {"보통": "**6.29 선언:** 1987년 6월 29일 당시 민정당 대표위원 노태우가 발표한 시국 수습 특별 선언. 대통령 직선제 개헌, 김대중 사면복권 등 8개항의 민주화 조치를 내용으로 하며, 6월 항쟁의 실질적인 승리를 의미했다."}, + "event_june_t1_assignment": "서울대학교 학생 박종철 군이 경찰 조사를 받다가 죽었어요. 경찰은 '책상을 탁 치니 억 하고 죽었다'고 이상하게 말했지만, 고문으로 죽었다는 의심이 커지고 있어요. 이 사건의 진짜 이유와 사람들의 반응을 알아보세요.", + "event_june_t1_source": "[알아두면 좋아요] 1987년 1월 14일, 박종철 학생은 경찰서(남영동 대공분��)에서 조사를 받다가 죽었어요. 경찰이 이상하게 설명해서 사람들이 많이 화가 났고, 진짜 이유를 밝히라는 목소리가 커지고 있어요. 전두환 대통령 정부에게 큰 문제가 될 것 같아요.", + "action_june_t1_opt1_text": "사건 담당 경찰서나 치안본부 근처에서 경찰들 이야기 몰래 듣기", + "action_june_t1_opt2_text": "박종철 학생 가족이나 서울대학교 친구들 만나보기", + "action_june_t1_opt3_text": "의사 선생님 중 박종철 학생 몸을 살펴본 분 몰래 만나보기 (왜 죽었는지)", + "info_june_t1_opt1_got": "새로운 사실: 치안본부에서 일하는 사람이 몰래 말해줬어요. '높은 사람이 이 사건 빨리 덮으라고 시켰어요. 그냥 놀라서 죽었다고 하래요.' (힌트: 경찰 윗사람 지시, 사건 숨기려 함, 놀라서 죽었다고 거짓말)", + "info_june_t1_opt2_got": "새로운 사실: 박종철 학생 아버지가 울면서 말했어요. '철아, 잘 가거라... 아빠는 할 말이 없다...' 친구들은 '고문해서 죽인 사람 벌주세요!' 하면서 화를 냈어요. (힌트: 박종철 가족 슬픔, 고문해서 죽였다고 화냄, 학생들 분노)", + "info_june_t1_opt3_got": "새로운 사실: 박종철 학생 몸을 본 의사 선생님이 조심스럽게 말했어요. '목에 눌린 자국이 있고 폐에서 이상한 소리가 났어요. 그냥 놀라서 죽은 것 같지 않아요. 물고문했을 수도 있어요.' (힌트: 의사 선생님 증언, 물고문 의심, 경찰 말과 다름)", + # Turn 2 (4.13 호헌 조치 발표와 민심 악화) + "event_june_t2_assignment": "전두환 대통령이 '지금 헌법(대통령을 직접 뽑지 않는 법)을 바꾸지 않겠다'는 '4.13 호헌 조치'를 발표했어요. 많은 사람들이 대통령을 직접 뽑고 싶어 했는데, 이 발표 때문에 더 화가 난 것 같아요. 사람들의 반응과 앞으로 시위가 더 커질지 알아보세요.", + "event_june_t2_source": "[알아두면 좋아요] 박종철 학생 사건으로 민주주의를 원하는 목소리가 커졌지만, 전두환 대통령은 4월 13일에 헌법을 고치지 않겠다고 발표했어요. 이건 국민들의 바람을 무시하는 거라서, 학생, 종교인, 일반 시민들까지 모두 크게 반발하고 있어요.", + "action_june_t2_opt1_text": "대학교에 가서 학생들 반응과 시위 계획 알아보기", + "action_june_t2_opt2_text": "종교 단체나 숨어서 활동하는 민주화 운동가들 만나보기", + "action_june_t2_opt3_text": "길거리에서 일반 시민들에게 '호헌 조치'에 대해 어떻게 생각하는지 물어보기", + "info_june_t2_opt1_got": "새로운 사실: 대학교 학생들이 '독재 타도! 직선제 쟁취!' 같은 구호를 외치며 시위를 준비하고 있어요. '더 이상 참을 수 없다'며 격렬하게 싸울 거라고 해요. (힌트: 학생들 분노, 직선제 요구, 큰 시위 예고)", + "info_june_t2_opt2_got": "새로운 사실: 한 신부님이 말했어요. '정부가 국민의 목소리를 듣지 않으니, 우리가 직접 나서서 민주주의를 되찾아야 합니다. 모든 양심 있는 사람들이 힘을 합칠 것입니다.' (힌트: 종교계 반발, 민주주의 되찾기, 힘 합치자)", + "info_june_t2_opt3_got": "새로운 사실: 시장에서 만난 아주머니가 말했어요. '대통령을 내 손으로 뽑고 싶은데, 왜 못하게 하는지 모르겠어요. 너무 답답해요.' 많은 사람들이 실망하고 화가 나 있어요. (힌트: 시민들 실망, 직선제 바람, 답답함)", + # Turn 3 (이한열 학생 피격 사건) + "event_june_t3_assignment": "6월 9일, 연세대학교에서 시위하던 이한열 학생이 경찰이 쏜 최루탄에 머리를 맞아 쓰러졌어요. 지금 아주 위독하다고 해요. 이 사건 때문에 사람들이 더 크게 분노하고 있어요. 사건 현장 상황과 학생들, 시민들 반응을 긴급히 취재해주세요.", + "event_june_t3_source": "[알아두면 좋아요] '4.13 호헌 조치' 이후 시위가 계속되던 중, 6월 9일 연세대 앞에서 이한열 학생이 경찰이 직격으로 쏜 최루탄에 맞아 의식을 잃었어요. 이 모습이 사진으로 알려지면서 국민들의 분노는 극에 달했고, 6월 항쟁이 전국적으로 확산되는 결정적인 계기가 되었어요.", + "action_june_t3_opt1_text": "이한열 학생이 쓰러진 연세대 앞 시위 현장 가보기 (위험!)", + "action_june_t3_opt2_text": "이한열 학생이 입원한 병원에 가서 상태 알아보고 학생들 만나보기", + "action_june_t3_opt3_text": "다른 대학교나 명동성당 등 시위가 예상되는 곳 분위기 살피기", + "info_june_t3_opt1_got": "새로운 사실: 연세대 앞은 전쟁터 같아요. 학생들이 돌을 던지고, 경찰은 최루탄을 마구 쏘고 있어요. 이한열 학생이 쓰러졌던 자리에는 아직도 핏자국이 남아있어��. (힌트: 연세대 시위 격렬, 최루탄 난사, 이한열 학생 피격 현장)", + "info_june_t3_opt2_got": "새로운 사실: 병원에서 만난 이한열 학생 친구들이 울면서 말했어요. '경찰이 한열이를 죽이려고 했어요! 이건 살인미수예요!' 학생은 의식이 없고 매우 위독한 상태라고 해요. (힌트: 이한열 학생 위독, 친구들 분노, 경찰 비판)", + "info_june_t3_opt3_got": "새로운 사실: 명동성당 주변에 학생들이 모여들고 있어요. '이한열을 살려내라!', '군부독재 물러가라!' 외치고 있어요. 내일(6월 10일) 아주 큰 시위가 있을 거라는 소문이 돌아요. (힌트: 명동성당 시위 준비, 이한열 살리자, 큰 시위 예고)", + # Turn 4 (6.10 국민대회와 항쟁의 확산) + "event_june_t4_assignment": "오늘 6월 10일, 전국에서 '박종철 고문살인 규탄 및 민주헌법 쟁취 국민대회'라는 아주 큰 시위가 열리고 있어요. 서울뿐 아니라 부산, 광주 등 다른 도시에서도 많은 사람들이 거리로 나왔다고 해요. 시위 규모와 모습, 경찰 대응, 그리고 '넥타이 부대'라고 불리는 회사원들 참여 모습 등을 취재해주세요.", + "event_june_t4_source": "[알아두면 좋아요] 이한열 학생 사건은 6월 10일로 예정되어 있던 국민대회에 기름을 부었어요. 전국 주요 도시에서 수십만 명의 학생과 시민들이 거리로 쏟아져 나와 '호헌 철폐', '독재 타도'를 외쳤어요. 특히 평범한 회사원들(넥타이 부대)까지 시위에 참여하면서 항쟁은 더욱 커졌어요.", + "action_june_t4_opt1_text": "서울 시청 앞이나 명동 등 주요 시위 현장 한복판에 가보기 (매우 위험!)", + "action_june_t4_opt2_text": "시위에 참여한 회사원(넥타이 부대) 만나서 이야기 듣기", + "action_june_t4_opt3_text": "지방 도시(부산, 대구, 광주 등) 특파원과 연락해 그곳 상황 알아보기", + "info_june_t4_opt1_got": "새로운 사실: 서울 시내가 온통 시위하는 사람들로 가득 찼어요! 경찰이 최루탄을 쏘며 막고 있지만, 사람들은 물러서지 않고 '독재 타도!'를 외치고 있어요. 여기저기서 싸움이 벌어지고 있어요. (힌트: 6.10 국민대회, 대규모 시위, 경찰과 충돌, 독재 타도)", + "info_june_t4_opt2_got": "새로운 사실: 양복 입은 회사원 아저씨가 말했어요. '더 이상 나라가 이렇게 되는 걸 보고만 있을 수 없어서 나왔습니다. 우리 아이들에게 부끄럽지 않은 나라를 만들어주고 싶어요.' (힌트: 넥타이 부대 참여, 민주주의 열망, 미래 세대 걱정)", + "info_june_t4_opt3_got": "새로운 사실: 부산 특파원이 알려왔어요. '부산역 광장에도 수만 명이 모여 시위를 벌이고 있습니다. 경찰과 격렬하게 대치 중이고, 부상자도 나오고 있습니다.' 전국이 들끓고 있어요. (힌트: 전국적 시위, 부산 상황, 지방도 뜨거움)", + # Turn 5 (명동성당 농성과 확산되는 민주화 요구) + "event_june_t5_assignment": "시위대 중 일부가 명동성당으로 들어가 농성을 시작했어요. 명동성당은 시위대에게 안전한 곳이 되어주고 있는 것 같아요. 성당 안팎의 분위기, 농성하는 사람들의 요구, 그리고 정부가 어떻게 나올지 사람들의 예상을 취재해주세요.", + "event_june_t5_source": "[알아두면 좋아요] 6월 항쟁 기간 동안 명동성당은 민주화 운동의 중요한 장소가 되었어요. 경찰의 폭력을 피해 많은 시위대가 성당으로 들어와 농성을 벌였고, 종교계는 이들을 보호했어요. 이는 정부에게 큰 부담을 주었어요.", + "action_june_t5_opt1_text": "명동성당 안으로 들어가 농성 중인 학생이나 시민들 만나보기", + "action_june_t5_opt2_text": "성당 밖에서 지지하는 시민들이나 성직자들 이야기 듣기", + "action_june_t5_opt3_text": "정부 관계자나 경찰 쪽에서 명동성당 상황을 어떻게 보고 있는지 알아보기", + "info_june_t5_opt1_got": "새로운 사실: 명동성당 안은 학생들과 시민들로 가득해요. 지쳤지만 눈빛은 살아있어요. '대통령 직선제 실시하라!', '민주정부 수립하자!' 같은 구호를 외치고 있어요. (힌트: 명동성당 농성, 직선제 요구, 민주정부 희망)", + "info_june_t5_opt2_got": "새로운 사실: 성당 밖에서 한 수녀님이 기도하며 말했어요. '저들이 평화롭게 자기 목소리를 낼 수 있도록, 그리고 아무도 다치지 않도록 기도하고 있어요. 정의가 이길 거예요.' (힌트: 성직자 지지, 평화 기원, 정의 승리 믿음)", + "info_june_t5_opt3_got": "새로운 사실: 경찰 관계자가 몰래 말했어요. '성당 안으로 함부로 들어갈 수가 없어서 골치 아파요. 하지만 계속 저렇게 둘 수는 없을 텐데...' 정부도 고민이 많은 ��� 같아요. (힌트: 경찰 고민, 성당 진입 어려움, 정부 압박감)", + # Turn 6 (6.26 평화대행진과 최루탄 없는 날) + "event_june_t6_assignment": "오늘은 '국민평화대행진'이 있는 날이에요. 전국적으로 100만 명이 넘는 사람들이 거리로 나올 거라고 해요. 특히 오늘은 경찰이 최루탄을 쏘지 않기로 했다는 소문도 있어요. 정말 평화로운 시위가 될지, 사람들의 열기는 어떨지 현장에서 확인해주세요.", + "event_june_t6_source": "[알아두면 좋아요] 6월 항쟁이 계속되면서 국민들의 민주화 요구는 더욱 거세졌어요. 6월 26일에는 전국 33개 도시에서 100만 명이 넘는 시민들이 참여하는 '국민평화대행진'이 계획되었어요. 정부도 더 이상 강경 대응만으로는 사태를 해결할 수 없다는 것을 느끼기 시작했어요.", + "action_june_t6_opt1_text": "서울 도심 평화대행진 행렬에 참여해서 시민들과 함께 걷기", + "action_june_t6_opt2_text": "정말 경찰이 최루탄을 사용하지 않는지, 시위 분위기는 어떤지 관찰하기", + "action_june_t6_opt3_text": "시위에 참여한 다양한 연령대의 사람들(어린이, 노인 등) 이야기 듣기", + "info_june_t6_opt1_got": "새로운 사실: 정말 많은 사람들이 거리로 나왔어요! 아이 손을 잡고 나온 가족, 나이 드신 할아버지 할머니까지 모두 함께 '민주주의'를 외치며 걷고 있어요. (힌트: 6.26 평화대행진, 엄청난 인파, 다양한 시민 참여)", + "info_june_t6_opt2_got": "새로운 사실: 신기하게도 오늘은 경찰이 최루탄을 쏘지 않아요! 시위는 아주 평화롭고 질서있게 진행되고 있어요. 마치 축제 같아요. 사람들은 노래도 부르고 춤도 춰요. (힌트: 최루탄 없는 날, 평화 시위, 축제 분위기)", + "info_june_t6_opt3_got": "새로운 사실: 한 초등학생이 아빠 목마를 타고 말했어요. '우리나라가 더 좋은 나라가 됐으면 좋겠어요!' 어른들은 이 모습을 보며 눈물을 글썽였어요. (힌트: 미래세대 희망, 감동적인 모습, 좋은 나라 염원)", + # Turn 7 (6.29 선언 발표) + "event_june_t7_assignment": "오늘, 정부 여당의 노태우 대표가 갑자기 '6.29 선언'이라는 것을 발표했어요! 대통령 직선제를 받아들이고, 김대중 씨도 풀어주겠다는 등 놀라운 내용이 많다고 해요. 이 발표 내용과 사람들의 반응, 그리고 진짜로 민주주의가 올지 마지막으로 취재해주세요. (이번엔 취재 활동 없이 바로 기사 쓰기로 가요.)", + "event_june_t7_source": "[긴급 뉴스] 6월 29일, 민정당 노태우 대표가 국민들의 민주화 요구를 받아들여 대통령 직선제 개헌, 김대중 사면복권 등 8개 항목의 시국 수습 방안을 발표했어요. 이것은 사실상 국민들의 승리를 의미해요!", + "action_june_t7_opt1_text": "6.29 선언 내용 자세히 살펴보고 중요한 점 정리하기", + "action_june_t7_opt2_text": "거리로 나온 시민들의 기뻐하는 모습과 이야기 듣기", + "info_june_t7_opt1_got": "새로운 사실: 6.29 선언 내용을 보니, 대통령을 우리 손으로 직접 뽑고, 김대중 아저씨도 다시 정치할 수 있게 하고, 언론도 자유롭게 해준다는 약속이 들어있어요! (힌트: 6.29 선언, 대통령 직접 뽑기, 김대중 아저씨 자유, 언론 자유 약속)", + "info_june_t7_opt2_got": "새로운 사실: 사람들이 거리로 뛰쳐나와 '민주주의 만세!'를 외치며 서로 얼싸안고 기뻐하고 있어요. 자동차들은 경적을 울리고, 가게에서는 축하 음악이 흘러나와요. 드디어 이긴 것 같아요! (힌트: 시민들 환호, 민주주의 승리, 축제 분위기, 감격)", + + "article_tone_fact_based": "진짜 있었던 일만 쓰기", + "article_tone_critical": "잘못된 점 콕콕 짚어 쓰기", + "article_tone_sympathetic": "슬프고 힘든 사람들 편에서 쓰기", + "article_tone_cautious": "조심조심, 생각 많이 하고 쓰기", + + "glossary_419_revolution_free_party": "**자유당:** 옛날에 이승만 대통령을 도와주던 힘센 정당이었어요. 하지만 나쁜 일을 많이 해서 4.19 혁명 때 사람들이 싫어하게 됐어요.", + "glossary_419_revolution_315_election": "**3.15 부정선거:** 1960년에 대통령을 뽑는데, 자유당이 이기려고 반칙을 많이 한 선거예요. 이것 때문에 4.19 혁명이 일어났어요.", + "glossary_419_revolution_kimjuyeol": "**김주열:** 마산상고 학생이었는데, 3.15 부정선거 반대 시위하다가 경찰이 쏜 최루탄에 맞아 죽었어요. 이 일로 사람들이 더 많이 화가 났어요.", + "glossary_419_revolution_gyeongmudae": "**경무대:** 지금의 청와대 같은 곳인데, 옛날 대통령이 살던 집이에요. 4.19 혁명 때 시위대가 여기로 가다가 경찰이 총을 쏴서 많은 ��람이 다쳤어요.", + "glossary_419_revolution_martial_law": "**계엄령:** 나라가 아주 위험할 때 군인들이 나와서 질서를 잡는 특별 명령이에요. 4.19 혁명 때 정부가 계엄령을 내렸어요.", + + "glossary_518_gwangju_new_military": "**신군부:** 옛날에 군인 아저씨들이 힘을 합쳐서 나라를 마음대로 하려고 했던 그룹이에요. 전두환, 노태우 아저씨가 대표적이었죠.", + "glossary_518_gwangju_517_measure": "**5.17 비상계엄 전국 확대:** 신군부가 '나라가 위험하다!' 하면서 군인들 힘을 더 키우고, 사람들 못 모이게 하고, 학교도 닫게 한 조치예요. 이것 때문에 5.18 광주 이야기가 시작됐어요.", + "glossary_518_gwangju_paratroopers": "**공수부대:** 하늘에서 뛰어내리는 훈련을 받은 특별한 군인들이에요. 5.18 때 광주에 와서 사람들을 아주 심하게 대했어요.", + "glossary_518_gwangju_geumnamno": "**금남로:** 광주에서 가장 크고 중요한 길이에요. 5.18 때 여기서 많은 사람들이 모여 시위하고 군인들과 싸웠어요.", + "glossary_518_gwangju_citizens_army": "**시민군:** 5.18 때 군인들이 너무 심하게 하니까, 광주 시민들이 스스로를 지키려고 무기를 들고 싸운 사람들이에요.", + "glossary_518_gwangju_sangmuchungjeong": "**상무충정작전:** 5.18 마지막 날 새벽에 군인들이 광주 시내로 다시 쳐들어가서 시민군을 힘으로 누른 작전 이름이에요. 아주 슬픈 날이었죠.", + + "glossary_june_struggle_parkjongchul": "**박종철:** 서울대학교 학생이었는데, 경찰한테 잡혀가서 고문을 받다가 죽었어요. '책상을 탁 치니 억 하고 죽었다'는 경찰 말이 거짓말인 게 밝혀져서 6월 항쟁이 시작되는 불씨가 됐어요.", + "glossary_june_struggle_413_measure": "**4.13 호헌 조치:** 전두환 대통령이 '대통령을 직접 뽑는 법으로 안 바꿀 거야!' 하고 발표한 거예요. 사람들이 엄청 화났어요.", + "glossary_june_struggle_leehanyeol": "**이한열:** 연세대학교 학생이었는데, 시위하다가 경찰이 쏜 최루탄에 머리를 맞아서 결국 죽었어요. 이한열 학생의 사진은 6월 항쟁을 보여주는 아주 유명한 사진이 됐어요.", + "glossary_june_struggle_610_rally": "**6.10 국민대회:** 1987년 6월 10일, 박종철 학생 사건의 진실을 밝히고 대통령을 직접 뽑게 해달라고 전국에서 아주 많은 사람들이 모여서 시위한 날이에요. 6월 항쟁이 본격적으로 시작된 날이죠.", + "glossary_june_struggle_myeongdong_cathedral": "**명동성당:** 서울 명동에 있는 아주 큰 성당인데, 6월 항쟁 때 시위하는 사람들이 경찰을 피해 숨기도 하고, 거기서 계속 싸우기도 했던 중요한 곳이에요.", + "glossary_june_struggle_necktie_brigade": "**넥타이 부대:** 6월 항쟁 때 시위에 참여한 회사원 아저씨들을 부르는 말이에요. 평범한 어른들도 함께 싸웠다는 걸 보여줘요.", + "glossary_june_struggle_629_declaration": "**6.29 선언:** 6월 항쟁이 너무 커지니까, 그때 정부 편이었던 노태우 아저씨가 '알겠다! 대통령 직접 뽑게 해주고, 민주주의를 위해 노력하겠다!' 하고 발표한 거예요. 사람들이 싸워서 이긴 거죠!", } -# --- 어휘 조정 함수 --- -def get_text(key, level="보통"): - level_texts = ALL_TEXTS.get(key) - if level_texts: - if level in level_texts: - return level_texts[level] - elif "보통" in level_texts: - return level_texts["보통"] +# --- 어휘 조정 함수 (단순화) --- +def get_text(key, level="초등"): + text_content = ALL_TEXTS.get(key) + if text_content: + return text_content + print(f"경고: 텍스트 키 '{key}'에 대한 내용을 ALL_TEXTS에서 찾을 수 없습니다.") return key + # --- 게임 상태 초기화 (기자 컨셉) --- def initialize_reporter_scenario_state(scenario_key): scenario_settings = SCENARIOS[scenario_key] - vocab_level = scenario_settings["vocab_level"] - get_text_func = lambda k: get_text(k, vocab_level) + get_text_func = lambda k: get_text(k) return { 'scenario_key': scenario_key, @@ -323,11 +423,11 @@ HISTORICAL_ASSIGNMENTS = { {"action_key": "action_419_t7_opt3_text", "cost_freedom_risk": 5, "safety_risk": 5, "info_key": "info_419_t7_opt3_got"}, ], "article_writing_phase": True}, {"turn": 8, "assignment_key": "event_419_t8_assignment", "source_key": "event_419_t8_source", - "options": [ # 이 턴은 정보 획득 선택지가 의미 없을 수 있으나, 형식상 유지 + "options": [ {"action_key": "action_419_t8_opt1_text", "cost_freedom_risk": 0, "safety_risk": 0, "info_key": "info_419_t8_opt1_got"}, {"action_key": "action_419_t8_opt2_text", "cost_freedom_risk": 0, "safety_risk": 0, "info_key": "info_419_t8_opt2_got"}, {"action_key": "action_419_t8_opt3_text", "cost_freedom_risk": 0, "safety_risk": 0, "info_key": "info_419_t8_opt3_got"}, - ], "article_writing_phase": True, "is_final_turn_event": True}, # 마지막 턴 표시 + ], "article_writing_phase": True, "is_final_turn_event": True}, ], "5.18_gwangju": [ {"turn": 1, "assignment_key": "event_518_t1_assignment", "source_key": "event_518_t1_source", @@ -335,16 +435,44 @@ HISTORICAL_ASSIGNMENTS = { {"action_key": "action_518_t1_opt1_text", "cost_freedom_risk": 15, "safety_risk": 25, "info_key": "info_518_t1_opt1_got"}, {"action_key": "action_518_t1_opt2_text", "cost_freedom_risk": 10, "safety_risk": 20, "info_key": "info_518_t1_opt2_got"}, {"action_key": "action_518_t1_opt3_text", "cost_freedom_risk": 20, "safety_risk": 30, "info_key": "info_518_t1_opt3_got"}, - ], "article_writing_phase": False}, # 초기에는 정보 수집만 + ], "article_writing_phase": False}, {"turn": 2, "assignment_key": "event_518_t2_assignment", "source_key": "event_518_t2_source", "options": [ {"action_key": "action_518_t2_opt1_text", "cost_freedom_risk": 30, "safety_risk": 40, "info_key": "info_518_t2_opt1_got"}, {"action_key": "action_518_t2_opt2_text", "cost_freedom_risk": 15, "safety_risk": 20, "info_key": "info_518_t2_opt2_got"}, {"action_key": "action_518_t2_opt3_text", "cost_freedom_risk": 10, "safety_risk": 15, "info_key": "info_518_t2_opt3_got"}, ], "article_writing_phase": True}, - # (이하 5.18 턴들 추가 필요 - 최대 8턴까지) - # 예시: 마지막 턴 - {"turn": 8, "assignment_key": "event_518_t8_assignment", "source_key": "event_518_t8_source", # 도청 진압 이후 상황 + {"turn": 3, "assignment_key": "event_518_t3_assignment", "source_key": "event_518_t3_source", + "options": [ + {"action_key": "action_518_t3_opt1_text", "cost_freedom_risk": 35, "safety_risk": 45, "info_key": "info_518_t3_opt1_got"}, + {"action_key": "action_518_t3_opt2_text", "cost_freedom_risk": 20, "safety_risk": 25, "info_key": "info_518_t3_opt2_got"}, + {"action_key": "action_518_t3_opt3_text", "cost_freedom_risk": 15, "safety_risk": 30, "info_key": "info_518_t3_opt3_got"}, + ], "article_writing_phase": True}, + {"turn": 4, "assignment_key": "event_518_t4_assignment", "source_key": "event_518_t4_source", + "options": [ + {"action_key": "action_518_t4_opt1_text", "cost_freedom_risk": 25, "safety_risk": 35, "info_key": "info_518_t4_opt1_got"}, + {"action_key": "action_518_t4_opt2_text", "cost_freedom_risk": 20, "safety_risk": 30, "info_key": "info_518_t4_opt2_got"}, + {"action_key": "action_518_t4_opt3_text", "cost_freedom_risk": 15, "safety_risk": 20, "info_key": "info_518_t4_opt3_got"}, + ], "article_writing_phase": True}, + {"turn": 5, "assignment_key": "event_518_t5_assignment", "source_key": "event_518_t5_source", + "options": [ + {"action_key": "action_518_t5_opt1_text", "cost_freedom_risk": 10, "safety_risk": 15, "info_key": "info_518_t5_opt1_got"}, + {"action_key": "action_518_t5_opt2_text", "cost_freedom_risk": 15, "safety_risk": 20, "info_key": "info_518_t5_opt2_got"}, + {"action_key": "action_518_t5_opt3_text", "cost_freedom_risk": 5, "safety_risk": 10, "info_key": "info_518_t5_opt3_got"}, + ], "article_writing_phase": True}, + {"turn": 6, "assignment_key": "event_518_t6_assignment", "source_key": "event_518_t6_source", + "options": [ + {"action_key": "action_518_t6_opt1_text", "cost_freedom_risk": 30, "safety_risk": 40, "info_key": "info_518_t6_opt1_got"}, + {"action_key": "action_518_t6_opt2_text", "cost_freedom_risk": 20, "safety_risk": 25, "info_key": "info_518_t6_opt2_got"}, + {"action_key": "action_518_t6_opt3_text", "cost_freedom_risk": 25, "safety_risk": 30, "info_key": "info_518_t6_opt3_got"}, + ], "article_writing_phase": True}, + {"turn": 7, "assignment_key": "event_518_t7_assignment", "source_key": "event_518_t7_source", + "options": [ + {"action_key": "action_518_t7_opt1_text", "cost_freedom_risk": 40, "safety_risk": 50, "info_key": "info_518_t7_opt1_got"}, + {"action_key": "action_518_t7_opt2_text", "cost_freedom_risk": 20, "safety_risk": 25, "info_key": "info_518_t7_opt2_got"}, + {"action_key": "action_518_t7_opt3_text", "cost_freedom_risk": 25, "safety_risk": 30, "info_key": "info_518_t7_opt3_got"}, + ], "article_writing_phase": True}, + {"turn": 8, "assignment_key": "event_518_t8_assignment", "source_key": "event_518_t8_source", "options": [ {"action_key": "action_518_t8_opt1_text", "cost_freedom_risk": 25, "safety_risk": 30, "info_key": "info_518_t8_opt1_got"}, {"action_key": "action_518_t8_opt2_text", "cost_freedom_risk": 30, "safety_risk": 20, "info_key": "info_518_t8_opt2_got"}, @@ -357,9 +485,37 @@ HISTORICAL_ASSIGNMENTS = { {"action_key": "action_june_t1_opt2_text", "cost_freedom_risk": 5, "safety_risk": 10, "info_key": "info_june_t1_opt2_got"}, {"action_key": "action_june_t1_opt3_text", "cost_freedom_risk": 5, "safety_risk": 5, "info_key": "info_june_t1_opt3_got"}, ], "article_writing_phase": True}, - # (이하 6월 항쟁 턴들 추가 필요 - 최대 7턴까지) - # 예시: 마지막 턴 - {"turn": 7, "assignment_key": "event_june_t7_assignment", "source_key": "event_june_t7_source", # 6.29 선언 + {"turn": 2, "assignment_key": "event_june_t2_assignment", "source_key": "event_june_t2_source", + "options": [ + {"action_key": "action_june_t2_opt1_text", "cost_freedom_risk": 10, "safety_risk": 10, "info_key": "info_june_t2_opt1_got"}, + {"action_key": "action_june_t2_opt2_text", "cost_freedom_risk": 15, "safety_risk": 20, "info_key": "info_june_t2_opt2_got"}, + {"action_key": "action_june_t2_opt3_text", "cost_freedom_risk": 5, "safety_risk": 5, "info_key": "info_june_t2_opt3_got"}, + ], "article_writing_phase": True}, + {"turn": 3, "assignment_key": "event_june_t3_assignment", "source_key": "event_june_t3_source", + "options": [ + {"action_key": "action_june_t3_opt1_text", "cost_freedom_risk": 20, "safety_risk": 30, "info_key": "info_june_t3_opt1_got"}, + {"action_key": "action_june_t3_opt2_text", "cost_freedom_risk": 15, "safety_risk": 20, "info_key": "info_june_t3_opt2_got"}, + {"action_key": "action_june_t3_opt3_text", "cost_freedom_risk": 10, "safety_risk": 15, "info_key": "info_june_t3_opt3_got"}, + ], "article_writing_phase": True}, + {"turn": 4, "assignment_key": "event_june_t4_assignment", "source_key": "event_june_t4_source", + "options": [ + {"action_key": "action_june_t4_opt1_text", "cost_freedom_risk": 25, "safety_risk": 35, "info_key": "info_june_t4_opt1_got"}, + {"action_key": "action_june_t4_opt2_text", "cost_freedom_risk": 5, "safety_risk": 10, "info_key": "info_june_t4_opt2_got"}, + {"action_key": "action_june_t4_opt3_text", "cost_freedom_risk": 10, "safety_risk": 5, "info_key": "info_june_t4_opt3_got"}, + ], "article_writing_phase": True}, + {"turn": 5, "assignment_key": "event_june_t5_assignment", "source_key": "event_june_t5_source", + "options": [ + {"action_key": "action_june_t5_opt1_text", "cost_freedom_risk": 15, "safety_risk": 20, "info_key": "info_june_t5_opt1_got"}, + {"action_key": "action_june_t5_opt2_text", "cost_freedom_risk": 5, "safety_risk": 10, "info_key": "info_june_t5_opt2_got"}, + {"action_key": "action_june_t5_opt3_text", "cost_freedom_risk": 20, "safety_risk": 10, "info_key": "info_june_t5_opt3_got"}, + ], "article_writing_phase": True}, + {"turn": 6, "assignment_key": "event_june_t6_assignment", "source_key": "event_june_t6_source", + "options": [ + {"action_key": "action_june_t6_opt1_text", "cost_freedom_risk": 5, "safety_risk": 5, "info_key": "info_june_t6_opt1_got"}, + {"action_key": "action_june_t6_opt2_text", "cost_freedom_risk": 0, "safety_risk": 0, "info_key": "info_june_t6_opt2_got"}, + {"action_key": "action_june_t6_opt3_text", "cost_freedom_risk": 5, "safety_risk": 5, "info_key": "info_june_t6_opt3_got"}, + ], "article_writing_phase": True}, + {"turn": 7, "assignment_key": "event_june_t7_assignment", "source_key": "event_june_t7_source", "options": [ {"action_key": "action_june_t7_opt1_text", "cost_freedom_risk": 0, "safety_risk": 0, "info_key": "info_june_t7_opt1_got"}, {"action_key": "action_june_t7_opt2_text", "cost_freedom_risk": 0, "safety_risk": 0, "info_key": "info_june_t7_opt2_got"}, @@ -369,13 +525,12 @@ HISTORICAL_ASSIGNMENTS = { # --- 다음 취재 지시 가져오기 --- def get_next_assignment(scenario_key, current_turn, game_state): scenario_assignments = HISTORICAL_ASSIGNMENTS.get(scenario_key, []) - for assignment_data_from_db in scenario_assignments: # 변수명 변경하여 혼동 방지 + for assignment_data_from_db in scenario_assignments: if assignment_data_from_db["turn"] == current_turn: - vocab_level = SCENARIOS[scenario_key]["vocab_level"] - get_text_for_assignment = lambda k: get_text(k, vocab_level) + get_text_for_assignment = lambda k: get_text(k) final_assignment = { - "assignment_key": assignment_data_from_db["assignment_key"], # <--- 이 줄 추가 + "assignment_key": assignment_data_from_db["assignment_key"], "assignment_text": get_text_for_assignment(assignment_data_from_db["assignment_key"]), "source_text": get_text_for_assignment(assignment_data_from_db.get("source_key", "")), "options": [], @@ -390,7 +545,7 @@ def get_next_assignment(scenario_key, current_turn, game_state): "info_key": opt_data.get("info_key", "") }) - log_message = f"{game_state['game_year']}년 {current_turn}번째 취재일: {final_assignment['assignment_text'][:30]}..." + log_message = f"{game_state['game_year']}년 {current_turn}번째 날: {final_assignment['assignment_text'][:30]}..." if game_state.get('event_log') is not None: game_state['event_log'].append(log_message) return final_assignment @@ -398,9 +553,7 @@ def get_next_assignment(scenario_key, current_turn, game_state): # --- 취재 활동 결과 처리 --- def process_reporter_action(selected_option, game_state): - scenario_key = game_state['scenario_key'] - vocab_level = SCENARIOS[scenario_key]["vocab_level"] - get_text_for_processing = lambda k: get_text(k, vocab_level) + get_text_for_processing = lambda k: get_text(k) status = game_state['status'] if random.random() < (selected_option.get("cost_freedom_risk", 0) / 100): @@ -429,8 +582,8 @@ def process_reporter_action(selected_option, game_state): return info_text # --- 기사 작성 인터페이스 생성 --- -def generate_article_interface(game_state, vocab_level): - get_text_func = lambda k: get_text(k, vocab_level) +def generate_article_interface(game_state): + get_text_func = lambda k: get_text(k) st.subheader(get_text_func("article_writing_title")) st.markdown("**" + get_text_func("reporter_notebook_title") + ":**") @@ -438,12 +591,12 @@ def generate_article_interface(game_state, vocab_level): for idx, note in enumerate(game_state['reporter_notebook']): st.markdown(f"- {note}") else: - st.caption("아직 취재한 내용이 없습니다. 취재 활동을 통해 정보를 수집하세요.") + st.caption("아직 취재한 내용이 없어요. 취재 활동을 해서 정보를 모아보세요.") st.markdown("---") with st.form(key="article_form"): - article_headline = st.text_input(get_text_func("article_headline_label"), placeholder="예: 3.15 부정선거, 그 추악한 실태 고발") - article_body_summary = st.text_area(get_text_func("article_body_label"), height=150, placeholder="예: 오늘 치러진 정부통령 선거에서 자유당은 조직적인 부정행위를 자행했다. 투표함 바꿔치기, 공개투표 강요 등 민주주의를 유린하는 행태가 곳곳에서 목격되었다...") + article_headline = st.text_input(get_text_func("article_headline_label"), placeholder="예: 나쁜 선거, 그 비밀을 밝힌다!") + article_body_summary = st.text_area(get_text_func("article_body_label"), height=150, placeholder="예: 오늘 대통령 뽑는 날, 나쁜 사람들이 몰래 표를 바꿨어요. 사람들이 화가 많이 났어요...") article_tones = { "fact_based": get_text_func("article_tone_fact_based"), @@ -464,8 +617,8 @@ def generate_article_interface(game_state, vocab_level): st.warning(get_text_func("warning_empty_article")) return None - if not game_state['reporter_notebook']: # 노트 내용 없으면 제출 불가 - st.warning("취재 노트에 내용이 없습니다. 최소한의 취재 정보가 있어야 기사를 작성할 수 있습니다.") + if not game_state['reporter_notebook']: + st.warning("취재 노트에 내용이 없어요. 조금이라도 알아낸 게 있어야 기사를 쓸 수 있어요.") return None return { @@ -473,49 +626,44 @@ def generate_article_interface(game_state, vocab_level): "headline": article_headline, "body_summary": article_body_summary, "tone": selected_tone_key, - "raw_notes": list(game_state['reporter_notebook']) + "raw_notes": list(game_state['reporter_notebook']), + "ai_score": 0 # AI 평가 후 채워짐 } return None # --- 기사 평가 및 데스크 피드백 (OpenAI 사용) --- -def evaluate_article_and_get_feedback_openai(article, game_state, assignment_data): # assignment_data는 st.session_state.current_assignment_data +def evaluate_article_and_get_feedback_openai(article, game_state, assignment_data): status = game_state['status'] - vocab_level = SCENARIOS[game_state['scenario_key']]["vocab_level"] - get_text_func = lambda k: get_text(k, vocab_level) - - # AI에게 전달할 정보 구성 - # current_assignment_text = get_text_func(assignment_data["assignment_key"]) # 기존 오류 라인 - current_assignment_text = assignment_data["assignment_text"] # <--- 이렇게 수정 (이미 변환된 텍스트 사용) - # 또는, get_next_assignment에서 저장한 원본 키를 사용하려면: - # current_assignment_text = get_text_func(assignment_data.get("assignment_key", "unknown_assignment")) - + get_text_func = lambda k: get_text(k) + current_assignment_text = assignment_data["assignment_text"] reporter_notes_str = "\n".join([f"- {note}" for note in article['raw_notes']]) article_tone_text = get_text_func(f"article_tone_{article['tone']}") prompt = f""" -당신은 대한민국 현대사를 다루는 신문사의 베테랑 편집장입니다. 신입 기자가 아래와 같은 취재 지시를 받고, 수집한 노트 내용을 바탕으로 기사를 작성했습니다. +당신은 어린이 신문사의 친절한 편집장입니다. 새내기 기자가 아래와 같은 취재 지시를 받고, 수집한 노트 내용을 바탕으로 기사를 작성했습니다. +이 신입 기자는 초등학생도 이해할 수 있도록 쉽고 명확한 단어와 문장을 사용하려고 노력하고 있습니다. 이 점을 감안하여 피드백을 제공해주세요. -[취재 지시 내용] +[오늘의 할 일] {current_assignment_text} -[기자가 수집한 노트 내용] +[기자가 적은 내용] {reporter_notes_str} -[기자가 작성한 기사] +[기자가 쓴 기사] - 제목: {article['headline']} -- 본문 요약: {article['body_summary']} -- 선택한 논조: {article_tone_text} +- 내용 요약: {article['body_summary']} +- 선택한 분위기: {article_tone_text} -[평가 지침] -1. **사실 부합도 및 중요 정보 포함 여부:** 기사가 취재 노트의 핵심 정보와 취재 지시의 주요 사항을 얼마나 잘 반영하고 있는가? 중요한 사실이 누락되거나 왜곡되지는 않았는가? (40점 만점) -2. **논리성 및 명확성:** 기사의 내용이 논리적으로 전개되며, 독자가 이해하기 쉽게 명확하게 작성되었는가? (30점 만점) -3. **논조의 적절성 및 영향력:** 선택한 논조가 현재 상황과 기사 내용에 적절하며, 사회에 긍정적 또는 부정적 영향을 미칠 가능성은 어떠한가? (기자의 안전도 고려) (30점 만점) +[평가 방법] +1. **내용이 진짜인가? 중요한 걸 다 썼나?:** 기사가 기자가 적은 내용과 오늘 할 일의 중요한 점을 얼마나 잘 담고 있나요? 중요한 이야기가 빠지거나 틀리진 않았나요? (40점 만점) +2. **말이 잘 이어지고 이해하기 쉬운가?:** 기사 내용이 순서대로 잘 이어지고, 어린이 독자가 이해하기 쉽게 쓰여졌나요? (30점 만점) +3. **분위기는 적절한가? 어떤 영향을 줄까?:** 선택한 분위기가 지금 상황과 기사 내용에 맞나요? 이 기사가 사람들에게 어떤 느낌을 줄까요? (기자님 안전도 생각해주세요) (30점 만점) -위 평가 지침에 따라 각 항목별로 간략한 코멘트와 함께 점수를 부여하고, 총점(100점 만점)과 종합적인 피드백(2-3문장)을 제공해주십시오. -피드백은 기자가 발전할 수 있도록 구체적이고 건설적인 내용으로 작성해주세요. +위 평가 방법에 따라 각 항목별로 짧은 칭찬이나 조언과 함께 점수를 주세요. 그리고 총점(100점 만점)과 전체적인 칭찬/조언(2-3문장)을 알려주세요. +피드백은 기자가 더 잘할 수 있도록 쉽고 따뜻한 말로 써주세요. -출력 형식은 다음과 같이 JSON 형태로 제공해주세요: +출력은 이렇게 JSON 모양으로 주세요: {{ "score_fact": 점수(숫자), "comment_fact": "코멘트(문자열)", @@ -524,28 +672,30 @@ def evaluate_article_and_get_feedback_openai(article, game_state, assignment_dat "score_tone": 점수(숫자), "comment_tone": "코멘트(문자열)", "total_score": 총점(숫자), - "overall_feedback": "종합 피드백(문자열)" + "overall_feedback": "전체적인 칭찬/조언(문자열)" }} """ try: - with st.spinner("AI 편집장이 기사를 평가 중입니다..."): + with st.spinner("AI 편집장님이 기사를 읽고 있어요..."): response = client.chat.completions.create( - model="gpt-4o-mini", # 또는 gpt-4o + model="gpt-4o-mini", messages=[{"role": "user", "content": prompt}], response_format={"type": "json_object"}, - temperature=0.5, - max_tokens=600 # 토큰 수 넉넉하게 + temperature=0.3, # 좀 더 일관된 피드백을 위해 약간 낮춤 + max_tokens=700 ) ai_evaluation_str = response.choices[0].message.content ai_evaluation = json.loads(ai_evaluation_str) total_score = ai_evaluation.get("total_score", 0) - overall_feedback = ai_evaluation.get("overall_feedback", "AI 평가를 가져오지 못했습니다.") + overall_feedback = ai_evaluation.get("overall_feedback", "AI 편집장님 연결에 문제가 생겨서 점수를 못 매겼어요. 하지만 잘 썼을 거예요!") except Exception as e: st.error(get_text_func("error_openai_api").format(error=str(e))) total_score = random.randint(40, 70) - overall_feedback = "AI 편집장 시스템 오��로 자동 평가되었습니다. 내용은 훌륭하지만, 조금 더 팩트 체크에 신경 써주세요." + overall_feedback = "AI 편집장님 시스템에 문제가 생겨서 자동으로 점수를 매겼어요. 내용은 좋지만, 진짜 있었던 일인지 한 번 더 확인하면 좋겠어요." + + article['ai_score'] = total_score # 기사 딕셔너리에 AI 점수 저장 trust_change = (total_score - 50) // 5 status['public_trust'] = max(0, min(100, status['public_trust'] + trust_change)) @@ -566,16 +716,14 @@ def evaluate_article_and_get_feedback_openai(article, game_state, assignment_dat game_state['event_log'].append(get_text_func("log_desk_feedback").format(feedback=overall_feedback)) if trust_change != 0: game_state['event_log'].append(get_text_func("log_trust_change").format(change=trust_change)) - game_state['submitted_articles'].append(article) + game_state['submitted_articles'].append(article) # 점수가 포함된 article 저장 game_state['reporter_notebook'] = [] return overall_feedback # --- UI 표시 함수들 --- def display_reporter_dashboard(game_state): - scenario_key = game_state['scenario_key'] - vocab_level = SCENARIOS[scenario_key]["vocab_level"] - get_text_for_ui = lambda k: get_text(k, vocab_level) + get_text_for_ui = lambda k: get_text(k) status = game_state['status'] avg_score = (status['article_score_total'] / status['article_count']) if status['article_count'] > 0 else 0 @@ -587,69 +735,58 @@ def display_reporter_dashboard(game_state): with col4: st.metric(get_text_for_ui("term_article_score_avg"), f"{avg_score:.1f}점") -def display_reporter_notebook(game_state, vocab_level): - get_text_func = lambda k: get_text(k, vocab_level) +def display_reporter_notebook(game_state): + get_text_func = lambda k: get_text(k) st.subheader(get_text_func("reporter_notebook_title")) if game_state['reporter_notebook']: for note in game_state['reporter_notebook']: st.markdown(f"- {note}") else: - st.caption("아직 취재 노트에 기록된 내용이 없습니다.") + st.caption("아직 내가 적은 내용이 없어요.") -def display_historical_glossary_for_reporter(scenario_key, vocab_level): - get_text_for_ui = lambda k: get_text(k, vocab_level) +def display_historical_glossary_for_reporter(scenario_key): + get_text_for_ui = lambda k: get_text(k) st.sidebar.subheader(get_text_for_ui("sidebar_glossary_title")) glossary_keys_for_scenario = [k for k in ALL_TEXTS if k.startswith(f'glossary_{scenario_key}_')] if not glossary_keys_for_scenario: - st.sidebar.caption(f"{SCENARIOS[scenario_key]['display_name']} 관련 용어/인물 정보가 아직 없습니다.") + st.sidebar.caption(f"{get_text(SCENARIOS[scenario_key]['display_name'])}에 대한 어려운 말/사람 이야기가 아직 없어요.") for key in glossary_keys_for_scenario: term_definition = get_text_for_ui(key) - parts = term_definition.split(':', 1) - term = parts[0].strip() - definition = parts[1].strip() if len(parts) > 1 else "" - st.sidebar.markdown(f"**{term}:** {definition}") + # ALL_TEXTS가 이미 "용어: 설명" 형태의 문자열을 직접 가지고 있으므로, 분리할 필요 없음 + st.sidebar.markdown(term_definition) # 전체를 마크다운으로 표시 st.sidebar.markdown("---") -# (상단 import 및 설정, 함수 정의 등은 기존 코드 유지) -# ... (initialize_reporter_scenario_state, get_next_assignment, process_reporter_action, -# generate_article_interface, evaluate_article_and_get_feedback_openai, -# display_reporter_dashboard, display_reporter_notebook, -# display_historical_glossary_for_reporter 등 함수 정의는 그대로 사용) ... - -# --- 세션 상태 초기화 (기존과 동일) --- +# --- 세션 상태 초기화 --- if 'game_mode' not in st.session_state: st.session_state.game_mode = 'scenario_select' if 'current_scenario_key' not in st.session_state: st.session_state.current_scenario_key = None if 'game_state' not in st.session_state: st.session_state.game_state = None if 'current_assignment_data' not in st.session_state: st.session_state.current_assignment_data = None if 'actions_taken_this_turn' not in st.session_state: st.session_state.actions_taken_this_turn = 0 if 'desk_feedback_message' not in st.session_state: st.session_state.desk_feedback_message = None -if 'active_main_tab' not in st.session_state: st.session_state.active_main_tab = "취재 브리핑" # 기본 활성 탭 +if 'active_main_tab' not in st.session_state: st.session_state.active_main_tab = "오늘 할 일 보기" # --- 메인 게임 로직 (기자 컨셉) --- def reporter_simulation_main(): - vocab_level = "보통" - if st.session_state.current_scenario_key: - vocab_level = SCENARIOS[st.session_state.current_scenario_key]["vocab_level"] - get_text_main = lambda key: get_text(key, vocab_level) + get_text_main = lambda key: get_text(key) st.title(get_text_main("game_title")) - # --- 시나리오 선택 (기존과 동일) --- + # --- 시나리오 선택 --- if st.session_state.game_mode == 'scenario_select': st.header(get_text_main("scenario_select_title")) scenario_descriptions = { - "4.19_revolution": "1960년, 격동의 현장으로! 자유당 정권의 3.15 부정선거 의혹부터 4.19 혁명의 순간까지, 신입 기자로서 진실을 추적하고 역사의 기록자가 되십시오.", - "5.18_gwangju": "1980년 5월, 통제된 도시 광주로... 신군부의 계엄 하에 고립된 광주의 참상을 목격하고, 검열을 뚫고 진실을 알려야 합니다. (주의: 민감한 내용을 다룹니다. 신중한 취재가 요구됩니다.)", - "june_struggle": "1987년, 민주화의 열기가 뜨거운 거리로! 박종철 고문치사부터 6월 항쟁의 함성까지, 독재에 맞선 시민들의 목소리를 담아내십시오." + "4.19_revolution": "1960년, 우리나라에 큰 변화가 있었던 때로 가봐요! 새내기 기자가 되어서 진짜 있었던 일을 알아내고 사람들에게 알려주는 거예요.", + "5.18_gwangju": "1980년 5월, 광주라는 도시에서 아주 슬픈 일이 있었어요. 용감한 기자가 되어서 그곳 사람들의 이야기를 듣고 진실을 알려야 해요. (조금 무섭거나 슬픈 내용이 나올 수 있어요.)", + "june_struggle": "1987년, 우리나라 사람들이 '우리 손으로 대통령을 뽑고 싶다!'고 외쳤던 때예요. 사회부 기자가 되어서 뜨거운 현장의 목소리를 담아보세요." } for key, scenario_info in SCENARIOS.items(): with st.container(border=True): - st.subheader(scenario_info["display_name"]) - st.caption(f"시대: {scenario_info['start_year']}년, 당신의 역할: {scenario_info['player_role']}") - st.markdown(scenario_descriptions.get(key, "이 시대의 취재 임무 설명이 준비되지 않았습니다.")) + st.subheader(get_text(scenario_info["display_name"])) # SCENARIOS의 display_name은 키가 아니므로 get_text 사용 + st.caption(f"언제: {scenario_info['start_year']}년, 나는 누구?: {scenario_info['player_role']}") + st.markdown(scenario_descriptions.get(key, "이 시대에는 어떤 일이 있었을까요?")) if st.button(get_text_main("scenario_select_button"), key=f"select_{key}"): st.session_state.current_scenario_key = key st.session_state.game_state = initialize_reporter_scenario_state(key) @@ -657,7 +794,7 @@ def reporter_simulation_main(): st.session_state.actions_taken_this_turn = 0 st.session_state.desk_feedback_message = None st.session_state.game_mode = 'assignment_briefing' - st.session_state.active_main_tab = "취재 브리핑" # 탭 초기화 + st.session_state.active_main_tab = "오늘 할 일 보기" st.rerun() st.stop() @@ -665,16 +802,15 @@ def reporter_simulation_main(): if st.session_state.game_mode != 'scenario_select' and st.session_state.game_state: game_state = st.session_state.game_state scenario_key = st.session_state.current_scenario_key - vocab_level = SCENARIOS[scenario_key]["vocab_level"] - get_text_main = lambda key: get_text(key, vocab_level) + get_text_main = lambda key: get_text(key) # --- 사이드바 구성 --- with st.sidebar: st.header(get_text_main("dashboard_title")) - st.caption(f"시나리오: {SCENARIOS[scenario_key]['display_name']}") - st.caption(f"역할: {game_state['player_role']}") + st.caption(f"지금 시대: {get_text(SCENARIOS[scenario_key]['display_name'])}") + st.caption(f"내 역할: {game_state['player_role']}") st.markdown(f"**{get_text_main('dashboard_term').format(year=game_state['game_year'], turn=game_state['current_turn'])}**") - display_reporter_dashboard(game_state) # 핵심 지표 표시 + display_reporter_dashboard(game_state) st.markdown("---") if st.button(get_text_main("button_next_day"), use_container_width=True, key="next_day_button_sidebar", @@ -683,7 +819,7 @@ def reporter_simulation_main(): st.session_state.actions_taken_this_turn < ACTIONS_PER_TURN_LIMIT and st.session_state.current_assignment_data and len(st.session_state.current_assignment_data.get("options", [])) > 0 - ) # 아직 할 수 있는 액션이 남았거나 기사 작성 중이면 비활성화 + ) ) ): current_turn = game_state['current_turn'] @@ -693,7 +829,7 @@ def reporter_simulation_main(): (st.session_state.current_assignment_data and st.session_state.current_assignment_data.get("is_final_turn_event", False)): st.session_state.game_mode = 'assignment_over' if game_state.get('event_log') is not None: - game_state['event_log'].append(get_text_main("log_assignment_over").format(scenario_name=SCENARIOS[scenario_key]['display_name'])) + game_state['event_log'].append(get_text_main("log_assignment_over").format(scenario_name=get_text(SCENARIOS[scenario_key]['display_name']))) else: game_state['current_turn'] += 1 if game_state.get('event_log') is not None: @@ -702,21 +838,21 @@ def reporter_simulation_main(): st.session_state.current_assignment_data = None st.session_state.actions_taken_this_turn = 0 - st.session_state.desk_feedback_message = None # 피드백 초기화 - st.session_state.active_main_tab = "취재 브리핑" # 탭 초기화 + st.session_state.desk_feedback_message = None + st.session_state.active_main_tab = "오늘 할 일 보기" st.rerun() st.markdown("---") - display_historical_glossary_for_reporter(scenario_key, vocab_level) + display_historical_glossary_for_reporter(scenario_key) st.subheader(get_text_main("sidebar_current_source_title")) - if st.session_state.current_assignment_data and st.session_state.current_assignment_data.get('source_text'): + if st.session_state.current_assignment_data and st.session_state.current_assignment_data.get('source_text') and st.session_state.current_assignment_data.get('source_text') != "[알아두면 좋아요]": # 빈 source_text 방지 st.sidebar.info(st.session_state.current_assignment_data.get('source_text')) else: st.sidebar.caption(get_text_main("sidebar_no_source")) st.markdown("---") - if st.button(get_text_main("button_back_to_scenario_select") + " (다른 시대 취재)", use_container_width=True): + if st.button(get_text_main("button_back_to_scenario_select") + " (다른 시대 가기)", use_container_width=True): st.session_state.game_mode = 'scenario_select' keys_to_clear = ['current_scenario_key', 'game_state', 'current_assignment_data', 'actions_taken_this_turn', 'desk_feedback_message', 'active_main_tab'] for k_to_clear in keys_to_clear: @@ -728,18 +864,16 @@ def reporter_simulation_main(): st.balloons() st.header(get_text_main("assignment_over_title")) st.subheader(get_text_main("assignment_over_subtitle")) - # 최종 대시보드는 사이드바에 이미 표시됨 - st.subheader("송고한 주요 기사 목록") + st.subheader("내가 보낸 주요 기사들") if game_state['submitted_articles']: for article_idx, article in enumerate(game_state['submitted_articles']): tone_text_key = f"article_tone_{article['tone']}" tone_display_text = get_text_main(tone_text_key) - # AI 점수는 article 딕셔너리에 저장해야 함 (evaluate 함수에서) - ai_score = article.get('ai_score', 'N/A') # 'ai_score' 키로 저장했다고 가정 - st.markdown(f"- **{article['headline']}** (논조: {tone_display_text}) - {article['turn']}일차 송고 (AI 점수: {ai_score}점)") + ai_score = article.get('ai_score', '점수 없음') + st.markdown(f"- **{article['headline']}** (분위기: {tone_display_text}) - {article['turn']}번째 날 보냄 (AI 점수: {ai_score}점)") else: - st.caption("이번 취재 기간 동안 송고한 기사가 없습니다.") + st.caption("이번 취재 동안 보낸 기사가 없어요.") with st.expander(get_text_main("term_event_log"), expanded=False): log_text = "\n".join(game_state.get('event_log', [])[::-1]) @@ -751,16 +885,12 @@ def reporter_simulation_main(): st.session_state.actions_taken_this_turn = 0 st.session_state.desk_feedback_message = None st.session_state.game_mode = 'assignment_briefing' - st.session_state.active_main_tab = "취재 브리핑" + st.session_state.active_main_tab = "오늘 할 일 보기" st.rerun() st.stop() # --- 메인 콘텐츠 영역 --- - # 탭 대신 단계별 UI 전환 또는 주요 정보만 표시하는 방식으로 변경 가능 - # 여기서는 주요 정보를 먼저 표시하고, 액션은 버튼으로 유도 - - # 1. 오늘의 취재 지시 로드 (assignment_briefing 모드에서 처리) if st.session_state.game_mode == 'assignment_briefing': if st.session_state.current_assignment_data is None: spinner_text = get_text_main('status_loading_assignment').format(year=game_state['game_year'], turn=game_state['current_turn']) @@ -770,115 +900,111 @@ def reporter_simulation_main(): if assignment: st.session_state.current_assignment_data = assignment st.session_state.actions_taken_this_turn = 0 - st.session_state.desk_feedback_message = None # 이전 피드백 초기화 - st.session_state.game_mode = 'reporter_action' # 바로 취재 활동으로 - st.session_state.active_main_tab = "취재 활동" # 탭 전환 + st.session_state.desk_feedback_message = None + st.session_state.game_mode = 'reporter_action' + st.session_state.active_main_tab = "🎤 무엇을 할까요?" st.rerun() else: st.session_state.game_mode = 'assignment_over' if game_state.get('event_log') is not None: - game_state['event_log'].append(get_text_main("log_assignment_over").format(scenario_name=SCENARIOS[scenario_key]['display_name'])) + game_state['event_log'].append(get_text_main("log_assignment_over").format(scenario_name=get_text(SCENARIOS[scenario_key]['display_name']))) st.rerun() - # 메인 화면에 현재 취재 지시 표시 if st.session_state.current_assignment_data: assignment_data = st.session_state.current_assignment_data st.header(get_text_main("current_assignment_title")) st.subheader(f"{assignment_data['assignment_text']}") - # 배경 정보는 사이드바로 이동했으므로 여기서는 생략 가능 st.markdown("---") - # 탭으로 주요 활동 구분 - tab_titles = ["🎤 취재 활동"] + tab_titles = ["🎤 무엇을 할까요?"] if st.session_state.current_assignment_data and st.session_state.current_assignment_data.get("article_writing_phase"): - tab_titles.append("🖋️ 기사 작성") + tab_titles.append("🖋️ 기사 쓰기") if st.session_state.desk_feedback_message: - tab_titles.append("📢 AI 편집장 평가") + tab_titles.append("📢 AI 편집장님의 한마디") - # 탭 상태 관리 (선택된 탭 유지) if 'active_main_tab' not in st.session_state or st.session_state.active_main_tab not in tab_titles: - st.session_state.active_main_tab = tab_titles[0] # 기본값 또는 유효한 값으로 설정 + st.session_state.active_main_tab = tab_titles[0] + + # 현재 활성화된 탭 인덱스 찾기 + try: + current_tab_index = tab_titles.index(st.session_state.active_main_tab) + except ValueError: + current_tab_index = 0 # 기본값 + st.session_state.active_main_tab = tab_titles[0] + - # 현재 활성화된 탭을 selected_tab으로 사용 - # selected_tab = st.radio("메인 활동 선택:", tab_titles, horizontal=True, key="main_activity_radio", index=tab_titles.index(st.session_state.active_main_tab)) - # st.session_state.active_main_tab = selected_tab # 선택된 탭 업데이트 - # radio 대신 st.tabs 사용 - tabs_ui = st.tabs(tab_titles) - with tabs_ui[0]: # 취재 활동 탭 - # st.header(get_text_main("reporter_actions_title")) # 탭 이름으로 대체 + with tabs_ui[0]: # 무엇을 할까요? 탭 if st.session_state.game_mode == 'reporter_action' and st.session_state.current_assignment_data: assignment_data = st.session_state.current_assignment_data if st.session_state.actions_taken_this_turn < ACTIONS_PER_TURN_LIMIT: - st.write(f"남은 활동 횟수: {ACTIONS_PER_TURN_LIMIT - st.session_state.actions_taken_this_turn}") + st.write(f"남은 활동 횟수: {ACTIONS_PER_TURN_LIMIT - st.session_state.actions_taken_this_turn}번") + + # 위험도 문자열 생성 로직 for i, opt in enumerate(assignment_data['options']): - risk_info = [] - if opt.get('cost_freedom_risk',0) > 0: risk_info.append(f"자유도↓{opt['cost_freedom_risk']}%") - if opt.get('safety_risk',0) > 0: risk_info.append(f"안전도↓{opt['safety_risk']}%") - risk_str = ", ".join(risk_info) if risk_info else "낮음" + total_risk_score = opt.get('cost_freedom_risk',0) + opt.get('safety_risk',0) + if total_risk_score > 40 : risk_str = "엄청 조심!!" + elif total_risk_score > 20 : risk_str = "많이 조심!" + elif total_risk_score > 0 : risk_str = "조금 조심" + else: risk_str = "안전함" + button_label = get_text_main("action_button_label").format(action=opt['action_text'], risk_str=risk_str) if st.button(button_label, key=f"rep_action_{game_state['current_turn']}_{i}_{scenario_key}", use_container_width=True): process_reporter_action(opt, game_state) - # 취재 활동 후 바로 기사 작성 탭으로 이동할지, 아니면 현재 탭 유지할지 결정 필요 - # 여기서는 현재 탭 유지하고, 모든 활동 끝나면 기사 작성 버튼 활성화 st.rerun() else: st.info(get_text_main("status_actions_taken")) - if assignment_data.get("article_writing_phase") and "🖋️ 기사 작성" in tab_titles: - st.success("모든 취재 활동을 마쳤습니다. '기사 작성' 탭으로 이동하여 기사를 작성하세요.") - # 자동으로 탭 이동은 어려우므로 사용자에게 안내 + if assignment_data.get("article_writing_phase") and "🖋️ 기사 쓰기" in tab_titles: + st.success("오늘 할 일을 다 했어요. '기사 쓰기' 탭으로 가서 기사를 써보세요!") elif not assignment_data.get("article_writing_phase"): - st.success("오늘의 모든 취재 활동을 마쳤습니다. 사이드바에서 '다음 날로' 버튼을 눌러 진행하세요.") - + st.success("오늘 할 일을 다 했어요. 옆 메뉴에서 '다음 날로 가기' 버튼을 눌러주세요.") - with st.expander("📝 나의 취재 노트 보기", expanded=False): - display_reporter_notebook(game_state, vocab_level) + with st.expander("📝 내가 적은 내용 보기", expanded=False): + display_reporter_notebook(game_state) - if "🖋️ 기사 작성" in tab_titles: - with tabs_ui[tab_titles.index("🖋️ 기사 작성")]: + if "🖋️ 기사 쓰기" in tab_titles: + with tabs_ui[tab_titles.index("🖋️ 기사 쓰기")]: if st.session_state.game_mode in ['reporter_action', 'article_writing'] and \ st.session_state.current_assignment_data and \ st.session_state.current_assignment_data.get("article_writing_phase") and \ - st.session_state.actions_taken_this_turn >= ACTIONS_PER_TURN_LIMIT: # 모든 취재 활동을 마친 후 + st.session_state.actions_taken_this_turn >= ACTIONS_PER_TURN_LIMIT: - # 기사 작성 중이 아니면, 작성 모드로 변경 if st.session_state.game_mode != 'article_writing': st.session_state.game_mode = 'article_writing' - # st.rerun() # generate_article_interface를 바로 호출하므로 rerun 불필요 assignment_data = st.session_state.current_assignment_data - submitted_article = generate_article_interface(game_state, vocab_level) + submitted_article = generate_article_interface(game_state) if submitted_article: feedback = evaluate_article_and_get_feedback_openai(submitted_article, game_state, assignment_data) st.session_state.desk_feedback_message = feedback - st.session_state.game_mode = 'reporter_action' # 피드백 표시 및 다음날로 진행 가능하도록 - st.session_state.active_main_tab = "📢 AI 편집장 평가" if "📢 AI 편집장 평가" in tab_titles else "🎤 취재 활동" + st.session_state.game_mode = 'reporter_action' + st.session_state.active_main_tab = "📢 AI 편집장님의 한마디" if "📢 AI 편집장님의 한마디" in tab_titles else "🎤 무엇을 할까요?" st.rerun() elif not (st.session_state.current_assignment_data and st.session_state.current_assignment_data.get("article_writing_phase")): - st.info("이번 턴에는 기사 작성이 예정되어 있지 않습니다.") + st.info("이번엔 기사 쓰는 날이 아니에요.") elif st.session_state.actions_taken_this_turn < ACTIONS_PER_TURN_LIMIT: - st.info(f"아직 오늘의 취재 활동이 남았습니다. (남은 활동: {ACTIONS_PER_TURN_LIMIT - st.session_state.actions_taken_this_turn}회)") + st.info(f"아직 오늘 할 일이 남았어요. (남은 활동: {ACTIONS_PER_TURN_LIMIT - st.session_state.actions_taken_this_turn}번)") - if "📢 AI 편집장 평가" in tab_titles: - with tabs_ui[tab_titles.index("📢 AI 편집장 평가")]: + if "📢 AI 편집장님의 한마디" in tab_titles: + with tabs_ui[tab_titles.index("📢 AI 편집장님의 한마디")]: if st.session_state.desk_feedback_message: st.subheader(get_text_main("desk_feedback_title")) st.warning(st.session_state.desk_feedback_message) - st.info("평가를 확인했으면 사이드바에서 '다음 날로' 버튼을 눌러 진행하세요.") + st.info("편집장님 말씀을 다 봤으면 옆 메뉴에서 '다음 날로 가기' 버튼을 눌러주세요.") else: - st.info("아직 평가된 기사가 없습니다. 기사를 먼저 작성하고 송고해주세요.") + st.info("아직 편집장님께 보여드린 기사가 없어요. 기사를 먼저 써서 보내주세요.") st.markdown("---") with st.expander(get_text_main("term_event_log") + " (최근 10개)", expanded=False): - log_text = "\n".join(game_state.get('event_log', [])[-10:][::-1]) # 최근 10개만 표시 - st.text_area("로그 내용", log_text, height=200, disabled=True, key="event_log_area_reporter_main") + log_text = "\n".join(game_state.get('event_log', [])[-10:][::-1]) + st.text_area("오늘 있었던 일", log_text, height=200, disabled=True, key="event_log_area_reporter_main") elif st.session_state.game_mode != 'scenario_select' and not st.session_state.game_state: - st.warning("게임 상태 정보가 유실되었습니다. 시나리오 선택 화면으로 돌아갑니다.") + st.warning("어이쿠! 게임 정보가 사라졌어요. 처음 화면으로 돌아갈게요.") st.session_state.game_mode = 'scenario_select' keys_to_clear = ['current_scenario_key', 'game_state', 'current_assignment_data', 'actions_taken_this_turn', 'desk_feedback_message', 'active_main_tab'] for k_to_clear in keys_to_clear: