diff --git "a/app.py" "b/app.py"
--- "a/app.py"
+++ "b/app.py"
@@ -1,13 +1,11 @@
import streamlit as st
import random
import time
-import math # 추가
+import math
# --- 게임 설정 ---
-MAX_YEARS = 5 # 대통령 임기 (5년)
-# INITIAL_POLITICAL_CAPITAL = 15 -> 난이도별 설정으로 변경
-# YEARLY_CAPITAL_GAIN = 8 -> 난이도별 설정으로 변경
-QUARTERLY_ACTIONS_LIMIT = 1 # 분기당 주요 행동 횟수 제한
+MAX_YEARS = 5
+QUARTERLY_ACTIONS_LIMIT = 1
# --- 난이도 설정 ---
DIFFICULTY_LEVELS = {
@@ -17,9 +15,9 @@ DIFFICULTY_LEVELS = {
"initial_approval_range": (50, 70),
"initial_congress_relations_range": (55, 75),
"initial_stability": 100,
- "event_impact_modifier": 0.8, # 긍정적 효과는 더 크게, 부정적 효과는 더 작게
- "checks_balances_leniency": 0.15, # 견제 강도 완화 (법안 통과율 증가, 위헌 결정 확률 감소 등)
- "vocab_level": "쉬움"
+ "event_impact_modifier": 0.8,
+ "checks_balances_leniency": 0.15,
+ "vocab_level": "쉬움" # 어휘 수준 키
},
"보통": {
"initial_capital": 15,
@@ -27,8 +25,8 @@ DIFFICULTY_LEVELS = {
"initial_approval_range": (40, 60),
"initial_congress_relations_range": (40, 60),
"initial_stability": 100,
- "event_impact_modifier": 1.0, # 기본값
- "checks_balances_leniency": 0.0, # 기본값
+ "event_impact_modifier": 1.0,
+ "checks_balances_leniency": 0.0,
"vocab_level": "보통"
},
"어려움": {
@@ -36,116 +34,335 @@ DIFFICULTY_LEVELS = {
"yearly_gain": 6,
"initial_approval_range": (30, 50),
"initial_congress_relations_range": (25, 45),
- "initial_stability": 90, # 시작 안정도 약간 감소
- "event_impact_modifier": 1.2, # 긍정적 효과는 더 작게, 부정적 효과는 더 크게
- "checks_balances_leniency": -0.15, # 견제 강도 강화
- "vocab_level": "어려움" # 필요시 어휘 조정 가능 (현재는 텍스트 직접 수정 필요)
+ "initial_stability": 90,
+ "event_impact_modifier": 1.2,
+ "checks_balances_leniency": -0.15,
+ "vocab_level": "어려움"
}
}
-# --- 어휘 조정 함수 (간단 예시) ---
+# --- 난이도별 텍스트 저장소 ---
+ALL_TEXTS = {
+ # 대시보드 용어
+ "term_approval": {
+ "쉬움": "국민들이 얼마나 좋아하나 (인기 점수)",
+ "보통": "국정 지지도",
+ "어려움": "국정 운영에 대한 국민적 지지율"
+ },
+ "term_political_capital": {
+ "쉬움": "대통령 힘 점수 (정치력)",
+ "보통": "대통령 정치력",
+ "어려움": "대통령의 정책 추진 동력 (정치적 자본)"
+ },
+ "term_stability": {
+ "쉬움": "나라가 얼마나 안정적인가",
+ "보통": "국가 안정도",
+ "어려움": "국가 시스템 안정성 지수"
+ },
+ "term_congress_relations": {
+ "쉬움": "국회랑 얼마나 친한가",
+ "보통": "국회 관계 점수",
+ "어려움": "대정부 입법부 협력/견제 지수"
+ },
+ "term_policy_goals": {
+ "쉬움": "대통령 약속 진행 상황",
+ "보통": "주요 공약 달성률",
+ "어려움": "핵심 국정 과제 이행률"
+ },
+ # 기관 이름
+ "term_congress_name": {
+ "쉬움": "국회 (법 만드는 곳)",
+ "보통": "국회 (입법부)",
+ "어려움": "입법부 (국회)"
+ },
+ "term_judiciary_name": {
+ "쉬움": "법원 (법 지키는지 보는 곳)",
+ "보통": "법원/헌법재판소 (사법부)",
+ "어려움": "사법부 (법원 및 헌법재판소)"
+ },
+ # UI 제목/라벨
+ "dashboard_title": {
+ "쉬움": "📊 나라 상황판",
+ "보통": "📊 국정 현황판",
+ "어려움": "📊 국정 운영 대시보드"
+ },
+ "dashboard_term": {
+ "쉬움": "대통령 {year}년차, {quarter}번째 계절",
+ "보통": "임기 {year}년차 {quarter}분기",
+ "어려움": "대통령 임기 {year}년차 제 {quarter}사분기"
+ },
+ "institutions_title": {
+ "쉬움": "다른 중요 기관들 소식",
+ "보통": "기관 동향",
+ "어려움": "타 국가기관 현황 브리핑"
+ },
+ "cabinet_title": {
+ "쉬움": "장관님들 소식",
+ "보통": "내각 현황",
+ "어려움": "행정 각 부처 장관 동향"
+ },
+ "agenda_title": {
+ "쉬움": "📰 이번 계절 보고서",
+ "보통": "📰 분기별 보고",
+ "어려움": "📰 분기별 국정 현안 보고"
+ },
+ "agenda_event_title": {
+ "쉬움": "이번 계절의 일: {title}",
+ "보통": "현안/기회: {title}",
+ "어려움": "분기 현안 브리핑: {title}"
+ },
+ "briefing_title": {
+ "쉬움": "📝 비서실 도움말",
+ "보통": "📝 보좌진 브리핑 및 대응 방안",
+ "어려움": "📝 참모진 현안 분석 및 ���고안"
+ },
+ "office_title": {
+ "쉬움": "🏛️ 대통령 방",
+ "보통": "🏛️ 대통령 집무실",
+ "어려움": "🏛️ 대통령 집무실" # 동일하게 사용
+ },
+ "office_available_capital": {
+ "쉬움": "쓸 수 있는 힘 점수: **{capital} P**",
+ "보통": "가용 정치력: **{capital} P**",
+ "어려움": "가용 정치적 자본: **{capital} P**"
+ },
+ "office_action_limit": {
+ "쉬움": "이번 계절에 할 수 있는 큰 결정: {remaining}번 남음",
+ "보통": "이번 분기 행동 가능 횟수: {remaining}회",
+ "어려움": "현 분기 주요 의사결정 잔여 횟수: {remaining}회"
+ },
+ "office_issue_actions": {
+ "쉬움": "지금 생긴 일 해결하기",
+ "보통": "현안 관련 조치",
+ "어려움": "당면 현안 대응 옵션"
+ },
+ "office_standard_actions": {
+ "쉬움": "평소에 할 수 있는 일들",
+ "보통": "상시 국정 활동",
+ "어려움": "상시 국정 운영 활동"
+ },
+ "term_event_log": {
+ "쉬움": "그동안 있었던 일들 기록",
+ "보통": "국정 운영 로그",
+ "어려움": "국정 운영 타임라인 기록"
+ },
+ "button_next_quarter": {
+ "쉬움": "➡️ 다음 계절로!",
+ "보통": "➡️ 다음 분기 진행",
+ "어려움": "➡️ 차기 분기 개시"
+ },
+ "button_restart": {
+ "쉬움": "다시 해볼래!",
+ "보통": "다시 시작하기",
+ "어려움": "게임 재시작"
+ },
+ # 이벤트 제목 예시
+ "event_minor_issue_title": {
+ "쉬움": "작은 문제 발생!",
+ "보통": "소규모 현안 발생",
+ "어려움": "국지적 문제 발생 보고"
+ },
+ "event_opportunity_title": {
+ "쉬움": "좋은 기회가 찾아왔어요!",
+ "보통": "기회 포착",
+ "어려움": "정책적 기회 요인 발생"
+ },
+ "event_political_move_title": {
+ "쉬움": "정치 쪽에서 시끌시끌해요",
+ "보통": "정치적 동향 보고",
+ "어려움": "정무적 상황 변동 보고"
+ },
+ "event_routine_report_title": {
+ "쉬움": "이번 계절은 조용했어요",
+ "보통": "일상 국정 보고",
+ "어려움": "정기 국정 운영 현황 보고"
+ },
+ "event_checks_balances_title": {
+ "쉬움": "[다른 기관 소식] ", # 쉬움 난이도에서는 별도 제목 대신 접두사만
+ "보통": "[견제와 균형] ",
+ "어려움": "[기관 간 견제 및 균형] "
+ },
+ # 행동 관련 메시지
+ "action_button_label": { # 버튼 레이블은 통일성 위해 보통 수준 유지
+ "쉬움": "{action} ({cost} 힘 점수)",
+ "보통": "{action} ({cost}P)",
+ "어려움": "{action} (정치자본 {cost} 소모)"
+ },
+ "action_cost_warning": {
+ "쉬움": "힘 점수가 모자라요!",
+ "보통": "정치력이 부족합니다!",
+ "어려움": "정치적 자본이 부족합니다!"
+ },
+ "action_success_message": {
+ "쉬움": "'{action}' 하라고 시켰어요.",
+ "보통": "'{action}' 지시 완료.",
+ "어려움": "'{action}' 관련 대통령령 발령 완료." # 예시
+ },
+ "action_impact_approval": {
+ "쉬움": "국민 인기도 {change:+}%p 바뀔 듯",
+ "보통": "국정 지지도 {change:+}%p 변동 예상",
+ "어려움": "국민 지지율 {change:+}%p 변동 예측"
+ },
+ "action_impact_stability":{
+ "쉬움": "나라 안정 점수 {change:+}%p 바뀔 듯",
+ "보통": "국가 안정도 {change:+}%p 변동 예상",
+ "어려움": "국가 안정성 지수 {change:+}%p 변동 예측"
+ },
+ "action_impact_congress":{
+ "쉬움": "국회랑 관계 점수 {change:+}%p 바뀔 듯",
+ "보통": "국회 관계 점수 {change:+}%p 변동 예상",
+ "어려움": "대 국회 관계 지수 {change:+}%p 변동 예측"
+ },
+ "action_impact_goal":{
+ "쉬움": "약속 '{goal}' {prog:+}%p 만큼 진행될 듯",
+ "보통": "공약 '{goal}' {prog:+}%p 달성 예상",
+ "어려움": "국정 과제 '{goal}' {prog:+}%p 진척 예상"
+ },
+ # 연말 결산
+ "checks_balances_title": {
+ "쉬움": "{year}년차, 한 해 돌아보기",
+ "보통": "{year}년차 연말 국정 결산 (견제와 균형)",
+ "어려움": "{year}년차 연말 국정 평가 (기관 간 상호작용 분석)"
+ },
+ "checks_balances_bill_submitted": {
+ "쉬움": "[국회] '{bill_name}' 법안 내봤어요.",
+ "보통": "[국회] '{bill_name}' 법안 제출됨.",
+ "어려움": "[입법부] '{bill_name}' 의안 상정됨."
+ },
+ "checks_balances_bill_passed": {
+ "쉬움": "[국회] '{bill_name}' 법안 통과! 👍",
+ "보통": "[국회] '{bill_name}' 법안 통과! 🎉",
+ "어려움": "[입법부] '{bill_name}' 의안 가결됨."
+ },
+ "checks_balances_bill_failed": {
+ "쉬움": "[국회] '{bill_name}' 법안 통과 못했어요 😥",
+ "보통": "[국회] '{bill_name}' 법안 부결.",
+ "어려움": "[입법부] '{bill_name}' 의안 부결됨."
+ },
+ "checks_balances_investigation": {
+ "쉬움": "[국회] 국회가 정부 하는 일 자세히 살펴보겠대요. 귀찮아질かも...",
+ "보통": "[국회] 특정 사안에 대한 국정조사/청문회가 발동되었습니다. 정부 부담 증가.",
+ "어려움": "[입법부] 국회의 국정조사권 또는 청문회 발동. 행정부 운영 부담 가중."
+ },
+ "checks_balances_judiciary_ruling":{
+ "쉬움": "[법원] '{case_name}' 사건 판결: {result}",
+ "보통": "[사법부] '{case_name}' 사건 판결: {result}",
+ "어려움": "[사법부] '{case_name}' 사안에 대한 사법적 판단: {result}"
+ },
+ "checks_balances_judiciary_uphold":{
+ "쉬움": "문제 없대요!",
+ "보통": "문제 없음 (합헌/적법)",
+ "어려움": "합헌 또는 적법 결정"
+ },
+ "checks_balances_judiciary_strike_down":{
+ "쉬움": "문제 있대요! 계획 바꾸거나 조심해야 함.",
+ "보통": "문제 있음! (위헌/위법) 정책 차질 발생.",
+ "어려움": "위헌 또는 위법 결정. 관련 정책 추진 제동."
+ },
+ "checks_balances_summary":{
+ "쉬움": "{year}년차 끝! (법안 통과: {passed}개, 실패: {failed}개)",
+ "보통": "{year}년차 결산 완료 (법안 통과: {passed}건, 부결: {failed}건)",
+ "어려움": "{year}년차 국정 평가 완료 (법안 가결: {passed}건, 부결: {failed}건)"
+ },
+ # 게임 오버
+ "game_over_title": {
+ "쉬움": "대통령 임기 끝! (총 {years}년)",
+ "보통": "임기 종료 (총 {years}년)",
+ "어려움": "대통령 임기 만료 (재임 기간: {years}년)"
+ },
+ "game_over_subtitle": {
+ "쉬움": "내가 대통령으로 한 일 결과",
+ "보통": "최종 국정 운영 결과",
+ "어려움": "임기 만료 시점 국정 운영 평가"
+ },
+ # 용어 사전 (쉬움/보통/어려움 순서)
+ "glossary_veto": {
+ "쉬움": "**법률안 거부권:** 국회가 만든 법이 마음에 안 들 때, 대통령이 '다시 생각해 보세요!'라고 돌려보낼 수 있는 힘. 하지만 국회 의원들이 아주 많이(2/3 이상) 찬성하면 거부 못함.",
+ "보통": "**법률안 거부권 (재의 요구권):** 국회가 통과시킨 법률안에 대해 대통령이 이의가 있을 때, 공포하지 않고 국회에 다시 심의해달라고 요구할 수 있는 권한. 국회는 재적의원 과반수 출석과 출석의원 3분의 2 이상의 찬성으로 재의결 가능.",
+ "어려움": "**법률안 재의 요구권 (거부권):** 입법부가 의결한 법률안에 대해 행정부 수반인 대통령이 이의를 제기하며 공포를 거부하고 입법부에 재심의를 요구하는 헌법상 권한. 국회 재의결 요건(재적 과반 출석, 출석 2/3 찬성) 충족 시 법률로 확정."
+ },
+ "glossary_exec_order": {
+ "쉬움": "**대통령 명령:** 법을 잘 지키기 위해 대통령이 내리는 자세한 규칙. 법보다 높을 순 없음.",
+ "보통": "**행정명령 (대통령령):** 대통령이 법률에서 위임받은 사항이나 법률을 집행하기 위해 필요한 사항에 대해 발하는 명령. 법률의 범위 내에서만 유효.",
+ "어려움": "**대통령령 (집행명령/위임명령):** 헌법과 법률에 근거하여 대통령이 발하는 행정입법의 한 형태. 법률 집행을 위한 집행명령과 법률의 위임에 따른 위임명령으로 구분되며, 사법심사의 대상."
+ },
+ "glossary_budget_proposal": {
+ "쉬움": "**예산안 만들기:** 내년에 나라 살림을 어떻게 쓸지 정부(대통령)가 계획 짜서 국회에 내는 것.",
+ "보통": "**예산안 편성권:** 정부(대통령)가 다음 해의 국가 살림 계획인 예산안을 짜서 국회에 제출할 수 있는 권한.",
+ "어려움": "**정부의 예산안 편성권:** 행정부가 차기 회계연도의 국가 재정 운용 계획인 예산안을 수립하여 입법부에 제출하는 헌법상 권한."
+ },
+ "glossary_budget_approval": {
+ "쉬움": "**예산안 심사/확정:** 국회가 정부가 낸 예산안을 보고 '이렇게 써도 좋다!' 결정하는 것. 돈을 깎거나 (정부 동의 얻어) 늘릴 수 있음.",
+ "보통": "**국회 예산 심의/확정권:** 정부가 제출한 예산안을 국회가 심사하고 최종적으로 확정하는 권한. 정부 예산안을 삭감하거나 증액(정부 동의 필요)할 수 있음.",
+ "어려움": "**국회의 예산안 심의·확정권:** 정부가 제출한 예산안에 대해 국회가 심의를 거�� 수정 또는 확정하는 권한. 재정 민주주의의 핵심 요소로, 감액은 자유로우나 증액 및 새 비목 설치는 정부 동의 필요."
+ },
+ "glossary_judicial_review_law": {
+ "쉬움": "**법률 심사권 (헌법재판소):** 국회가 만든 법이 가장 큰 법인 '헌법'에 어긋나는지 아닌지 헌법재판소가 판단하는 힘.",
+ "보통": "**위헌법률심판권:** 국회가 만든 법률이 헌법에 위배되는지 여부를 헌법재판소가 심판하는 권한.",
+ "어려움": "**위헌법률심판 제청권/심판권:** 법률의 위헌 여부가 재판의 전제가 된 경우 법원의 제청 또는 당사자의 신청에 의해 헌법재판소가 해당 법률의 헌법 합치성을 심판하는 권한."
+ },
+ "glossary_judicial_review_order":{
+ "쉬움": "**명령/규칙 심사권 (대법원):** 대통령 명령 같은 규칙이 헌법이나 법률에 맞는지 대법원이 최종 판단하는 힘.",
+ "보통": "**명령·규칙·처분 심사권:** 대통령령 등 행정기관이 만든 명령이나 규칙, 또는 행정 처분이 헌법이나 법률에 위반되는지 여부를 대법원이 최종적으로 심사하는 권한.",
+ "어려움": "**명령·규칙·처분에 대한 최종 심사권:** 행정입법(명령, 규칙)이나 행정처분의 위헌·위법성이 재판의 전제가 된 경우, 대법원이 이를 최종적으로 심사하여 판단하는 권한."
+ },
+ "glossary_parliamentary_audit":{
+ "쉬움": "**국정감사/조사:** 국회가 정부가 일 잘 하고 있는지, 잘못은 없는지 감시하고 조사하는 활동.",
+ "보통": "**국정감사/조사권:** 국회가 정부의 국정 운영 전반이나 특정 사안에 대해 잘못된 점이 없는지 감사하거나 조사할 수 있는 권한. 행정부를 견제하는 주요 수단.",
+ "어려움": "**국정감사 및 조사권:** 국회가 정부의 국정 수행 실태를 파악하고 감독하기 위해 매년 정기적으로(감사) 또는 특정 현안에 대해(조사) 행사하는 헌법상 권한."
+ },
+ "glossary_impeachment":{
+ "쉬움": "**탄핵:** 대통령 같은 높은 공무원이 아주 큰 잘못(헌법/법률 위반)을 했을 때, 국회가 그만두게 해달라고 헌법재판소에 요청하는 것.",
+ "보통": "**탄핵소추권:** 대통령 등 고위 공직자가 직무상 중대한 헌법이나 법률 위반 시, 국회가 파면을 결정해달라고 헌법재판소에 청구할 수 있는 권한.",
+ "어려움": "**탄핵소추 의결권 및 심판 청구권:** 국회가 헌법 또는 법률을 중대하게 위반한 특정 고위 공직자에 대해 파면을 구하는 소추안을 의결하고 헌법재판소에 심판을 청구하는 권한."
+ },
+ "glossary_confirmation_hearing":{
+ "쉬움": "**인사청문회:** 대통령이 뽑으려는 장관 같은 높은 공무원이 그 일 할 능력 있는지, 문제는 없는지 국회가 미리 살펴보는 자리.",
+ "보통": "**인사청문회:** 대통령이 임명하는 고위 공직 후보자에 대해 국회가 직무수행 능력과 도덕성 등을 검증하는 절차. 일부 직위는 국회 동의가 필수적.",
+ "어려움": "**인사청문회 실시권:** 대통령이 임명하는 주요 공직 후보자의 자질, 능력, 도덕성 등을 국회 상임위원회 또는 특별위원회 차원에서 검증하는 제도. 임명동의안 처리 또는 임명 전 검증 절차로 기능."
+ },
+ "glossary_political_capital":{
+ "쉬움": "**정치력 (게임 점수):** 대통령이 자기 뜻대로 일을 할 때 쓰는 힘 점수. 중요한 결정 할 때 필요.",
+ "보통": "**정치력 (Political Capital):** 대통령이 자신의 정책을 추진하거나 영향력을 행사하는 데 사용할 수 있는 비공식적인 자원. 지지도, 협상력, 리더십 등을 포함하는 개념으로 게임 내 행동력으로 사용됨.",
+ "어려움": "**정치적 자본 (Political Capital):** 대통령이 국정 운영 목표 달성을 위해 동원할 수 있는 무형의 자산. 국민적 지지, 의회 내 영향력, 정책 정당성, 리더십 등을 포괄하며, 정치적 행위의 비용으로 소모됨."
+ },
+ # ... (다른 모든 텍스트 키에 대해서도 유사하게 추가)
+}
+
+# --- 어휘 조정 함수 (난이도별 텍스트 반환) ---
def get_text(key, level="보통"):
- """난이도에 따라 다른 텍스트 반환 (향후 확장 가능)"""
- # 현재는 모든 난이도에 동일 텍스트 사용. 필요시 아래처럼 분기
- # if level == "쉬움":
- # texts = {"term_approval": "국민들이 얼마나 좋아하나 (지지율)", ...}
- # elif level == "보통":
- # texts = {"term_approval": "국정 지지도", ...}
- # else: # 어려움
- # texts = {"term_approval": "국정 운영 지지율", ...}
-
- # 간단 구현: 모든 난이도에서 동일 텍스트 반환
- texts = {
- "term_approval": "국정 지지도",
- "term_political_capital": "대통령 정치력",
- "term_stability": "국가 안정도",
- "term_congress_relations": "국회 관계",
- "term_policy_goals": "주요 공약 달성률",
- "term_congress_name": "국회 (법 만드는 곳)",
- "term_judiciary_name": "법원/헌법재판소 (법 지키는지 보는 곳)",
- "term_cabinet_status": "장관님들 현황",
- "term_event_log": "국정 운영 기록",
- "event_minor_issue_title": "작은 문제 발생",
- "event_opportunity_title": "좋은 기회 발생",
- "event_political_move_title": "정치적 움직임",
- "event_routine_report_title": "일상 국정 보고",
- "briefing_title": "📝 보좌진 브리핑 및 대응 방안",
- "action_button_label": "{action} ({cost}P)",
- "action_cost_warning": "정치력이 부족해요!",
- "action_success_message": "'{action}' 지시 완료.",
- "action_impact_approval": "국민 지지도 {change:+}%p 변화 예상",
- "action_impact_stability": "국가 안정도 {change:+}%p 변화 예상",
- "action_impact_congress": "국회 관계 점수 {change:+}%p 변화 예상",
- "action_impact_goal": "공약 '{goal}' {prog:+}%p 달성 예상",
- "checks_balances_title": "{year}년차 연말 국정 결산 (견제와 균형)",
- "checks_balances_bill_submitted": "[국회] '{bill_name}' 법안 제출됨.",
- "checks_balances_bill_passed": "[국회] '{bill_name}' 법안 통과! 🎉",
- "checks_balances_bill_failed": "[국회] '{bill_name}' 법안 통과 실패 😥",
- "checks_balances_investigation": "[국회] 특별 조사/청문회 시작! 정부 부담 증가.",
- "checks_balances_judiciary_ruling": "[사법부] '{case_name}' 사건 판결: {result}",
- "checks_balances_judiciary_uphold": "문제 없음 (합헌/적법)",
- "checks_balances_judiciary_strike_down": "문제 있음! (위헌/위법) 정책 차질 발생.",
- "checks_balances_summary": "{year}년차 결산 완료 (법안 통과: {passed}건, 실패: {failed}건)",
- "game_over_title": "임기 종료 (총 {years}년)",
- "game_over_subtitle": "최종 국정 운영 결과",
- "game_over_final_approval": "최종 국정 지지도",
- "game_over_final_stability": "최종 국가 안정도",
- "game_over_final_congress": "최종 국회 관계",
- "game_over_final_goals": "주요 공약 최종 달성률:",
- "game_over_log_title": "국정 운영 기록 돌아보기",
- "button_restart": "다시 시작하기",
- "button_next_quarter": "➡️ 다음 분기 진행",
- "status_loading_report": "{year}년 {quarter}분기 보고 준비 중...",
- "status_waiting_report": "다음 분기 보고를 기다리고 있습니다.",
- "status_action_limit_reached": "이번 분기({quarter}Q) 주요 활동을 완료했습니다. 다음 분기로 넘어가세요.",
- "dashboard_title": "📊 국정 현황판",
- "dashboard_term": "임기 {year}년차 {quarter}분기",
- "institutions_title": "기관 동향",
- "cabinet_title": "내각 현황",
- "agenda_title": "📰 분기별 보고",
- "agenda_event_title": "현안/기회: {title}",
- "office_title": "🏛️ 대통령 집무실",
- "office_available_capital": "가용 정치력: **{capital} P**",
- "office_action_limit": "이번 분기 행동 가능 횟수: {remaining}회",
- "office_issue_actions": "현안 관련 조치",
- "office_standard_actions": "상시 국정 활동",
- "sidebar_title": "사이드 메뉴",
- "sidebar_glossary_title": "🏛️ 정부 용어 사전 (쉬운 설명)",
- # 용어 사전 내용도 난이도별 조정 가능
- "glossary_veto": "**법률안 거부권:** 국회가 만든 법이 마음에 안 들 때, 대통령이 '다시 생각해 보세요!'라고 돌려보낼 수 있는 힘. 하지만 국회 의원들이 많이 찬성하면(3분의 2 이상) 거부 못함.",
- "glossary_exec_order": "**대통령 명령:** 법을 잘 실행하기 위해 대통령이 내리는 세부 규칙. 법의 테두리 안에서만 가능.",
- "glossary_budget_proposal": "**예산안 만들기:** 정부(대통령)가 내년에 나라 살림을 어떻게 쓸지 계획(예산안)을 짜서 국회에 내는 것.",
- "glossary_budget_approval": "**예산안 심사/확정:** 국회가 정부가 낸 예산안을 꼼꼼히 살펴보고 최종 결정하는 것. 돈을 깎거나, 정부 동의 얻어 늘릴 수 있음.",
- "glossary_judicial_review_law": "**법률 심사권 (헌법재판소):** 국회가 만든 법이 최고 법인 '헌법'에 어긋나는지 아닌지 헌법재판소가 판단하는 힘.",
- "glossary_judicial_review_order": "**명령/규칙 심사권 (대법원):** 대통령 명령 같은 행정부 규칙이 헌법��나 법률에 맞는지 대법원이 최종 판단하는 힘.",
- "glossary_parliamentary_audit": "**국정감사/조사:** 국회가 정부가 일을 잘 하고 있는지, 잘못한 건 없는지 감시하고 조사하는 활동.",
- "glossary_impeachment": "**탄핵:** 대통령 같은 높은 공무원이 아주 큰 잘못(헌법/법률 위반)을 했을 때, 국회가 그만두게 해달라고 헌법재판소에 요청하는 것.",
- "glossary_confirmation_hearing": "**인사청문회:** 대통령이 뽑으려는 장관 같은 높은 공무원이 그 일을 할 능력이 있는지, 문제는 없는지 국회가 미리 살펴보는 자리.",
- "glossary_political_capital": "**정치력 (게임 점수):** 대통령이 자기 뜻대로 일을 추진할 때 쓰는 힘 점수. 중요한 결정을 할 때마다 필요.",
- }
- return texts.get(key, key) # 키가 없으면 키 자체를 반환
+ """난이도에 따라 다른 텍스트 반환, 없으면 '보통' -> 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)
+ # st.error(f"텍스트 키 '{key}' 찾을 수 없음!") # 디버깅용
+ return key
# --- 정부 및 다른 기관 초기화 함수 ---
def initialize_government(difficulty):
"""대통령 임기 시작 시 상태 및 다른 기관 정보 초기화 (난이도 적용)"""
settings = DIFFICULTY_LEVELS[difficulty]
- vocab = settings["vocab_level"] # 현재는 사용 안함, 추후 get_text 에 전달 가능
+ vocab_level = settings["vocab_level"]
+ get_text_func = lambda k: get_text(k, vocab_level) # 초기화 시점 어휘 수준 적용
- # 정책 목표 (모든 난이도 공통 또는 약간 조정 가능)
- policy_options = ["경제 성장시키기", "일자리 많이 만들기", "집값 안정시키기", "미래 기술 키우기", "다른 나라와 친하게 지내기", "나라 튼튼히 지키기", "어려운 사람 돕기 예산 늘리기", "깨끗한 환경 만들기"]
+ # 정책 목표 (텍스트 수준은 여기서 직접 조정하지 않음, 표시는 UI에서 get_text 사용)
+ policy_options = ["경제 성장률 5% 달성", "청년 실업률 5% 이하 달성", "부동산 시장 안정화", "미래 산업 육성", "외교 관계 개선", "국방력 강화", "복지 예산 10% 증액", "탄소 배출 감축"]
selected_goals = random.sample(policy_options, 3)
initial_goals = {goal: 0 for goal in selected_goals}
- # 국회 의석수 (여소야대 가능성 조정 가능)
total_seats = 300
gov_party_seats_base = random.randint(120, 170)
- if difficulty == "어려움":
- gov_party_seats = min(gov_party_seats_base, random.randint(100, 155)) # 여소야대 확률 증가
- elif difficulty == "쉬움":
- gov_party_seats = max(gov_party_seats_base, random.randint(145, 180)) # 과반 확률 증가
- else:
- gov_party_seats = gov_party_seats_base
-
+ if difficulty == "어려움": gov_party_seats = min(gov_party_seats_base, random.randint(100, 155))
+ elif difficulty == "쉬움": gov_party_seats = max(gov_party_seats_base, random.randint(145, 180))
+ else: gov_party_seats = gov_party_seats_base
opp_party_seats = total_seats - gov_party_seats - random.randint(5, 15)
other_seats = total_seats - gov_party_seats - opp_party_seats
@@ -159,22 +376,22 @@ def initialize_government(difficulty):
},
'other_branches': {
'Congress': {
- 'name': get_text("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),
+ 'key_focus': random.sample(['민생 안정', '정부 견제', '개혁 입법', '지역 예산 확보'], 2),
'pending_bills': [],
- 'relations_score': random.randint(*settings['initial_congress_relations_range']) # 대통령 상태와 동기화
+ 'relations_score': random.randint(*settings['initial_congress_relations_range'])
},
'Judiciary': {
- 'name': get_text("term_judiciary_name"), # 난이도별 텍스트 적용 가능
+ 'name': get_text_func("term_judiciary_name"), # 난이도별 텍스트 적용
'status': '특별한 사건 없음',
- 'independence_level': random.randint(70, 95) if difficulty != "어려움" else random.randint(80, 100), # 어려움에서 독립성 더 강할 수 있음
+ 'independence_level': random.randint(70, 95) if difficulty != "어려움" else random.randint(80, 100),
'pending_cases': [],
- 'stance_modifier': 0 # 0 = 중립, +면 정부 우호, -면 정부 비판적 (추후 사용 가능)
+ 'stance_modifier': 0
}
},
- 'cabinet': { # 내각 정보 추가 (난이도 영향 받을 수 있음)
+ 'cabinet': {
'경제부': {'minister_approval': random.randint(30,70), 'performance': 50},
'사회부': {'minister_approval': random.randint(30,70), 'performance': 50},
'외교부': {'minister_approval': random.randint(30,70), 'performance': 50},
@@ -192,160 +409,182 @@ if 'difficulty' not in st.session_state:
# --- 난이도 선택 화면 ---
if not st.session_state.game_started:
st.title("👑 대통령의 균형추: 삼권분립 리더십 시뮬레이션")
- st.write("초등학교 6학년 친구들도 이해할 수 있도록 만들었어요!")
+ st.write("게임을 시작하기 전에 난이도를 선택해주세요. 난이도에 따라 게임 설명과 용어가 달라집니다.")
selected_difficulty = st.radio(
"게임 난이도를 선택하세요:",
list(DIFFICULTY_LEVELS.keys()),
- index=1, # 기본 '보통' 선택
+ index=1,
horizontal=True,
+ captions=["쉬운 단어와 설명으로 게임해요.", "표준적인 설명으로 게임해요.", "전문적인 용어와 설명으로 게임해요."]
)
if st.button("게임 시작!"):
st.session_state['difficulty'] = selected_difficulty
st.session_state['game_year'] = 1
st.session_state['game_quarter'] = 1
st.session_state['game_state'] = initialize_government(selected_difficulty)
- st.session_state.game_state['event_log'].append(f"초기 국정 지지도: {st.session_state.game_state['presidency_status']['approval_rating']}%")
- st.session_state.game_state['event_log'].append(f"선택된 주요 공약: {', '.join(st.session_state.game_state['presidency_status']['policy_goals'].keys())}")
+ # 초기 로그 메시지 추가 (난이도별 텍스트 사용)
+ vocab_level = DIFFICULTY_LEVELS[selected_difficulty]["vocab_level"]
+ get_text_func = lambda k: get_text(k, vocab_level)
+ 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}%")
+ 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['current_quarterly_event'] = None
st.session_state['event_briefing'] = None
st.session_state['game_over'] = False
st.session_state['actions_taken_this_quarter'] = 0
st.session_state['game_started'] = True
st.rerun()
- st.stop() # 게임 시작 전까지는 아래 코드 실행 안 함
+ st.stop()
# --- 게임 진행 중 ---
-difficulty_setting = DIFFICULTY_LEVELS[st.session_state.difficulty]
-vocab_level = difficulty_setting["vocab_level"] # 현재 미사용, get_text 에 전달 가능
+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)
-# --- 분기별 현안/기회 생성 함수 (난이도 및 견제 요소 강화) ---
+# --- 분기별 현안/기회 생성 함수 ---
def generate_quarterly_event(year, quarter, game_state, difficulty):
"""매 분기 발생하는 현안/기회 생성 (난이도 및 견제 요소 반영)"""
settings = DIFFICULTY_LEVELS[difficulty]
+ vocab_level = settings["vocab_level"]
presidency_status = game_state['presidency_status']
congress = game_state['other_branches']['Congress']
judiciary = game_state['other_branches']['Judiciary']
event_types = ["minor_issue", "opportunity", "political_move", "checks_balances_event", "random"]
- # 난이도에 따라 부정적 이벤트 확률 조정
- weights = [30, 25, 20, 15, 10] # 기본 가중치
- if difficulty == "어려움":
- weights = [35, 15, 25, 20, 5] # 이슈, 정치, 견제 증가, 기회 감소
- elif difficulty == "쉬움":
- weights = [20, 35, 15, 10, 20] # 기회, 랜덤 증가, 이슈 감소
-
- # 국회 관계가 나쁘면 견제 이벤트 확률 증가
+ weights = [30, 25, 20, 15, 10]
+ if difficulty == "어려움": weights = [35, 15, 25, 20, 5]
+ elif difficulty == "쉬움": weights = [20, 35, 15, 10, 20]
if congress['relations_score'] < 40:
- weights[3] += 10 # checks_balances_event 확률 증가
- weights[2] += 5 # political_move 확률 증가
+ weights[3] += 10
+ weights[2] += 5
chosen_type = random.choices(event_types, weights=weights, k=1)[0]
- event = {"title": "", "description": "", "type": chosen_type, "options": []}
-
- # 어휘 함수 사용
- get_text_func = lambda key: get_text(key, vocab_level)
+ event = {"title_key": "", "description_key": "", "type": chosen_type, "options": []} # 키로 저장
- # Placeholder 로직 (내용 보강 및 난이도별 조정)
+ # 이벤트 내용 정의 (키 사용)
if chosen_type == "minor_issue":
issues = [
- {"title": "특정 지역 작은 재난 발생", "desc": "갑작스런 폭우나 작은 산불로 동네 몇 군데가 피해를 입었어요. 빨리 도와줘야 할 것 같아요."},
- {"title": "작은 시위 발생", "desc": "어떤 문제 때문에 일부 시민들이 모여서 목소리를 내고 있어요. 큰 문제는 아니지만 신경은 써야 할 것 같아요."},
- {"title": "물가 약간 상승", "desc": "가게 물건값이 조금 올라서 사람들이 걱정하기 시작했어요. 안심시키는 말이 필요해요."},
+ {"title_key": "event_title_minor_disaster", "desc_key": "event_desc_minor_disaster"},
+ {"title_key": "event_title_small_protest", "desc_key": "event_desc_small_protest"},
+ {"title_key": "event_title_price_rise", "desc_key": "event_desc_price_rise"},
]
selected = random.choice(issues)
- event["title"] = get_text_func("event_minor_issue_title") + f": {selected['title']}"
- event["description"] = selected["desc"]
+ event["title_key"] = selected["title_key"]
+ event["description_key"] = selected["desc_key"]
event["options"] = [
- {"action": "피해 지역 방문해서 위로하기", "cost": math.ceil(2 * (1/settings['event_impact_modifier'])), "impact": {"approval": random.randint(1,3), "stability": random.randint(0,2)}},
- {"action": "시위대 이야기 들어보기", "cost": math.ceil(1 * (1/settings['event_impact_modifier'])), "impact": {"stability": random.randint(0,1)}},
- {"action": "물가 안정 노력 설명하기 (TV 연설)", "cost": math.ceil(1 * (1/settings['event_impact_modifier'])), "impact": {"approval": random.randint(-1,2)}},
+ {"action_key": "action_visit_disaster_area", "cost": math.ceil(2 * (1/settings['event_impact_modifier'])), "impact": {"approval": random.randint(1,3), "stability": random.randint(0,2)}},
+ {"action_key": "action_meet_protesters", "cost": math.ceil(1 * (1/settings['event_impact_modifier'])), "impact": {"stability": random.randint(0,1)}},
+ {"action_key": "action_address_prices", "cost": math.ceil(1 * (1/settings['event_impact_modifier'])), "impact": {"approval": random.randint(-1,2)}},
]
elif chosen_type == "opportunity":
opps = [
- {"title": "다른 나라 대통령과 만날 기회", "desc": "이웃 나라 대통령이 만나자고 연락이 왔어요. 친하게 지내면 우리나라에 도움이 될 거예요."},
- {"title": "큰 국제 행사 우리나라에서 열까?", "desc": "올림픽 같은 큰 국제 행사를 우리나라에서 열 수 있을지 알아보고 있대요. 잘 되면 나라 자랑도 하고 경제에도 좋아요."},
- {"title": "새로운 기술 투자 제안", "desc": "미래에 중요해질 새로운 기술에 투자하면 좋겠다는 보고가 들어왔어요. 잘 키우면 우리나라가 더 발전할 수 있어요."},
- ]
+ {"title_key": "event_title_summit_offer", "desc_key": "event_desc_summit_offer"},
+ {"title_key": "event_title_host_event", "desc_key": "event_desc_host_event"},
+ {"title_key": "event_title_tech_investment", "desc_key": "event_desc_tech_investment"},
+ ]
selected = random.choice(opps)
- event["title"] = get_text_func("event_opportunity_title") + f": {selected['title']}"
- event["description"] = selected["desc"]
+ event["title_key"] = selected["title_key"]
+ event["description_key"] = selected["desc_key"]
event["options"] = [
- {"action": "만남 수락하고 좋은 이야기 나눌 준비", "cost": math.ceil(2 * (1/settings['event_impact_modifier'])), "impact": {"approval": random.randint(0,2), "policy_goals": {"다른 나라와 친하게 지내기": random.randint(1,3)}}},
- {"action": "국제 행사 유치 적극 지원 지시", "cost": math.ceil(3 * (1/settings['event_impact_modifier'])), "impact": {"stability": random.randint(1,2), "approval": random.randint(1,3)}},
- {"action": "새 기술 연구비 지원 검토 지시", "cost": math.ceil(2 * (1/settings['event_impact_modifier'])), "impact": {"policy_goals": {"미래 기술 키우기": random.randint(2,5)}}},
- ]
+ {"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)}}},
+ ]
+ # ... (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())) # 장관 이름 필요
moves = [
- {"title": "야당, 특정 장관 비판", "desc": f"국회 야당 의원들이 {random.choice(list(game_state['cabinet'].keys()))} 장관이 일을 잘못하고 있다고 계속 비판하고 있어요."},
- {"title": "여당 내 다른 목소리", "desc": "대통령과 같은 편인 여당 안에서도 일부 의원들이 정부 정책에 대해 다른 생각을 이야기하기 시작했어요."},
- {"title": "언론의 특정 정책 비판", "desc": "신문이나 뉴스에서 정부가 하는 일 중 하나를 골라 문제점을 지적하고 있어요. 국민 여론이 나빠질 수 있어요."},
+ {"title_key": "event_title_opposition_criticism", "desc_key": "event_desc_opposition_criticism", "minister": minister_name},
+ {"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"] = get_text_func("event_political_move_title") + f": {selected['title']}"
- event["description"] = selected["desc"]
+ event["title_key"] = selected["title_key"]
+ event["description_key"] = selected["desc_key"]
+ event["context"] = {"minister": selected.get("minister")} # 설명문에 필요한 정보 전달
event["options"] = [
- {"action": "해당 장관 감싸고 야당 설득 시도", "cost": math.ceil(2 * (1/settings['event_impact_modifier'])), "impact": {"congress_relations": random.randint(-4,1)}}, # 관계 악화 가능성 증가
- {"action": "여당 의원들 만나서 이야기 나누기", "cost": math.ceil(1 * (1/settings['event_impact_modifier'])), "impact": {"political_capital": 1}},
- {"action": "언론 인터뷰로 정책 설명하기", "cost": math.ceil(1 * (1/settings['event_impact_modifier'])), "impact": {"approval": random.randint(-2,2)}},
+ {"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_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)}},
]
- elif chosen_type == "checks_balances_event": # 견제와 균형 관련 이벤트
+ # 예시: checks_balances_event
+ elif chosen_type == "checks_balances_event":
cb_events = []
- # 국회 관련
if congress['relations_score'] < 50 or difficulty == "어려움":
- cb_events.append({"title": "국회, 정부 정책 자료 요구", "desc": "국회에서 정부가 추진 중인 정책에 대해 자세한 자료를 제출하라고 요구했어요. 준비하는데 시간과 노력이 필요해요.", "options": [{"action": "성실히 자료 제출 준비 지시", "cost": 1, "impact": {"congress_relations": random.randint(0,2)}}, {"action": "자료 제출 최소화 (관계 악화 위험)", "cost": 0, "impact": {"congress_relations": random.randint(-3,0)}}]})
- cb_events.append({"title": "국회, 특정 사안 청문회 개최 검토", "desc": "국회에서 논란이 되는 문제에 대해 담당자들을 불러 질문하는 청문회를 열지 고민 중이에요. 열리면 정부에 부담이 될 수 있어요.", "options": [{"action": "여당 통해 청문회 무마 시도", "cost": 2, "impact": {"congress_relations": random.randint(-2,1)}}, {"action": "청문회 대비 철저히 준비 지시", "cost": 1, "impact": {"stability": random.randint(-2,0)}}]})
- # 사법부 관련
+ cb_events.append({"title_key": "event_title_congress_data_request", "desc_key": "event_desc_congress_data_request", "options": [{"action_key": "action_submit_data", "cost": 1, "impact": {"congress_relations": random.randint(0,2)}}, {"action_key": "action_minimize_data", "cost": 0, "impact": {"congress_relations": random.randint(-3,0)}}]})
+ cb_events.append({"title_key": "event_title_congress_hearing_review", "desc_key": "event_desc_congress_hearing_review", "options": [{"action_key": "action_prevent_hearing", "cost": 2, "impact": {"congress_relations": random.randint(-2,1)}}, {"action_key": "action_prepare_hearing", "cost": 1, "impact": {"stability": random.randint(-2,0)}}]})
if judiciary['independence_level'] > 80 or random.random() < 0.1:
- cb_events.append({"title": "법원, 정부 정책 관련 소송 접수", "desc": "정부가 시행한 정책에 문제가 있다며 누군가 법원에 소송을 제기했어요. 판결 결과에 따라 정책 추진에 영향이 있을 수 있어요.", "options": [{"action": "법무부에 법적 대응 준비 지시", "cost": 1, "impact": {}}, {"action": "국민 설득 노력 강화 (여론전)", "cost": 1, "impact": {"approval": random.randint(0,1)}}]})
+ cb_events.append({"title_key": "event_title_judiciary_lawsuit", "desc_key": "event_desc_judiciary_lawsuit", "options": [{"action_key": "action_prepare_legal_defense", "cost": 1, "impact": {}}, {"action_key": "action_persuade_public", "cost": 1, "impact": {"approval": random.randint(0,1)}}]})
- if not cb_events: # 만약 조건 맞는게 없으면 일반 랜덤 이벤트로 대체
- chosen_type = "random"
+ if not cb_events:
+ chosen_type = "random" # 대체
else:
selected = random.choice(cb_events)
- event["title"] = "[견제와 균형] " + selected["title"]
- event["description"] = selected["desc"]
+ event["title_key"] = selected["title_key"]
+ event["description_key"] = selected["desc_key"]
event["options"] = selected["options"]
+ event["type"] = "checks_balances_event" # 타입 명시
- # Random (기존 유지, 약간 조정)
+ # Random 타입 처리
if chosen_type == "random":
- event["title"] = get_text_func("event_routine_report_title")
- event["description"] = "이번 분기는 큰 사건 없이 조용히 지나갔어요. 하던 일에 계속 집중하면 될 것 같아요."
+ event["title_key"] = "event_title_routine_report"
+ event["description_key"] = "event_desc_routine_report"
+ event["type"] = "random"
event["options"] = [
- {"action": "주요 공약 진행 상황 점검", "cost": math.ceil(1 * (1/settings['event_impact_modifier'])), "impact": {}},
- {"action": "정책 홍보 활동 강화 지시", "cost": math.ceil(1 * (1/settings['event_impact_modifier'])), "impact": {"approval": random.randint(0,1)}},
+ {"action_key": "action_check_goal_progress", "cost": math.ceil(1 * (1/settings['event_impact_modifier'])), "impact": {}},
+ {"action_key": "action_strengthen_pr", "cost": math.ceil(1 * (1/settings['event_impact_modifier'])), "impact": {"approval": random.randint(0,1)}},
]
- # 모든 이벤트에 공통 옵션 추가
- event["options"].append({"action": "이번 분기 특별 조치 없음", "cost": 0, "impact": {}})
+ # 공통 옵션 추가 (키 사용)
+ event["options"].append({"action_key": "action_no_special_action", "cost": 0, "impact": {}})
- log_message = f"{year}년차 {quarter}분기 현안: {event['title']}"
+ # 최종 이벤트 객체 생성 (텍스트 변환)
+ 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", {})),
+ "type": event["type"],
+ "options": []
+ }
+ for opt in event["options"]:
+ final_event["options"].append({
+ "action": get_text(opt["action_key"], vocab_level).format(**opt.get("context", {})),
+ "cost": opt["cost"],
+ "impact": opt["impact"]
+ })
+
+ log_message = f"{year}년차 {quarter}분기 현안: {final_event['title']}"
if 'event_log' in game_state:
game_state['event_log'].append(log_message)
- return event
+ return final_event
-# --- 이벤트 브리핑 제공 함수 (난이도별 텍스트 적용) ---
+# --- 이벤트 브리핑 제공 함수 ---
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) # 어휘 함수 가져오기
- title = event['title']
- briefing = f"**{st.session_state['game_year']}년차 {st.session_state['game_quarter']}분기 보고: {title}**\n\n"
- briefing += f"{event['description']}\n\n"
- briefing += "**대응 방안 제안:**\n"
+ 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"{event['description']}\n\n" # 이미 변환된 텍스트 사용
+ briefing += f"**{get_text_func('briefing_title')}**\n" # 브리핑 제목도 난이도별로
options_data = []
for i, opt in enumerate(event.get("options", [])):
- # 난이도에 따른 비용 조정 반영 (이미 generate_event에서 계산됨)
cost = opt['cost']
- briefing += f"{i+1}. **{opt['action']}** ({get_text_func('action_button_label').format(action='', cost=cost)})\n" # 비용만 표시
+ action_text = opt['action'] # 이미 변환된 텍스트 사용
+ # 버튼 라벨 형식은 난이도별로 다르게 적용
+ briefing += f"{i+1}. **{action_text}** ({get_text_func('action_button_label').format(action='', cost=cost)})\n"
- # 간단한 예상 효과 명시 (실제 로직은 execute에서 처리, 난이도 영향 반영)
effects = []
impact_modifier = settings['event_impact_modifier']
+ # 예상 효과 텍스트도 난이도별로
if 'approval' in opt['impact']:
- # 쉬움 난이도에서는 긍정 효과 증가, 부정 효과 감소 / 어려움은 반대
val = opt['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))
@@ -361,17 +600,18 @@ def provide_event_briefing(event, game_state, difficulty):
for goal, prog in opt['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.split(" ")[0], prog=adjusted_val)) # 간단히 첫 단어만
+ 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))
- if effects: briefing += f" - *주요 예상 효과:* {', '.join(effects)}\n"
- options_data.append(opt) # 행동 실행 위해 데이터 저장
+ if effects: briefing += f" - *예상 결과:* {', '.join(effects)}\n" # '예상 결과' 텍스트도 키로 관리 가능
+ options_data.append(opt)
return {"text": briefing, "options": options_data}
-# --- 대통령 행동 실행 함수 (난이도 영향 적용) ---
+# --- 대통령 행동 실행 함수 ---
def execute_presidential_action(action_index, briefing_data, game_state, difficulty):
- """선택된 대통령 행동을 실행하고 게임 상태 업데이트 (난이도 영향 적용)"""
+ """선택된 대통령 행동 실행 (난이도 영향 적용)"""
settings = DIFFICULTY_LEVELS[difficulty]
impact_modifier = settings['event_impact_modifier']
vocab_level = settings["vocab_level"]
@@ -379,12 +619,12 @@ def execute_presidential_action(action_index, briefing_data, game_state, difficu
options = briefing_data.get("options", [])
if not (0 <= action_index < len(options)):
- st.error("잘못된 행동 선택입니다.")
+ st.error("잘못된 행동 선택입니다.") # 이 메시지도 get_text 사용 가능
return False
selected_action = options[action_index]
- action_name = selected_action['action']
- cost = selected_action['cost'] # 비용은 이미 난이도 반영됨
+ action_name = selected_action['action'] # 이미 변환된 텍스트
+ cost = selected_action['cost']
impact = selected_action.get('impact', {})
presidency_status = game_state['presidency_status']
other_branches = game_state['other_branches']
@@ -394,28 +634,39 @@ def execute_presidential_action(action_index, briefing_data, game_state, difficu
st.warning(get_text_func('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}' 수행 (정치력 {cost} 소모)"
+ log_message = f" - 대통령 지시({st.session_state.game_quarter}Q): '{action_name}' 수행 ({get_text_func('term_political_capital')} {cost} 소모)" # 로그 메시지도 난이도별 용어 사용
game_state['event_log'].append(log_message)
st.success(get_text_func('action_success_message').format(action=action_name))
- # 행동 결과 반영 (impact 딕셔너리 기반, 난이도 조정)
+ # 결과 반영 (기존 로직 유지, 로그 메시지에서 get_text 사용 고려)
+ approval_change_log = 0
+ stability_change_log = 0
+ congress_change_log = 0
+
if 'approval' in impact:
change = impact['approval']
adjusted_change = math.ceil(change / impact_modifier) if change < 0 else math.floor(change * impact_modifier)
presidency_status['approval_rating'] += adjusted_change
- if adjusted_change != 0: game_state['event_log'].append(f" - 국정 지지도 {adjusted_change:+}%p 변동.")
+ approval_change_log = adjusted_change
if 'stability' in impact:
change = impact['stability']
adjusted_change = math.ceil(change / impact_modifier) if change < 0 else math.floor(change * impact_modifier)
presidency_status['stability'] += adjusted_change
- if adjusted_change != 0: game_state['event_log'].append(f" - 국가 안정도 {adjusted_change:+}%p 변동.")
+ stability_change_log = adjusted_change
if 'congress_relations' in impact:
change = impact['congress_relations']
adjusted_change = math.ceil(change / impact_modifier) if change < 0 else math.floor(change * impact_modifier)
other_branches['Congress']['relations_score'] += adjusted_change
- if adjusted_change != 0: game_state['event_log'].append(f" - 국회 관계 점수 {adjusted_change:+}%p 변동.")
+ 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 'policy_goals' in impact:
for goal, progress in impact['policy_goals'].items():
if goal in presidency_status['policy_goals']:
@@ -425,45 +676,31 @@ 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" - 공약 '{goal}' 달성률이 {adjusted_change}%p 상승했습니다. (현재 {new_progress}%)")
+ game_state['event_log'].append(f" - {get_text_func('term_policy_goals')} '{goal}' {adjusted_change}%p 상승 (현재 {new_progress}%)")
- # 내각 인사 관련 (기존 유지, 난이도 영향 추가 가능)
- if "장관 교체" in action_name:
+ # 장관 교체 등 다른 로직은 기존 유지 (필요시 로그 메시지에 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)
cabinet[minister_to_replace]['performance'] = 50
- # 교체 영향도 난이도 따라 조정 가능
approval_change = random.randint(-4, 4) if difficulty == "어려움" else (random.randint(-2, 5) if difficulty == "쉬움" else random.randint(-3, 3))
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" - 지지도 {approval_change:+} 변동.")
- if congress_change != 0: game_state['event_log'].append(f" - 국회 관계 {congress_change:+} 변동.")
+ 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['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['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}' 제출 준비 착수.")
- # 견제와 균형 관련 행동 추가 (예시)
- if "야당 지도부 만나기" in action_name:
- change = random.randint(1, 4) if difficulty == "쉬움" else (random.randint(-1, 3) if difficulty == "보통" else random.randint(-3, 2))
- other_branches['Congress']['relations_score'] += change
- if change != 0: game_state['event_log'].append(f" - 야당과의 대화 시도: 국회 관계 점수 {change:+}%p 변동.")
- if "사법부 존중 메시지 발표" in action_name:
- # 사법부와의 직접적 관계 점수는 없으므로, 안정도나 지지도에 영향
- change = random.randint(0, 2)
- presidency_status['stability'] += change
- if change != 0: game_state['event_log'].append(f" - 사법부 존중 메시지 발표: 국가 안정도 {change:+}%p 변동.")
-
-
# 지표 범위 유지
presidency_status['approval_rating'] = max(0, min(100, presidency_status['approval_rating']))
presidency_status['stability'] = max(0, min(100, presidency_status['stability']))
@@ -474,28 +711,28 @@ def execute_presidential_action(action_index, briefing_data, game_state, difficu
st.session_state['actions_taken_this_quarter'] += 1
return True
-# --- 견제와 균형 시뮬레이션 함수 (연말 실행, 강화 및 난이도 적용) ---
+# --- 견제와 균형 시뮬레이션 함수 ---
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)
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']
- get_text_func = lambda key: get_text(key, vocab_level)
log.append(f"--- {get_text_func('checks_balances_title').format(year=year)} ---")
- # 1. 국회 시뮬레이션 (법안 처리, 국정조사 등)
- # 법안 제출
+ # 1. 국회 시뮬레이션
if 'pending_legislation' in game_state:
for bill_to_submit in game_state['pending_legislation']:
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'])}")
- game_state['pending_legislation'] = [] # 제출 후 목록 비우기
+ game_state['pending_legislation'] = []
processed_bills_indices = []
bills_passed_this_year = 0
@@ -503,69 +740,56 @@ def simulate_checks_and_balances(game_state, difficulty):
for i, bill in enumerate(congress['pending_bills']):
if bill.get('status') == '제출됨':
- # 법안 통과 확률 계산 (견제 강화 및 난이도 반영)
- base_chance = 0.4 # 기본 통과 확률
- # 관계 점수 영향력 강화 (50점 기준, 점수당 0.7%p)
+ base_chance = 0.4
relation_bonus = (congress['relations_score'] - 50) * 0.007
- # 지지도 영향 (50점 기준, 점수당 0.3%p)
approval_bonus = (presidency_status['approval_rating'] - 50) * 0.003
- # 여소야대 페널티 강화
is_minority_gov = congress['seats']['Government'] < (sum(congress['seats'].values()) / 2)
minority_penalty = -0.25 if is_minority_gov else 0
- # 난이도 영향 (쉬움 +15%, 어려움 -15%)
difficulty_modifier = settings['checks_balances_leniency']
-
pass_chance = base_chance + relation_bonus + approval_bonus + minority_penalty + difficulty_modifier
- pass_chance = max(0.05, min(0.95, pass_chance)) # 5% ~ 95% 범위
+ 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%})")
if random.random() < pass_chance:
bill['status'] = '통과'
log.append(f" - {get_text_func('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']:
goal_to_update = bill['goal_related']
- progress = random.randint(10, 25) # 통과 시 효과 증대
- # 난이도 영향 (쉬움에서 더 많이 오르고, 어려움에서 덜 오름)
+ 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" - 공약 '{goal_to_update}' 달성률 {adjusted_progress}%p 상승 (현재 {new_prog}%)")
- # 통과 시 긍정적 효과 (난이도 영향)
- 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" - 지지도 {approval_gain:+}%p 상승.")
- if relation_gain > 0: log.append(f" - 국회 관계 {relation_gain:+}%p 상승.")
-
+ if new_prog > current_prog: log.append(f" - {get_text_func('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'])}")
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" - 지지도 {-approval_loss}%p 하락.")
- if relation_loss > 0: log.append(f" - 국회 관계 {-relation_loss}%p 하락.")
- # 관련 공약 후퇴 가능성 (낮은 확률)
+ 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:
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" - 공약 '{goal_to_update}' 달성률 {-setback}%p 후퇴 (현재 {new_prog}%)")
+ if new_prog < current_prog: log.append(f" - {get_text_func('term_policy_goals')} '{goal_to_update}' {-setback}%p 후퇴 (현재 {new_prog}%)")
+ processed_bills_indices.append(i)
- processed_bills_indices.append(i) # 처리된 것으로 표시 (상태 변경으로 충분)
-
- # 국회 랜덤 이벤트 (국정조사/청문회) - 관계 나쁘거나 어려움 난이도에서 확률 증가
investigation_chance = 0.10
if congress['relations_score'] < 35: investigation_chance += 0.15
if difficulty == "어려움": investigation_chance += 0.10
@@ -575,24 +799,20 @@ def simulate_checks_and_balances(game_state, difficulty):
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" - 국가 안정도 {-stability_loss}%p 하락, 국회 관계 {-relation_loss}%p 하락.")
+ log.append(f" - {get_text_func('term_stability')} {-stability_loss}%p 하락, {get_text_func('term_congress_relations')} {-relation_loss}%p 하락.")
- # 2. 사법부 시뮬레이션 (판결 영향력 강화 및 난이도 적용)
+ # 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'].append({"name": new_case_name, "status": "접수됨"})
- log.append(f" - [사법부] '{new_case_name}' 사건이 새롭게 접수되었습니다.")
+ log.append(f" - [{get_text_func('term_judiciary_name')}] '{new_case_name}' 사건 접수됨.") # 기관명도 난이도별로
judiciary['status'] = "주요 사건 심리 중"
for i, case in enumerate(judiciary['pending_cases']):
if case.get('status') == '접수됨' or case.get('status') == '심리중':
- # 판결 확률 (독립성 + 난이도 영향)
- # 독립성 높을수록 정부에 불리한 판결 가능성 증가
- # 쉬움 난이도는 정부 유리, 어려움은 불리하게 조정
- independence_factor = (judiciary['independence_level'] - 75) * 0.008 # 75 기준, 100이면 +0.2
- difficulty_factor = settings['checks_balances_leniency'] * -1 # 쉬움은 -0.15, 어려움은 +0.15 (정부 불리 판결 확률)
+ independence_factor = (judiciary['independence_level'] - 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))
@@ -600,42 +820,36 @@ def simulate_checks_and_balances(game_state, difficulty):
if random.random() < strike_down_chance:
result_text = get_text_func('checks_balances_judiciary_strike_down')
- case['status'] = f'판결완료: {result_text}'
+ case['status'] = f'판결완료: {result_text}' # 상태는 간단히 유지
log.append(f" - {get_text_func('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" - 지지도 {-approval_loss}%p 하락, 안정도 {-stability_loss}%p 하락.")
- # 관련 공약 후퇴 로직 강화 가능 (예: 특정 정책 관련 소송이었다면 해당 공약 5-10%p 후퇴)
+ log.append(f" - {get_text_func('term_approval')} {-approval_loss}%p 하락, {get_text_func('term_stability')} {-stability_loss}%p 하락.")
else:
result_text = get_text_func('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)}")
- # 긍정적 판결 시 약간의 안정도/지지도 상승 가능 (난이도 영향)
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" - 지지도 {approval_gain:+}%p 상승.")
- if stability_gain > 0: log.append(f" - 안정도 {stability_gain:+}%p 상승.")
+ 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 상승.")
- ruled_cases_indices.append(i) # 판결 완료 표시
+ ruled_cases_indices.append(i)
- # 판결 완료된 사건 외에 심리중인 사건이 있는지 확인하여 사법부 상태 업데이트
has_pending = any(c.get('status') == '접수됨' or c.get('status') == '심리중' for c in judiciary['pending_cases'])
- if not has_pending:
- judiciary['status'] = "특별한 사건 없음"
+ if not has_pending: judiciary['status'] = "특별한 사건 없음"
- # 3. 연말 최종 상태 업데이트 (자연 변동폭 난이도 영향)
+ # 3. 연말 최종 상태 업데이트
approval_fluctuation = random.randint(-4, 4) if difficulty == "어려움" else (random.randint(-2, 5) if difficulty == "쉬움" else random.randint(-3, 3))
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" - 연말 자연 변동: 지지도 {approval_fluctuation:+}%p, 안정도 {stability_fluctuation:+}%p")
+ log.append(f" - 연말 자연 변동: {get_text_func('term_approval')} {approval_fluctuation:+}%p, {get_text_func('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']))
@@ -643,10 +857,9 @@ def simulate_checks_and_balances(game_state, difficulty):
log.append(f"--- {get_text_func('checks_balances_summary').format(year=year, passed=bills_passed_this_year, failed=bills_rejected_this_year)} ---")
-# --- UI 표시 함수들 (난이도별 텍스트 적용) ---
+# --- UI 표시 함수들 ---
def display_presidency_dashboard(game_state, difficulty):
- settings = DIFFICULTY_LEVELS[difficulty]
- vocab_level = settings["vocab_level"]
+ vocab_level = DIFFICULTY_LEVELS[difficulty]["vocab_level"]
get_text_func = lambda key: get_text(key, vocab_level)
status = game_state['presidency_status']
st.metric(get_text_func("term_approval"), f"{status['approval_rating']}%")
@@ -657,98 +870,90 @@ def display_presidency_dashboard(game_state, difficulty):
st.subheader(get_text_func("term_policy_goals"))
goals = status['policy_goals']
if not goals:
- st.caption("설정된 공약이 없습니다.")
+ st.caption("설정된 공약이 없습니다.") # 이 텍스트도 키로 관리 가능
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):
- settings = DIFFICULTY_LEVELS[difficulty]
- vocab_level = settings["vocab_level"]
+ vocab_level = DIFFICULTY_LEVELS[difficulty]["vocab_level"]
get_text_func = 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']} (관계 점수: {congress['relations_score']})", expanded=True):
+ # 국회 정보 표시 (기관명은 이미 난이도별 적용됨)
+ with st.expander(f"{congress['name']} ({get_text_func('term_congress_relations')}: {congress['relations_score']})", expanded=True):
seats = congress['seats']
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("[주의] 여소야대 상황입니다. 법안 통과가 어려울 수 있습니다.", 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(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") # 라벨 키로 관리 가능
def display_cabinet_status(game_state, difficulty):
- settings = DIFFICULTY_LEVELS[difficulty]
- vocab_level = settings["vocab_level"]
+ vocab_level = DIFFICULTY_LEVELS[difficulty]["vocab_level"]
get_text_func = lambda key: get_text(key, vocab_level)
cabinet = game_state.get('cabinet', {})
with st.expander(get_text_func("cabinet_title")):
if not cabinet:
- st.caption("내각 정보가 없습니다.")
+ st.caption("내각 정보가 없습니다.") # 키로 관리 가능
return
cols = st.columns(len(cabinet))
i = 0
for minister, data in cabinet.items():
with cols[i]:
- st.metric(f"{minister} 장관 지지율", f"{data['minister_approval']}%")
- # st.caption(f"업무 성과: {data['performance']}") # 성과 지표 추가 가능
+ # 장관 이름 + '지지율' 텍스트 조합
+ st.metric(f"{minister} 장관 {get_text_func('term_approval')}", f"{data['minister_approval']}%")
i += 1
def display_gov_terms_glossary(difficulty):
- settings = DIFFICULTY_LEVELS[difficulty]
- vocab_level = settings["vocab_level"]
- get_text_func = lambda key: get_text(key, vocab_level) # 어휘 함수 사용
-
- glossary = {
- get_text_func("glossary_veto").split(":")[0]: get_text_func("glossary_veto").split(":")[1].strip(),
- get_text_func("glossary_exec_order").split(":")[0]: get_text_func("glossary_exec_order").split(":")[1].strip(),
- get_text_func("glossary_budget_proposal").split(":")[0]: get_text_func("glossary_budget_proposal").split(":")[1].strip(),
- get_text_func("glossary_budget_approval").split(":")[0]: get_text_func("glossary_budget_approval").split(":")[1].strip(),
- get_text_func("glossary_judicial_review_law").split(":")[0]: get_text_func("glossary_judicial_review_law").split(":")[1].strip(),
- get_text_func("glossary_judicial_review_order").split(":")[0]: get_text_func("glossary_judicial_review_order").split(":")[1].strip(),
- get_text_func("glossary_parliamentary_audit").split(":")[0]: get_text_func("glossary_parliamentary_audit").split(":")[1].strip(),
- get_text_func("glossary_impeachment").split(":")[0]: get_text_func("glossary_impeachment").split(":")[1].strip(),
- get_text_func("glossary_confirmation_hearing").split(":")[0]: get_text_func("glossary_confirmation_hearing").split(":")[1].strip(),
- get_text_func("glossary_political_capital").split(":")[0]: get_text_func("glossary_political_capital").split(":")[1].strip(),
- }
+ vocab_level = DIFFICULTY_LEVELS[difficulty]["vocab_level"]
+ get_text_func = 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):
- for term, definition in glossary.items():
+ for key in glossary_keys:
+ # 난이도별 텍스트 가져오기
+ term_definition = get_text_func(key)
+ # 첫번째 ':' 기준으로 용어와 설명 분리 (만약 ':' 없으면 전체를 용어로)
+ parts = term_definition.split(':', 1)
+ term = parts[0].strip()
+ definition = parts[1].strip() if len(parts) > 1 else ""
st.markdown(f"**{term}:** {definition}")
st.markdown("---")
# --- 메인 게임 루프 ---
def main():
- st.set_page_config(layout="wide") # 넓은 레이아웃 사용
+ st.set_page_config(layout="wide")
- # 게임 시작 전 난이도 선택 화면 처리
if not st.session_state.game_started:
- # 위에서 처리하고 st.stop() 했으므로 여기는 도달하지 않음
- return
+ return # 시작 화면 처리
- # 게임 시작 후
difficulty = st.session_state.difficulty
settings = DIFFICULTY_LEVELS[difficulty]
vocab_level = settings["vocab_level"]
- get_text_func = lambda key: get_text(key, vocab_level) # 어휘 함수 사용
+ get_text_func = lambda key: get_text(key, vocab_level)
st.title("👑 대통령의 균형추: 삼권분립 리더십 시뮬레이션")
- st.caption(f"난이도: {difficulty}") # 현재 난이도 표시
+ st.caption(f"난이도: {difficulty}")
- game_state = st.session_state.game_state # 편의상 변수 할당
+ game_state = st.session_state.game_state
# --- 게임 오버 처리 ---
if st.session_state.get('game_over', False):
@@ -757,11 +962,12 @@ def main():
st.subheader(get_text_func("game_over_subtitle"))
final_status = game_state['presidency_status']
col1, col2, col3 = st.columns(3)
- with col1: st.metric(get_text_func("game_over_final_approval"), f"{final_status['approval_rating']}%")
- with col2: st.metric(get_text_func("game_over_final_stability"), f"{final_status['stability']}")
- with col3: st.metric(get_text_func("game_over_final_congress"), f"{game_state['other_branches']['Congress']['relations_score']}")
+ # 최종 결과 메트릭 (용어 난이도별 적용)
+ 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']}")
- st.write(get_text_func("game_over_final_goals"))
+ st.write(get_text_func("term_policy_goals")) # 최종 공약 라벨
goals = final_status['policy_goals']
if goals:
for goal, progress in goals.items():
@@ -769,22 +975,19 @@ def main():
else:
st.caption("설정된 공약이 없습니다.")
- st.subheader(get_text_func("game_over_log_title"))
- log_text = "\n".join(game_state['event_log'][::-1]) # 역순으로 표시
+ 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")):
- # 세션 상태 초기화 (game_started 제외)
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 # 시작 화면으로 돌아가기 위해
+ for key in keys_to_delete: del st.session_state[key]
+ st.session_state.game_started = False
st.rerun()
return
- # --- 메인 게임 화면 (3단 구성) ---
- col_dashboard, col_agenda, col_actions = st.columns([1.2, 1.8, 1.5]) # 비율 조정
+ # --- 메인 게임 화면 ---
+ 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'])}**")
@@ -793,40 +996,41 @@ def main():
st.subheader(get_text_func("institutions_title"))
display_other_branches_status(game_state, difficulty)
st.divider()
- display_cabinet_status(game_state, difficulty) # 내각 현황 추가
+ display_cabinet_status(game_state, difficulty)
- # --- 가운데: 분기별 현안 ---
with col_agenda:
st.header(get_text_func("agenda_title"))
- # 새 분기 현안 생성 (자동)
if st.session_state['current_quarterly_event'] is None:
- spinner_text = get_text_func('status_loading_report').format(year=st.session_state['game_year'], quarter=st.session_state['game_quarter'])
+ spinner_text = get_text('status_loading_report', vocab_level).format(year=st.session_state['game_year'], quarter=st.session_state['game_quarter']) # 로딩 메시지도 get_text 사용
with st.spinner(spinner_text):
- time.sleep(0.5) # 로딩 효과
+ time.sleep(0.5)
+ # generate_quarterly_event 호출 시 난이도 전달
event = generate_quarterly_event(st.session_state['game_year'], st.session_state['game_quarter'], 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.session_state['actions_taken_this_quarter'] = 0
st.rerun()
else:
- st.error("분기 보고 생성에 실패했습니다.")
+ st.error("분기 보고 생성 실패") # 오류 메시지 키로 관리 가능
if st.session_state['current_quarterly_event']:
event_data = st.session_state['current_quarterly_event']
- st.subheader(get_text_func("agenda_event_title").format(title=event_data['title']))
+ # 이벤트 제목/설명은 이미 generate/provide 함수에서 난이도별 텍스트로 변환됨
+ st.subheader(f"{get_text_func('agenda_event_title').split(':')[0]}: {event_data['title']}") # ':' 앞부분만 가져오기
st.markdown(event_data['description'])
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) # HTML 허용 (색상 등)
+ st.markdown(st.session_state['event_briefing']['text'], unsafe_allow_html=True)
else:
- st.warning("브리핑 정보를 불러오는 중입니다.")
+ st.warning("브리핑 정보 로딩 중...") # 키로 관리 가능
else:
- st.info(get_text_func("status_waiting_report"))
+ st.info(get_text('status_waiting_report', vocab_level)) # 대기 메시지 키로 관리 가능
- # --- 오른쪽: 대통령 행동 선택 및 로그 ---
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']))
@@ -837,103 +1041,177 @@ def main():
st.session_state['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", [])
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'])
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):
- # 행동 성공 시, 현안/브리핑 유지하고 UI만 업데이트 (rerun 대신)
- # 단, 행동 횟수 소진 시 버튼 비활성화 필요
- st.rerun() # 일단은 rerun으로 상태 반영
+ st.rerun()
- # 상시 국정 활동 (행동 횟수 남았을 때만 가능)
if remaining_actions > 0:
st.divider()
st.subheader(get_text_func("office_standard_actions"))
- # 상시 가능한 행동 추가 (견제와 균형 관련 포함)
- standard_actions = [
- {"action": f"{random.choice(list(game_state['cabinet'].keys()))} 장관 교체", "cost": math.ceil(4 * (1/settings['event_impact_modifier'])), "impact": {}}, # 비용 난이도 반영
- {"action": "법률안 국회 제출 준비 (공약 관련)", "cost": math.ceil(3 * (1/settings['event_impact_modifier'])), "impact": {}},
- {"action": "여당 지도부와 만찬 회동", "cost": math.ceil(2 * (1/settings['event_impact_modifier'])), "impact": {"congress_relations": random.randint(1,4)}}, # 긍정적 효과 위주
- {"action": "야당 지도부 만나기 (관계 개선 시도)", "cost": math.ceil(3 * (1/settings['event_impact_modifier'])), "impact": {}}, # execute에서 처리
- {"action": "주요 경제 단체 간담회", "cost": math.ceil(1 * (1/settings['event_impact_modifier'])), "impact": {"approval": random.randint(0,2)}},
- {"action": "사법부 존중 메시지 발표", "cost": math.ceil(1 * (1/settings['event_impact_modifier'])), "impact": {}}, # execute에서 처리
+ # 상시 행동 정의 (action_key 사용)
+ standard_actions_defs = [
+ {"action_key": "action_replace_minister", "cost_base": 4, "context": {"minister": random.choice(list(game_state['cabinet'].keys()))}},
+ {"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},
+ {"action_key": "action_meet_biz_leaders", "cost_base": 1, "impact": {"approval": random.randint(0,2)}},
+ {"action_key": "action_respect_judiciary", "cost_base": 1},
]
- for j, std_opt in enumerate(standard_actions):
- button_label = get_text_func('action_button_label').format(action=std_opt['action'], cost=std_opt['cost'])
+ 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'] < std_opt['cost'])
- temp_briefing_data = {"options": [std_opt]} # 리스트로 감싸기
+ is_disabled = (game_state['presidency_status']['political_capital'] < cost)
+ # 실행 위해 임시 briefing_data 생성
+ temp_briefing_data = {"options": [{
+ "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):
- if execute_presidential_action(0, temp_briefing_data, game_state, difficulty): # 인덱스는 항상 0
- st.rerun() # 상태 반영
+ # 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_func("status_action_limit_reached").format(quarter=st.session_state.game_quarter))
+ 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_func("status_waiting_report"))
-
+ st.info(get_text('status_waiting_report', vocab_level))
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']
- # 연말(4분기)이면 시뮬레이션 실행
if current_quarter == 4:
- spinner_text = f"{current_year}년차 국정 결산 중..."
+ 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" - 연말 보너스 정치력 {capital_gain}P 획득.")
- time.sleep(1.5) # 결산 시간
+ # 연말 보너스 로그 (용어 난이도 적용)
+ game_state['event_log'].append(f" - 연말 보너스 {get_text_func('term_political_capital')} {capital_gain}P 획득.")
+ time.sleep(1.5)
st.session_state['game_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"--- 임기 종료 ---")
+ game_state['event_log'].append(f"--- {get_text_func('game_over_title').split('(')[0].strip()} ---") # 임기 종료 텍스트 사용
else:
- game_state['event_log'].append(f"--- {st.session_state['game_year']}년차 시작 ---")
+ game_state['event_log'].append(f"--- {st.session_state['game_year']}년차 시작 ---") # 키로 관리 가능
else:
st.session_state['game_quarter'] += 1
- game_state['event_log'].append(f"--- {st.session_state['game_year']}년차 {st.session_state['game_quarter']}분기 시작 ---")
+ 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['current_quarterly_event'] = None
st.session_state['event_briefing'] = None
- st.session_state['actions_taken_this_quarter'] = 0 # 행동 횟수 리셋
-
+ st.session_state['actions_taken_this_quarter'] = 0
st.rerun()
st.divider()
st.subheader(get_text_func("term_event_log"))
- log_text = "\n".join(game_state['event_log'][::-1]) # 역순으로 표시
+ 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")
- # --- 사이드바 ---
with st.sidebar:
st.header(get_text_func("sidebar_title"))
- display_gov_terms_glossary(difficulty) # 정부 용어 사전 표시 (난이도별 텍스트)
+ display_gov_terms_glossary(difficulty)
st.divider()
- # 게임 가이드 등 추가 가능
st.markdown("---")
st.caption(f"현재 난이도: {difficulty}")
- if st.button("게임 재시작 (난이도 변경)"):
+ if st.button(get_text_func("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]
+ 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