File size: 92,435 Bytes
fd8f1df ba63f2d 5cdb81a ba25b53 14115e9 ba63f2d b5d87e2 b01ffab b5d87e2 14115e9 f3edf46 14115e9 f3edf46 e02c8b9 150511c e02c8b9 b01ffab c5ed497 b01ffab 14115e9 e02c8b9 150511c e02c8b9 b01ffab c5ed497 150511c b01ffab 14115e9 e02c8b9 b01ffab e02c8b9 150511c b01ffab 14115e9 3d57d8f b01ffab ba25b53 e02c8b9 b01ffab 569cd00 b01ffab 00c4641 b01ffab 00c4641 b01ffab 150511c 9313759 b01ffab c5ed497 9313759 b01ffab 150511c c5ed497 9313759 b01ffab fdc7183 b01ffab ba25b53 b01ffab d39af66 b01ffab 150511c e02c8b9 d39af66 baca1c4 e02c8b9 b5d87e2 e02c8b9 150511c 14115e9 150511c f3edf46 c5ed497 150511c baca1c4 ed648bd 150511c e02c8b9 c5ed497 14115e9 c5ed497 14115e9 b01ffab 14115e9 b01ffab e02c8b9 c5ed497 14115e9 7ef6ba4 14115e9 b01ffab 14115e9 e02c8b9 c5ed497 14115e9 b01ffab 14115e9 e02c8b9 150511c b01ffab 0e123e0 b01ffab 150511c b01ffab 0e123e0 b5d87e2 0e123e0 e02c8b9 0e123e0 150511c e02c8b9 b01ffab 150511c b5d87e2 150511c b5d87e2 e02c8b9 150511c b01ffab 150511c e02c8b9 150511c c5ed497 150511c c5ed497 150511c c5ed497 150511c d39af66 c5ed497 150511c d39af66 c5ed497 150511c 3d57d8f 150511c b01ffab 00c4641 9313759 00c4641 150511c fd8f1df c5ed497 b01ffab 9313759 150511c c5ed497 150511c c5ed497 00c4641 c5ed497 b01ffab 9313759 14115e9 c5ed497 9313759 c5ed497 150511c b5d87e2 14115e9 b01ffab 150511c b01ffab 14115e9 9313759 14115e9 00c4641 14115e9 00c4641 14115e9 9313759 14115e9 9313759 14115e9 d39af66 14115e9 00c4641 d39af66 b01ffab a35c585 00c4641 150511c a35c585 d39af66 a35c585 d39af66 a35c585 d39af66 a35c585 14115e9 c5ed497 150511c a35c585 c5ed497 a35c585 0e123e0 b5d87e2 150511c e02c8b9 14115e9 9313759 fdc7183 9313759 fdc7183 9313759 fdc7183 9313759 d39af66 9313759 f3edf46 00c4641 9313759 00c4641 9313759 00c4641 9313759 00c4641 9313759 00c4641 9313759 00c4641 b01ffab 9313759 e02c8b9 d39af66 150511c 9313759 e02c8b9 d39af66 e02c8b9 9313759 00c4641 d39af66 c5ed497 b01ffab e02c8b9 9313759 e02c8b9 9313759 150511c 9313759 e02c8b9 9313759 d39af66 9313759 34cc154 9313759 d39af66 9313759 d39af66 9313759 d39af66 00c4641 9313759 d39af66 9313759 d39af66 9313759 b5d87e2 ba63f2d 150511c |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 |
# -*- coding: utf-8 -*-
import streamlit as st
import random
import time
import math
import os
from openai import OpenAI
import json
# --- 페이지 설정 (스크립트 최상단) ---
st.set_page_config(layout="wide", page_title="진실을 찾아서: 우리 역사 이야기")
# --- OpenAI API 키 설정 ---
if "OPENAI_API_KEY" not in os.environ:
st.error("OPENAI_API_KEY 환경 변수가 설정되지 않았습니다. API 키를 설정해주세요.")
st.stop()
client = OpenAI(api_key=os.environ["OPENAI_API_KEY"])
# --- 게임 설정 ---
ACTIONS_PER_TURN_LIMIT = 2
# --- 시나리오 설정 ---
SCENARIOS = {
"4.19_revolution": {
"display_name": "4.19 혁명 취재 (1960)",
"start_year": 1960,
"player_role": "새내기 기자 (자유일보)",
"initial_press_freedom": 40,
"initial_reporter_safety": 70,
"initial_public_trust": 50,
"vocab_level": "초등",
"max_turns": 8,
},
"5.18_gwangju": {
"display_name": "5.18 광주 현장 취재 (1980)",
"start_year": 1980,
"player_role": "지방 기자 (민주신문)",
"initial_press_freedom": 20,
"initial_reporter_safety": 50,
"initial_public_trust": 40,
"vocab_level": "초등",
"max_turns": 8,
},
"june_struggle": {
"display_name": "6월 항쟁 함께 취재 (1987)",
"start_year": 1987,
"player_role": "사회부 기자 (시민일보)",
"initial_press_freedom": 30,
"initial_reporter_safety": 60,
"initial_public_trust": 45,
"vocab_level": "초등",
"max_turns": 7,
}
}
# --- 텍스트 저장소 (모든 텍스트 초등 수준으로 변경) ---
ALL_TEXTS = {
# --- 공통 UI ---
"game_title": "🎙️ 진실을 찾아서: 우리 역사 이야기",
"scenario_select_title": "📰 어떤 시대로 가볼까요?",
"scenario_select_button": "이 시대로 출발!",
# --- 추가된 display_name 키 ---
"4.19 혁명 취재 (1960)": "4.19 혁명 취재 (1960)",
"5.18 광주 현장 취재 (1980)": "5.18 광주 현장 취재 (1980)",
"6월 항쟁 함께 취재 (1987)": "6월 항쟁 함께 취재 (1987)",
# --- 나머지 공통 UI ---
"dashboard_title": "📊 기자님 현재 상황",
"dashboard_term": "{year}년 {turn}번째 날",
"term_press_freedom": "기사 쓰는 자유",
"term_article_score_avg": "평균 기사 점수",
"term_reporter_safety": "기자님 안전",
"term_public_trust": "사람들의 믿음",
"current_assignment_title": "📋 오늘 할 일",
"reporter_actions_title": "🎤 무엇을 할까요?",
"action_button_label": "{action} (이걸 하면? {risk_str})",
"action_success_message": "'{action}' 취재 끝!",
"button_next_day": "➡️ 다음 날로 가기",
"button_restart_assignment": "이번 취재 다시 하기",
"button_back_to_scenario_select": "다른 시대로 가기",
"assignment_over_title": "🎉 취재 끝! 수고하셨습니다!",
"assignment_over_subtitle": "마지막 취재 결과와 점수",
"term_event_log": "오늘 있었던 일",
"historical_source_title": "💡 도움되는 이야기",
"reporter_notebook_title": "📝 내가 적은 내용",
"article_writing_title": "🖋️ 기사 쓰기",
"desk_feedback_title": "📢 AI 편집장님의 한마디",
"status_loading_assignment": "{year}년 {turn}번째 날, 무슨 일이 있을까? 기다려주세요...",
"status_actions_taken": "오늘 할 일을 다 했어요. 기사를 쓰거나 다음 날로 넘어가세요.",
"sidebar_glossary_title": "📰 어려운 말/사람 이야기",
"button_submit_article": "기사 보내기 (AI 편집장님께)",
"article_headline_label": "기사 제목:",
"article_body_label": "기사 내용 요약 (짧게 3~5줄):",
"article_tone_label": "기사 분위기 선택:",
"warning_empty_article": "기사 제목과 내용을 모두 써 주세요.",
"info_no_special_info": "특별한 건 알아내지 못했어요.",
"log_freedom_loss": " - 취재가 힘들어졌어요. 기사 쓰는 자유가 {loss}만큼 줄었어요.",
"log_safety_loss": " - 취재하다 위험했어요. 기자님 안전이 {loss}만큼 줄었어요.",
"log_info_acquired": " - 새로운 사실 발견: {info}",
"log_no_info_acquired": " - 특별히 알아낸 건 없어요.",
"log_article_submitted": "기사 보냄: '{headline}' (분위기: {tone}) - AI 편집장님 점수: {score}점",
"log_desk_feedback": " - AI 편집장님 한마디: {feedback}",
"log_trust_change": " - 사람들이 나를 {change:+}만큼 더 믿거나 덜 믿게 됐어요.",
"log_freedom_change_article": " - 기사 쓰는 자유가 {change:+}만큼 바뀌었어요.",
"log_safety_change_article": " - 기자님 안전이 {change:+}만큼 바뀌었어요.",
"log_assignment_over": "--- {scenario_name} 취재 끝 ---",
"log_next_day_start": "--- {year}년 {turn}번째 날 시작 ---",
"error_openai_api": "AI 편집장님 연결에 문제가 생겼어요: {error}",
# --- 4.19 혁명 취재 시나리오 ---
"scenario_4.19_revolution_name": "4.19 혁명 이야기 (1960년)",
"event_419_t1_assignment": "오늘은 3월 15일, 대통령과 부통령을 뽑는 날이에요. 투표하는 곳에서 나쁜 사람들이 규칙을 어기고 자기편만 뽑으려고 할지도 몰라요. 그런 이상한 점을 찾아내고, 투표를 지켜보는 사람, 투표하는 사람, 선거를 관리하는 사람들에게 이야기를 들어보는 것이 오늘 할 일이에요. 특히 반대편 사람들이 잘 감시하는지, 힘 있는 쪽 사람들이 몰래 나쁜 일을 꾸미는지 잘 살펴보세요.",
"event_419_t1_source": "[알아두면 좋아요] 지금 자유당이라는 당이 오랫동안 나라를 다스려서 사람들이 불만이 많아요. 이번 선거에서 이승만 대통령이 또 대통령이 되고, 이기붕 아저씨가 부통령이 되려고 자유당이 나쁜 방법을 쓸 거라는 소문이 많아요. 미리 투표한 표를 몰래 바꾸거나, 없는 사람 표를 넣거나, 여럿이 같이 보면서 투표하게 만들거나, 반대편 감시하는 사람들을 쫓아낸다는 이야기가 돌고 있어요.",
"action_419_t1_opt1_text": "서울 투표하는 곳에 몰래 들어가서 사진 찍어보기",
"action_419_t1_opt2_text": "선거 감시하는 사람들과 함께 나쁜 일 찾아보기",
"action_419_t1_opt3_text": "선거 관리하는 곳 사람 중 몰래 알려줄 사람 만나보기",
"info_419_t1_opt1_got": "새로운 사실: 종로 A투표소에서 자유당 표시를 한 사람들이 투표함에 표를 많이 넣는 걸 멀리서 봤어요. 가까이 가려니까 무섭게 쳐다봤어요. (힌트: 표 몰래 넣기, 자유당 표시, 무서움)",
"info_419_t1_opt2_got": "새로운 사실: 민주당 쪽 감시원 박 아저씨가 화나서 말했어요. '성북 B투표소에서 경찰이 어떤 사람들 투표하는 곳까지 따라가서 누굴 찍는지 봤어요! 안 된다고 했는데 내 말을 안 들었어요!' 사진도 조금 찍었대요. (힌트: 경찰이 투표 방해, 감시원 말 무시, 민주당)",
"info_419_t1_opt3_got": "새로운 사실: 이름을 밝히기 싫어하는 선거 관리 직원이 떨면서 말했어요. '오늘 새벽에 어떤 투표함들을 이상한 차가 가져가는 걸 봤어요. 너무 무서워요.' (힌트: 투표함 몰래 바꾼 듯, 선거 관리 직원 제보, 무서움)",
"event_419_t2_assignment": "마산에서 나쁜 선거에 반대하며 시위하던 김주열 학생이 사라졌는데, 바다에서 슬픈 모습으로 발견됐어요. 왜 김주열 학생이 죽었는지, 경찰은 처음에 어떻게 했는지, 마산 사람들이 얼마나 화가 났는지 자세히 알아보세요.",
"event_419_t2_source": "[알아두면 좋아요] 4월 11일, 마산 앞바다에서 눈에 최루탄이 박힌 김주열 학생의 모습은 사람들에게 큰 충격을 줬어요. 경찰은 처음엔 그냥 물에 빠져 죽었다고 하려 했지만, 모습이 알려지면서 거짓말 아니냐는 말이 많아졌어요. 마산은 이미 시위 때문에 분위기가 안 좋았어요.",
"action_419_t2_opt1_text": "김주열 학생이 있는 병원에 가서 의사 선생님 만나보기",
"action_419_t2_opt2_text": "마산 학생들이 시위하는 곳(마산상고 등)에 직접 가보기",
"action_419_t2_opt3_text": "김주열 학생을 처음 본 어부 아저씨와 가족들 이야기 듣기",
"info_419_t2_opt1_got": "새로운 사실: 병원 관계자가 몰래 말해줬어요. '김주열 학생은 최루탄 때문에 머리를 다쳐서 죽은 것 같아요. 경찰이 이걸 알리지 말라고 하고 있어요.' (힌트: 최루탄 때문에 죽음, 머리 다침, 경찰이 숨김)",
"info_419_t2_opt2_got": "새로운 사실: 마산상고 학생들이 '친구를 살려내라!', '나쁜 경찰 혼내주자!' 외치며 경찰과 싸우고 있어요. 돌멩이랑 불도 던지고, 경찰은 최루탄을 마구 쏴요. 다친 학생들이 많아요. (힌트: 마산 학생 시위, 경찰이 심하게 막음, 다친 사람 많음)",
"info_419_t2_opt3_got": "새로운 사실: 김주열 학생 어머니가 울면서 말했어요. '우리 아들은 시위하러 간다고 하고 나갔어요. 경찰이 죽인 게 틀림없어요. 너무 억울해요.' (힌트: 김주열 가족, 경찰이 죽였다고 생각, 억울함)",
"event_419_t3_assignment": "4월 18일, 나쁜 선거를 반대하는 시위를 마치고 학교로 돌아가던 고려대학교 학생들이 나쁜 아저씨들에게 맞았어요. 무슨 일이 있었는지, 경찰은 뭘 했는지, 다른 사람들은 어떻게 생각하는지 알아보세요.",
"event_419_t3_source": "[알아두면 좋아요] 김주열 학생 일 때문에 학생들이 더 많이 시위하고 있는데, 이번엔 깡패 아저씨들이 나타나서 학생들을 때렸어요. 사람들이 더 화가 났어요. 경찰이 이걸 보고도 못 본 척한 거 아니냐는 말도 나와요.",
"action_419_t3_opt1_text": "학생들이 맞은 곳과 다친 학생들이 있는 병원에 가보기",
"action_419_t3_opt2_text": "경찰서에 가서 어떻게 조사하고 있는지, 깡패들 뒤에 누가 있는지 물어보기",
"action_419_t3_opt3_text": "고려대학교 학생 대표와 다른 대학교 학생 대표들 이야기 듣기",
"info_419_t3_opt1_got": "새로운 사실: 다친 학생이 말했어요. '시위 끝나고 조용히 가는데 갑자기 쇠파이프 든 아저씨들이 때렸어요. 살려달라고 해도 마구 때렸어요.' 병원에는 다친 학생들이 많았어요. (힌트: 고려대생 맞음, 깡패, 쇠파이프, 단체로 때림)",
"info_419_t3_opt2_got": "새로운 사실: 경찰 아저씨가 말했어요. '학생들끼리 싸운 것 같아요. 깡패가 있다는 건 그냥 소문이에요.' 더 조사할 생각은 없어 보였어요. (힌트: 경찰이 대충 조사, 그냥 싸웠다고 함, 뒤에 누가 있는지 모른 척)",
"info_419_t3_opt3_got": "새로운 사실: 서울대 학생 대표가 말했어요. '이건 나쁜 테러예요! 나라에서 도와주지 않으면 불가능한 일이에요. 모든 학생이 힘을 합쳐 싸울 거예요!' (힌트: 다른 학생들도 화남, 나라가 뒤에 있다고 의심, 같이 싸우자)",
"event_419_t4_assignment": "4월 19일, 서울에서 아주 큰 시위가 일어나서 대통령이 사는 경무대로 가고 있어요. 얼마나 많은 사람들이 모였는지, 뭘 원하는지, 경찰은 어떻게 하는지(총을 쏘는지 포함), 다치거나 죽은 사람은 없는지 빨리 알려야 해요. 아주 위험하니까 조심 또 조심하세요!",
"event_419_t4_source": "[알아두면 좋아요] 고려대 학생들이 맞은 일 때문에 서울에 있는 대학생, 중고등학생, 어른들까지 거리로 나와서 '이승만 대통령 물러나라!', '나쁜 선거 다시 하자!' 외치면서 경무대로 가고 있어요. 경찰은 최루탄이랑 소방차로 막고 있지만 사람들이 너무 많아요.",
"action_419_t4_opt1_text": "경무대 근처 시위대 맨 앞에 가서 직접 보기 (아주 위험!)",
"action_419_t4_opt2_text": "안전한 건물 위에서 시위 전체 모습과 경찰 행동 살피기",
"action_419_t4_opt3_text": "병원 응급실에 가서 다치거나 죽은 사람 있는지 알아보기",
"info_419_t4_opt1_got": "새로운 사실: 시위대가 경찰 막는 걸 뚫고 경무대로 가려고 해요. 경찰이 시위대한테 마구 총을 쏘기 시작했어요! 눈앞에서 학생들이 피 흘리며 쓰러져요. 너무 무서운 현장이에요. (힌트: 경무대에서 총쏨, 마구 쏨, 학생들 죽음, 끔찍함)",
"info_419_t4_opt2_got": "새로운 사실: 수만 명의 사람들이 태평로와 광화문을 꽉 채웠어요. 경찰이 최루탄이랑 진짜 총알을 쏘는 걸 봤어요. 길거리가 전쟁터 같아요. (힌트: 아주 큰 시위, 경찰이 진짜 총쏨, 전쟁터 같음)",
"info_419_t4_opt3_got": "새로운 사실: 세브란스 병원 응급실에 총 맞은 사람들로 가득해요. 죽은 사람도 많아요. 의사 선생님들이 바쁘게 움직이지만 사람이 너무 많아요. '학생들이 죽어가고 있어요!' 하고 소리쳐요. (힌트: 총 맞은 환자, 많이 죽음, 병원도 힘듦, 의사 부족)",
"event_419_t5_assignment": "정부가 서울이랑 다른 큰 도시에 '비상계엄'을 내렸어요. 군인들이 어디에 있는지, 사람들은 어떻게 생각하는지, 계엄령 아래서 신문이나 방송은 어떻게 되는지 알아보세요.",
"event_419_t5_source": "[알아두면 좋아요] 4.19 시위가 너무 커지니까 정부가 4월 19일 오후 5시에 서울에 비상계엄을 내리고 군인들을 보냈어요. 그 후 부산, 대구, 광주 같은 큰 도시에도 계엄령이 내려졌어요. 계엄사령부는 모이거나 시위하는 걸 금지하고, 신문 기사도 미리 검사한다고 했어요.",
"action_419_t5_opt1_text": "시내 중요 장소에 군인들이 있는지, 사람들 지나가는 거 검사하는지 보기",
"action_419_t5_opt2_text": "계엄령 아래 있는 사람들 이야기 듣기 (무서워도 싸우고 싶은 마음)",
"action_419_t5_opt3_text": "계엄사령부에 가서 신문 기사 어떻게 검사하는지 알아보기",
"info_419_t5_opt1_got": "새로운 사실: 탱크랑 장갑차를 탄 군인들이 길이랑 중요한 건물들을 지키고 있어요. 사람들이 마음대로 못 다니게 하고, 어떤 곳에서는 학생들을 막 잡아갔어요. (힌트: 군인이 도시 장악, 탱크 장갑차, 못 다니게 함, 강제로 잡아감)",
"info_419_t5_opt2_got": "새로운 사실: 어떤 아저씨가 말했어요. '군인들이 총 들고 다니니까 무섭지만, 이렇게 나쁜 정치를 그냥 둘 수는 없어요. 기회가 되면 다시 시위할 거예요.' (힌트: 계엄령 속 사람들 마음, 무섭지만 싸우고 싶음, 나쁜 정치 싫음)",
"info_419_t5_opt3_got": "새로운 사실: 계엄사령부에서 말했어요. '나라를 안전하게 하려고 신문 내용을 미리 검사할 거예요. 거짓 소문 퍼뜨리면 혼내줄 거예요.' 사실상 정부가 시키는 대로만 써야 해요. (힌트: 신문 검사, 정부 말만 쓰게 함, 계엄사령부, 정보 막음)",
"event_419_t6_assignment": "4월 25일, 전국 대학교수님들이 '우리도 할 말이 있다!' 하면서 거리로 나왔어요. 교수님들이 뭘 원하는지, 얼마나 많이 모였는지, 정부랑 사람들은 어떻게 생각하는지 알아보세요.",
"event_419_t6_source": "[알아두면 좋아요] 학생들이 피 흘리는 걸 보고 똑똑한 어른들도 화가 났어요. 서울대학교 교수님들을 시작으로 전국 27개 대학교 258명의 교수님들이 '학생들의 피에 보답하라!' 하면서 이승만 대통령 물러나고 정부도 다 그만두라고 외치며 거리로 나왔어요. 이건 정부에게 큰 충격이었어요.",
"action_419_t6_opt1_text": "교수님들 시위하는 곳(국회의사당 앞 등)에 같이 가보기",
"action_419_t6_opt2_text": "시위 이끄는 교수님 만나서 왜 하는지, 뭘 원하는지 듣기",
"action_419_t6_opt3_text": "사람들이 교수님들 시위 응원하는 모습 보기",
"info_419_t6_opt1_got": "새로운 사실: 수백 명의 교수님들이 '이승만 물러나라', '민주주의 지키자' 같은 글을 들고 조용히 걸었어요. 사람들은 박수치고 응원했어요. 경찰도 전보다 덜 막았어요. (힌트: 교수님들 시위, 이승만 물러나라고 함, 사람들 응원, 조용한 시위)",
"info_419_t6_opt2_got": "새로운 사실: 서울대 K교수님이 말했어요. '더 이상 나쁜 일을 보고만 있을 수 없었어요. 이 대통령은 빨리 물러나고, 민주주의를 다시 찾아야 해요.' (힌트: 교수님들 생각, 나쁜 일 못 참음, 민주주의 되찾자)",
"info_419_t6_opt3_got": "새로운 사실: 시위 보던 어떤 아줌마가 울면서 말했어요. '교수님들까지 나오시니 이제 정말 이 정권 끝났어요. 우리 학생들, 사람들 힘내요!' (힌트: 사람들 감동, 교수님들 응원, 정권 끝날 것 같음)",
"event_419_t7_assignment": "미국 정부가 지금 우리나라 상황이 걱정된다면서 이승만 대통령에게 중요한 결정을 하라고 했다는 소문이 있어요. 이승만 대통령 마음이 어떻게 변했는지, 정말 물러날 건지, 자유당 사람들은 어떻게 움직이는지 빨리 알아보세요.",
"event_419_t7_source": "[알아두면 좋아요] 4.19 혁명이 커지니까 미국 정부가 우리나라에 있는 미국 대사를 통해 이승만 대통령에게 사실상 물러나라고 했어요. 외국에서도 외면받고, 나라 안에서도 사람들이 계속 반대하니까 이 대통령은 아주 중요한 결정을 해야 해요.",
"action_419_t7_opt1_text": "경무대 근처에서 대통령 주변 사람들 어떻게 하는지 보기",
"action_419_t7_opt2_text": "자유당 높은 사람들 만나서 당 분위기랑 앞으로 어떻게 할 건지 듣기",
"action_419_t7_opt3_text": "미국 대사관 근처에서 미국 생각이 바뀌었는지 알아보기",
"info_419_t7_opt1_got": "새로운 사실: 경무대에서 일하는 사람이 몰래 말해줬어요. '대통령님이 며칠 동안 잠도 못 자고 깊이 고민하고 계세요. 곧 아주 중요한 발표가 있을 거라는 소문이 많아요.' (힌트: 이승만 대통령 고민, 중요한 발표 곧 할 듯, 경무대 분위기 심각)",
"info_419_t7_opt2_got": "새로운 사실: 자유당 국회의원 M아저씨가 말했어요. '이미 끝났어요. 대통령님이 멋있게 물러나시는 게 유일한 방법이에요. 우리 당 안에서도 물러나시라고 말해야 한다는 목소리가 커지고 있어요.' (힌트: 자유당도 물러나라고 함, 멋있게 그만두길 바람, 당 안에서도 의견 갈림)",
"info_419_t7_opt3_got": "새로운 사실: 미국 대사관 사람이 몰래 말해줬어요. '미국 정부는 한국이 다시 민주주의를 찾고, 평화롭게 정권이 바뀌길 바라요. 지금 상황이 계속되는 건 좋지 않아요.' (힌트: 미국 정부 생각, 민주주의 되찾길 바람, 평화롭게 바뀌길 바람)",
"event_419_t8_assignment": "4월 26일, 이승만 대통령이 물러나겠다고 발표했어요! 대통령이 뭐라고 말했는지, 사람들은 어떤 반응인지, 앞으로 나라는 어떻게 될지 다 합쳐서 특별 기사를 써야 해요. (이번엔 취재 활동 없이 바로 기사 쓰기로 가요.)",
"event_419_t8_source": "[긴급 뉴스] 이승만 대통령, 국민들이 원해서 대통령 자리에서 물러나겠다고 발표. 라디오로 이야기했어요. 사람들이 거리로 나와서 기뻐하고 있어요. 12년 동안 계속된 자유당 정치가 끝났어요.",
"action_419_t8_opt1_text": "대통령이 물러나면서 한 말 자세히 보기",
"action_419_t8_opt2_text": "사람들이 기뻐하는 모습과 이야기 듣기",
"action_419_t8_opt3_text": "정치인들과 똑똑한 사람들이 앞으로 어떻게 될지 이야기하는 것 듣기",
"info_419_t8_opt1_got": "새로운 사실: 이승만 대통령이 물러나면서 한 말 전문을 구했어요. '국민이 원하면 대통령 그만두겠다', '3.15 선거는 잘못됐으니 다시 하라고 했다', '나라 다스리는 방법도 바꾸겠다' 같은 내용이 있었어요. (힌트: 이승만 대통령 물러남, 국민 뜻 따름, 나쁜 선거 인정, 정치 방식 바꿈)",
"info_419_t8_opt2_got": "새로운 사실: 서울 길거리에 사람들이 뛰쳐나와 '나쁜 정치 끝났다, 민주주의 이겼다!' 외치면서 서로 껴안고 울었어요. 자동차들이 빵빵거리며 축제 분위기였어요. (힌트: 사람들 기뻐함, 민주주의 승리, 축제 분위기, 나쁜 정치 끝)",
"info_419_t8_opt3_got": "새로운 사실: 정치학자 P교수님이 말했어요. '허정 아저씨가 잠깐 나라를 맡고, 곧 국회의원 선거를 다시 할 것 같아요. 민주당이 중심이 돼서 나라를 다스릴 가능성이 높아요. 하지만 좀 시끄럽고 사람들이 원하는 게 많아질 수도 있어요.' (힌트: 허정 아저씨가 임시로 맡음, 다시 선거, 민주당 중심 정치, 좀 시끄러울 수도 있음)",
# --- 5.18 광주 취재 시나리오 ---
"scenario_5.18_gwangju_name": "5.18 광주 이야기 (1980년)",
"event_518_t1_assignment": "5월 17일 밤부터 '비상계엄'이 전국으로 커졌어요. 광주 분위기는 어떤지, 중요한 사람들(학생 대표, 숨어있는 어른들)은 어떻게 움직이는지, 군인들은 뭘 하는지 알아보고 알려주세요. 신문이나 방송을 못 믿게 하니까 몰래 조심해서 취재해야 해요.",
"event_518_t1_source": "[알아두면 좋아요] 10.26 사건 뒤에 '서울의 봄'이라고 해서 좋은 세상이 올 것 같았지만, 새로운 군인 아저씨들이 12.12 군사반란으로 힘을 잡으면서 다시 무서워졌어요. 새 군인들은 나라가 시끄럽다면서 비상계엄을 전국으로 넓히고, 김대중, 김영삼 같은 유명한 정치인들을 잡아가거나 못 나오게 했어요. 광주 대학교에서는 학생들이 시위하려는 움직임이 보여요.",
"action_518_t1_opt1_text": "전남대학교 같은 대학교 학생회관 근처에서 이야기 들어보기",
"action_518_t1_opt2_text": "광주 시내 큰 길이나 중요한 건물에 군인들이 있는지 확인하기",
"action_518_t1_opt3_text": "광주에 사는 숨어있는 어른이나 종교 지도자 몰래 만나보기",
"info_518_t1_opt1_got": "새로운 사실: 전남대 학생 대표들이 '계엄 확대는 나쁜 짓이다!' 하면서 내일(18일) 아침에 학교에서 시위할 계획이래요. '학교 문 닫지 마라, 계엄령 없애라!' 외칠 준비를 하고 있어요. (힌트: 전남대 학생 시위 예고, 계엄 반대, 학교 문 열라고 함)",
"info_518_t1_opt2_got": "새로운 사실: 광주역, 버스터미널, 도청 같은 중요한 곳에 무서운 무기를 든 공수부대 군인들이 나타나기 시작했어요. 사람들은 무서워하고 불안해해요. (힌트: 공수부대 나타남, 무섭게 지킴, 사람들 불안)",
"info_518_t1_opt3_got": "새로운 사실: 이름을 밝히기 싫어하는 종교 지도자가 한숨 쉬며 말했어요. '새 군인들이 자기들 마음대로 하려고 사람들을 아주 심하게 혼내줄 것 같아요. 광주가 큰일 날까 봐 걱정돼요.' (힌트: 새 군인들 무섭게 할 듯, 광주 걱정, 종교 어른 생각)",
"event_518_t2_assignment": "5월 18일 아침, 전남대학교 앞에서 학생들과 군인들이 처음으로 싸웠어요. 왜 싸움이 났는지, 어떻게 싸웠는지, 학생들과 군인들은 얼마나 다쳤는지, 다른 사람들은 어떻게 생각하는지 빨리 알아보세요. 현장에 갈 땐 아주 조심해야 해요!",
"event_518_t2_source": "[알아두면 좋아요] 어제(17일) 비상계엄이 전국으로 커지면서 대학교 문을 닫으라고 했지만, 전남대 학생들은 반대하면서 학교 문 앞에서 시위를 했어요. 계엄군(공수부대)은 이걸 아주 세게 막기 시작했어요.",
"action_518_t2_opt1_text": "전남대학교 정문 앞 시위 현장에 직접 가보기 (아주 위험!)",
"action_518_t2_opt2_text": "다친 학생들이 간 근처 병원에 가서 얼마나 다쳤는지 알아보기",
"action_518_t2_opt3_text": "현장 근처 가게 주인이나 동네 사람들한테 본 이야기 듣기",
"info_518_t2_opt1_got": "새로운 사실: 공수부대 군인들이 학교 문으로 들어가려는 학생들을 몽둥이로 마구 때리고 군홧발로 찼어요. 여자든 남자든 가리지 않고 때렸어요. 학생들이 피 흘리며 쓰러지고 끌려가는 걸 봤어요. (힌트: 공수부대 너무 심하게 때림, 마구 때림, 학생들 다침, 전남대 정문)",
"info_518_t2_opt2_got": "새로운 사실: 병원 응급실에 머리나 뼈를 다친 학생들로 가득해요. 한 학생은 '그냥 학교에 들어가려고 했는데, 군인들이 갑자기 몽둥이로 때렸어요!' 하면서 울었어요. (힌트: 학생들 많이 다침, 병원 응급실, 군인이 때렸다고 함)",
"info_518_t2_opt3_got": "새로운 사실: 근처 가게 주인이 화내면서 말했어요. '학생들이 뭘 그렇게 잘못했다고 저렇게까지 때리나. 이건 너무 심해요. 군인이 아니라 깡패 같아요!' (힌트: 사람들 화남, 군인들 나쁘다고 함, 너무 심하게 막는 거 봄)",
"event_518_t3_assignment": "학생들 시위가 광주 시내 전체로 퍼지고 있어요. 일반 시민들도 함께하고 있어요. 하지만 공수부대 군인들이 더 잔인하게 사람들을 때리고 잡아가고 있다는 소문이 들려요. 이 상황을 자세히 취재해주세요. 정말 위험하니 몸조심하세요!",
"event_518_t3_source": "[알아두면 좋아요] 전남대 앞에서 시작된 군인들의 폭력은 오히려 시민들의 분노를 키웠어요. 학생들뿐만 아니라 일반 시민들도 거리로 나와 '계엄 철폐', '살인마 전두환 물러가라' 등을 외치고 있어요. 공수부대는 시위대뿐 아니라 길 가던 사람들에게도 폭력을 행사하고 있다는 목격담이 나오고 있어요.",
"action_518_t3_opt1_text": "금남로 등 시위가 격렬한 곳으로 가서 상황 보기 (매우 위험!)",
"action_518_t3_opt2_text": "시위에 참여한 시민들 이야기 들어보기 (왜 나왔는지, 뭘 봤는지)",
"action_518_t3_opt3_text": "군인들에게 맞거나 끌려간 사람들의 가족 만나보기",
"info_518_t3_opt1_got": "새로운 사실: 금남로에서 군인들이 곤봉과 대검으로 사람들을 마구 찌르고 때리고 있어요. 길바닥에 피가 흥건하고, 비명소리가 끊이지 않아요. 젊은이, 노인 가리지 않아요. (힌트: 금남로, 군인들 잔인함, 피, 비명)",
"info_518_t3_opt2_got": "새로운 사실: 한 아주머니가 울면서 말했어요. '내 아들이 학생도 아닌데 길 가다가 군인들에게 끌려갔어요! 살려주세요!' 많은 시민들이 군인들의 만행에 치를 떨고 있어요. (힌트: 시민들 분노, 아무나 잡아감, 군인 만행)",
"info_518_t3_opt3_got": "새로운 사실: 군인에게 맞아서 다리가 부러진 아저씨를 만났어요. '그냥 집에 가던 길이었는데, 갑자기 군인 서너 명이 달려들어 때렸어요. 이유도 없었어요.' (힌트: 무차별 폭행, 이유 없는 폭력, 시민 피해)",
"event_518_t4_assignment": "군인들의 폭력이 너무 심해지자, 일부 시민들이 스스로를 지키기 위해 무기를 들기 시작했다는 소식이 있어요. '시민군'이 만들어졌다는 말도 들려요. 광주 상황이 어떻게 변하고 있는지, 시민들은 왜 무기를 들었는지 알아보세요.",
"event_518_t4_source": "[알아두면 좋아요] 계엄군의 무자비한 살상 행위에 맞서 시민들은 더 이상 맨손으로 저항할 수 없다고 판단하기 시작했어요. 경찰서나 예비군 무기고에서 총기 등을 확보하고, 스스로를 '시민군'이라 부르며 조직적으로 저항하려는 움직임이 나타나고 있어요. 광주는 외부와 완전히 차단된 상태예요.",
"action_518_t4_opt1_text": "시민군이 모여 있다는 곳(도청 주변 등)에 조심스럽게 접근해보기",
"action_518_t4_opt2_text": "무기를 든 시민에게 왜 그랬는지, 앞으로 뭘 할 건지 물어보기",
"action_518_t4_opt3_text": "광주 시내 병원에 가서 총상 환자가 있는지, 의료 상황은 어떤지 확인하기",
"info_518_t4_opt1_got": "새로운 사실: 도청 주변에 젊은이들이 총을 들고 모여 있어요. 스스로를 '시민군'이라고 부르며, '계엄군으로부터 광주를 지키겠다'고 외치고 있어요. 분위기가 아주 긴장돼요. (힌트: 시민군 등장, 도청, 총 든 시민, 광주 지키기)",
"info_518_t4_opt2_got": "새로운 사실: 총을 든 한 청년이 말했어요. '우리 가족과 친구들이 군인들에게 맞아 죽는 걸 더는 볼 수 없었어요. 우리도 살기 위해 싸우는 거예요!' (힌트: 시민군 된 이유, 가족 보호, 살기 위한 싸움)",
"info_518_t4_opt3_got": "새로운 사실: 병원에 총 맞은 사람들이 계속 실려오고 있어요. 의사, 간호사, 약품 모두 부족해요. '제발 도와주세요!' 하는 소리가 들려요. (힌트: 총상 환자 많음, 병원 부족, 도움 필요)",
"event_518_t5_assignment": "계엄군이 잠시 광주 외곽으로 물러나고, 시민들이 광주를 스스로 다스리고 있다는 소식이 있어요. 이 짧은 '해방 광주' 기간 동안 시민들은 어떻게 지내고 있는지, 질서는 잘 지켜지는지, 앞으로 뭘 걱정하는지 취재해주세요.",
"event_518_t5_source": "[알아두면 좋아요] 시민들의 거센 저항에 밀려 계엄군이 5월 21일 광주 시내에서 철수했어요. 이후 며칠간 시민들은 스스로 질서를 유지하며 식량과 생필품을 나누고, 부상자를 돌봤어요. 하지만 계엄군이 다시 공격해올 거라는 불안감도 컸어요.",
"action_518_t5_opt1_text": "시민들이 모여 회의하는 곳(도청 광장 등)에 가보기",
"action_518_t5_opt2_text": "시민들에게 지금 생활이 어떤지, 뭘 가장 바라는지 물어보기",
"action_518_t5_opt3_text": "식량이나 물건을 나눠주는 곳에 가서 시민들 돕는 모습 보기",
"info_518_t5_opt1_got": "새로운 사실: 도청 광장에서 시민들이 모여 앞으로 어떻게 할지 이야기하고 있어요. '우리의 요구를 정부에 알려야 한다', '끝까지 싸우자' 같은 목소리가 나와요. (힌트: 시민 회의, 도청 광장, 요구 전달, 계속 싸우자)",
"info_518_t5_opt2_got": "새로운 사실: 한 상인이 말했어요. '군인들이 없으니 잠시 평화롭지만, 언제 다시 쳐들어올지 몰라 무서워요. 제발 이 일이 빨리 해결됐으면 좋겠어요.' (힌트: 잠시 평화, 다시 공격 걱정, 빨리 해결되길 바람)",
"info_518_t5_opt3_got": "새로운 사실: 아주머니들이 주먹밥을 만들어서 시민군과 배고픈 사람들에게 나눠주고 있어요. 서로 돕고 아끼는 모습이 감동적이에요. (힌트: 시민들 서로 도움, 주먹밥 나눔, 감동적)",
"event_518_t6_assignment": "계엄군이 다시 광주로 쳐들어올 거라는 소문이 파다해요. 시민들은 마지막까지 싸울 준비를 하고 있는 것 같아요. 도청을 중심으로 한 시민군의 상황과 광주 전체의 긴장된 분위기를 전해주세요. 매우 위험한 상황입니다.",
"event_518_t6_source": "[알아두면 좋아요] '해방 광주'는 오래가지 못했어요. 신군부는 대규모 병력을 동원해 광주를 다시 점령할 계획을 세웠어요. 시민들은 이 사실을 알고 있었지만, 많은 이들이 끝까지 남아 광주를 지키려 했어요. 외부와의 통신은 거의 끊긴 상태예요.",
"action_518_t6_opt1_text": "도청 주변 시민군들의 마지막 방어 준비 모습 살펴보기 (극도로 위험!)",
"action_518_t6_opt2_text": "남아있는 시민들에게 왜 떠나지 않았는지, 심정이 어떤지 듣기",
"action_518_t6_opt3_text": "외신기자나 외부와 연락하려는 사람들을 찾아보기",
"info_518_t6_opt1_got": "새로운 사실: 도청 주변에 시민군들이 바리케이드를 쌓고 무기를 점검하고 있어요. 표정은 굳어있지만, 눈빛은 결연해요. '광주는 우리가 지킨다!'는 말이 들려요. (힌트: 도청 방어 준비, 시민군 결의, 마지막 저항)",
"info_518_t6_opt2_got": "새로운 사실: 어린 학생 시민군이 말했어요. '무섭지만 도망가지 않을 거예요. 여기서 죽더라도 광주를 지키고 싶어요.' 많은 사람들이 비장한 각오를 하고 있어요. (힌트: 남은 시민들 각오, 두려움과 용기, 광주 지키기)",
"info_518_t6_opt3_got": "새로운 사실: 광주의 진실을 알리려는 일부 시민들이 몰래 외부로 편지나 사진을 보내려고 애쓰고 있어요. 하지만 군인들이 철저히 막고 있어서 쉽지 않아 보여요. (힌트: 진실 알리기 노력, 외부 연락 시도, 군인 통제)",
"event_518_t7_assignment": "5월 27일 새벽, 결국 계엄군이 탱크를 앞세우고 도청으로 쳐들어왔어요. 마지막까지 저항하던 시민군과 계엄군 사이에 큰 전투가 벌어지고 있어요. 이 비극적인 상황을 기록해야 합니다. 안전을 최우선으로 하세요.",
"event_518_t7_source": "[알아두면 좋아요] 5월 27일 새벽, 계엄군은 '상무충정작전'이라는 이름으로 전남도청을 무력으로 점령했어요. 도청을 사수하던 많은 시민군이 이 과정에서 희생되었어요. 이로써 열흘간의 광주민주화운동은 비극적으로 막을 내리게 됩니다.",
"action_518_t7_opt1_text": "도청 근처 안전한 곳에서 총소리와 상황 파악하기 (매우 위험!)",
"action_518_t7_opt2_text": "진압 작전 후 거리 모습과 시민들 반응 살피기",
"action_518_t7_opt3_text": "병원으로 실려 오는 부상자나 사망자 상황 확인하기",
"info_518_t7_opt1_got": "새로운 사실: 새벽부터 도청 쪽에서 총소리가 쉴 새 없이 들려요. 탱크 소리도 들리고, 하늘에는 헬리콥터가 날아다녀요. 마치 전쟁터 같아요. (힌트: 도청 진압, 총소리, 탱크, 전쟁터)",
"info_518_t7_opt2_got": "새로운 사실: 날이 밝자 군인들이 도청을 완전히 장악했어요. 거리에는 군인들만 보이고, 시민들은 두려움에 떨며 숨어있어요. 광주 전체가 슬픔과 절망에 빠졌어요. (힌트: 군인들 도청 장악, 시민들 공포, 슬픔과 절망)",
"info_518_t7_opt3_got": "새로운 사실: 병원에는 새벽 전투로 다치거나 죽은 시민군들이 계속 들어오고 있어요. 가족들의 울음소리가 끊이지 않아요. 너무나 많은 희생자가 나왔어요. (힌트: 많은 사상자, 병원 비상, 가족들 슬픔)",
"event_518_t8_assignment": "광주에서의 큰 싸움은 끝났지만, 슬픔과 아픔은 계속되고 있어요. 살아남은 사람들의 이야기, 숨겨진 진실, 그리고 앞으로 광주가 어떻게 될지 마지막으로 취재해서 알려주세요.",
"event_518_t8_source": "[알아두면 좋아요] 5.18 광주민주화운동은 비록 군인들에게 진압되었지만, 이후 한국 민주주의 발전에 큰 영향을 주었어요. 하지만 오랫동안 진실이 제대로 알려지지 않아 많은 사람들이 아픔을 겪었어요.",
"action_518_t8_opt1_text": "희생자 가족이나 살아남은 시민군을 만나 이야기 듣기",
"action_518_t8_opt2_text": "군인들이 숨기려는 이야기나 증거 찾아보기",
"info_518_t8_opt1_got": "새로운 사실: 아들을 잃은 어머니가 말했어요. '내 아들은 나쁜 사람이 아니었어요. 옳은 일을 하다가 죽었어요. 제발 잊지 말아 주세요.' 많은 사람들이 억울함과 슬픔을 안고 살아가고 있어요. (힌트: 남은 가족들 슬픔, 억울함, 잊지 말아달라는 부탁)",
"info_518_t8_opt2_got": "새로운 사실: 군인들이 시민들을 몰래 묻었다는 소문이 있어요. 정부는 사망자 수를 줄여서 발표하고, 진실을 숨기려고 해요. 사람들은 언젠가 모든 것이 밝혀지길 바라고 있어요. (힌트: 숨겨진 진실, 정부의 은폐, 진실 규명 바람)",
# --- 6월 항쟁 취재 시나리오 ---
"scenario_june_struggle_name": "6월 항쟁 이야기 (1987년)",
"event_june_t1_assignment": "서울대학교 학생 박종철 군이 경찰 조사를 받다가 죽었어요. 경찰은 '책상을 탁 치니 억 하고 죽었다'고 이상하게 말했지만, 고문으로 죽었다는 의심이 커지고 있어요. 이 사건의 진짜 이유와 사람들의 반응을 알아보세요.",
"event_june_t1_source": "[알아두면 좋아요] 1987년 1월 14일, 박종철 학생은 경찰서(남영동 대공분실)에서 조사를 받다가 죽었어요. 경찰이 이상하게 설명해서 사람들이 많이 화가 났고, 진짜 이유를 밝히라는 목소리가 커지고 있어요. 전두환 대통령 정부에게 큰 문제가 될 것 같아요.",
"action_june_t1_opt1_text": "사건 담당 경찰서나 치안본부 근처에서 경찰들 이야기 몰래 듣기",
"action_june_t1_opt2_text": "박종철 학생 가족이나 서울대학교 친구들 만나보기",
"action_june_t1_opt3_text": "의사 선생님 중 박종철 학생 몸을 살펴본 분 몰래 만나보기 (왜 죽었는지)",
"info_june_t1_opt1_got": "새로운 사실: 치안본부에서 일하는 사람이 몰래 말해줬어요. '높은 사람이 이 사건 빨리 덮으라고 시켰어요. 그냥 놀라서 죽었다고 하래요.' (힌트: 경찰 윗사람 지시, 사건 숨기려 함, 놀라서 죽었다고 거짓말)",
"info_june_t1_opt2_got": "새로운 사실: 박종철 학생 아버지가 울면서 말했어요. '철아, 잘 가거라... 아빠는 할 말이 없다...' 친구들은 '고문해서 죽인 사람 벌주세요!' 하면서 화를 냈어요. (힌트: 박종철 가족 슬픔, 고문해서 죽였다고 화냄, 학생들 분노)",
"info_june_t1_opt3_got": "새로운 사실: 박종철 학생 몸을 본 의사 선생님이 조심스럽게 말했어요. '목에 눌린 자국이 있고 폐에서 이상한 소리가 났어요. 그냥 놀라서 죽은 것 같지 않아요. 물고문했을 수도 있어요.' (힌트: 의사 선생님 증언, 물고문 의심, 경찰 말과 다름)",
"event_june_t2_assignment": "전두환 대통령이 '지금 헌법(대통령을 직접 뽑지 않는 법)을 바꾸지 않겠다'는 '4.13 호헌 조치'를 발표했어요. 많은 사람들이 대통령을 직접 뽑고 싶어 했는데, 이 발표 때문에 더 화가 난 것 같아요. 사람들의 반응과 앞으로 시위가 더 커질지 알아보세요.",
"event_june_t2_source": "[알아두면 좋아요] 박종철 학생 사건으로 민주주의를 원하는 목소리가 커졌지만, 전두환 대통령은 4월 13일에 헌법을 고치지 않겠다고 발표했어요. 이건 국민들의 바람을 무시하는 거라서, 학생, 종교인, 일반 시민들까지 모두 크게 반발하고 있어요.",
"action_june_t2_opt1_text": "대학교에 가서 학생들 반응과 시위 계획 알아보기",
"action_june_t2_opt2_text": "종교 단체나 숨어서 활동하는 민주화 운동가들 만나보기",
"action_june_t2_opt3_text": "길거리에서 일반 시민들에게 '호헌 조치'에 대해 어떻게 생각하는지 물어보기",
"info_june_t2_opt1_got": "새로운 사실: 대학교 학생들이 '독재 타도! 직선제 쟁취!' 같은 구호를 외치며 시위를 준비하고 있어요. '더 이상 참을 수 없다'며 격렬하게 싸울 거라고 해요. (힌트: 학생들 분노, 직선제 요구, 큰 시위 예고)",
"info_june_t2_opt2_got": "새로운 사실: 한 신부님이 말했어요. '정부가 국민의 목소리를 듣지 않으니, 우리가 직접 나서서 민주주의를 되찾아야 합니다. 모든 양심 있는 사람들이 힘을 합칠 것입니다.' (힌트: 종교계 반발, 민주주의 되찾기, 힘 합치자)",
"info_june_t2_opt3_got": "새로운 사실: 시장에서 만난 아주머니가 말했어요. '대통령을 내 손으로 뽑고 싶은데, 왜 못하게 하는지 모르겠어요. 너무 답답해요.' 많은 사람들이 실망하고 화가 나 있어요. (힌트: 시민들 실망, 직선제 바람, 답답함)",
"event_june_t3_assignment": "6월 9일, 연세대학교에서 시위하던 이한열 학생이 경찰이 쏜 최루탄에 머리를 맞아 쓰러졌어요. 지금 아주 위독하다고 해요. 이 사건 때문에 사람들이 더 크게 분노하고 있어요. 사건 현장 상황과 학생들, 시민들 반응을 긴급히 취재해주세요.",
"event_june_t3_source": "[알아두면 좋아요] '4.13 호헌 조치' 이후 시위가 계속되던 중, 6월 9일 연세대 앞에서 이한열 학생이 경찰이 직격으로 쏜 최루탄에 맞아 의식을 잃었어요. 이 모습이 사진으로 알려지면서 국민들의 분노는 극에 달했고, 6월 항쟁이 전국적으로 확산되는 결정적인 계기가 되었어요.",
"action_june_t3_opt1_text": "이한열 학생이 쓰러진 연세대 앞 시위 현장 가보기 (위험!)",
"action_june_t3_opt2_text": "이한열 학생이 입원한 병원에 가서 상태 알아보고 학생들 만나보기",
"action_june_t3_opt3_text": "다른 대학교나 명동성당 등 시위가 예상되는 곳 분위기 살피기",
"info_june_t3_opt1_got": "새로운 사실: 연세대 앞은 전쟁터 같아요. 학생들이 돌을 던지고, 경찰은 최루탄을 마구 쏘고 있어요. 이한열 학생이 쓰러졌던 자리에는 아직도 핏자국이 남아있어요. (힌트: 연세대 시위 격렬, 최루탄 난사, 이한열 학생 피격 현장)",
"info_june_t3_opt2_got": "새로운 사실: 병원에서 만난 이한열 학생 친구들이 울면서 말했어요. '경찰이 한열이를 죽이려고 했어요! 이건 살인미수예요!' 학생은 의식이 없고 매우 위독한 상태라고 해요. (힌트: 이한열 학생 위독, 친구들 분노, 경찰 비판)",
"info_june_t3_opt3_got": "새로운 사실: 명동성당 주변에 학생들이 모여들고 있어요. '이한열을 살려내라!', '군부독재 물러가라!' 외치고 있어요. 내일(6월 10일) 아주 큰 시위가 있을 거라는 소문이 돌아요. (힌트: 명동성당 시위 준비, 이한열 살리자, 큰 시위 예고)",
"event_june_t4_assignment": "오늘 6월 10일, 전국에서 '박종철 고문살인 규탄 및 민주헌법 쟁취 국민대회'라는 아주 큰 시위가 열리고 있어요. 서울뿐 아니라 부산, 광주 등 다른 도시에서도 많은 사람들이 거리로 나왔다고 해요. 시위 규모와 모습, 경찰 대응, 그리고 '넥타이 부대'라고 불리는 회사원들 참여 모습 등을 취재해주세요.",
"event_june_t4_source": "[알아두면 좋아요] 이한열 학생 사건은 6월 10일로 예정되어 있던 국민대회에 기름을 부었어요. 전국 주요 도시에서 수십만 명의 학생과 시민들이 거리로 쏟아져 나와 '호헌 철폐', '독재 타도'를 외쳤어요. 특히 평범한 회사원들(넥타이 부대)까지 시위에 참여하면서 항쟁은 더욱 커졌어요.",
"action_june_t4_opt1_text": "서울 시청 앞이나 명동 등 주요 시위 현장 한복판에 가보기 (매우 위험!)",
"action_june_t4_opt2_text": "시위에 참여한 회사원(넥타이 부대) 만나서 이야기 듣기",
"action_june_t4_opt3_text": "지방 도시(부산, 대구, 광주 등) 특파원과 연락해 그곳 상황 알아보기",
"info_june_t4_opt1_got": "새로운 사실: 서울 시내가 온통 시위하는 사람들로 가득 찼어요! 경찰이 최루탄을 쏘며 막고 있지만, 사람들은 물러서지 않고 '독재 타도!'를 외치고 있어요. 여기저기서 싸움이 벌어지고 있어요. (힌트: 6.10 국민대회, 대규모 시위, 경찰과 충돌, 독재 타도)",
"info_june_t4_opt2_got": "새로운 사실: 양복 입은 회사원 아저씨가 말했어요. '더 이상 나라가 이렇게 되는 걸 보고만 있을 수 없어서 나왔습니다. 우리 아이들에게 부끄럽지 않은 나라를 만들어주고 싶어요.' (힌트: 넥타이 부대 참여, 민주주의 열망, 미래 세대 걱정)",
"info_june_t4_opt3_got": "새로운 사실: 부산 특파원이 알려왔어요. '부산역 광장에도 수만 명이 모여 시위를 벌이고 있습니다. 경찰과 격렬하게 대치 중이고, 부상자도 나오고 있습니다.' 전국이 들끓고 있어요. (힌트: 전국적 시위, 부산 상황, 지방도 뜨거움)",
"event_june_t5_assignment": "시위대 중 일부가 명동성당으로 들어가 농성을 시작했어요. 명동성당은 시위대에게 안전한 곳이 되어주고 있는 것 같아요. 성당 안팎의 분위기, 농성하는 사람들의 요구, 그리고 정부가 어떻게 나올지 사람들의 예상을 취재해주세요.",
"event_june_t5_source": "[알아두면 좋아요] 6월 항쟁 기간 동안 명동성당은 민주화 운동의 중요한 장소가 되었어요. 경찰의 폭력을 피해 많은 시위대가 성당으로 들어와 농성을 벌였고, 종교계는 이들을 보호했어요. 이는 정부에게 큰 부담을 주었어요.",
"action_june_t5_opt1_text": "명동성당 안으로 들어가 농성 중인 학생이나 시민들 만나보기",
"action_june_t5_opt2_text": "성당 밖에서 지지하는 시민들이나 성직자들 이야기 듣기",
"action_june_t5_opt3_text": "정부 관계자나 경찰 쪽에서 명동성당 상황을 어떻게 보고 있는지 알아보기",
"info_june_t5_opt1_got": "새로운 사실: 명동성당 안은 학생들과 시민들로 가득해요. 지쳤지만 눈빛은 살아있어요. '대통령 직선제 실시하라!', '민주정부 수립하자!' 같은 구호를 외치고 있어요. (힌트: 명동성당 농성, 직선제 요구, 민주정부 희망)",
"info_june_t5_opt2_got": "새로운 사실: 성당 밖에서 한 수녀님이 기도하며 말했어요. '저들이 평화롭게 자기 목소리를 낼 수 있도록, 그리고 아무도 다치지 않도록 기도하고 있어요. 정의가 이길 거예요.' (힌트: 성직자 지지, 평화 기원, 정의 승리 믿음)",
"info_june_t5_opt3_got": "새로운 사실: 경찰 관계자가 몰래 말했어요. '성당 안으로 함부로 들어갈 수가 없어서 골치 아파요. 하지만 계속 저렇게 둘 수는 없을 텐데...' 정부도 고민이 많은 것 같아요. (힌트: 경찰 고민, 성당 진입 어려움, 정부 압박감)",
"event_june_t6_assignment": "오늘은 '국민평화대행진'이 있는 날이에요. 전국적으로 100만 명이 넘는 사람들이 거리로 나올 거라고 해요. 특히 오늘은 경찰이 최루탄을 쏘지 않기로 했다는 소문도 있어요. 정말 평화로운 시위가 될지, 사람들의 열기는 어떨지 현장에서 확인해주세요.",
"event_june_t6_source": "[알아두면 좋아요] 6월 항쟁이 계속되면서 국민들의 민주화 요구는 더욱 거세졌어요. 6월 26일에는 전국 33개 도시에서 100만 명이 넘는 시민들이 참여하는 '국민평화대행진'이 계획되었어요. 정부도 더 이상 강경 대응만으로는 사태를 해결할 수 없다는 것을 느끼기 시작했어요.",
"action_june_t6_opt1_text": "서울 도심 평화대행진 행렬에 참여해서 시민들과 함께 걷기",
"action_june_t6_opt2_text": "정말 경찰이 최루탄을 사용하지 않는지, 시위 분위기는 어떤지 관찰하기",
"action_june_t6_opt3_text": "시위에 참여한 다양한 연령대의 사람들(어린이, 노인 등) 이야기 듣기",
"info_june_t6_opt1_got": "새로운 사실: 정말 많은 사람들이 거리로 나왔어요! 아이 손을 잡고 나온 가족, 나이 드신 할아버지 할머니까지 모두 함께 '민주주의'를 외치며 걷고 있어요. (힌트: 6.26 평화대행진, 엄청난 인파, 다양한 시민 참여)",
"info_june_t6_opt2_got": "새로운 사실: 신기하게도 오늘은 경찰이 최루탄을 쏘지 않아요! 시위는 아주 평화롭고 질서있게 진행되고 있어요. 마치 축제 같아요. 사람들은 노래도 부르고 춤도 춰요. (힌트: 최루탄 없는 날, 평화 시위, 축제 분위기)",
"info_june_t6_opt3_got": "새로운 사실: 한 초등학생이 아빠 목마를 타고 말했어요. '우리나라가 더 좋은 나라가 됐으면 좋겠어요!' 어른들은 이 모습을 보며 눈물을 글썽였어요. (힌트: 미래세대 희망, 감동적인 모습, 좋은 나라 염원)",
"event_june_t7_assignment": "오늘, 정부 여당의 노태우 대표가 갑자기 '6.29 선언'이라는 것을 발표했어요! 대통령 직선제를 받아들이고, 김대중 씨도 풀어주겠다는 등 놀라운 내용이 많다고 해요. 이 발표 내용과 사람들의 반응, 그리고 진짜로 민주주의가 올지 마지막으로 취재해주세요. (이번엔 취재 활동 없이 바로 기사 쓰기로 가요.)",
"event_june_t7_source": "[긴급 뉴스] 6월 29일, 민정당 노태우 대표가 국민들의 민주화 요구를 받아들여 대통령 직선제 개헌, 김대중 사면복권 등 8개 항목의 시국 수습 방안을 발표했어요. 이것은 사실상 국민들의 승리를 의미해요!",
"action_june_t7_opt1_text": "6.29 선언 내용 자세히 살펴보고 중요한 점 정리하기",
"action_june_t7_opt2_text": "거리로 나온 시민들의 기뻐하는 모습과 이야기 듣기",
"info_june_t7_opt1_got": "새로운 사실: 6.29 선언 내용을 보니, 대통령을 우리 손으로 직접 뽑고, 김대중 아저씨도 다시 정치할 수 있게 하고, 언론도 자유롭게 해준다는 약속이 들어있어요! (힌트: 6.29 선언, 대통령 직접 뽑기, 김대중 아저씨 자유, 언론 자유 약속)",
"info_june_t7_opt2_got": "새로운 사실: 사람들이 거리로 뛰쳐나와 '민주주의 만세!'를 외치며 서로 얼싸안고 기뻐하고 있어요. 자동차들은 경적을 울리고, 가게에서는 축하 음악이 흘러나와요. 드디어 이긴 것 같아요! (힌트: 시민들 환호, 민주주의 승리, 축제 분위기, 감격)",
"article_tone_fact_based": "진짜 있었던 일만 쓰기",
"article_tone_critical": "잘못된 점 콕콕 짚어 쓰기",
"article_tone_sympathetic": "슬프고 힘든 사람들 편에서 쓰기",
"article_tone_cautious": "조심조심, 생각 많이 하고 쓰기",
# [수정] 용어 사전 키를 시나리오 키와 일치하도록 변경 (예: 419 -> 4.19)
"glossary_4.19_revolution_free_party": "**자유당:** 옛날에 이승만 대통령을 도와주던 힘센 정당이었어요. 하지만 나쁜 일을 많이 해서 4.19 혁명 때 사람들이 싫어하게 됐어요.",
"glossary_4.19_revolution_315_election": "**3.15 부정선거:** 1960년에 대통령을 뽑는데, 자유당이 이기려고 반칙을 많이 한 선거예요. 이것 때문에 4.19 혁명이 일어났어요.",
"glossary_4.19_revolution_kimjuyeol": "**김주열:** 마산상고 학생이었는데, 3.15 부정선거 반대 시위하다가 경찰이 쏜 최루탄에 맞아 죽었어요. 이 일로 사람들이 더 많이 화가 났어요.",
"glossary_4.19_revolution_gyeongmudae": "**경무대:** 지금의 청와대 같은 곳인데, 옛날 대통령이 살던 집이에요. 4.19 혁명 때 시위대가 여기로 가다가 경찰이 총을 쏴서 많은 사람이 다쳤어요.",
"glossary_4.19_revolution_martial_law": "**계엄령:** 나라가 아주 위험할 때 군인들이 나와서 질서를 잡는 특별 명령이에요. 4.19 혁명 때 정부가 계엄령을 내렸어요.",
"glossary_5.18_gwangju_new_military": "**신군부:** 옛날에 군인 아저씨들이 힘을 합쳐서 나라를 마음대로 하려고 했던 그룹이에요. 전두환, 노태우 아저씨가 대표적이었죠.",
"glossary_5.18_gwangju_517_measure": "**5.17 비상계엄 전국 확대:** 신군부가 '나라가 위험하다!' 하면서 군인들 힘을 더 키우고, 사람들 못 모이게 하고, 학교도 닫게 한 조치예요. 이것 때문에 5.18 광주 이야기가 시작됐어요.",
"glossary_5.18_gwangju_paratroopers": "**공수부대:** 하늘에서 뛰어내리는 훈련을 받은 특별한 군인들이에요. 5.18 때 광주에 와서 사람들을 아주 심하게 대했어요.",
"glossary_5.18_gwangju_geumnamno": "**금남로:** 광주에서 가장 크고 중요한 길이에요. 5.18 때 여기서 많은 사람들이 모여 시위하고 군인들과 싸웠어요.",
"glossary_5.18_gwangju_citizens_army": "**시민군:** 5.18 때 군인들이 너무 심하게 하니까, 광주 시민들이 스스로를 지키려고 무기를 들고 싸운 사람들이에요.",
"glossary_5.18_gwangju_sangmuchungjeong": "**상무충정작전:** 5.18 마지막 날 새벽에 군인들이 광주 시내로 다시 쳐들어가서 시민군을 힘으로 누른 작전 이름이에요. 아주 슬픈 날이었죠.",
"glossary_june_struggle_parkjongchul": "**박종철:** 서울대학교 학생이었는데, 경찰한테 잡혀가서 고문을 받다가 죽었어요. '책상을 탁 치니 억 하고 죽었다'는 경찰 말이 거짓말인 게 밝혀져서 6월 항쟁이 시작되는 불씨가 됐어요.",
"glossary_june_struggle_413_measure": "**4.13 호헌 조치:** 전두환 대통령이 '대통령을 직접 뽑는 법으로 안 바꿀 거야!' 하고 발표한 거예요. 사람들이 엄청 화났어요.",
"glossary_june_struggle_leehanyeol": "**이한열:** 연세대학교 학생이었는데, 시위하다가 경찰이 쏜 최루탄에 머리를 맞아서 결국 죽었어요. 이한열 학생의 사진은 6월 항쟁을 보여주는 아주 유명한 사진이 됐어요.",
"glossary_june_struggle_610_rally": "**6.10 국민대회:** 1987년 6월 10일, 박종철 학생 사건의 진실을 밝히고 대통령을 직접 뽑게 해달라고 전국에서 아주 많은 사람들이 모여서 시위한 날이에요. 6월 항쟁이 본격적으로 시작된 날이죠.",
"glossary_june_struggle_myeongdong_cathedral": "**명동성당:** 서울 명동에 있는 아주 큰 성당인데, 6월 항쟁 때 시위하는 사람들이 경찰을 피해 숨기도 하고, 거기서 계속 싸우기도 했던 중요한 곳이에요.",
"glossary_june_struggle_necktie_brigade": "**넥타이 부대:** 6월 항쟁 때 시위에 참여한 회사원 아저씨들을 부르는 말이에요. 평범한 어른들도 함께 싸웠다는 걸 보여줘요.",
"glossary_june_struggle_629_declaration": "**6.29 선언:** 6월 항쟁이 너무 커지니까, 그때 정부 편이었던 노태우 아저씨가 '알겠다! 대통령 직접 뽑게 해주고, 민주주의를 위해 노력하겠다!' 하고 발표한 거예요. 사람들이 싸워서 이긴 거죠!",
}
# --- 어휘 조정 함수 (단순화) ---
def get_text(key, level="초등"):
return ALL_TEXTS.get(key, key)
# --- 게임 상태 초기화 (기자 컨셉) ---
def initialize_reporter_scenario_state(scenario_key):
scenario_settings = SCENARIOS[scenario_key]
get_text_func = lambda k: get_text(k)
return {
'scenario_key': scenario_key,
'player_role': scenario_settings['player_role'],
'current_turn': 1,
'max_turns': scenario_settings['max_turns'],
'game_year': scenario_settings['start_year'],
'status': {
'press_freedom': scenario_settings['initial_press_freedom'],
'article_score_total': 0,
'article_count': 0,
'reporter_safety': scenario_settings['initial_reporter_safety'],
'public_trust': scenario_settings['initial_public_trust'],
},
'reporter_notebook': [],
'submitted_articles': [],
'event_log': [f"{get_text_func(f'scenario_{scenario_key}_name')} ({scenario_settings['player_role']}) 취재 시작"],
}
# --- 역사 이벤트 데이터 (기자 컨셉) ---
HISTORICAL_ASSIGNMENTS = {
"4.19_revolution": [
{"turn": 1, "assignment_key": "event_419_t1_assignment", "source_key": "event_419_t1_source",
"options": [
{"action_key": "action_419_t1_opt1_text", "cost_freedom_risk": 10, "safety_risk": 20, "info_key": "info_419_t1_opt1_got"},
{"action_key": "action_419_t1_opt2_text", "cost_freedom_risk": 5, "safety_risk": 5, "info_key": "info_419_t1_opt2_got"},
{"action_key": "action_419_t1_opt3_text", "cost_freedom_risk": 5, "safety_risk": 10, "info_key": "info_419_t1_opt3_got"},
], "article_writing_phase": True},
{"turn": 2, "assignment_key": "event_419_t2_assignment", "source_key": "event_419_t2_source",
"options": [
{"action_key": "action_419_t2_opt1_text", "cost_freedom_risk": 15, "safety_risk": 25, "info_key": "info_419_t2_opt1_got"},
{"action_key": "action_419_t2_opt2_text", "cost_freedom_risk": 10, "safety_risk": 15, "info_key": "info_419_t2_opt2_got"},
{"action_key": "action_419_t2_opt3_text", "cost_freedom_risk": 20, "safety_risk": 10, "info_key": "info_419_t2_opt3_got"},
], "article_writing_phase": True},
{"turn": 3, "assignment_key": "event_419_t3_assignment", "source_key": "event_419_t3_source",
"options": [
{"action_key": "action_419_t3_opt1_text", "cost_freedom_risk": 10, "safety_risk": 20, "info_key": "info_419_t3_opt1_got"},
{"action_key": "action_419_t3_opt2_text", "cost_freedom_risk": 15, "safety_risk": 5, "info_key": "info_419_t3_opt2_got"},
{"action_key": "action_419_t3_opt3_text", "cost_freedom_risk": 5, "safety_risk": 10, "info_key": "info_419_t3_opt3_got"},
], "article_writing_phase": True},
{"turn": 4, "assignment_key": "event_419_t4_assignment", "source_key": "event_419_t4_source",
"options": [
{"action_key": "action_419_t4_opt1_text", "cost_freedom_risk": 25, "safety_risk": 35, "info_key": "info_419_t4_opt1_got"},
{"action_key": "action_419_t4_opt2_text", "cost_freedom_risk": 5, "safety_risk": 10, "info_key": "info_419_t4_opt2_got"},
{"action_key": "action_419_t4_opt3_text", "cost_freedom_risk": 10, "safety_risk": 15, "info_key": "info_419_t4_opt3_got"},
], "article_writing_phase": True},
{"turn": 5, "assignment_key": "event_419_t5_assignment", "source_key": "event_419_t5_source",
"options": [
{"action_key": "action_419_t5_opt1_text", "cost_freedom_risk": 10, "safety_risk": 15, "info_key": "info_419_t5_opt1_got"},
{"action_key": "action_419_t5_opt2_text", "cost_freedom_risk": 15, "safety_risk": 20, "info_key": "info_419_t5_opt2_got"},
{"action_key": "action_419_t5_opt3_text", "cost_freedom_risk": 20, "safety_risk": 5, "info_key": "info_419_t5_opt3_got"},
], "article_writing_phase": True},
{"turn": 6, "assignment_key": "event_419_t6_assignment", "source_key": "event_419_t6_source",
"options": [
{"action_key": "action_419_t6_opt1_text", "cost_freedom_risk": 5, "safety_risk": 10, "info_key": "info_419_t6_opt1_got"},
{"action_key": "action_419_t6_opt2_text", "cost_freedom_risk": 10, "safety_risk": 5, "info_key": "info_419_t6_opt2_got"},
{"action_key": "action_419_t6_opt3_text", "cost_freedom_risk": 5, "safety_risk": 5, "info_key": "info_419_t6_opt3_got"},
], "article_writing_phase": True},
{"turn": 7, "assignment_key": "event_419_t7_assignment", "source_key": "event_419_t7_source",
"options": [
{"action_key": "action_419_t7_opt1_text", "cost_freedom_risk": 10, "safety_risk": 10, "info_key": "info_419_t7_opt1_got"},
{"action_key": "action_419_t7_opt2_text", "cost_freedom_risk": 15, "safety_risk": 5, "info_key": "info_419_t7_opt2_got"},
{"action_key": "action_419_t7_opt3_text", "cost_freedom_risk": 5, "safety_risk": 5, "info_key": "info_419_t7_opt3_got"},
], "article_writing_phase": True},
{"turn": 8, "assignment_key": "event_419_t8_assignment", "source_key": "event_419_t8_source",
"options": [
{"action_key": "action_419_t8_opt1_text", "cost_freedom_risk": 0, "safety_risk": 0, "info_key": "info_419_t8_opt1_got"},
{"action_key": "action_419_t8_opt2_text", "cost_freedom_risk": 0, "safety_risk": 0, "info_key": "info_419_t8_opt2_got"},
{"action_key": "action_419_t8_opt3_text", "cost_freedom_risk": 0, "safety_risk": 0, "info_key": "info_419_t8_opt3_got"},
], "article_writing_phase": True, "is_final_turn_event": True},
],
"5.18_gwangju": [
{"turn": 1, "assignment_key": "event_518_t1_assignment", "source_key": "event_518_t1_source",
"options": [
{"action_key": "action_518_t1_opt1_text", "cost_freedom_risk": 15, "safety_risk": 25, "info_key": "info_518_t1_opt1_got"},
{"action_key": "action_518_t1_opt2_text", "cost_freedom_risk": 10, "safety_risk": 20, "info_key": "info_518_t1_opt2_got"},
{"action_key": "action_518_t1_opt3_text", "cost_freedom_risk": 20, "safety_risk": 30, "info_key": "info_518_t1_opt3_got"},
], "article_writing_phase": False}, # 5.18 첫 턴은 기사 작성 없음
{"turn": 2, "assignment_key": "event_518_t2_assignment", "source_key": "event_518_t2_source",
"options": [
{"action_key": "action_518_t2_opt1_text", "cost_freedom_risk": 30, "safety_risk": 40, "info_key": "info_518_t2_opt1_got"},
{"action_key": "action_518_t2_opt2_text", "cost_freedom_risk": 15, "safety_risk": 20, "info_key": "info_518_t2_opt2_got"},
{"action_key": "action_518_t2_opt3_text", "cost_freedom_risk": 10, "safety_risk": 15, "info_key": "info_518_t2_opt3_got"},
], "article_writing_phase": True},
{"turn": 3, "assignment_key": "event_518_t3_assignment", "source_key": "event_518_t3_source",
"options": [
{"action_key": "action_518_t3_opt1_text", "cost_freedom_risk": 35, "safety_risk": 45, "info_key": "info_518_t3_opt1_got"},
{"action_key": "action_518_t3_opt2_text", "cost_freedom_risk": 20, "safety_risk": 25, "info_key": "info_518_t3_opt2_got"},
{"action_key": "action_518_t3_opt3_text", "cost_freedom_risk": 15, "safety_risk": 30, "info_key": "info_518_t3_opt3_got"},
], "article_writing_phase": True},
{"turn": 4, "assignment_key": "event_518_t4_assignment", "source_key": "event_518_t4_source",
"options": [
{"action_key": "action_518_t4_opt1_text", "cost_freedom_risk": 25, "safety_risk": 35, "info_key": "info_518_t4_opt1_got"},
{"action_key": "action_518_t4_opt2_text", "cost_freedom_risk": 20, "safety_risk": 30, "info_key": "info_518_t4_opt2_got"},
{"action_key": "action_518_t4_opt3_text", "cost_freedom_risk": 15, "safety_risk": 20, "info_key": "info_518_t4_opt3_got"},
], "article_writing_phase": True},
{"turn": 5, "assignment_key": "event_518_t5_assignment", "source_key": "event_518_t5_source",
"options": [
{"action_key": "action_518_t5_opt1_text", "cost_freedom_risk": 10, "safety_risk": 15, "info_key": "info_518_t5_opt1_got"},
{"action_key": "action_518_t5_opt2_text", "cost_freedom_risk": 15, "safety_risk": 20, "info_key": "info_518_t5_opt2_got"},
{"action_key": "action_518_t5_opt3_text", "cost_freedom_risk": 5, "safety_risk": 10, "info_key": "info_518_t5_opt3_got"},
], "article_writing_phase": True},
{"turn": 6, "assignment_key": "event_518_t6_assignment", "source_key": "event_518_t6_source",
"options": [
{"action_key": "action_518_t6_opt1_text", "cost_freedom_risk": 30, "safety_risk": 40, "info_key": "info_518_t6_opt1_got"},
{"action_key": "action_518_t6_opt2_text", "cost_freedom_risk": 20, "safety_risk": 25, "info_key": "info_518_t6_opt2_got"},
{"action_key": "action_518_t6_opt3_text", "cost_freedom_risk": 25, "safety_risk": 30, "info_key": "info_518_t6_opt3_got"},
], "article_writing_phase": True},
{"turn": 7, "assignment_key": "event_518_t7_assignment", "source_key": "event_518_t7_source",
"options": [
{"action_key": "action_518_t7_opt1_text", "cost_freedom_risk": 40, "safety_risk": 50, "info_key": "info_518_t7_opt1_got"},
{"action_key": "action_518_t7_opt2_text", "cost_freedom_risk": 20, "safety_risk": 25, "info_key": "info_518_t7_opt2_got"},
{"action_key": "action_518_t7_opt3_text", "cost_freedom_risk": 25, "safety_risk": 30, "info_key": "info_518_t7_opt3_got"},
], "article_writing_phase": True},
{"turn": 8, "assignment_key": "event_518_t8_assignment", "source_key": "event_518_t8_source",
"options": [
{"action_key": "action_518_t8_opt1_text", "cost_freedom_risk": 25, "safety_risk": 30, "info_key": "info_518_t8_opt1_got"},
{"action_key": "action_518_t8_opt2_text", "cost_freedom_risk": 30, "safety_risk": 20, "info_key": "info_518_t8_opt2_got"},
], "article_writing_phase": True, "is_final_turn_event": True},
],
"june_struggle": [
{"turn": 1, "assignment_key": "event_june_t1_assignment", "source_key": "event_june_t1_source",
"options": [
{"action_key": "action_june_t1_opt1_text", "cost_freedom_risk": 10, "safety_risk": 15, "info_key": "info_june_t1_opt1_got"},
{"action_key": "action_june_t1_opt2_text", "cost_freedom_risk": 5, "safety_risk": 10, "info_key": "info_june_t1_opt2_got"},
{"action_key": "action_june_t1_opt3_text", "cost_freedom_risk": 5, "safety_risk": 5, "info_key": "info_june_t1_opt3_got"},
], "article_writing_phase": True},
{"turn": 2, "assignment_key": "event_june_t2_assignment", "source_key": "event_june_t2_source",
"options": [
{"action_key": "action_june_t2_opt1_text", "cost_freedom_risk": 10, "safety_risk": 10, "info_key": "info_june_t2_opt1_got"},
{"action_key": "action_june_t2_opt2_text", "cost_freedom_risk": 15, "safety_risk": 20, "info_key": "info_june_t2_opt2_got"},
{"action_key": "action_june_t2_opt3_text", "cost_freedom_risk": 5, "safety_risk": 5, "info_key": "info_june_t2_opt3_got"},
], "article_writing_phase": True},
{"turn": 3, "assignment_key": "event_june_t3_assignment", "source_key": "event_june_t3_source",
"options": [
{"action_key": "action_june_t3_opt1_text", "cost_freedom_risk": 20, "safety_risk": 30, "info_key": "info_june_t3_opt1_got"},
{"action_key": "action_june_t3_opt2_text", "cost_freedom_risk": 15, "safety_risk": 20, "info_key": "info_june_t3_opt2_got"},
{"action_key": "action_june_t3_opt3_text", "cost_freedom_risk": 10, "safety_risk": 15, "info_key": "info_june_t3_opt3_got"},
], "article_writing_phase": True},
{"turn": 4, "assignment_key": "event_june_t4_assignment", "source_key": "event_june_t4_source",
"options": [
{"action_key": "action_june_t4_opt1_text", "cost_freedom_risk": 25, "safety_risk": 35, "info_key": "info_june_t4_opt1_got"},
{"action_key": "action_june_t4_opt2_text", "cost_freedom_risk": 5, "safety_risk": 10, "info_key": "info_june_t4_opt2_got"},
{"action_key": "action_june_t4_opt3_text", "cost_freedom_risk": 10, "safety_risk": 5, "info_key": "info_june_t4_opt3_got"},
], "article_writing_phase": True},
{"turn": 5, "assignment_key": "event_june_t5_assignment", "source_key": "event_june_t5_source",
"options": [
{"action_key": "action_june_t5_opt1_text", "cost_freedom_risk": 15, "safety_risk": 20, "info_key": "info_june_t5_opt1_got"},
{"action_key": "action_june_t5_opt2_text", "cost_freedom_risk": 5, "safety_risk": 10, "info_key": "info_june_t5_opt2_got"},
{"action_key": "action_june_t5_opt3_text", "cost_freedom_risk": 20, "safety_risk": 10, "info_key": "info_june_t5_opt3_got"},
], "article_writing_phase": True},
{"turn": 6, "assignment_key": "event_june_t6_assignment", "source_key": "event_june_t6_source",
"options": [
{"action_key": "action_june_t6_opt1_text", "cost_freedom_risk": 5, "safety_risk": 5, "info_key": "info_june_t6_opt1_got"},
{"action_key": "action_june_t6_opt2_text", "cost_freedom_risk": 0, "safety_risk": 0, "info_key": "info_june_t6_opt2_got"},
{"action_key": "action_june_t6_opt3_text", "cost_freedom_risk": 5, "safety_risk": 5, "info_key": "info_june_t6_opt3_got"},
], "article_writing_phase": True},
{"turn": 7, "assignment_key": "event_june_t7_assignment", "source_key": "event_june_t7_source",
"options": [
{"action_key": "action_june_t7_opt1_text", "cost_freedom_risk": 0, "safety_risk": 0, "info_key": "info_june_t7_opt1_got"},
{"action_key": "action_june_t7_opt2_text", "cost_freedom_risk": 0, "safety_risk": 0, "info_key": "info_june_t7_opt2_got"},
], "article_writing_phase": True, "is_final_turn_event": True},
]
}
# --- 다음 취재 지시 가져오기 ---
def get_next_assignment(scenario_key, current_turn, game_state):
scenario_assignments = HISTORICAL_ASSIGNMENTS.get(scenario_key, [])
for assignment_data_from_db in scenario_assignments:
if assignment_data_from_db["turn"] == current_turn:
get_text_for_assignment = lambda k: get_text(k)
final_assignment = {
"assignment_key": assignment_data_from_db["assignment_key"],
"assignment_text": get_text_for_assignment(assignment_data_from_db["assignment_key"]),
"source_text": get_text_for_assignment(assignment_data_from_db.get("source_key", "")),
"options": [],
"article_writing_phase": assignment_data_from_db.get("article_writing_phase", False),
"is_final_turn_event": assignment_data_from_db.get("is_final_turn_event", False)
}
for opt_data in assignment_data_from_db.get("options", []):
final_assignment["options"].append({
"action_text": get_text_for_assignment(opt_data["action_key"]),
"cost_freedom_risk": opt_data.get("cost_freedom_risk", 0),
"safety_risk": opt_data.get("safety_risk", 0),
"info_key": opt_data.get("info_key", "")
})
log_message = f"{game_state['game_year']}년 {current_turn}번째 날: {final_assignment['assignment_text'][:30]}..."
if game_state.get('event_log') is not None:
game_state['event_log'].append(log_message)
return final_assignment
return None
# --- 취재 활동 결과 처리 ---
def process_reporter_action(selected_option, game_state):
get_text_for_processing = lambda k: get_text(k)
status = game_state['status']
if random.random() < (selected_option.get("cost_freedom_risk", 0) / 100):
freedom_loss = random.randint(1, 5)
status['press_freedom'] -= freedom_loss
game_state['event_log'].append(get_text_for_processing("log_freedom_loss").format(loss=freedom_loss))
if random.random() < (selected_option.get("safety_risk", 0) / 100):
safety_loss = random.randint(1, 10)
status['reporter_safety'] -= safety_loss
game_state['event_log'].append(get_text_for_processing("log_safety_loss").format(loss=safety_loss))
info_text = ""
if selected_option.get("info_key"):
info_text = get_text_for_processing(selected_option["info_key"])
game_state['reporter_notebook'].append(info_text)
st.toast(f"💡 새로운 사실 발견!", icon="💡")
game_state['event_log'].append(get_text_for_processing("log_info_acquired").format(info=info_text[:50]))
else:
st.toast(get_text_for_processing("info_no_special_info"), icon="🤔")
game_state['event_log'].append(get_text_for_processing("log_no_info_acquired"))
status['press_freedom'] = max(0, min(100, status['press_freedom']))
status['reporter_safety'] = max(0, min(100, status['reporter_safety']))
st.session_state['actions_taken_this_turn'] += 1
# --- 기사 작성 인터페이스 생성 ---
def generate_article_interface(game_state):
get_text_func = lambda k: get_text(k)
with st.expander(f"**{get_text_func('reporter_notebook_title')} 다시 보기**"):
if game_state['reporter_notebook']:
for idx, note in enumerate(game_state['reporter_notebook']):
st.markdown(f"- {note}")
else:
st.caption("아직 취재한 내용이 없어요.")
st.markdown("---")
with st.form(key="article_form"):
article_headline = st.text_input(get_text_func("article_headline_label"), placeholder="예: 나쁜 선거, 그 비밀을 밝힌다!")
article_body_summary = st.text_area(get_text_func("article_body_label"), height=150, placeholder="예: 오늘 대통령 뽑는 날, 나쁜 사람들이 몰래 표를 바꿨어요...")
article_tones = {
"fact_based": get_text_func("article_tone_fact_based"),
"critical": get_text_func("article_tone_critical"),
"sympathetic": get_text_func("article_tone_sympathetic"),
"cautious": get_text_func("article_tone_cautious"),
}
selected_tone_key = st.selectbox(
get_text_func("article_tone_label"),
options=list(article_tones.keys()),
format_func=lambda key: article_tones[key]
)
submitted_form = st.form_submit_button(get_text_func("button_submit_article"), use_container_width=True)
if submitted_form:
if not article_headline or not article_body_summary:
st.warning(get_text_func("warning_empty_article"))
return None
if not game_state['reporter_notebook']:
st.warning("취재 노트에 내용이 없어요. 기사를 쓸 수 없어요.")
return None
return {
"turn": game_state['current_turn'], "headline": article_headline, "body_summary": article_body_summary,
"tone": selected_tone_key, "raw_notes": list(game_state['reporter_notebook']), "ai_score": 0
}
return None
# --- 기사 평가 및 데스크 피드백 (OpenAI 사용) ---
def evaluate_article_and_get_feedback_openai(article, game_state, assignment_data):
status = game_state['status']
get_text_func = lambda k: get_text(k)
current_assignment_text = assignment_data["assignment_text"]
reporter_notes_str = "\n".join([f"- {note}" for note in article['raw_notes']])
article_tone_text = get_text_func(f"article_tone_{article['tone']}")
prompt = f"""
당신은 어린이 신문사의 따뜻하면서도 명철한 편집장입니다. 당신의 목표는 새내기 기자가 최고의 기사를 쓸 수 있도록 돕는 것입니다.
이 기자는 초등학생 독자들도 이해할 수 있는 글을 쓰려고 노력하고 있습니다. 칭찬할 부분은 구체적으로 언급하여 격려하고, 개선이 필요한 부분은 명확한 근거와 함께 친절하게 설명해주세요.
피드백은 기자가 **어떤 부분을 잘했고, 어떤 부분을 왜, 어떻게 개선해야 하는지** 명확히 이해하도록 돕는 데 초점을 맞춥니다.
[오늘의 할 일 (취재 지시)]
{current_assignment_text}
[기자가 적은 내용 (취재 노트)]
{reporter_notes_str}
[기자가 쓴 기사]
- 제목: {article['headline']}
- 내용 요약: {article['body_summary']}
- 선택한 분위기: {article_tone_text}
[피드백 작성 가이드]
1. **칭찬과 개선점의 조화:** 잘한 점과 아쉬운 점을 균형 있게 언급해주세요.
2. **구체적인 인용:** 피드백 시, **기자가 작성한 제목, 내용 요약, 또는 취재 노트의 특정 부분을 직접 인용**하며 설명해주세요.
예: "제목에서 'OOO'라는 표현은 독자들의 호기심을 자극하는 좋은 시도예요." 또는 "내용 요약 중 'XXX' 부분은 YY라는 점에서 조금 아쉬워요. ZZZ처럼 바꿔보면 어떨까요?"
3. **초등학생 눈높이 고려:** 모든 설명은 초등학생 기자가 이해할 수 있도록 쉽고 명확해야 합니다.
[총평 및 최종 조언]
각 항목별 점수와 피드백을 바탕으로 총점(100점 만점)을 계산하고, "overall_feedback"에는 기사의 전반적인 강점과 개선점을 균형 있게 요약하여 전달합니다.
**칭찬할 부분은 구체적으로 언급하고, 개선이 필요한 부분은 기자가 다음 기사에서 더욱 발전할 수 있도록 명확하고 건설적인 조언을 담아주세요.**
예시: "이번 기사는 [구체적인 칭찬 내용, 예: '제목의 OOO 표현' 또는 '내용 요약의 XXX 부분']에서 기자님의 고민과 성장이 엿보여 정말 좋았어요. 다만, [가장 개선이 필요한 부분, 예: '논리적 연결' 또는 '어휘 선택']에 대해서는 조금 더 신경 써주면 훨씬 훌륭한 기사가 될 거예요. 특히 [가장 중요한 개선점 한 가지]를 다음 취재 때 꼭 기억해주세요!"
반드시 아래 JSON 형식으로 응답해주세요:
{{
"total_score": 총점(숫자),
"overall_feedback": "기사의 전반적인 강점과 개선 방향에 대한 따뜻하지만 명확한 조언 (문자열, 칭찬과 개선점 균형있게)"
}}
"""
try:
with st.spinner("AI 편집장님이 기사를 꼼꼼히 검토하고 있습니다..."):
response = client.chat.completions.create(
model="gpt-4o-mini",
messages=[{"role": "user", "content": prompt}],
response_format={"type": "json_object"},
temperature=0.1, max_tokens=1000
)
ai_evaluation = json.loads(response.choices[0].message.content)
total_score = ai_evaluation.get("total_score", 0)
overall_feedback = ai_evaluation.get("overall_feedback", "AI 편집장 연결 오류로 자동 평가되었습니다.")
except Exception as e:
st.error(get_text_func("error_openai_api").format(error=str(e)))
total_score = random.randint(30, 60)
overall_feedback = "AI 편집장 시스템 오류로 자동 평가되었습니다."
article['ai_score'] = total_score
trust_change = (total_score - 60) // 6
status['public_trust'] = max(0, min(100, status['public_trust'] + trust_change))
if article['tone'] == "critical":
freedom_penalty_chance = 0.2 + ((50 - status['press_freedom']) / 200)
safety_penalty_chance = 0.2 + ((40 - status['reporter_safety']) / 200)
if random.random() < freedom_penalty_chance:
freedom_change = -random.randint(3, 8)
status['press_freedom'] += freedom_change
if freedom_change != 0: game_state['event_log'].append(get_text_func("log_freedom_change_article").format(change=freedom_change))
if random.random() < safety_penalty_chance:
safety_change = -random.randint(5, 12)
status['reporter_safety'] += safety_change
if safety_change != 0: game_state['event_log'].append(get_text_func("log_safety_change_article").format(change=safety_change))
status['article_score_total'] += total_score
status['article_count'] += 1
tone_display_text = get_text_func(f"article_tone_{article['tone']}")
game_state['event_log'].append(get_text_func("log_article_submitted").format(headline=article['headline'], tone=tone_display_text, score=total_score))
game_state['event_log'].append(get_text_func("log_desk_feedback").format(feedback=overall_feedback))
if trust_change != 0: game_state['event_log'].append(get_text_func("log_trust_change").format(change=trust_change))
game_state['submitted_articles'].append(article)
game_state['reporter_notebook'] = []
return overall_feedback
# --- UI 표시 함수들 ---
def display_reporter_dashboard(game_state):
status = game_state['status']
avg_score = (status['article_score_total'] / status['article_count']) if status['article_count'] > 0 else 0
col1, col2, col3, col4 = st.columns(4)
with col1: st.metric(get_text("term_public_trust"), f"{status['public_trust']}%")
with col2: st.metric(get_text("term_press_freedom"), f"{status['press_freedom']}%")
with col3: st.metric(get_text("term_reporter_safety"), f"{status['reporter_safety']}%")
with col4: st.metric(get_text("term_article_score_avg"), f"{avg_score:.1f}점")
# [수정] 용어 사전 표시 함수
def display_historical_glossary(scenario_key):
# 시나리오 키를 기반으로 정확한 접두사 생성
glossary_prefix = f'glossary_{scenario_key}_'
glossary_keys = sorted([k for k in ALL_TEXTS if k.startswith(glossary_prefix)])
if not glossary_keys:
st.caption("이 시대의 용어 정보가 아직 없어요.")
else:
for key in glossary_keys:
st.markdown(get_text(key))
def display_final_results(game_state):
st.balloons()
st.header(get_text("assignment_over_title"))
with st.container(border=True):
st.subheader(get_text("assignment_over_subtitle"))
display_reporter_dashboard(game_state)
st.divider()
with st.container(border=True):
st.subheader("🗞️ 내가 보낸 주요 기사들")
if game_state['submitted_articles']:
for article in game_state['submitted_articles']:
tone_display = get_text(f"article_tone_{article['tone']}")
score = article.get('ai_score', 'N/A')
st.markdown(f"**{article['turn']}일차:** \"{article['headline']}\" (분위기: {tone_display}, 점수: **{score}점**)")
else:
st.caption("이번 취재 동안 보낸 기사가 없어요.")
# --- 세션 상태 초기화 ---
if 'game_mode' not in st.session_state:
st.session_state.game_mode = 'scenario_select'
st.session_state.game_state = None
st.session_state.current_assignment_data = None
st.session_state.actions_taken_this_turn = 0
st.session_state.desk_feedback_message = None
# --- 메인 게임 로직 ---
def reporter_simulation_main():
st.title(get_text("game_title"))
# --- 시나리오 선택 화면 ---
if st.session_state.game_mode == 'scenario_select':
st.header(get_text("scenario_select_title"))
st.write("기자가 되어 우리나라의 중요한 역사적 순간으로 시간 여행을 떠나보세요!")
st.divider()
scenario_descriptions = {
"4.19_revolution": "1960년, 우리나라에 큰 변화가 있었던 때로 가봐요! 새내기 기자가 되어서 진짜 있었던 일을 알아내고 사람들에게 알려주는 거예요.",
"5.18_gwangju": "1980년 5월, 광주라는 도시에서 아주 슬픈 일이 있었어요. 용감한 기자가 되어서 그곳 사람들의 이야기를 듣고 진실을 알려야 해요. (조금 무섭거나 슬픈 내용이 나올 수 있어요.)",
"june_struggle": "1987년, 우리나라 사람들이 '우리 손으로 대통령을 뽑고 싶다!'고 외쳤던 때예요. 사회부 기자가 되어서 뜨거운 현장의 목소리를 담아보세요."
}
for key, info in SCENARIOS.items():
with st.container(border=True):
st.subheader(get_text(info["display_name"]))
st.caption(f"🕰️ **언제:** {info['start_year']}년 | 🧑💼 **나는 누구?:** {info['player_role']}")
st.markdown(scenario_descriptions.get(key, ""))
if st.button(get_text("scenario_select_button"), key=f"select_{key}", use_container_width=True):
st.session_state.game_state = initialize_reporter_scenario_state(key)
st.session_state.game_mode = 'assignment_loading'
st.rerun()
st.stop()
# --- 게임 진행 화면 ---
game_state = st.session_state.game_state
if not game_state:
st.warning("게임 상태 정보가 없습니다. 시나리오 선택 화면으로 돌아갑니다.")
st.session_state.game_mode = 'scenario_select'
st.rerun()
scenario_key = game_state['scenario_key']
# --- 취재 종료 화면 ---
if st.session_state.game_mode == 'assignment_over':
display_final_results(game_state)
c1, c2 = st.columns(2)
if c1.button(get_text("button_restart_assignment"), use_container_width=True):
st.session_state.game_state = initialize_reporter_scenario_state(scenario_key)
st.session_state.game_mode = 'assignment_loading'
st.rerun()
if c2.button(get_text("button_back_to_scenario_select"), use_container_width=True):
st.session_state.game_mode = 'scenario_select'
st.rerun()
st.stop()
# --- 새 턴 데이터 로딩 ---
if st.session_state.game_mode == 'assignment_loading':
spinner_text = get_text('status_loading_assignment').format(year=game_state['game_year'], turn=game_state['current_turn'])
with st.spinner(spinner_text):
time.sleep(0.5)
assignment = get_next_assignment(scenario_key, game_state['current_turn'], game_state)
if assignment:
st.session_state.current_assignment_data = assignment
st.session_state.actions_taken_this_turn = 0
st.session_state.desk_feedback_message = None
st.session_state.game_mode = 'in_progress'
else:
st.session_state.game_mode = 'assignment_over'
st.rerun()
# --- 게임 진행 중 화면 ---
assignment_data = st.session_state.current_assignment_data
if st.session_state.game_mode == 'in_progress' and assignment_data:
# --- 상단 고정 정보: 상태 대시보드 ---
with st.expander(f"**{get_text('dashboard_term').format(year=game_state['game_year'], turn=game_state['current_turn'])} - {get_text('dashboard_title')}**"):
display_reporter_dashboard(game_state)
if st.button("다른 시대로 가기", key="quit_ingame", use_container_width=True):
st.session_state.game_mode = 'scenario_select'
st.rerun()
st.divider()
# --- 중앙 메인 화면: 단계별 진행 ---
actions_done = st.session_state.actions_taken_this_turn >= ACTIONS_PER_TURN_LIMIT
article_submitted = st.session_state.desk_feedback_message is not None
# 1. 오늘의 할 일 (브리핑)
st.info(f"**{get_text('current_assignment_title')}:** {assignment_data['assignment_text']}")
st.divider()
# 2. 취재 활동 또는 기사 작성/피드백
if not actions_done:
st.subheader(get_text("reporter_actions_title"))
st.caption(f"남은 활동 횟수: **{ACTIONS_PER_TURN_LIMIT - st.session_state.actions_taken_this_turn}번**")
for i, opt in enumerate(assignment_data['options']):
risk_score = opt.get('cost_freedom_risk',0) + opt.get('safety_risk',0)
risk_str = "🚨 매우 위험!" if risk_score > 40 else "⚠️ 조금 위험" if risk_score > 0 else "👍 안전함"
if st.button(get_text("action_button_label").format(action=opt['action_text'], risk_str=risk_str), key=f"action_{i}", use_container_width=True):
process_reporter_action(opt, game_state)
st.rerun()
elif assignment_data['article_writing_phase'] and not article_submitted:
st.subheader(get_text("article_writing_title"))
submitted_article = generate_article_interface(game_state)
if submitted_article:
feedback = evaluate_article_and_get_feedback_openai(submitted_article, game_state, assignment_data)
st.session_state.desk_feedback_message = feedback
st.rerun()
else:
if st.session_state.desk_feedback_message:
st.subheader(get_text("desk_feedback_title"))
st.success(f"**AI 편집장님:** {st.session_state.desk_feedback_message}")
else: # 기사 작성 단계가 없는 턴
st.success(get_text("status_actions_taken"))
if st.button(get_text("button_next_day"), use_container_width=True, type="primary"):
if game_state['current_turn'] >= game_state['max_turns']:
st.session_state.game_mode = 'assignment_over'
else:
game_state['current_turn'] += 1
st.session_state.game_mode = 'assignment_loading'
st.rerun()
st.divider()
# --- 하단 정보 탭 ---
tab1, tab2, tab3 = st.tabs([get_text("historical_source_title"), get_text("sidebar_glossary_title"), "💡 FAQ & 게임 팁"])
with tab1:
st.write(assignment_data['source_text'])
with tab2:
display_historical_glossary(scenario_key)
with tab3:
st.markdown("""
**Q. 이 게임은 무엇인가요?**
A. 옛날 신문 기자가 되어서, 우리나라의 중요한 역사 속으로 들어가 직접 취재하고 기사를 써보는 게임이에요.
**Q. 점수는 왜 자꾸 바뀌나요?**
A. 위험한 곳을 취재하거나, 정부가 싫어하는 기사를 쓰면 '자유'나 '안전' 점수가 낮아질 수 있어요. 옛날 기자들의 어려움을 체험해보는 거예요.
**Q. 기사는 어떻게 써야 점수가 높나요?**
A. '내가 적은 내용'에 있는 힌트를 잘 활용하고, '오늘 할 일'에서 시킨 내용을 빠짐없이 담아보세요.
**Q. 문제가 생기면 어떻게 해요?**
A. **ll7098ll@bonggokcho.com (구미봉곡초 교사 이병민)** 으로 이메일을 보내주세요.
""")
if __name__ == "__main__":
reporter_simulation_main() |