diff --git "a/app.py" "b/app.py"
--- "a/app.py"
+++ "b/app.py"
@@ -1,8 +1,13 @@
+# -*- coding: utf-8 -*-
import streamlit as st
import random
import time
import math
+# --- 페이지 설정 (스크립트 최상단) ---
+# 이 부분이 가장 먼저 실행되어야 합니다!
+st.set_page_config(layout="wide")
+
# --- 게임 설정 ---
MAX_YEARS = 5
QUARTERLY_ACTIONS_LIMIT = 1
@@ -42,6 +47,7 @@ DIFFICULTY_LEVELS = {
}
# --- 난이도별 텍스트 저장소 ---
+# (이하 ALL_TEXTS 사전 정의는 이전 답변과 동일하게 유지됩니다)
ALL_TEXTS = {
# 대시보드 용어
"term_approval": {
@@ -157,31 +163,62 @@ ALL_TEXTS = {
"어려움": "게임 재시작"
},
# 이벤트 제목 예시
- "event_minor_issue_title": {
- "쉬움": "작은 문제 발생!",
- "보통": "소규모 현안 발생",
- "어려움": "국지적 문제 발생 보고"
- },
- "event_opportunity_title": {
- "쉬움": "좋은 기회가 찾아왔어요!",
- "보통": "기회 포착",
- "어려움": "정책적 기회 요인 발생"
- },
- "event_political_move_title": {
- "쉬움": "정치 쪽에서 시끌시끌해요",
- "보통": "정치적 동향 보고",
- "어려움": "정무적 상황 변동 보고"
- },
- "event_routine_report_title": {
- "쉬움": "이번 계절은 조용했어요",
- "보통": "일상 국정 보고",
- "어려움": "정기 국정 운영 현황 보고"
- },
- "event_checks_balances_title": {
- "쉬움": "[다른 기관 소식] ", # 쉬움 난이도에서는 별도 제목 대신 접두사만
- "보통": "[견제와 균형] ",
- "어려움": "[기관 간 견제 및 균형] "
- },
+ "event_title_minor_disaster": { "쉬움": "작은 재난 발생", "보통": "소규모 재난 발생", "어려움": "국지적 자연재해 발생"},
+ "event_desc_minor_disaster": { "쉬움": "비가 많이 오거나 불이 나서 동네 몇 군데가 피해를 입었어요. 빨리 도와줘야 해요.", "보통": "집중 호우 또는 산불 등으로 특정 지역에 피해가 발생했습니다. 신속한 지원이 필요합니다.", "어려움": "국지성 호우 또는 산불로 인해 일부 지역에서 물적 피해가 보고되었습니다. 긴급 구호 및 복구 계획 수립이 요구됩니다."},
+ "action_visit_disaster_area": { "쉬움": "피해 지역 가서 위로하기", "보통": "피해 지역 현장 방문 및 지원 약속", "어려움": "피해 지역 순방 및 정부 차원 지원 공표"},
+
+ "event_title_small_protest": { "쉬움": "사람들이 모여서 외치고 있어요", "보통": "소규모 시위 발생", "어려움": "제한적 규모의 집회 발생"},
+ "event_desc_small_protest": { "쉬움": "어떤 문제 때문에 몇몇 사람들이 모여 목소리를 내고 있어요. 시끄럽지만 큰 문제는 아니에요.", "보통": "특정 현안에 대한 불만으로 일부 시민들이 소규모 집회를 열고 있습니다. 상황 관리가 필요합니다.", "어려움": "특정 정책 또는 사회 현안에 대한 이견 표출로 소규모 집회가 개최되었습니다. 확산 가능성 주시 요망."},
+ "action_meet_protesters": { "쉬움": "시위대 이야기 들어보기", "보통": "시위대 대표 면담 추진", "어려움": "집회 주동자 대화 채널 구축 시도"},
+
+ "event_title_price_rise": {"쉬움": "물건값이 조금 올랐어요", "보통": "물가 소폭 상승", "어려움": "소비자 물가 지수 소폭 상승"},
+ "event_desc_price_rise": {"쉬움": "가게 물건값이 조금 올라서 사람들이 걱정해요. 안심시켜야 해요.", "보통": "일부 품목의 가격 상승으로 소비자 물가가 소폭 상승했습니다. 시장 불안 심리 차단이 필요합니다.", "어려움": "주요 소비재 가격 인상으로 인해 단기 인플레이션 압력이 감지됩니다. 선제적 시장 안정화 조치가 요구됩니다."},
+ "action_address_prices": {"쉬움": "물가 괜찮다고 말하기", "보통": "물가 안정 노력 관련 대국민 메시지 발표", "어려움": "물가 안정 기조 유지 관련 정부 입장 표명"},
+
+ "event_title_summit_offer": {"쉬움": "다른 나라 대통령 만나자고 해요", "보통": "정상회담 개최 제안", "어려움": "양자 정상회담 개최 제의 접수"},
+ "event_desc_summit_offer": {"쉬움": "이웃 나라 대통령이 만나자고 연락 왔어요. 친하게 지내면 좋아요.", "보통": "주요 동맹국/주변국 정상으로부터 양자 회담 개최 제안이 왔습니다. 외교적 성과 기회입니다.", "어려움": "주요 외교 파트너 국가 수반의 공식적인 양자 정상회담 제의가 접수되었습니다. 의제 조율 및 전략 수립이 필요합니다."},
+ "action_accept_summit": {"쉬움": "만나서 좋은 얘기하기", "보통": "정상회담 적극 수락 및 의제 준비 지시", "어려움": "정상회담 제의 수락 및 실무 준비 TF 구성 지시"},
+
+ "event_title_host_event": {"쉬움": "큰 국제 행사 우리나라에서 열까?", "보통": "대규모 국제 행사 유치 가능성", "어려움": "메가 이벤트 국내 유치 타당성 검토"},
+ "event_desc_host_event": {"쉬움": "올림픽 같은 큰 행사를 우리나라에서 열 수 있을지 알아보고 있대요. 좋겠죠?", "보통": "대규모 국제 스포츠/문화 행사 유치 경쟁에서 유리한 고지를 점했다는 보고입니다. 국가 이미지 제고 효과가 기대됩니다.", "어려움": "주요 국제 스포츠/문화 행사의 차기 개최지 선정과 관련하여 유력 후보로 부상했다는 분석입니다. 국가 브랜드 가치 제고 및 경제적 파급 효과가 예상됩니다."} ,
+ "action_support_hosting": {"쉬움": "행사 유치 돕기", "보통": "국제 행사 유치위원회에 예산/행정 지원 강화", "어려움": "범정부 차원의 국제 행사 유치 지원 체계 구축"},
+
+ "event_title_tech_investment": {"쉬움": "새로운 기술에 투자할까?", "보통": "신기술 분야 투자 적기 보고", "어려움": "미래 전략기술 분야 투자 최적 시점 분석"},
+ "event_desc_tech_investment": {"쉬움": "미래에 중요해질 새 기술에 투자하면 좋겠다는 보고예요. 돈 벌 수 있을까요?", "보통": "미래 산업 관련 핵심 신기술 분야에 대한 국내외 투자 환경이 유리하다는 분석입니다. 정부 지원 시 관련 공약 달성에 도움이 될 수 있습니다.", "어려움": "차세대 핵심 기술 분야의 R&D 및 상용화 투자 환경이 우호적으로 조성되었다는 분석 보고입니다. 국가 경쟁력 강화 및 관련 국정 과제 이행의 기회입니다."},
+ "action_review_tech_funding": {"쉬움": "새 기술 연구비 지원 알아보기", "보통": "신기술 분야 R&D 예산 증액 국회 요청 준비", "어려움": "전략기술 R&D 예산 확대 편성 및 입법부 설득 전략 수립"},
+
+ "event_title_opposition_criticism": {"쉬움": "야당이 {minister} 장관 싫어해요", "보통": "야당, {minister} 장관 책임론 제기", "어려움": "야당의 {minister} 장관에 대한 문책 요구"},
+ "event_desc_opposition_criticism": {"쉬움": "국회 반대편 의원들이 {minister} 장관이 일 못한다고 계속 비판해요.", "보통": "야당에서 {minister} 장관의 정책 실패 또는 부적절한 처신을 이유로 책임론을 강하게 제기하고 있습니다.", "어려움": "주요 야당은 {minister} 장관의 직무 수행 능력 및 정책적 판단에 심각한 문제가 있다며 사퇴 또는 해임 건의를 검토 중입니다."},
+ "action_defend_minister": {"쉬움": "{minister} 장관 편들어주기", "보통": "{minister} 장관 엄호 및 야당 설득 시도", "어려움": "{minister} 장관에 대한 신임 재확인 및 야당 공세 대응"},
+
+ "event_title_party_dissent": {"쉬움": "우리 편에서도 다른 소리가 나와요", "보통": "여당 내 특정 현안 관련 이견 노출", "어려움": "집권여당 내 정책 노선 관련 이견 표출"},
+ "event_desc_party_dissent": {"쉬움": "대통령이랑 같은 편 의원들 중에서도 정부가 하는 일에 대해 다른 생각을 말하기 시작했어요.", "보통": "정부 주요 정책 방향에 대해 여당 내 일부 의원들이 공개적으로 다른 목소리를 내기 시작했습니다. 내부 조율이 필요해 보입니다.", "어려움": "주요 국정 현안에 대한 당정 간 이견이 일부 언론을 통해 노출되었습니다. 당내 결속력 약화 및 정책 추진 동력 저하가 우려됩니다."},
+ "action_meet_party_members": {"쉬움": "우리 편 의원들 만나서 얘기하기", "보통": "여당 지도부/중진 의원들과 비공개 회동", "어려움": "여당 의원들과의 정책 간담회를 통한 내부 이견 조율"},
+
+ "event_title_media_criticism": {"쉬움": "신문/뉴스에서 정부 욕해요", "보통": "언론의 특정 정책 비판 보도", "어려움": "주요 언론의 정부 정책 비판 기조 강화"},
+ "event_desc_media_criticism": {"쉬움": "신문이나 뉴스에서 정부가 하는 일 하나를 콕 집어서 나쁘다고 말해요. 사람들이 믿으면 어쩌죠?", "보통": "주요 언론에서 정부의 특정 정책에 대한 문제점을 지적하거나 부정적인 여론을 부각하는 보도가 이어지고 있습니다.", "어려움": "복수의 주요 언론 매체에서 특정 정부 정책의 문제점 및 부작용을 집중적으로 보도하며 비판적 여론 형성을 주도하고 있습니다."},
+ "action_media_interview": {"쉬움": "기자들 만나서 설명하기", "보통": "언론 인터뷰를 통해 정책 설명 및 오해 해소", "어려움": "대통령 또는 주무 장관의 언론 브리핑을 통한 정책 정당성 설파"},
+
+ "event_title_congress_data_request": {"쉬움": "국회에서 자료 달래요", "보통": "국회, 정부 정책 자료 요구", "어려움": "국회의 행정부에 대한 자료 제출 요구"},
+ "event_desc_congress_data_request": {"쉬움": "국회의원들이 정부가 하는 일에 대해 자세히 알려달라고 자료를 내래요. 귀찮네요.", "보통": "국회 상임위원회에서 정부가 추진 중인 정책과 관련된 상세 자료 제출을 공식적으로 요구했습니다.", "어려움": "국회 소관 상임위원회에서 특정 정책의 추진 경과 및 예산 집행 내역 등 민감한 자료의 제출을 요구하여 행정부 부담이 가중되고 있습니다."},
+ "action_submit_data": {"쉬움": "자료 잘 만들어서 주기", "보통": "성실히 자료 제출 준비 지시", "어려움": "국회 요구 자료의 신속하고 정확한 제출 지시"},
+ "action_minimize_data": {"쉬움": "자료 조금만 주기 (혼날지도?)", "보통": "자료 제출 범위 최소화 검토 (관계 악화 위험)", "어려움": "제출 자료 범위에 대한 법적 검토 및 최소 수준 제출 추진"},
+
+ "event_title_congress_hearing_review": {"쉬움": "국회가 청문회 할지 고민 중이래요", "보통": "국회, 특정 사안 청문회 개최 검토", "어려움": "국회의 특정 현안 관련 청문회 개최 검토"},
+ "event_desc_congress_hearing_review": {"쉬움": "국회에서 시끄러운 문제에 대해 담당자 불러서 물어보는 청문회를 열지 말지 생각 중이래요. 열리면 골치 아파요.", "보통": "국회에서 논란이 되는 특정 사안에 대해 관계 부처 장관 등을 출석시켜 질의하는 청문회 개최 여부를 검토 중입니다. 개최 시 정부에 부담이 될 수 있습니다.", "어려움": "특정 국정 현안의 진상 규명 또는 책임 소재 파악을 위해 국회 차원의 청문회 개최 필요성이 제기되어 관련 상임위에서 논의가 진행 중입니다."},
+ "action_prevent_hearing": {"쉬움": "청문회 못 열게 막아보기", "보통": "여당 통해 청문회 개최 저지 또는 연기 시도", "어려움": "여당과 협력하여 청문회 개최의 부당성 설파 및 무산 유도"},
+ "action_prepare_hearing": {"쉬움": "청문회 잘 대답하게 준비하기", "보통": "청문회 대비 관계부처 합동 준비 지시", "어려움": "예상 쟁점 분석 및 대응 논리 개발 등 청문회 철저 대비 지시"},
+
+ "event_title_judiciary_lawsuit": {"쉬움": "누가 정부를 법원에 고소했어요", "보통": "법원, 정부 정책 관련 소송 접수", "어려움": "정부 정책 관련 행정소송 제기"},
+ "event_desc_judiciary_lawsuit": {"쉬움": "정부가 한 일이 잘못됐다면서 누가 법원에 고소했어요. 재판에서 지면 큰일나요.", "보통": "정부가 시행한 특정 정책의 위법 또는 부당성을 주장하며 시민 또는 단체가 행정소송을 제기했습니다. 판결 결과에 따라 정책 추진에 차질이 발생할 수 있습니다.", "어려움": "정부의 특정 행정 처분 또는 부작위에 대해 그 효력을 다투는 행정소송이 관할 법원에 접수되었습니다. 사법부의 판단에 따라 해당 정책의 지속 가능성이 결정될 수 있습니다."},
+ "action_prepare_legal_defense": {"쉬움": "변호사 시켜서 잘 싸우라고 하기", "보통": "법무부에 법적 대응 논리 개발 및 준비 지시", "어려움": "법무부 주관 하에 정부 소송대리인단 구성 및 적극적 변론 준비 지시"},
+ "action_persuade_public": {"쉬움": "국민들에게 우리 편 들어달라고 설득하기", "보통": "정책의 정당성 관련 대국민 홍보 강화", "어려움": "해당 정책의 공익성 및 불가피성에 대한 적극적 여론 형성 노력"},
+
+ "event_title_routine_report": { "쉬움": "이번 계절은 조용했어요", "보통": "일상 국정 보고", "어려움": "정기 국정 운영 현황 보고"},
+ "event_desc_routine_report": { "쉬움": "이번 계절은 별일 없었어요. 하던 일 계속하면 돼요.", "보통": "이번 분기는 특별한 현안 없이 국정이 비교적 안정적으로 운영되고 있다는 보고입니다. 기존 정책 추진에 집중할 시기입니다.", "어려움": "현 분기 특이사항 없이 안정적인 국정 운영 기조가 유지되고 있다는 정례 보고입니다. 기존 정책과제의 지속적인 추진이 권고됩니다."},
+ "action_check_goal_progress": { "쉬움": "약속 얼마나 지켰나 보기", "보통": "주요 공약 진행 상황 점검", "어려움": "핵심 국정 과제 이행 현황 중간 점검"},
+ "action_strengthen_pr": { "쉬움": "정부가 잘하고 있다고 자랑하기", "보통": "정책 홍보 활동 강화 지시", "어려움": "국정 운영 성과 홍보 전략 강화 지시"},
+
# 행동 관련 메시지
"action_button_label": { # 버튼 레이블은 통일성 위해 보통 수준 유지
"쉬움": "{action} ({cost} 힘 점수)",
@@ -326,25 +363,62 @@ ALL_TEXTS = {
"보통": "**정치력 (Political Capital):** 대통령이 자신의 정책을 추진하거나 영향력을 행사하는 데 사용할 수 있는 비공식적인 자원. 지지도, 협상력, 리더십 등을 포함하는 개념으로 게임 내 행동력으로 사용됨.",
"어려움": "**정치적 자본 (Political Capital):** 대통령이 국정 운영 목표 달성을 위해 동원할 수 있는 무형의 자산. 국민적 지지, 의회 내 영향력, 정책 정당성, 리더십 등을 포괄하며, 정치적 행위의 비용으로 소모됨."
},
- # ... (다른 모든 텍스트 키에 대해서도 유사하게 추가)
+ # 상시 행동 키
+ "action_replace_minister": {"쉬움": "{minister} 장관 바꾸기", "보통": "{minister} 장관 교체", "어려움": "{minister} 장관 경질"},
+ "action_prepare_bill": {"쉬움": "새로운 법 만들기 준비", "보통": "법률안 국회 제출 준비", "어려움": "입법안 발의 준비 착수"},
+ "action_meet_ruling_party": {"쉬움": "우리 편 의원들이랑 밥 먹기", "보통": "여당 지도부와 만찬 회동", "어려움": "집권여당 지도부와 정례 회동"},
+ "action_meet_opposition": {"쉬움": "반대편 의원들 만나보기", "보통": "야당 지도부 만나기 (관계 개선 시도)", "어려움": "주요 야당 지도부와 협의 채널 구축"},
+ "action_meet_biz_leaders": {"쉬움": "회사 사장님들 만나기", "보통": "주요 경제 단체 간담회", "어려움": "주요 경제계 인사 초청 간담회"},
+ "action_respect_judiciary": {"쉬움": "법원 존중한다고 말하기", "보통": "사법부 존중 메시지 발표", "어려움": "사법부 독립성 존중 관련 대국민 메시지 발표"},
+ "action_no_special_action": {"쉬움": "이번엔 그냥 넘어가기", "보통": "이번 분기 특별 조치 없음", "어려움": "현 분기 특이 조치 보류"},
+ # 상태 메시지 키
+ "status_loading_report": {"쉬움": "{year}년 {quarter}번째 계절 보고서 만드는 중...", "보통": "{year}년 {quarter}분기 보고 준비 중...", "어려움": "{year}년 제 {quarter}사분기 국정 현안 브리핑 준비 중..."} ,
+ "status_waiting_report": {"쉬움": "다음 계절 보고서 기다리는 중...", "보통": "다음 분기 보고를 기다리고 있습니다.", "어려움": "차기 분기 보고 대기 중..."} ,
+ "status_action_limit_reached": {"쉬움": "이번 계절({quarter})에 할 큰 결정 다 했어요. 다음 계절로 넘어가요.", "보통": "이번 분기({quarter}Q) 주요 활동을 완료했습니다. 다음 분기로 넘어가세요.", "어려움": "현 분기({quarter}Q) 주요 의사결정 한도를 소진했습니다. 차기 분기로 진행하십시오."},
+ # 사이드바 키
+ "sidebar_title": {"쉬움": "메뉴", "보통": "사이드 메뉴", "어려움": "부가 기능 메뉴"},
+ "sidebar_glossary_title": {"쉬움": "🏛️ 어려운 말 사전", "보통": "🏛️ 정부 용어 사전", "어려움": "🏛️ 주요 정부 용어 해설"},
+ # 기타 UI 텍스트
+ "error_invalid_action": {"쉬움": "잘못 골랐어요!", "보통": "잘못된 행동 선택입니다.", "어려움": "유효하지 않은 의사결정입니다."},
+ "error_event_generation_failed": {"쉬움": "보고서 만드는데 실패했어요 ㅠㅠ", "보통": "분기 보고 생성에 실패했습니다.", "어려움": "분기 현안 브리핑 생성 중 오류가 발생했습니다."},
+ "warning_briefing_loading": {"쉬움": "도움말 가져오는 중...", "보통": "브리핑 정보를 불러오는 중입니다.", "어려움": "참모진 권고안 로딩 중..."},
+ "caption_no_goals": {"쉬움": "정한 약속이 없어요.", "보통": "설정된 공약이 없습니다.", "어려움": "설정된 국정 과제가 없습니다."},
+ "caption_no_cabinet": {"쉬움": "장관님들 정보가 없어요.", "보통": "내각 정보가 없습니다.", "어려움": "행정 각료 정보가 없습니다."},
+ "caption_no_pending_bills": {"쉬움": "국회에서 지금 얘기 중인 법안이 없어요.", "보통": "현재 특별히 논의 중인 법안 없음", "어려움": "현재 계류 중인 주요 의안 없음"},
+ "caption_no_pending_cases": {"쉬움": "법원에서 지금 다루는 특별한 사건이 없어요.", "보통": "현재 특별한 사건 없음", "어려움": "현재 계류 중인 주요 사법 사건 없음"},
+ "label_pending_bills": {"쉬움": "국회에서 얘기 중인 법안들", "보통": "논의 중인 법안", "어려움": "계류 의안 목록"},
+ "label_pending_cases": {"쉬움": "법원에서 다루는 사건들", "보통": "진행 중인 주요 사건", "어려움": "계류 사법 사건 목록"},
+ "log_initial_approval": {"쉬움": "처음 인기도", "보통": "초기 국정 지지도", "어려움": "임기 개시 시점 지지율"},
+ "log_initial_goals": {"쉬움": "내가 하기로 한 약속들", "보통": "선택된 주요 공약", "어려움": "선정된 핵심 국정 과제"},
+ "log_action_result": {"쉬움": "결과:", "보통": "결과:", "어려움": "파급 ��과:"},
+ "log_minister_change": {"쉬움": "{minister} 장관 바꿈.", "보통": "{minister} 장관 교체.", "어려움": "{minister} 장관 경질."},
+ "log_minister_old_approval": {"쉬움": "전 장관 인기도", "보통": "구 장관 지지도", "어려움": "전임 장관 지지율"},
+ "log_minister_new_approval": {"쉬움": "새 장관 인기도", "보통": "신 장관 지지도", "어려움": "신임 장관 지지율"},
+ "log_bill_prep_start": {"쉬움": "'{bill_name}' 법 만들기 시작.", "보통": "'{bill_name}' 제출 준비 착수.", "어려움": "'{bill_name}' 입법 준비 개시."},
+ "log_yearly_capital_gain": {"쉬움": "연말 보너스 힘 점수", "보통": "연말 보너스 정치력", "어려움": "연말 정치적 자본 회복"},
+ "log_end_of_term": {"쉬움": "--- 대통령 임기 끝! ---", "보통": "--- 임기 종료 ---", "어려움": "--- 대통령 임기 만료 ---"},
+ "log_start_year": {"쉬움": "--- {year}년차 시작! ---", "보통": "--- {year}년차 시작 ---", "어려움": "--- 임기 {year}년차 개시 ---"},
+ "log_start_quarter": {"쉬움": "--- {year}년차 {quarter}번째 계절 시작! ---", "보통": "--- {year}년차 {quarter}분기 시작 ---", "어려움": "--- {year}년차 제 {quarter}사분기 개시 ---"},
+ "log_error_minister_not_found": {"쉬움": "오류: {minister} 부서 못 찾음.", "보통": "오류: {minister} 부처를 찾을 수 없습니다.", "어려움": "오류: {minister} 부처 정보 부재."},
+ "log_bill_pass_chance": {"쉬움": "'{bill_name}' 통과 가능성", "보통": "'{bill_name}' 통과 확률", "어려움": "'{bill_name}' 가결 확률"},
+ "log_judiciary_case_received": {"쉬움": "[{judiciary_name}] '{case_name}' 사건 들어옴.", "보통": "[{judiciary_name}] '{case_name}' 사건 접수됨.", "어려움": "[{judiciary_name}] '{case_name}' 사안 계류됨."},
+ "log_judiciary_strike_down_chance": {"쉬움": "'{case_name}' 문제 있다고 판결할 가능성", "보통": "'{case_name}' 위헌/위법 판결 확률", "어려움": "'{case_name}' 위헌/위법 결정 확률"},
+ "log_natural_fluctuation": {"쉬움": "연말 점수 변화", "보통": "연말 자연 변동", "어려움": "연말 지표 자연 변동성"},
}
+
# --- 어휘 조정 함수 (난이도별 텍스트 반환) ---
def get_text(key, level="보통"):
"""난이도에 따라 다른 텍스트 반환, 없으면 '보통' -> key 순으로 fallback"""
- # 1. 해당 난이도 텍스트 시도
level_texts = ALL_TEXTS.get(key)
- if level_texts and level in level_texts:
- return level_texts[level]
-
- # 2. '보통' 난이도 텍스트 시도 (fallback)
- if level_texts and "보통" in level_texts:
- # st.warning(f"텍스트 키 '{key}'에 대한 '{level}' 난이도 텍스트 없음. '보통' 사용.") # 디버깅용
- return level_texts["보통"]
-
- # 3. 키 자체 반환 (최후 fallback)
+ if level_texts:
+ if level in level_texts:
+ return level_texts[level]
+ elif "보통" in level_texts:
+ # st.warning(f"텍스트 키 '{key}'에 대한 '{level}' 난이도 텍스트 없음. '보통' 사용.") # 디버깅용
+ return level_texts["보통"]
# st.error(f"텍스트 키 '{key}' 찾을 수 없음!") # 디버깅용
- return key
+ return key # 키 자체를 반환 (최후 fallback)
# --- 정부 및 다른 기관 초기화 함수 ---
def initialize_government(difficulty):
@@ -353,7 +427,6 @@ def initialize_government(difficulty):
vocab_level = settings["vocab_level"]
get_text_func = lambda k: get_text(k, vocab_level) # 초기화 시점 어휘 수준 적용
- # 정책 목표 (텍스트 수준은 여기서 직접 조정하지 않음, 표시는 UI에서 get_text 사용)
policy_options = ["경제 성장률 5% 달성", "청년 실업률 5% 이하 달성", "부동산 시장 안정화", "미래 산업 육성", "외교 관계 개선", "국방력 강화", "복지 예산 10% 증액", "탄소 배출 감축"]
selected_goals = random.sample(policy_options, 3)
initial_goals = {goal: 0 for goal in selected_goals}
@@ -376,7 +449,7 @@ def initialize_government(difficulty):
},
'other_branches': {
'Congress': {
- 'name': get_text_func("term_congress_name"), # 난이도별 텍스트 적용
+ 'name': get_text_func("term_congress_name"),
'seats': {'Government': gov_party_seats, 'Opposition': opp_party_seats, 'Others': other_seats},
'stance': '사안별 협조 및 견제' if difficulty == "보통" else ("대체로 협조적" if difficulty == "쉬움" else "대체로 비판적/견제"),
'key_focus': random.sample(['민생 안정', '정부 견제', '개혁 입법', '지역 예산 확보'], 2),
@@ -384,7 +457,7 @@ def initialize_government(difficulty):
'relations_score': random.randint(*settings['initial_congress_relations_range'])
},
'Judiciary': {
- 'name': get_text_func("term_judiciary_name"), # 난이도별 텍스트 적용
+ 'name': get_text_func("term_judiciary_name"),
'status': '특별한 사건 없음',
'independence_level': random.randint(70, 95) if difficulty != "어려움" else random.randint(80, 100),
'pending_cases': [],
@@ -423,12 +496,12 @@ if not st.session_state.game_started:
st.session_state['game_quarter'] = 1
st.session_state['game_state'] = initialize_government(selected_difficulty)
# 초기 로그 메시지 추가 (난이도별 텍스트 사용)
- vocab_level = DIFFICULTY_LEVELS[selected_difficulty]["vocab_level"]
- get_text_func = lambda k: get_text(k, vocab_level)
+ vocab_level_init = DIFFICULTY_LEVELS[selected_difficulty]["vocab_level"] # 여기에서 vocab_level 정의
+ get_text_func_init = lambda k: get_text(k, vocab_level_init) # 초기화용 get_text 함수
initial_approval = st.session_state.game_state['presidency_status']['approval_rating']
- st.session_state.game_state['event_log'].append(f"초기 {get_text_func('term_approval')}: {initial_approval}%")
+ st.session_state.game_state['event_log'].append(f"{get_text_func_init('log_initial_approval')}: {initial_approval}%")
goals = st.session_state.game_state['presidency_status']['policy_goals'].keys()
- st.session_state.game_state['event_log'].append(f"선택된 {get_text_func('term_policy_goals')}: {', '.join(goals)}")
+ st.session_state.game_state['event_log'].append(f"{get_text_func_init('log_initial_goals')}: {', '.join(goals)}")
st.session_state['current_quarterly_event'] = None
st.session_state['event_briefing'] = None
@@ -439,17 +512,18 @@ if not st.session_state.game_started:
st.stop()
# --- 게임 진행 중 ---
+# 현재 게임 난이도 및 어휘 수준 가져오기
difficulty = st.session_state.difficulty
settings = DIFFICULTY_LEVELS[difficulty]
vocab_level = settings["vocab_level"]
-# 이제 모든 텍스트 표시에 get_text(key, vocab_level) 사용
-get_text_func = lambda key: get_text(key, vocab_level)
+get_text_func = lambda key: get_text(key, vocab_level) # 게임 전반에 사용할 get_text 함수
# --- 분기별 현안/기회 생성 함수 ---
def generate_quarterly_event(year, quarter, game_state, difficulty):
"""매 분기 발생하는 현안/기회 생성 (난이도 및 견제 요소 반영)"""
settings = DIFFICULTY_LEVELS[difficulty]
vocab_level = settings["vocab_level"]
+ get_text_for_event = lambda k: get_text(k, vocab_level) # 이벤트 생성 시 사용할 get_text
presidency_status = game_state['presidency_status']
congress = game_state['other_branches']['Congress']
judiciary = game_state['other_branches']['Judiciary']
@@ -463,7 +537,7 @@ def generate_quarterly_event(year, quarter, game_state, difficulty):
weights[2] += 5
chosen_type = random.choices(event_types, weights=weights, k=1)[0]
- event = {"title_key": "", "description_key": "", "type": chosen_type, "options": []} # 키로 저장
+ event = {"title_key": "", "description_key": "", "type": chosen_type, "options": [], "context": {}} # 키로 저장, context 추가
# 이벤트 내용 정의 (키 사용)
if chosen_type == "minor_issue":
@@ -490,29 +564,27 @@ def generate_quarterly_event(year, quarter, game_state, difficulty):
event["title_key"] = selected["title_key"]
event["description_key"] = selected["desc_key"]
event["options"] = [
- {"action_key": "action_accept_summit", "cost": math.ceil(2 * (1/settings['event_impact_modifier'])), "impact": {"approval": random.randint(0,2), "policy_goals": {"다른 나라와 친하게 지내기": random.randint(1,3)}}}, # 공약 이름은 일단 하드코딩 유지
+ {"action_key": "action_accept_summit", "cost": math.ceil(2 * (1/settings['event_impact_modifier'])), "impact": {"approval": random.randint(0,2), "policy_goals": {"외교 관계 개선": random.randint(1,3)}}}, # 공약 이름은 일단 하드코딩 유지
{"action_key": "action_support_hosting", "cost": math.ceil(3 * (1/settings['event_impact_modifier'])), "impact": {"stability": random.randint(1,2), "approval": random.randint(1,3)}},
- {"action_key": "action_review_tech_funding", "cost": math.ceil(2 * (1/settings['event_impact_modifier'])), "impact": {"policy_goals": {"미래 기술 키우기": random.randint(2,5)}}},
+ {"action_key": "action_review_tech_funding", "cost": math.ceil(2 * (1/settings['event_impact_modifier'])), "impact": {"policy_goals": {"미래 산업 육성": random.randint(2,5)}}},
]
- # ... (political_move, checks_balances_event, random 타입도 유사하게 title_key, description_key, action_key 사용하도록 수정) ...
- # 예시: political_move
elif chosen_type == "political_move":
- minister_name = random.choice(list(game_state['cabinet'].keys())) # 장관 이름 필요
+ minister_name = random.choice(list(game_state['cabinet'].keys())) if game_state['cabinet'] else "특정"
+ event["context"]["minister"] = minister_name # context에 장관 이름 저장
moves = [
- {"title_key": "event_title_opposition_criticism", "desc_key": "event_desc_opposition_criticism", "minister": minister_name},
+ {"title_key": "event_title_opposition_criticism", "desc_key": "event_desc_opposition_criticism"},
{"title_key": "event_title_party_dissent", "desc_key": "event_desc_party_dissent"},
{"title_key": "event_title_media_criticism", "desc_key": "event_desc_media_criticism"},
]
selected = random.choice(moves)
event["title_key"] = selected["title_key"]
event["description_key"] = selected["desc_key"]
- event["context"] = {"minister": selected.get("minister")} # 설명문에 필요한 정보 전달
+ # 옵션에도 context 전달 필요 시 추가
event["options"] = [
- {"action_key": "action_defend_minister", "cost": math.ceil(2 * (1/settings['event_impact_modifier'])), "impact": {"congress_relations": random.randint(-4,1)}, "context": {"minister": selected.get("minister")}},
+ {"action_key": "action_defend_minister", "cost": math.ceil(2 * (1/settings['event_impact_modifier'])), "impact": {"congress_relations": random.randint(-4,1)}, "context": {"minister": minister_name}},
{"action_key": "action_meet_party_members", "cost": math.ceil(1 * (1/settings['event_impact_modifier'])), "impact": {"political_capital": 1}},
{"action_key": "action_media_interview", "cost": math.ceil(1 * (1/settings['event_impact_modifier'])), "impact": {"approval": random.randint(-2,2)}},
]
- # 예시: checks_balances_event
elif chosen_type == "checks_balances_event":
cb_events = []
if congress['relations_score'] < 50 or difficulty == "어려움":
@@ -545,16 +617,16 @@ def generate_quarterly_event(year, quarter, game_state, difficulty):
# 최종 이벤트 객체 생성 (텍스트 변환)
final_event = {
- "title": get_text(event["title_key"], vocab_level).format(**event.get("context", {})),
- "description": get_text(event["description_key"], vocab_level).format(**event.get("context", {})),
+ "title": get_text_for_event(event["title_key"]).format(**event.get("context", {})),
+ "description": get_text_for_event(event["description_key"]).format(**event.get("context", {})),
"type": event["type"],
"options": []
}
- for opt in event["options"]:
+ for opt in event.get("options", []): # options가 없을 수도 있으므로 get 사용
final_event["options"].append({
- "action": get_text(opt["action_key"], vocab_level).format(**opt.get("context", {})),
+ "action": get_text_for_event(opt["action_key"]).format(**opt.get("context", {})),
"cost": opt["cost"],
- "impact": opt["impact"]
+ "impact": opt.get("impact", {}) # impact가 없을 수도 있음
})
log_message = f"{year}년차 {quarter}분기 현안: {final_event['title']}"
@@ -567,44 +639,43 @@ def provide_event_briefing(event, game_state, difficulty):
"""분기별 현안/기회에 대한 브리핑 생성 (난이도별 어휘 적용)"""
settings = DIFFICULTY_LEVELS[difficulty]
vocab_level = settings["vocab_level"]
- get_text_func = lambda key: get_text(key, vocab_level) # 어휘 함수 가져오기
+ get_text_for_briefing = lambda key: get_text(key, vocab_level) # 브리핑용 get_text
title = event['title'] # 이미 변환된 텍스트 사용
- briefing = f"**{get_text_func('dashboard_term').format(year=st.session_state['game_year'], quarter=st.session_state['game_quarter'])} 보고: {title}**\n\n"
+ briefing = f"**{get_text_for_briefing('dashboard_term').format(year=st.session_state['game_year'], quarter=st.session_state['game_quarter'])} 보고: {title}**\n\n"
briefing += f"{event['description']}\n\n" # 이미 변환된 텍스트 사용
- briefing += f"**{get_text_func('briefing_title')}**\n" # 브리핑 제목도 난이도별로
+ briefing += f"**{get_text_for_briefing('briefing_title')}**\n" # 브리핑 제목도 난이도별로
options_data = []
for i, opt in enumerate(event.get("options", [])):
cost = opt['cost']
action_text = opt['action'] # 이미 변환된 텍스트 사용
- # 버튼 라벨 형식은 난이도별로 다르게 적용
- briefing += f"{i+1}. **{action_text}** ({get_text_func('action_button_label').format(action='', cost=cost)})\n"
+ briefing += f"{i+1}. **{action_text}** ({get_text_for_briefing('action_button_label').format(action='', cost=cost)})\n"
effects = []
impact_modifier = settings['event_impact_modifier']
- # 예상 효과 텍스트도 난이도별로
- if 'approval' in opt['impact']:
- val = opt['impact']['approval']
+ impact = opt.get("impact", {}) # impact가 없을 수도 있음
+
+ if 'approval' in impact:
+ val = impact['approval']
adjusted_val = math.ceil(val / impact_modifier) if val < 0 else math.floor(val * impact_modifier)
- effects.append(get_text_func('action_impact_approval').format(change=adjusted_val))
- if 'stability' in opt['impact']:
- val = opt['impact']['stability']
+ effects.append(get_text_for_briefing('action_impact_approval').format(change=adjusted_val))
+ if 'stability' in impact:
+ val = impact['stability']
adjusted_val = math.ceil(val / impact_modifier) if val < 0 else math.floor(val * impact_modifier)
- effects.append(get_text_func('action_impact_stability').format(change=adjusted_val))
- if 'congress_relations' in opt['impact']:
- val = opt['impact']['congress_relations']
+ effects.append(get_text_for_briefing('action_impact_stability').format(change=adjusted_val))
+ if 'congress_relations' in impact:
+ val = impact['congress_relations']
adjusted_val = math.ceil(val / impact_modifier) if val < 0 else math.floor(val * impact_modifier)
- effects.append(get_text_func('action_impact_congress').format(change=adjusted_val))
- if 'policy_goals' in opt['impact']:
- for goal, prog in opt['impact']['policy_goals'].items():
+ effects.append(get_text_for_briefing('action_impact_congress').format(change=adjusted_val))
+ if 'policy_goals' in impact:
+ for goal, prog in impact['policy_goals'].items():
if goal in game_state['presidency_status']['policy_goals']:
val = prog
adjusted_val = math.ceil(val / impact_modifier) if val < 0 else math.floor(val * impact_modifier)
- # 공약 이름은 일단 그대로 두고, 설명 텍스트만 난이도별로
- effects.append(get_text_func('action_impact_goal').format(goal=goal, prog=adjusted_val))
+ effects.append(get_text_for_briefing('action_impact_goal').format(goal=goal, prog=adjusted_val))
- if effects: briefing += f" - *예상 결과:* {', '.join(effects)}\n" # '예상 결과' 텍스트도 키로 관리 가능
+ if effects: briefing += f" - *예상 결과:* {', '.join(effects)}\n"
options_data.append(opt)
return {"text": briefing, "options": options_data}
@@ -615,11 +686,11 @@ def execute_presidential_action(action_index, briefing_data, game_state, difficu
settings = DIFFICULTY_LEVELS[difficulty]
impact_modifier = settings['event_impact_modifier']
vocab_level = settings["vocab_level"]
- get_text_func = lambda key: get_text(key, vocab_level)
+ get_text_for_exec = lambda key: get_text(key, vocab_level) # 실행 시 사용할 get_text
options = briefing_data.get("options", [])
if not (0 <= action_index < len(options)):
- st.error("잘못된 행동 선택입니다.") # 이 메시지도 get_text 사용 가능
+ st.error(get_text_for_exec("error_invalid_action"))
return False
selected_action = options[action_index]
@@ -628,18 +699,17 @@ def execute_presidential_action(action_index, briefing_data, game_state, difficu
impact = selected_action.get('impact', {})
presidency_status = game_state['presidency_status']
other_branches = game_state['other_branches']
- cabinet = game_state['cabinet']
+ cabinet = game_state.get('cabinet', {}) # cabinet이 없을 경우 대비
if presidency_status['political_capital'] < cost:
- st.warning(get_text_func('action_cost_warning') + f" (필요: {cost}, 보유: {presidency_status['political_capital']})")
+ st.warning(get_text_for_exec('action_cost_warning') + f" (필요: {cost}, 보유: {presidency_status['political_capital']})")
return False
presidency_status['political_capital'] -= cost
- log_message = f" - 대통령 지시({st.session_state.game_quarter}Q): '{action_name}' 수행 ({get_text_func('term_political_capital')} {cost} 소모)" # 로그 메시지도 난이도별 용어 사용
+ log_message = f" - 대통령 지시({st.session_state.game_quarter}Q): '{action_name}' 수행 ({get_text_for_exec('term_political_capital')} {cost} 소모)"
game_state['event_log'].append(log_message)
- st.success(get_text_func('action_success_message').format(action=action_name))
+ st.success(get_text_for_exec('action_success_message').format(action=action_name))
- # 결과 반영 (기존 로직 유지, 로그 메시지에서 get_text 사용 고려)
approval_change_log = 0
stability_change_log = 0
congress_change_log = 0
@@ -660,12 +730,11 @@ def execute_presidential_action(action_index, briefing_data, game_state, difficu
other_branches['Congress']['relations_score'] += adjusted_change
congress_change_log = adjusted_change
- # 로그 통합 출력
log_parts = []
- if approval_change_log != 0: log_parts.append(f"{get_text_func('term_approval')} {approval_change_log:+}%p")
- if stability_change_log != 0: log_parts.append(f"{get_text_func('term_stability')} {stability_change_log:+}%p")
- if congress_change_log != 0: log_parts.append(f"{get_text_func('term_congress_relations')} {congress_change_log:+}%p")
- if log_parts: game_state['event_log'].append(f" - 결과: {', '.join(log_parts)} 변동.")
+ if approval_change_log != 0: log_parts.append(f"{get_text_for_exec('term_approval')} {approval_change_log:+}%p")
+ if stability_change_log != 0: log_parts.append(f"{get_text_for_exec('term_stability')} {stability_change_log:+}%p")
+ if congress_change_log != 0: log_parts.append(f"{get_text_for_exec('term_congress_relations')} {congress_change_log:+}%p")
+ if log_parts: game_state['event_log'].append(f" - {get_text_for_exec('log_action_result')} {', '.join(log_parts)} 변동.")
if 'policy_goals' in impact:
for goal, progress in impact['policy_goals'].items():
@@ -676,11 +745,16 @@ def execute_presidential_action(action_index, briefing_data, game_state, difficu
new_progress = min(100, current_progress + adjusted_change)
presidency_status['policy_goals'][goal] = new_progress
if new_progress > current_progress:
- game_state['event_log'].append(f" - {get_text_func('term_policy_goals')} '{goal}' {adjusted_change}%p 상승 (현재 {new_progress}%)")
+ game_state['event_log'].append(f" - {get_text_for_exec('term_policy_goals')} '{goal}' {adjusted_change}%p 상승 (현재 {new_progress}%)")
+
+ # 장관 교체 로직 수정: 키를 기반으로 비교
+ minister_replace_action_key = "action_replace_minister"
+ minister_replace_action_text_template = get_text(minister_replace_action_key, vocab_level)
+ # action_name이 "어떤장관 장관 교체" 형태인지 확인
+ if minister_replace_action_text_template.startswith('{minister}') and \
+ minister_replace_action_text_template.endswith(action_name.split(' ')[-1]): # "장관 바꾸기", "장관 교체", "장관 경질" 등 끝부분 일치 확인
+ minister_to_replace = action_name.replace(minister_replace_action_text_template.split(' ')[-1], '').strip() # 끝부분 제거하고 이름 추출
- # 장관 교체 등 다른 로직은 기존 유지 (필요시 로그 메시지에 get_text 적용)
- if "장관 교체" in action_name: # action_name은 이미 get_text 처리됨
- minister_to_replace = action_name.split(" ")[0]
if minister_to_replace in cabinet:
old_approval = cabinet[minister_to_replace]['minister_approval']
cabinet[minister_to_replace]['minister_approval'] = random.randint(40, 70)
@@ -689,24 +763,28 @@ def execute_presidential_action(action_index, briefing_data, game_state, difficu
congress_change = random.randint(-6, 1) if difficulty == "어려움" else (random.randint(-3, 4) if difficulty == "쉬움" else random.randint(-5, 2))
presidency_status['approval_rating'] += approval_change
other_branches['Congress']['relations_score'] += congress_change
- game_state['event_log'].append(f" - {minister_to_replace} 장관 교체. (구 지지도: {old_approval}%, 신 지지도: {cabinet[minister_to_replace]['minister_approval']}%)")
- if approval_change != 0: game_state['event_log'].append(f" - {get_text_func('term_approval')} {approval_change:+} 변동.")
- if congress_change != 0: game_state['event_log'].append(f" - {get_text_func('term_congress_relations')} {congress_change:+} 변동.")
- else:
- game_state['event_log'].append(f" - 오류: {minister_to_replace} 부처를 찾을 수 없습니다.")
-
- if "법률안 국회 제출 준비" in action_name:
- bill_name = f"{st.session_state['game_year']}년-{action_name.split(' ')[0]}-법안"
+ game_state['event_log'].append(f" - {get_text_for_exec('log_minister_change').format(minister=minister_to_replace)} ({get_text_for_exec('log_minister_old_approval')}: {old_approval}%, {get_text_for_exec('log_minister_new_approval')}: {cabinet[minister_to_replace]['minister_approval']}%)")
+ if approval_change != 0: game_state['event_log'].append(f" - {get_text_for_exec('term_approval')} {approval_change:+} 변동.")
+ if congress_change != 0: game_state['event_log'].append(f" - {get_text_for_exec('term_congress_relations')} {congress_change:+} 변동.")
+ elif minister_to_replace: # 이름이 추출되었는데 cabinet에 없는 경우
+ game_state['event_log'].append(get_text_for_exec('log_error_minister_not_found').format(minister=minister_to_replace))
+ # 이름 추출 실패 시 (예: action_name 형식이 예상과 다를 때) 별도 처리 없음
+
+ # 법안 제출 준비 로직 수정: 키를 기반으로 비교
+ bill_prep_action_key = "action_prepare_bill"
+ if action_name == get_text(bill_prep_action_key, vocab_level):
+ bill_name = f"{st.session_state['game_year']}년-{random.choice(['경제','사회','환경','외교'])}-법안" # 예시 이름
game_state['pending_legislation'] = game_state.get('pending_legislation', [])
game_state['pending_legislation'].append({"name": bill_name, "status": "준비중", "goal_related": random.choice(list(presidency_status['policy_goals'].keys())) if presidency_status['policy_goals'] else None})
- game_state['event_log'].append(f" - '{bill_name}' 제출 준비 착수.")
+ game_state['event_log'].append(f" - {get_text_for_exec('log_bill_prep_start').format(bill_name=bill_name)}")
# 지표 범위 유지
presidency_status['approval_rating'] = max(0, min(100, presidency_status['approval_rating']))
presidency_status['stability'] = max(0, min(100, presidency_status['stability']))
other_branches['Congress']['relations_score'] = max(0, min(100, other_branches['Congress']['relations_score']))
- for goal in presidency_status['policy_goals']:
- presidency_status['policy_goals'][goal] = max(0, min(100, presidency_status['policy_goals'][goal]))
+ if presidency_status.get('policy_goals'): # policy_goals가 없을 경우 대비
+ for goal in presidency_status['policy_goals']:
+ presidency_status['policy_goals'][goal] = max(0, min(100, presidency_status['policy_goals'][goal]))
st.session_state['actions_taken_this_quarter'] += 1
return True
@@ -716,14 +794,14 @@ def simulate_checks_and_balances(game_state, difficulty):
"""(연말 실행) 국회와 사법부 반응 시뮬레이션 (난이도 적용 및 텍스트 사용)"""
settings = DIFFICULTY_LEVELS[difficulty]
vocab_level = settings["vocab_level"]
- get_text_func = lambda key: get_text(key, vocab_level)
+ get_text_for_sim = lambda key: get_text(key, vocab_level) # 시뮬레이션용 get_text
presidency_status = game_state['presidency_status']
congress = game_state['other_branches']['Congress']
judiciary = game_state['other_branches']['Judiciary']
log = game_state['event_log']
year = st.session_state['game_year']
- log.append(f"--- {get_text_func('checks_balances_title').format(year=year)} ---")
+ log.append(f"--- {get_text_for_sim('checks_balances_title').format(year=year)} ---")
# 1. 국회 시뮬레이션
if 'pending_legislation' in game_state:
@@ -731,14 +809,14 @@ def simulate_checks_and_balances(game_state, difficulty):
if bill_to_submit['status'] == '준비중':
bill_to_submit['status'] = '제출됨'
congress['pending_bills'].append(bill_to_submit)
- log.append(f" - {get_text_func('checks_balances_bill_submitted').format(bill_name=bill_to_submit['name'])}")
+ log.append(f" - {get_text_for_sim('checks_balances_bill_submitted').format(bill_name=bill_to_submit['name'])}")
game_state['pending_legislation'] = []
processed_bills_indices = []
bills_passed_this_year = 0
bills_rejected_this_year = 0
- for i, bill in enumerate(congress['pending_bills']):
+ for i, bill in enumerate(congress.get('pending_bills', [])): # pending_bills 없을 경우 대비
if bill.get('status') == '제출됨':
base_chance = 0.4
relation_bonus = (congress['relations_score'] - 50) * 0.007
@@ -749,44 +827,43 @@ def simulate_checks_and_balances(game_state, difficulty):
pass_chance = base_chance + relation_bonus + approval_bonus + minority_penalty + difficulty_modifier
pass_chance = max(0.05, min(0.95, pass_chance))
- # 로그에 확률 표시 (텍스트는 보통 수준 유지)
- log.append(f" - '{bill['name']}' 통과 확률: {pass_chance:.1%} (관계:{relation_bonus:.1%}, 지지도:{approval_bonus:.1%}, 여소야대:{minority_penalty:.1%}, 난이도:{difficulty_modifier:.1%})")
+ log.append(f" - {get_text_for_sim('log_bill_pass_chance').format(bill_name=bill['name'])}: {pass_chance:.1%} (관계:{relation_bonus:.1%}, 지지도:{approval_bonus:.1%}, 여소야대:{minority_penalty:.1%}, 난이도:{difficulty_modifier:.1%})")
if random.random() < pass_chance:
bill['status'] = '통과'
- log.append(f" - {get_text_func('checks_balances_bill_passed').format(bill_name=bill['name'])}")
+ log.append(f" - {get_text_for_sim('checks_balances_bill_passed').format(bill_name=bill['name'])}")
bills_passed_this_year += 1
approval_gain = math.floor(random.randint(2, 5) * (1 + settings['checks_balances_leniency']))
relation_gain = math.floor(random.randint(3, 7) * (1 + settings['checks_balances_leniency']))
presidency_status['approval_rating'] += approval_gain
congress['relations_score'] = min(100, congress['relations_score'] + relation_gain)
- if approval_gain > 0: log.append(f" - {get_text_func('term_approval')} {approval_gain:+}%p 상승.")
- if relation_gain > 0: log.append(f" - {get_text_func('term_congress_relations')} {relation_gain:+}%p 상승.")
- if bill.get('goal_related') and bill['goal_related'] in presidency_status['policy_goals']:
+ if approval_gain > 0: log.append(f" - {get_text_for_sim('term_approval')} {approval_gain:+}%p 상승.")
+ if relation_gain > 0: log.append(f" - {get_text_for_sim('term_congress_relations')} {relation_gain:+}%p 상승.")
+ if bill.get('goal_related') and bill['goal_related'] in presidency_status.get('policy_goals', {}): # policy_goals 없을 경우 대비
goal_to_update = bill['goal_related']
progress = random.randint(10, 25)
adjusted_progress = math.floor(progress * (1 + settings['checks_balances_leniency'] * 0.5))
current_prog = presidency_status['policy_goals'][goal_to_update]
new_prog = min(100, current_prog + adjusted_progress)
presidency_status['policy_goals'][goal_to_update] = new_prog
- if new_prog > current_prog: log.append(f" - {get_text_func('term_policy_goals')} '{goal_to_update}' {adjusted_progress}%p 상승 (현재 {new_prog}%)")
+ if new_prog > current_prog: log.append(f" - {get_text_for_sim('term_policy_goals')} '{goal_to_update}' {adjusted_progress}%p 상승 (현재 {new_prog}%)")
else:
bill['status'] = '부결'
- log.append(f" - {get_text_func('checks_balances_bill_failed').format(bill_name=bill['name'])}")
+ log.append(f" - {get_text_for_sim('checks_balances_bill_failed').format(bill_name=bill['name'])}")
bills_rejected_this_year += 1
approval_loss = math.ceil(random.randint(2, 4) * (1 - settings['checks_balances_leniency']))
relation_loss = math.ceil(random.randint(2, 5) * (1 - settings['checks_balances_leniency']))
presidency_status['approval_rating'] -= approval_loss
congress['relations_score'] = max(0, congress['relations_score'] - relation_loss)
- if approval_loss > 0: log.append(f" - {get_text_func('term_approval')} {-approval_loss}%p 하락.")
- if relation_loss > 0: log.append(f" - {get_text_func('term_congress_relations')} {-relation_loss}%p 하락.")
- if bill.get('goal_related') and bill['goal_related'] in presidency_status['policy_goals'] and random.random() < 0.2:
+ if approval_loss > 0: log.append(f" - {get_text_for_sim('term_approval')} {-approval_loss}%p 하락.")
+ if relation_loss > 0: log.append(f" - {get_text_for_sim('term_congress_relations')} {-relation_loss}%p 하락.")
+ if bill.get('goal_related') and bill['goal_related'] in presidency_status.get('policy_goals', {}) and random.random() < 0.2:
goal_to_update = bill['goal_related']
setback = random.randint(1, 5)
current_prog = presidency_status['policy_goals'][goal_to_update]
new_prog = max(0, current_prog - setback)
presidency_status['policy_goals'][goal_to_update] = new_prog
- if new_prog < current_prog: log.append(f" - {get_text_func('term_policy_goals')} '{goal_to_update}' {-setback}%p 후퇴 (현재 {new_prog}%)")
+ if new_prog < current_prog: log.append(f" - {get_text_for_sim('term_policy_goals')} '{goal_to_update}' {-setback}%p 후퇴 (현재 {new_prog}%)")
processed_bills_indices.append(i)
@@ -794,53 +871,54 @@ def simulate_checks_and_balances(game_state, difficulty):
if congress['relations_score'] < 35: investigation_chance += 0.15
if difficulty == "어려움": investigation_chance += 0.10
if random.random() < investigation_chance:
- log.append(f" - {get_text_func('checks_balances_investigation')}")
+ log.append(f" - {get_text_for_sim('checks_balances_investigation')}")
stability_loss = math.ceil(random.randint(5, 10) * (1 - settings['checks_balances_leniency']))
relation_loss = math.ceil(random.randint(7, 14) * (1 - settings['checks_balances_leniency']))
presidency_status['stability'] -= stability_loss
congress['relations_score'] = max(0, congress['relations_score'] - relation_loss)
- log.append(f" - {get_text_func('term_stability')} {-stability_loss}%p 하락, {get_text_func('term_congress_relations')} {-relation_loss}%p 하락.")
+ log.append(f" - {get_text_for_sim('term_stability')} {-stability_loss}%p 하락, {get_text_for_sim('term_congress_relations')} {-relation_loss}%p 하락.")
# 2. 사법부 시뮬레이션
ruled_cases_indices = []
if random.random() < (0.1 + (0.1 if difficulty == '어려움' else 0)):
new_case_name = f"{year}년-{random.choice(['정책','인사','법률'])}-관련소송"
+ judiciary['pending_cases'] = judiciary.get('pending_cases', []) # 없을 경우 초기화
judiciary['pending_cases'].append({"name": new_case_name, "status": "접수됨"})
- log.append(f" - [{get_text_func('term_judiciary_name')}] '{new_case_name}' 사건 접수됨.") # 기관명도 난이도별로
+ log.append(f" - {get_text_for_sim('log_judiciary_case_received').format(judiciary_name=judiciary['name'], case_name=new_case_name)}")
judiciary['status'] = "주요 사건 심리 중"
- for i, case in enumerate(judiciary['pending_cases']):
+ for i, case in enumerate(judiciary.get('pending_cases', [])): # pending_cases 없을 경우 대비
if case.get('status') == '접수됨' or case.get('status') == '심리중':
- independence_factor = (judiciary['independence_level'] - 75) * 0.008
+ independence_factor = (judiciary.get('independence_level', 80) - 75) * 0.008 # 없을 경우 기본값
difficulty_factor = settings['checks_balances_leniency'] * -1
strike_down_chance = 0.3 + independence_factor + difficulty_factor
strike_down_chance = max(0.05, min(0.95, strike_down_chance))
- log.append(f" - '{case['name']}' 위헌/위법 판결 확률: {strike_down_chance:.1%} (독립성:{independence_factor:.1%}, 난이도:{difficulty_factor:.1%})")
+ log.append(f" - {get_text_for_sim('log_judiciary_strike_down_chance').format(case_name=case['name'])}: {strike_down_chance:.1%} (독립성:{independence_factor:.1%}, 난이도:{difficulty_factor:.1%})")
if random.random() < strike_down_chance:
- result_text = get_text_func('checks_balances_judiciary_strike_down')
- case['status'] = f'판결완료: {result_text}' # 상태는 간단히 유지
- log.append(f" - {get_text_func('checks_balances_judiciary_ruling').format(case_name=case['name'], result=result_text)}")
+ result_text = get_text_for_sim('checks_balances_judiciary_strike_down')
+ case['status'] = f'판결완료: {result_text}'
+ log.append(f" - {get_text_for_sim('checks_balances_judiciary_ruling').format(case_name=case['name'], result=result_text)}")
approval_loss = math.ceil(random.randint(5, 10) * (1 - settings['checks_balances_leniency']))
stability_loss = math.ceil(random.randint(4, 8) * (1 - settings['checks_balances_leniency']))
presidency_status['approval_rating'] -= approval_loss
presidency_status['stability'] -= stability_loss
- log.append(f" - {get_text_func('term_approval')} {-approval_loss}%p 하락, {get_text_func('term_stability')} {-stability_loss}%p 하락.")
+ log.append(f" - {get_text_for_sim('term_approval')} {-approval_loss}%p 하락, {get_text_for_sim('term_stability')} {-stability_loss}%p 하락.")
else:
- result_text = get_text_func('checks_balances_judiciary_uphold')
+ result_text = get_text_for_sim('checks_balances_judiciary_uphold')
case['status'] = f'판결완료: {result_text}'
- log.append(f" - {get_text_func('checks_balances_judiciary_ruling').format(case_name=case['name'], result=result_text)}")
+ log.append(f" - {get_text_for_sim('checks_balances_judiciary_ruling').format(case_name=case['name'], result=result_text)}")
approval_gain = math.floor(random.randint(0, 2) * (1 + settings['checks_balances_leniency']))
stability_gain = math.floor(random.randint(0, 3) * (1 + settings['checks_balances_leniency']))
presidency_status['approval_rating'] += approval_gain
presidency_status['stability'] += stability_gain
- if approval_gain > 0: log.append(f" - {get_text_func('term_approval')} {approval_gain:+}%p 상승.")
- if stability_gain > 0: log.append(f" - {get_text_func('term_stability')} {stability_gain:+}%p 상승.")
+ if approval_gain > 0: log.append(f" - {get_text_for_sim('term_approval')} {approval_gain:+}%p 상승.")
+ if stability_gain > 0: log.append(f" - {get_text_for_sim('term_stability')} {stability_gain:+}%p 상승.")
ruled_cases_indices.append(i)
- has_pending = any(c.get('status') == '접수됨' or c.get('status') == '심리중' for c in judiciary['pending_cases'])
+ has_pending = any(c.get('status') == '접수됨' or c.get('status') == '심리중' for c in judiciary.get('pending_cases', []))
if not has_pending: judiciary['status'] = "특별한 사건 없음"
# 3. 연말 최종 상태 업데이트
@@ -848,91 +926,85 @@ def simulate_checks_and_balances(game_state, difficulty):
stability_fluctuation = random.randint(-5, 2) if difficulty == "어려움" else (random.randint(-2, 4) if difficulty == "쉬움" else random.randint(-4, 2))
presidency_status['approval_rating'] += approval_fluctuation
presidency_status['stability'] += stability_fluctuation
- log.append(f" - 연말 자연 변동: {get_text_func('term_approval')} {approval_fluctuation:+}%p, {get_text_func('term_stability')} {stability_fluctuation:+}%p")
+ log.append(f" - {get_text_for_sim('log_natural_fluctuation')}: {get_text_for_sim('term_approval')} {approval_fluctuation:+}%p, {get_text_for_sim('term_stability')} {stability_fluctuation:+}%p")
presidency_status['approval_rating'] = max(0, min(100, presidency_status['approval_rating']))
presidency_status['stability'] = max(0, min(100, presidency_status['stability']))
congress['relations_score'] = max(0, min(100, congress['relations_score']))
- log.append(f"--- {get_text_func('checks_balances_summary').format(year=year, passed=bills_passed_this_year, failed=bills_rejected_this_year)} ---")
+ log.append(f"--- {get_text_for_sim('checks_balances_summary').format(year=year, passed=bills_passed_this_year, failed=bills_rejected_this_year)} ---")
# --- UI 표시 함수들 ---
def display_presidency_dashboard(game_state, difficulty):
vocab_level = DIFFICULTY_LEVELS[difficulty]["vocab_level"]
- get_text_func = lambda key: get_text(key, vocab_level)
+ get_text_for_ui = lambda key: get_text(key, vocab_level) # UI용 get_text
status = game_state['presidency_status']
- st.metric(get_text_func("term_approval"), f"{status['approval_rating']}%")
- st.metric(get_text_func("term_political_capital"), f"{status['political_capital']} P")
- st.metric(get_text_func("term_stability"), f"{status['stability']} / 100")
- st.metric(get_text_func("term_congress_relations"), f"{game_state['other_branches']['Congress']['relations_score']} / 100")
+ st.metric(get_text_for_ui("term_approval"), f"{status['approval_rating']}%")
+ st.metric(get_text_for_ui("term_political_capital"), f"{status['political_capital']} P")
+ st.metric(get_text_for_ui("term_stability"), f"{status['stability']} / 100")
+ st.metric(get_text_for_ui("term_congress_relations"), f"{game_state['other_branches']['Congress']['relations_score']} / 100")
- st.subheader(get_text_func("term_policy_goals"))
- goals = status['policy_goals']
+ st.subheader(get_text_for_ui("term_policy_goals"))
+ goals = status.get('policy_goals', {}) # 없을 경우 대비
if not goals:
- st.caption("설정된 공약이 없습니다.") # 이 텍스트도 키로 관리 가능
+ st.caption(get_text_for_ui("caption_no_goals"))
return
cols = st.columns(len(goals))
i = 0
for goal, progress in goals.items():
with cols[i]:
st.progress(progress / 100)
- st.caption(f"{goal} ({progress}%)") # 공약 이름 자체는 난이도별 변경 어려움
+ st.caption(f"{goal} ({progress}%)")
i += 1
def display_other_branches_status(game_state, difficulty):
vocab_level = DIFFICULTY_LEVELS[difficulty]["vocab_level"]
- get_text_func = lambda key: get_text(key, vocab_level)
+ get_text_for_ui = lambda key: get_text(key, vocab_level)
congress = game_state['other_branches']['Congress']
judiciary = game_state['other_branches']['Judiciary']
- # 국회 정보 표시 (기관명은 이미 난이도별 적용됨)
- with st.expander(f"{congress['name']} ({get_text_func('term_congress_relations')}: {congress['relations_score']})", expanded=True):
- seats = congress['seats']
+ with st.expander(f"{congress['name']} ({get_text_for_ui('term_congress_relations')}: {congress.get('relations_score', 50)})", expanded=True): # 기본값 추가
+ seats = congress.get('seats', {'Government': 150, 'Opposition': 130, 'Others': 20}) # 기본값 추가
st.markdown(f"**의석:** 여당 {seats['Government']} / 야당 {seats['Opposition']} / 기타 {seats['Others']} (총 {sum(seats.values())})")
if seats['Government'] < sum(seats.values()) / 2:
- st.markdown("[주의] 여소야대 상황입니다. 법안 통과가 어려울 수 있습니다.", unsafe_allow_html=True) # 이 경고도 키로 관리 가능
- st.markdown(f"**주요 관심사:** {', '.join(congress['key_focus'])}")
- st.markdown(f"**현재 태도:** {congress['stance']}") # 태도 텍스트도 키로 관리 가능
- pending_bills_str = "\n".join([f"- {b['name']} ({b.get('status', '알수없음')})" for b in congress['pending_bills'] if b.get('status') != '통과' and b.get('status') != '부결'])
- if not pending_bills_str: pending_bills_str = "현재 특별히 논의 중인 법안 없음" # 키로 관리 가능
- st.text_area("논의 중인 법안", pending_bills_str, height=100, disabled=True, key="pending_bills_display") # 라벨 키로 관리 가능
-
- # 사법부 정보 표시 (기관명은 이미 난이도별 적용됨)
- with st.expander(f"{judiciary['name']} (독립성: {judiciary['independence_level']})"): # '독립성' 키로 관리 가능
- st.markdown(f"**현재 상태:** {judiciary['status']}") # 상태 텍스트 키로 관리 가능
- pending_cases_str = "\n".join([f"- {c['name']} ({c.get('status', '심리중')})" for c in judiciary['pending_cases'] if '판결완료' not in c.get('status', '')])
- if not pending_cases_str: pending_cases_str = "현재 특별한 사건 없음" # 키로 관리 가능
- st.text_area("진행 중인 주요 사건", pending_cases_str, height=100, disabled=True, key="pending_cases_display") # 라벨 키로 관리 가능
+ st.markdown("[주의] 여소야대 상황입니다. 법안 통과가 어려울 수 있습니다.", unsafe_allow_html=True)
+ st.markdown(f"**주요 관심사:** {', '.join(congress.get('key_focus', ['민생 안정']))}") # 기본값 추가
+ st.markdown(f"**현재 태도:** {congress.get('stance', '중립')}") # 기본값 추가
+ pending_bills_str = "\n".join([f"- {b['name']} ({b.get('status', '알수없음')})" for b in congress.get('pending_bills', []) if b.get('status') != '통과' and b.get('status') != '부결'])
+ if not pending_bills_str: pending_bills_str = get_text_for_ui("caption_no_pending_bills")
+ st.text_area(get_text_for_ui("label_pending_bills"), pending_bills_str, height=100, disabled=True, key="pending_bills_display")
+
+ with st.expander(f"{judiciary['name']} (독립성: {judiciary.get('independence_level', 80)})", expanded=True): # 기본값 추가
+ st.markdown(f"**현재 상태:** {judiciary.get('status', '사건 없음')}") # 기본값 추가
+ pending_cases_str = "\n".join([f"- {c['name']} ({c.get('status', '심리중')})" for c in judiciary.get('pending_cases', []) if '판결완료' not in c.get('status', '')])
+ if not pending_cases_str: pending_cases_str = get_text_for_ui("caption_no_pending_cases")
+ st.text_area(get_text_for_ui("label_pending_cases"), pending_cases_str, height=100, disabled=True, key="pending_cases_display")
def display_cabinet_status(game_state, difficulty):
vocab_level = DIFFICULTY_LEVELS[difficulty]["vocab_level"]
- get_text_func = lambda key: get_text(key, vocab_level)
+ get_text_for_ui = lambda key: get_text(key, vocab_level)
cabinet = game_state.get('cabinet', {})
- with st.expander(get_text_func("cabinet_title")):
+ with st.expander(get_text_for_ui("cabinet_title")):
if not cabinet:
- st.caption("내각 정보가 없습니다.") # 키로 관리 가능
+ st.caption(get_text_for_ui("caption_no_cabinet"))
return
cols = st.columns(len(cabinet))
i = 0
for minister, data in cabinet.items():
with cols[i]:
- # 장관 이름 + '지지율' 텍스트 조합
- st.metric(f"{minister} 장관 {get_text_func('term_approval')}", f"{data['minister_approval']}%")
+ st.metric(f"{minister} 장관 {get_text_for_ui('term_approval')}", f"{data.get('minister_approval', 50)}%") # 기본값 추가
i += 1
def display_gov_terms_glossary(difficulty):
vocab_level = DIFFICULTY_LEVELS[difficulty]["vocab_level"]
- get_text_func = lambda key: get_text(key, vocab_level)
+ get_text_for_ui = lambda key: get_text(key, vocab_level)
- # ALL_TEXTS에서 glossary 관련 키만 가져오기
glossary_keys = [k for k in ALL_TEXTS if k.startswith('glossary_')]
- with st.sidebar.expander(get_text_func("sidebar_glossary_title"), expanded=False):
+ with st.sidebar.expander(get_text_for_ui("sidebar_glossary_title"), expanded=False):
for key in glossary_keys:
- # 난이도별 텍스트 가져오기
- term_definition = get_text_func(key)
- # 첫번째 ':' 기준으로 용어와 설명 분리 (만약 ':' 없으면 전체를 용어로)
+ 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 ""
@@ -941,44 +1013,58 @@ def display_gov_terms_glossary(difficulty):
# --- 메인 게임 루프 ---
def main():
- st.set_page_config(layout="wide")
+ # 페이지 설정은 스크립트 최상단으로 이동했으므로 여기서는 호출하지 않음
if not st.session_state.game_started:
- return # 시작 화면 처리
+ # 시작 화면 처리 루틴이 이 함수 위에 있으므로,
+ # game_started가 False이면 이 함수는 호출되지 않거나,
+ # 호출되더라도 바로 종료되어야 함.
+ # 만약을 위해 return 추가
+ return
- difficulty = st.session_state.difficulty
+ # 게임 진행 중 사용할 난이도 및 어휘 수준 로드
+ # st.session_state에 값이 없을 경우를 대비해 기본값 설정
+ difficulty = st.session_state.get('difficulty', '보통')
settings = DIFFICULTY_LEVELS[difficulty]
vocab_level = settings["vocab_level"]
- get_text_func = lambda key: get_text(key, vocab_level)
+ get_text_main = lambda key: get_text(key, vocab_level) # main 함수 내에서 사용할 get_text
+
st.title("👑 대통령의 균형추: 삼권분립 리더십 시뮬레이션")
st.caption(f"��이도: {difficulty}")
+ # game_state가 없을 경우 초기화 (오류 방지)
+ if 'game_state' not in st.session_state:
+ st.session_state.game_state = initialize_government(difficulty)
+ st.warning("게임 상태가 초기화되었습니다.") # 사용자에게 알림
+ st.rerun() # 초기화 후 다시 실행
+
game_state = st.session_state.game_state
# --- 게임 오버 처리 ---
if st.session_state.get('game_over', False):
st.balloons()
- st.header(get_text_func("game_over_title").format(years=MAX_YEARS))
- st.subheader(get_text_func("game_over_subtitle"))
- final_status = game_state['presidency_status']
+ st.header(get_text_main("game_over_title").format(years=MAX_YEARS))
+ st.subheader(get_text_main("game_over_subtitle"))
+ final_status = game_state.get('presidency_status', {}) # 없을 경우 대비
+ other_branches = game_state.get('other_branches', {})
+ congress_state = other_branches.get('Congress', {})
col1, col2, col3 = st.columns(3)
- # 최종 결과 메트릭 (용어 난이도별 적용)
- with col1: st.metric(get_text_func("term_approval"), f"{final_status['approval_rating']}%")
- with col2: st.metric(get_text_func("term_stability"), f"{final_status['stability']}")
- with col3: st.metric(get_text_func("term_congress_relations"), f"{game_state['other_branches']['Congress']['relations_score']}")
+ with col1: st.metric(get_text_main("term_approval"), f"{final_status.get('approval_rating', 'N/A')}%")
+ with col2: st.metric(get_text_main("term_stability"), f"{final_status.get('stability', 'N/A')}")
+ with col3: st.metric(get_text_main("term_congress_relations"), f"{congress_state.get('relations_score', 'N/A')}")
- st.write(get_text_func("term_policy_goals")) # 최종 공약 라벨
- goals = final_status['policy_goals']
+ st.write(get_text_main("term_policy_goals"))
+ goals = final_status.get('policy_goals', {})
if goals:
for goal, progress in goals.items():
st.progress(progress / 100, text=f"{goal} ({progress}%)")
else:
- st.caption("설정된 공약이 없습니다.")
+ st.caption(get_text_main("caption_no_goals"))
- st.subheader(get_text_func("term_event_log")) # 최종 로그 제목
- log_text = "\n".join(game_state['event_log'][::-1])
- st.text_area(get_text_func("term_event_log"), log_text, height=400, disabled=True, key="final_log")
- if st.button(get_text_func("button_restart")):
+ st.subheader(get_text_main("term_event_log"))
+ log_text = "\n".join(game_state.get('event_log', [])[::-1]) # 없을 경우 대비
+ st.text_area(get_text_main("term_event_log"), log_text, height=400, disabled=True, key="final_log")
+ if st.button(get_text_main("button_restart")):
keys_to_delete = [k for k in st.session_state.keys() if k != 'game_started']
for key in keys_to_delete: del st.session_state[key]
st.session_state.game_started = False
@@ -989,77 +1075,76 @@ def main():
col_dashboard, col_agenda, col_actions = st.columns([1.2, 1.8, 1.5])
with col_dashboard:
- st.header(get_text_func("dashboard_title"))
- st.markdown(f"**{get_text_func('dashboard_term').format(year=st.session_state['game_year'], quarter=st.session_state['game_quarter'])}**")
+ st.header(get_text_main("dashboard_title"))
+ st.markdown(f"**{get_text_main('dashboard_term').format(year=st.session_state.get('game_year', 1), quarter=st.session_state.get('game_quarter', 1))}**") # 기본값 추가
display_presidency_dashboard(game_state, difficulty)
st.divider()
- st.subheader(get_text_func("institutions_title"))
+ st.subheader(get_text_main("institutions_title"))
display_other_branches_status(game_state, difficulty)
st.divider()
display_cabinet_status(game_state, difficulty)
with col_agenda:
- st.header(get_text_func("agenda_title"))
+ st.header(get_text_main("agenda_title"))
- if st.session_state['current_quarterly_event'] is None:
- spinner_text = get_text('status_loading_report', vocab_level).format(year=st.session_state['game_year'], quarter=st.session_state['game_quarter']) # 로딩 메시지도 get_text 사용
+ if 'current_quarterly_event' not in st.session_state or st.session_state['current_quarterly_event'] is None:
+ spinner_text = get_text_main('status_loading_report').format(year=st.session_state.get('game_year', 1), quarter=st.session_state.get('game_quarter', 1))
with st.spinner(spinner_text):
time.sleep(0.5)
- # generate_quarterly_event 호출 시 난이도 전달
- event = generate_quarterly_event(st.session_state['game_year'], st.session_state['game_quarter'], game_state, difficulty)
+ event = generate_quarterly_event(st.session_state.get('game_year', 1), st.session_state.get('game_quarter', 1), game_state, difficulty)
if event:
st.session_state['current_quarterly_event'] = event
- # provide_event_briefing 호출 시 난이도 전달
st.session_state['event_briefing'] = provide_event_briefing(event, game_state, difficulty)
st.session_state['actions_taken_this_quarter'] = 0
st.rerun()
else:
- st.error("분기 보고 생성 실패") # 오류 메시지 키로 관리 가능
+ st.error(get_text_main("error_event_generation_failed"))
- if st.session_state['current_quarterly_event']:
+ if st.session_state.get('current_quarterly_event'): # get 사용
event_data = st.session_state['current_quarterly_event']
- # 이벤트 제목/설명은 이미 generate/provide 함수에서 난이도별 텍스트로 변환됨
- st.subheader(f"{get_text_func('agenda_event_title').split(':')[0]}: {event_data['title']}") # ':' 앞부분만 가져오기
- st.markdown(event_data['description'])
+ title_prefix = get_text_main('agenda_event_title').split(':')[0]
+ st.subheader(f"{title_prefix}: {event_data.get('title', '알 수 없는 현안')}") # get 사용
+ st.markdown(event_data.get('description', '')) # get 사용
st.divider()
- if st.session_state['event_briefing']:
- # 브리핑 제목은 briefing_data 안에 포함되지 않으므로 여기서 get_text 사용
- st.subheader(get_text_func("briefing_title"))
- st.markdown(st.session_state['event_briefing']['text'], unsafe_allow_html=True)
+ if st.session_state.get('event_briefing'): # get 사용
+ st.subheader(get_text_main("briefing_title"))
+ st.markdown(st.session_state['event_briefing'].get('text', ''), unsafe_allow_html=True) # get 사용
else:
- st.warning("브리핑 정보 로딩 중...") # 키로 관리 가능
- else:
- st.info(get_text('status_waiting_report', vocab_level)) # 대기 메시지 키로 관리 가능
+ st.warning(get_text_main("warning_briefing_loading"))
+ elif 'game_started' in st.session_state and st.session_state.game_started: # 게임 시작 후에만 표시
+ st.info(get_text_main("status_waiting_report"))
+
with col_actions:
- st.header(get_text_func("office_title"))
- st.markdown(get_text_func("office_available_capital").format(capital=game_state['presidency_status']['political_capital']))
- remaining_actions = QUARTERLY_ACTIONS_LIMIT - st.session_state['actions_taken_this_quarter']
- st.warning(get_text_func("office_action_limit").format(remaining=remaining_actions))
+ st.header(get_text_main("office_title"))
+ st.markdown(get_text_main("office_available_capital").format(capital=game_state.get('presidency_status', {}).get('political_capital', 0))) # 기본값 추가
+ remaining_actions = QUARTERLY_ACTIONS_LIMIT - st.session_state.get('actions_taken_this_quarter', 0) # 기본값 추가
+ st.warning(get_text_main("office_action_limit").format(remaining=remaining_actions))
- action_possible = (st.session_state['current_quarterly_event'] and
- st.session_state['event_briefing'] and
+ action_possible = (st.session_state.get('current_quarterly_event') and
+ st.session_state.get('event_briefing') and
remaining_actions > 0)
if action_possible:
- st.subheader(get_text_func("office_issue_actions"))
- options = st.session_state['event_briefing'].get("options", [])
+ st.subheader(get_text_main("office_issue_actions"))
+ options = st.session_state.get('event_briefing', {}).get("options", []) # 기본값 추가
for i, opt in enumerate(options):
- # 버튼 라벨은 briefing 생성 시 이미 난이도별 텍스트 적용됨
- button_label = get_text_func('action_button_label').format(action=opt['action'], cost=opt['cost'])
- button_key = f"action_{st.session_state['game_year']}_{st.session_state['game_quarter']}_{i}"
- is_disabled = (game_state['presidency_status']['political_capital'] < opt['cost'])
+ button_label = get_text_main('action_button_label').format(action=opt.get('action', '알 수 없는 행동'), cost=opt.get('cost', 0)) # 기본값 추가
+ button_key = f"action_{st.session_state.get('game_year', 1)}_{st.session_state.get('game_quarter', 1)}_{i}"
+ is_disabled = (game_state.get('presidency_status', {}).get('political_capital', 0) < opt.get('cost', 0))
if st.button(button_label, key=button_key, use_container_width=True, disabled=is_disabled):
- # execute_presidential_action 호출 시 난이도 전달
if execute_presidential_action(i, st.session_state['event_briefing'], game_state, difficulty):
st.rerun()
if remaining_actions > 0:
st.divider()
- st.subheader(get_text_func("office_standard_actions"))
- # 상시 행동 정의 (action_key 사용)
+ st.subheader(get_text_main("office_standard_actions"))
+ # 상시 행동 정의 시 cabinet 존재 여부 확인
+ cabinet_ministers = list(game_state.get('cabinet', {}).keys())
+ default_minister = "특정" if not cabinet_ministers else random.choice(cabinet_ministers)
+
standard_actions_defs = [
- {"action_key": "action_replace_minister", "cost_base": 4, "context": {"minister": random.choice(list(game_state['cabinet'].keys()))}},
+ {"action_key": "action_replace_minister", "cost_base": 4, "context": {"minister": default_minister}},
{"action_key": "action_prepare_bill", "cost_base": 3},
{"action_key": "action_meet_ruling_party", "cost_base": 2, "impact": {"congress_relations": random.randint(1,4)}},
{"action_key": "action_meet_opposition", "cost_base": 3},
@@ -1068,51 +1153,50 @@ def main():
]
for j, std_def in enumerate(standard_actions_defs):
cost = math.ceil(std_def['cost_base'] * (1/settings['event_impact_modifier']))
- action_text = get_text_func(std_def['action_key']).format(**std_def.get("context", {}))
- button_label = get_text_func('action_button_label').format(action=action_text, cost=cost)
- button_key = f"std_action_{st.session_state['game_year']}_{st.session_state['game_quarter']}_{j}"
- is_disabled = (game_state['presidency_status']['political_capital'] < cost)
- # 실행 위해 임시 briefing_data 생성
+ action_text = get_text_main(std_def['action_key']).format(**std_def.get("context", {}))
+ button_label = get_text_main('action_button_label').format(action=action_text, cost=cost)
+ button_key = f"std_action_{st.session_state.get('game_year', 1)}_{st.session_state.get('game_quarter', 1)}_{j}"
+ is_disabled = (game_state.get('presidency_status', {}).get('political_capital', 0) < cost)
temp_briefing_data = {"options": [{
- "action": action_text, # 이미 변환된 텍스트 전달
+ "action": action_text,
"cost": cost,
"impact": std_def.get("impact", {})
}]}
if st.button(button_label, key=button_key, use_container_width=True, disabled=is_disabled):
- # execute_presidential_action 호출 시 난이도 전달
if execute_presidential_action(0, temp_briefing_data, game_state, difficulty):
st.rerun()
- elif st.session_state['actions_taken_this_quarter'] >= QUARTERLY_ACTIONS_LIMIT and st.session_state['current_quarterly_event']:
- st.info(get_text('status_action_limit_reached', vocab_level).format(quarter=st.session_state.game_quarter))
- elif not st.session_state['current_quarterly_event']:
- st.info(get_text('status_waiting_report', vocab_level))
+ elif st.session_state.get('actions_taken_this_quarter', 0) >= QUARTERLY_ACTIONS_LIMIT and st.session_state.get('current_quarterly_event'):
+ st.info(get_text_main("status_action_limit_reached").format(quarter=st.session_state.get('game_quarter', 1)))
+ elif 'game_started' in st.session_state and st.session_state.game_started and not st.session_state.get('current_quarterly_event'): # 게임 시작 후 & 이벤트 없을 때
+ st.info(get_text_main("status_waiting_report"))
+
st.divider()
- if st.button(get_text_func("button_next_quarter"), use_container_width=True, key="next_quarter_button"):
- current_quarter = st.session_state['game_quarter']
- current_year = st.session_state['game_year']
+ if st.button(get_text_main("button_next_quarter"), use_container_width=True, key="next_quarter_button"):
+ current_quarter = st.session_state.get('game_quarter', 1)
+ current_year = st.session_state.get('game_year', 1)
if current_quarter == 4:
spinner_text = f"{current_year}년차 국정 결산 중..." # 키로 관리 가능
with st.spinner(spinner_text):
- # simulate_checks_and_balances 호출 시 난이도 전달
simulate_checks_and_balances(game_state, difficulty)
capital_gain = settings['yearly_gain']
- game_state['presidency_status']['political_capital'] += capital_gain
- # 연말 보너스 로그 (용어 난이도 적용)
- game_state['event_log'].append(f" - 연말 보너스 {get_text_func('term_political_capital')} {capital_gain}P 획득.")
+ game_state['presidency_status']['political_capital'] = game_state.get('presidency_status', {}).get('political_capital', 0) + capital_gain # 안전하게 접근
+ game_state['event_log'] = game_state.get('event_log', []) # 로그 없을 경우 초기화
+ game_state['event_log'].append(f" - {get_text_main('log_yearly_capital_gain')} {capital_gain}P 획득.")
time.sleep(1.5)
- st.session_state['game_year'] += 1
+ st.session_state['game_year'] = current_year + 1
st.session_state['game_quarter'] = 1
if st.session_state['game_year'] > MAX_YEARS:
st.session_state['game_over'] = True
- game_state['event_log'].append(f"--- {get_text_func('game_over_title').split('(')[0].strip()} ---") # 임기 종료 텍스트 사용
+ game_state['event_log'].append(get_text_main('log_end_of_term'))
else:
- game_state['event_log'].append(f"--- {st.session_state['game_year']}년차 시작 ---") # 키로 관리 가능
+ game_state['event_log'].append(get_text_main('log_start_year').format(year=st.session_state['game_year']))
else:
- st.session_state['game_quarter'] += 1
- game_state['event_log'].append(f"--- {get_text_func('dashboard_term').format(year=st.session_state['game_year'], quarter=st.session_state['game_quarter'])} 시작 ---") # 키로 관리 가능
+ st.session_state['game_quarter'] = current_quarter + 1
+ game_state['event_log'] = game_state.get('event_log', [])
+ game_state['event_log'].append(get_text_main('log_start_quarter').format(year=current_year, quarter=st.session_state['game_quarter']))
st.session_state['current_quarterly_event'] = None
st.session_state['event_briefing'] = None
@@ -1120,98 +1204,21 @@ def main():
st.rerun()
st.divider()
- st.subheader(get_text_func("term_event_log"))
- log_text = "\n".join(game_state['event_log'][::-1])
- st.text_area(get_text_func("term_event_log"), log_text, height=300, disabled=True, key="event_log_area_main")
+ st.subheader(get_text_main("term_event_log"))
+ log_text = "\n".join(game_state.get('event_log', [])[::-1])
+ st.text_area(get_text_main("term_event_log"), log_text, height=300, disabled=True, key="event_log_area_main")
with st.sidebar:
- st.header(get_text_func("sidebar_title"))
+ st.header(get_text_main("sidebar_title"))
display_gov_terms_glossary(difficulty)
st.divider()
st.markdown("---")
st.caption(f"현재 난이도: {difficulty}")
- if st.button(get_text_func("button_restart") + " (난이도 변경)"): # 버튼 텍스트 조합
+ if st.button(get_text_main("button_restart") + " (난이도 변경)"):
keys_to_delete = [k for k in st.session_state.keys() if k != 'game_started']
for key in keys_to_delete: del st.session_state[key]
st.session_state.game_started = False
st.rerun()
-# --- 추가 텍스트 키 정의 (generate_quarterly_event 등에서 사용) ---
-# 이 부분은 ALL_TEXTS 딕셔너리 안에 포함되어야 합니다.
-# 예시:
-"""
-ALL_TEXTS = {
- # ... 기존 키들 ...
-
- # generate_quarterly_event 에서 사용할 키
- "event_title_minor_disaster": { "쉬움": "작은 재난 발생", "보통": "소규모 재난 발생", "어려움": "국지적 자연재해 발생"},
- "event_desc_minor_disaster": { "쉬움": "비가 많이 오거나 불이 나서 동네 몇 군데가 피해를 입었어요. 빨리 도와줘야 해요.", "보통": "집중 호우 또는 산불 등으로 특정 지역에 피해가 발생했습니다. 신속한 지원이 필요합니다.", "어려움": "국지성 호우 또는 산불로 인해 일부 지역에서 물적 피해가 보고되었습니다. 긴급 구호 및 복구 계획 수립이 요구됩니다."},
- "action_visit_disaster_area": { "쉬움": "피해 지역 가서 위로하기", "보통": "피해 지역 현장 방문 및 지원 약속", "어려움": "피해 지역 순방 및 정부 차원 지원 공표"},
-
- "event_title_small_protest": { "쉬움": "사람들이 모여서 외치고 있어요", "보통": "소규모 시위 발생", "어려움": "제한적 규모의 집회 발생"},
- "event_desc_small_protest": { "쉬움": "어떤 문제 때문에 몇몇 사람들이 모여 목소리를 내고 있어요. 시끄럽지만 큰 문제는 아니에요.", "보통": "특정 현안에 대한 불만으로 일부 시민들이 소규모 집회를 열고 있습니다. 상황 관리가 필요합니다.", "어려움": "특정 정책 또는 사회 현안에 대한 이견 표출로 소규모 집회가 개최되었습니다. 확산 가능성 주시 요망."},
- "action_meet_protesters": { "쉬움": "시위대 이야기 들어보기", "보통": "시위대 대표 면담 추진", "어려움": "집회 주동자 대화 채널 구축 시도"},
-
- # ... (다른 이벤트 및 액션 키 정의) ...
-
- "action_replace_minister": {"쉬움": "{minister} 장관 바꾸기", "보통": "{minister} 장관 교체", "어려움": "{minister} 장관 경질"},
- "action_prepare_bill": {"쉬움": "새로운 법 만들기 준비", "보통": "법률안 국회 제출 준비", "어려움": "입법안 발의 준비 착수"},
- "action_meet_ruling_party": {"쉬움": "우리 편 의원들이랑 밥 먹기", "보통": "여당 지도부와 만찬 회동", "어려움": "집권여당 지도부와 정례 회동"},
- "action_meet_opposition": {"쉬움": "반대편 의원들 만나보기", "보통": "야당 지도부 만나기 (관계 개선 시도)", "어려움": "주요 야당 지도부와 협의 채널 구축"},
- "action_meet_biz_leaders": {"쉬움": "회사 사장님들 만나기", "보통": "주요 경제 단체 간담회", "어려움": "주요 경제계 인사 초청 간담회"},
- "action_respect_judiciary": {"쉬움": "법원 존중한다고 말하기", "보통": "사법부 존중 메시지 발표", "어려움": "사법부 독립성 존중 관련 대국민 메시지 발표"},
- "action_no_special_action": {"쉬움": "이번엔 그냥 넘어가기", "보통": "이번 분기 특별 조치 없음", "어려움": "현 분기 특이 조치 보류"},
-
- # ... (더 많은 키 추가) ...
-}
-"""
-
if __name__ == "__main__":
- # ALL_TEXTS 딕셔너리에 위에 주석 처리된 예시들을 실제로 추가해야 합니다.
- # 편의상 코드 실행을 위해 몇 개만 직접 추가합니다.
- ALL_TEXTS["event_title_minor_disaster"]= { "쉬움": "작은 재난 발생", "보통": "소규모 재난 발생", "어려움": "국지적 자연재해 발생"}
- ALL_TEXTS["event_desc_minor_disaster"]= { "쉬움": "비가 많이 오거나 불이 나서 동네 몇 군데가 피해를 입었어요. 빨리 도와줘야 해요.", "보통": "집중 호우 또는 산불 등으로 특정 지역에 피해가 발생했습니다. 신속한 지원이 필요합니다.", "어려움": "국지성 호우 또는 산불로 인해 일부 지역에서 물적 피해가 보고되었습니다. 긴급 구호 및 복구 계획 수립이 요구됩니다."}
- ALL_TEXTS["action_visit_disaster_area"]= { "쉬움": "피해 지역 가서 위로하기", "보통": "피해 지역 현장 방문 및 지원 약속", "어려움": "피해 지역 순방 및 정부 차원 지원 공표"}
- ALL_TEXTS["event_title_small_protest"] = { "쉬움": "사람들이 모여서 외치고 있어요", "보통": "소규모 시위 발생", "어려움": "제한적 규모의 집회 발생"}
- ALL_TEXTS["event_desc_small_protest"] = { "쉬움": "어떤 문제 때문에 몇몇 사람들이 모여 목소리를 내고 있어요. 시끄럽지만 큰 문제는 아니에요.", "보통": "특정 현안에 대한 불만으로 일부 시민들이 소규모 집회를 열고 있습니다. 상황 관리가 필요합니다.", "어려움": "특정 정책 또는 사회 현안에 대한 이견 표출로 소규모 집회가 개최되었습니다. 확산 가능성 주시 요망."}
- ALL_TEXTS["action_meet_protesters"] = { "쉬움": "시위대 이야기 들어보기", "보통": "시위대 대표 면담 추진", "어려움": "집회 주동자 대화 채널 구축 시도"}
- ALL_TEXTS["event_title_price_rise"] = {"쉬움": "물건값이 조금 올랐어요", "보통": "물가 소폭 상승", "어려움": "소비자 물가 지수 소폭 상승"}
- ALL_TEXTS["event_desc_price_rise"] = {"쉬움": "가게 물건값이 조금 올라서 사람들이 걱정해요. 안심시켜야 해요.", "보통": "일부 품목의 가격 상승으로 소비자 물가가 소폭 상승했습니다. 시장 불안 심리 차단이 필요합니다.", "어려움": "주요 소비재 가격 인상으로 인해 단기 인플레이션 압력이 감지됩니다. 선제적 시장 안정화 조치가 요구됩니다."}
- ALL_TEXTS["action_address_prices"] = {"쉬움": "물가 괜찮다고 말하기", "보통": "물가 안정 노력 관련 대국민 메시지 발표", "어려움": "물가 안정 기조 유지 관련 정부 입장 표명"}
- ALL_TEXTS["event_title_summit_offer"] = {"쉬움": "다른 나라 대통령 만나자고 해요", "보통": "정상회담 개최 제안", "어려움": "양자 정상회담 개최 제의 접수"}
- ALL_TEXTS["event_desc_summit_offer"] = {"쉬움": "이웃 나라 대통령이 만나자고 연락 왔어요. 친하게 지내면 좋아요.", "보통": "주요 동맹국/주변국 정상으로부터 양자 회담 개최 제안이 왔습니다. 외교적 성과 기회입니다.", "어려움": "주요 외교 파트너 국가 수반의 공식적인 양자 정상회담 제의가 접수되었습니다. 의제 조율 및 전략 수립이 필요합니다."}
- ALL_TEXTS["action_accept_summit"] = {"쉬움": "만나서 좋은 얘기하기", "보통": "정상회담 적극 수락 및 의제 준비 지시", "어려움": "정상회담 제의 수락 및 실무 준비 TF 구성 지시"}
- ALL_TEXTS["event_title_host_event"] = {"쉬움": "큰 국제 행사 우리나라에서 열까?", "보통": "대규모 국제 행사 유치 가능성", "어려움": "메가 이벤트 국내 유치 타당성 검토"}
- ALL_TEXTS["event_desc_host_event"] = {"쉬움": "올림픽 같은 큰 행사를 우리나라에서 열 수 있을지 알아보고 있대요. 좋겠죠?", "보통": "대규모 국제 스포츠/문화 행사 유치 경쟁에서 유리한 고지를 점했다는 보고입니다. 국가 이미지 제고 효과가 기대됩니다.", "어려움": "주요 국제 스포츠/문화 행사의 차기 개최지 선정과 관련하여 유력 후보로 부상했다는 분석입니다. 국가 브랜드 가치 제고 및 경제적 파급 효과가 예상됩니다."}
- ALL_TEXTS["action_support_hosting"] = {"쉬움": "행사 유치 돕기", "보통": "국제 행사 유치위원회에 예산/행정 지원 강화", "어려움": "범정부 차원의 국제 행사 유치 지원 체계 구축"}
- ALL_TEXTS["event_title_tech_investment"] = {"쉬움": "새로운 기술에 투자할까?", "보통": "신기술 분야 투자 적기 보고", "어려움": "미래 전략기술 분야 투자 최적 시점 분석"}
- ALL_TEXTS["event_desc_tech_investment"] = {"쉬움": "미래에 중요해질 새 기술에 투자하면 좋겠다는 보고예요. 돈 벌 수 있을까요?", "보통": "미래 산업 관련 핵심 신기술 분야에 대한 국내외 투자 환경이 유리하다는 분석입니다. 정부 지원 시 관련 공약 달성에 도움이 될 수 있습니다.", "어려움": "차세대 핵심 기술 분야의 R&D 및 상용화 투자 환경이 우호적으로 조성되었다는 분석 보고입니다. 국가 경쟁력 강화 및 관련 국정 과제 이행의 기회입니다."}
- ALL_TEXTS["action_review_tech_funding"] = {"쉬움": "새 기술 연구비 지원 알아보기", "보통": "신기술 분야 R&D 예산 증액 국회 요청 준비", "어려움": "전략기술 R&D 예산 확대 편성 및 입법부 설득 전략 수립"}
- ALL_TEXTS["event_title_opposition_criticism"] = {"쉬움": "야당이 {minister} 장관 싫어해요", "보통": "야당, {minister} 장관 책임론 제기", "어려움": "야당의 {minister} 장관에 대한 문책 요구"}
- ALL_TEXTS["event_desc_opposition_criticism"] = {"쉬움": "국회 반대편 의원들이 {minister} 장관이 일 못한다고 계속 비판해요.", "보통": "야당에서 {minister} 장관의 정책 실패 또는 부적절한 처신을 이유로 책임론을 강하게 제기하고 있습니다.", "어려움": "주요 야당은 {minister} 장관의 직무 수행 능력 및 정책적 판단에 심각한 문제가 있다며 사퇴 또는 해임 건의를 검토 중입니다."}
- ALL_TEXTS["action_defend_minister"] = {"쉬움": "{minister} 장관 편들어주기", "보통": "{minister} 장관 엄호 및 야당 설득 시도", "어려움": "{minister} 장관에 대한 신임 재확인 및 야당 공세 대응"}
- ALL_TEXTS["event_title_party_dissent"] = {"쉬움": "우리 편에서도 다른 소리가 나와요", "보통": "여당 내 특정 현안 관련 이견 노출", "어려움": "집권여당 내 정책 노선 관련 이견 표출"}
- ALL_TEXTS["event_desc_party_dissent"] = {"쉬움": "대통령이랑 같은 편 의원들 중에서도 정부가 하는 일에 대해 다른 생각을 말하기 시작했어요.", "보통": "정부 주요 정책 방향에 대해 여당 내 일부 의원들이 공개적으로 다른 목소리를 내기 시작했습니다. 내부 조율이 필요해 보입니다.", "어려움": "주요 국정 현안에 대한 당정 간 이견이 일부 언론을 통해 노출되었습니다. 당내 결속력 약화 및 정책 추진 동력 저하가 우려됩니다."}
- ALL_TEXTS["action_meet_party_members"] = {"쉬움": "우리 편 의원들 만나서 얘기하기", "보통": "여당 지도부/중진 의원들과 비공개 회동", "어려움": "여당 의원들과의 정책 간담회를 통한 내부 이견 조율"}
- ALL_TEXTS["event_title_media_criticism"] = {"쉬움": "신문/뉴스에서 정부 욕해요", "보통": "언론의 특정 정책 비판 보도", "어려움": "주요 언론의 정부 정책 비판 기조 강화"}
- ALL_TEXTS["event_desc_media_criticism"] = {"쉬움": "신문이나 뉴스에서 정부가 하는 일 하나를 콕 집어서 나쁘다고 말해요. 사람들이 믿으면 어쩌죠?", "보통": "주요 언론에서 정부의 특정 정책에 대한 문제점을 지적하거나 부정적인 여론을 부각하는 보도가 이어지고 있습니다.", "어려움": "복수의 주요 언론 매체에서 특정 정부 정책의 문제점 및 부작용을 집중적으로 보도하며 비판적 여론 형성을 주도하고 있습니다."}
- ALL_TEXTS["action_media_interview"] = {"쉬움": "기자들 만나서 설명하기", "보통": "언론 인터뷰를 통해 정책 설명 및 오해 해소", "어려움": "대통령 또는 주무 장관의 언론 브리핑을 통한 정책 정당성 설파"}
- ALL_TEXTS["event_title_congress_data_request"] = {"쉬움": "국회에서 자료 달래요", "보통": "국회, 정부 정책 자료 요구", "어려움": "국회의 행정부에 대한 자료 제출 요구"}
- ALL_TEXTS["event_desc_congress_data_request"] = {"쉬움": "국회의원들이 정부가 하는 일에 대해 자세히 알려달라고 자료를 내래요. 귀찮네요.", "보통": "국회 상임위원회에서 정부가 추진 중인 정책과 관련된 상세 자료 제출을 공식적으로 요구했습니다.", "어려움": "국회 소관 상임위원회에서 특정 정책의 추진 경과 및 예산 집행 내역 등 민감한 자료의 제출을 요구하여 행정부 부담이 가중되고 있습니다."}
- ALL_TEXTS["action_submit_data"] = {"쉬움": "자료 잘 만들어서 주기", "보통": "성실히 자료 제출 준비 지시", "어려움": "국회 요구 자료의 신속하고 정확한 제출 지시"}
- ALL_TEXTS["action_minimize_data"] = {"쉬움": "자료 조금만 주기 (혼날지도?)", "보통": "자료 제출 범위 최소화 검토 (관계 악화 위험)", "어려움": "제출 자료 범위에 대한 법적 검토 및 최소 수준 제출 추진"}
- # ... 나머지 키들 추가 필요 ...
- ALL_TEXTS["action_replace_minister"]= {"쉬움": "{minister} 장관 바꾸기", "보통": "{minister} 장관 교체", "어려움": "{minister} 장관 경질"}
- ALL_TEXTS["action_prepare_bill"]= {"쉬움": "새로운 법 만들기 준비", "보통": "법률안 국회 제출 준비", "어려움": "입법안 발의 준비 착수"}
- ALL_TEXTS["action_meet_ruling_party"]= {"쉬움": "우리 편 의원들이랑 밥 먹기", "보통": "여당 지도부와 만찬 회동", "어려움": "집권여당 지도부와 정례 회동"}
- ALL_TEXTS["action_meet_opposition"]= {"쉬움": "반대편 의원들 만나보기", "보통": "야당 지도부 만나기 (관계 개선 시도)", "어려움": "주요 야당 지도부와 협의 채널 구축"}
- ALL_TEXTS["action_meet_biz_leaders"]= {"쉬움": "회사 사장님들 만나기", "보통": "주요 경제 단체 간담회", "어려움": "주요 경제계 인사 초청 간담회"}
- ALL_TEXTS["action_respect_judiciary"]= {"쉬움": "법원 존중한다고 말하기", "보통": "사법부 존중 메시지 발표", "어려움": "사법부 독립성 존중 관련 대국민 메시지 발표"}
- ALL_TEXTS["action_no_special_action"]= {"쉬움": "이번엔 그냥 넘어가기", "보통": "이번 분기 특별 조치 없음", "어려움": "현 분기 특이 조치 보류"}
- ALL_TEXTS["status_loading_report"] = {"쉬움": "{year}년 {quarter}번째 계절 보고서 만드는 중...", "보통": "{year}년 {quarter}분기 보고 준비 중...", "어려움": "{year}년 제 {quarter}사분기 국정 현안 브리핑 준비 중..."}
- ALL_TEXTS["status_waiting_report"] = {"쉬움": "다음 계절 보고서 기다리는 중...", "보통": "다음 분기 보고를 기다리고 있습니다.", "어려움": "차기 분기 보고 대기 중..."}
- ALL_TEXTS["status_action_limit_reached"] = {"쉬움": "이번 계절({quarter})에 할 큰 결정 다 했어요. 다음 계절로 넘어가요.", "보통": "이번 분기({quarter}Q) 주요 활동을 완료했습니다. 다음 분기로 넘어가세요.", "어려움": "현 분기({quarter}Q) 주요 의사결정 한도를 소진했습니다. 차기 분기로 진행하십시오."}
- ALL_TEXTS["sidebar_title"] = {"쉬움": "메뉴", "보통": "사이드 메뉴", "어려움": "부가 기능 메뉴"}
- ALL_TEXTS["sidebar_glossary_title"] = {"쉬움": "🏛️ 어려운 말 사전", "보통": "🏛️ 정부 용어 사전", "어려움": "🏛️ 주요 정부 용어 해설"}
-
main()
\ No newline at end of file