커서와 스트림릿으로 꽃이름 맞추는 게임 웹앱으로 배포하기

소개

시도하고자 했던 것과 그 이유를 알려주세요.

꽃 이미지를 보고 이름을 맞추는 게임으로 꽃이름을 궁금해하는 사람들을 위해 꽃을 보고 이름을 알 수 있는 연습을 할 수 있도록 만들고 있습니다.

진행 방법

어떤 도구를 사용했고, 어떻게 활용하셨나요?

커서AI에서 파이썬을 사용해서 스트림릿으로 배포하도록 입코딩으로 작성하고 있습니다. 커서에서 작성하려는 게임의 PRD작성을 요청하고 PRD대로 입코딩을 합니다.

Tip: 사용한 프롬프트 전문을 꼭 포함하고, 내용을 짧게 소개해 주세요.

Tip: 활용 이미지나 캡처 화면을 꼭 남겨주세요.

Tip: 코드 전문은 코드블록에 감싸서 작성해주세요. ( / 을 눌러 '코드 블록'을 선택)

  1. 첫 프롬프트 : 한국의 야생화를 이미지를 보고 이름을 맞추는 게임을 만들어서 스트림릿에 배포하려고 해. 어떻게 하면 될지 PRD를 작성해줘.

    한국 야생화 퀴즈 게임을 위한 PRD를 작성해드리겠습니다.

    # 한국 야생화 퀴즈 게임 PRD

    ## 1. 제품 개요

    - 제품명: 한국 야생화 퀴즈

    - 목적: 사용자들이 한국의 야생화를 이미지를 통해 학습하고 즐겁게 퀴즈를 풀 수 있는 웹 애플리케이션

    - 대상: 야생화에 관심 있는 일반 사용자, 교육자, 학생

    ## 2. 핵심 기능

    ### 2.1 메인 화면

    - 게임 시작 버튼

    - 간단한 게임 설명

    - 최고 점수 표시

    - 난이도 선택 옵션 (초급/중급/고급)

    ### 2.2 퀴즈 게임

    - 야생화 이미지 표시

    - 4개의 선택지 제공

    - 정답/오답 피드백

    - 점수 시스템

    - 진행 상황 표시 (예: 5/10)

    ### 2.3 결과 화면

    - 최종 점수 표시

    - 틀린 문제 복습 기능

    - 다시 시작 버튼

    - 공유하기 기능

    ## 3. 기술 스택

    - 프론트엔드: Streamlit

    - 데이터베이스: SQLite (문제 데이터 저장)

    - 이미지 저장소: AWS S3 또는 GitHub

    - 배포: Streamlit Cloud

    ## 4. 데이터 구조

    ```python

    # 문제 데이터 구조

    {

    "id": int,

    "image_url": str,

    "correct_answer": str,

    "options": [str],

    "difficulty": str,

    "description": str

    }

    ```

    ## 5. 구현 단계

    ### Phase 1: 기본 구조

    1. Streamlit 프로젝트 설정

    2. 기본 UI 레이아웃 구현

    3. 데이터베이스 스키마 설계

    ### Phase 2: 핵심 기능

    1. 이미지 표시 기능

    2. 퀴즈 로직 구현

    3. 점수 시스템 구현

    ### Phase 3: 개선 및 배포

    1. UI/UX 개선

    2. 성능 최적화

    3. Streamlit Cloud 배포

    ## 6. 성공 지표

    - 일일 활성 사용자 수

    - 평균 게임 완료 시간

    - 정답률 통계

    - 사용자 피드백

    ## 7. 향후 확장 계획

    - 다국어 지원

    - 사용자 계정 시스템

    - 리더보드 기능

    - 커스텀 퀴즈 생성 기능

    이 PRD를 바탕으로 개발을 시작하시겠습니까? 특정 부분에 대해 더 자세한 설명이 필요하시다면 말씀해 주세요.

  2. 두번째 프롬프트 : 개발을 시작해줘

    1. 이제 기본적인 애플리케이션이 완성되었습니다. 주요 기능은 다음과 같습니다:

      1. 난이도 선택 (초급/중급/고급)

      1. 문제 수 선택 (5-20문제)

      1. 랜덤으로 섞인 문제 제공

      1. 정답/오답 피드백과 설명 제공

      1. 진행 상황과 현재 점수 표시

      1. 최종 정답률 계산

      실행하기 위해서는 다음 단계가 필요합니다:

      1. images 폴더에 각 야생화 이미지를 추가해야 합니다:

      • gaenari.jpg (개나리)

      • jindallae.jpg (진달래)

      • beotkkot.jpg (벚꽃)

      • mugunghwa.jpg (무궁화)

      • azalea.jpg (진달래)

      • cosmos.jpg (코스모스)

      • chrysanthemum.jpg (국화)

Adobe Adobe Adobe Adobe에서 퀴즈 게임의 스크린 샷
한국 텍스트가있는 코드 편집기의 스크린 샷
  1. 꽃이미지를 검색해서 image폴더에 저장하고 추가 프로프트를 작성했습니다.

    1. 이미지 크기 조정

    2. 정답과 오답을 메시지로 알려주기

    3. 예문을 세로에서 가로로 표시

  2. 실행화면

한국 가입 페이지의 스크린 샷
오렌지 꽃이 달린 한국 앱의 스크린 샷
import streamlit as st
import pandas as pd
from PIL import Image
import random
import json
import os

# 페이지 설정
st.set_page_config(
    page_title="한국 야생화 퀴즈",
    page_icon="🌸",
    layout="wide",
    initial_sidebar_state="collapsed"
)

# 세션 상태 초기화
def init_session_state():
    if 'score' not in st.session_state:
        st.session_state.score = 0
    if 'current_question' not in st.session_state:
        st.session_state.current_question = 0
    if 'total_questions' not in st.session_state:
        st.session_state.total_questions = 10
    if 'game_started' not in st.session_state:
        st.session_state.game_started = False
    if 'difficulty' not in st.session_state:
        st.session_state.difficulty = "초급"
    if 'questions' not in st.session_state:
        st.session_state.questions = []

# 문제 데이터 로드
def load_questions():
    try:
        with open('questions.json', 'r', encoding='utf-8') as f:
            data = json.load(f)
            # 난이도에 따라 문제 필터링
            filtered_questions = [q for q in data['questions'] if q['difficulty'] == st.session_state.difficulty]
            if not filtered_questions:
                st.error(f"{st.session_state.difficulty} 난이도의 문제가 없습니다. 다른 난이도를 선택해주세요.")
                return []
            
            # 사용 가능한 문제 수 확인
            available_questions = len(filtered_questions)
            if available_questions < st.session_state.total_questions:
                st.warning(f"선택한 난이도의 문제가 {available_questions}개 밖에 없습니다. 문제 수를 조정합니다.")
                st.session_state.total_questions = available_questions
            
            # 문제 순서를 랜덤으로 섞기
            random.shuffle(filtered_questions)
            
            # 선택한 문제 수만큼 반환
            return filtered_questions[:st.session_state.total_questions]
    except FileNotFoundError:
        st.error("문제 데이터 파일(questions.json)을 찾을 수 없습니다.")
        return []
    except json.JSONDecodeError:
        st.error("문제 데이터 파일의 형식이 잘못되었습니다.")
        return []
    except Exception as e:
        st.error(f"문제 데이터를 불러오는 중 오류가 발생했습니다: {str(e)}")
        return []

# 이미지 로드 함수
def load_image(image_path):
    try:
        if not os.path.exists(image_path):
            st.error(f"이미지 파일을 찾을 수 없습니다: {image_path}")
            return None
        return Image.open(image_path)
    except Exception as e:
        st.error(f"이미지를 불러오는 중 오류가 발생했습니다: {str(e)}")
        return None

# 메인 페이지
def main():
    # 세션 상태 초기화
    init_session_state()
    
    st.title("🌸 한국 야생화 퀴즈 🌸")
    
    if not st.session_state.game_started:
        st.write("한국의 아름다운 야생화를 알아보세요!")
        st.write("각 문제에서 보여주는 야생화의 이름을 맞춰보세요.")
        
        # 난이도 선택
        st.session_state.difficulty = st.selectbox(
            "난이도를 선택하세요",
            ["초급", "중급", "고급"]
        )
        
        # 문제 수 선택
        st.session_state.total_questions = st.slider(
            "문제 수를 선택하세요",
            min_value=5,
            max_value=20,
            value=10,
            step=5
        )
        
        if st.button("게임 시작하기"):
            questions = load_questions()
            if questions:  # 문제가 있는 경우에만 게임 시작
                st.session_state.game_started = True
                st.session_state.score = 0
                st.session_state.current_question = 0
                st.session_state.questions = questions
                st.rerun()
    else:
        if not st.session_state.questions:  # 문제가 없는 경우
            st.error("문제를 불러올 수 없습니다. 다시 시작해주세요.")
            if st.button("다시 시작하기"):
                st.session_state.game_started = False
                st.rerun()
        elif st.session_state.current_question < len(st.session_state.questions):
            current_q = st.session_state.questions[st.session_state.current_question]
            
            # 진행 상황 표시
            col1, col2 = st.columns([3, 1])
            with col1:
                st.progress(st.session_state.current_question / len(st.session_state.questions))
            with col2:
                st.write(f"현재 점수: {st.session_state.score}")
            
            st.write(f"문제 {st.session_state.current_question + 1}/{len(st.session_state.questions)}")
            
            # 이미지 표시
            image = load_image(current_q["image_url"])
            if image:
                # 이미지 크기 조정
                max_width = 400
                ratio = max_width / image.width
                new_height = int(image.height * ratio)
                resized_image = image.resize((max_width, new_height))
                st.image(resized_image, use_container_width=False)
            
            # 선택지 표시
            selected = st.radio("이 야생화의 이름은 무엇일까요?", current_q["options"], horizontal=True, index=None)
            
            if selected is not None:
                if selected == current_q["correct_answer"]:
                    st.success("정답입니다! 🎉")
                    st.write(f"설명: {current_q['description']}")
                    st.session_state.score += 1
                else:
                    st.error(f"틀렸습니다. 정답은 {current_q['correct_answer']}입니다.")
                    st.write(f"설명: {current_q['description']}")
                
                if st.button("다음 문제"):
                    st.session_state.current_question += 1
                    st.rerun()
        else:
            # 게임 종료 화면
            st.balloons()
            st.write(f"🎉 게임이 끝났습니다! 🎉")
            st.write(f"최종 점수: {st.session_state.score}/{len(st.session_state.questions)}")
            
            # 정답률 계산
            percentage = (st.session_state.score / len(st.session_state.questions)) * 100
            st.write(f"정답률: {percentage:.1f}%")
            
            if st.button("다시 시작하기"):
                st.session_state.game_started = False
                st.rerun()

if __name__ == "__main__":
    main() 

결과와 배운 점

배운 점과 나만의 꿀팁을 알려주세요.

-PRD문서로 작성하고 입코딩하니 기간이 많이 절약되고 입코딩 효율이 좋습니다.

과정 중에 어떤 시행착오를 겪었나요?

-스트림릿 테스트에서 파일을 업로드가 아닌 테스트라서 스마트폰테스트를 하지 못했습니다.

도움이 필요한 부분이 있나요?

앞으로의 계획이 있다면 들려주세요.

-좀 더 많은 이미지와 정확한 설명을 작성해서 완성도를 높일 계획입니다.

도움 받은 글 (옵션)

참고한 지피터스 글이나 외부 사례를 알려주세요.

(내용 입력)

1

👉 이 게시글도 읽어보세요