ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 파이썬, flask, SQLAlchemy, SQLite, jsonify로 가위 바위 보 게임 코드 웹 페이지에 올리기
    Python 2024. 7. 10. 04:10

    파이썬 코드, flask, SQLAlchemy를 활용하여 웹 페이지 구현

     

     

    얼마 전 만든 파이썬 가위바위보 게임 코드를 flask, SQLAlchemy, html, css 등을 활용하여 웹페이지에 올려보았다.

    파이참의 파일 구조는 이렇다. 

     

    .venv

    instance

    game_history.db

    static 파일 

    style.css

    templates 파일

     index.html

    app.py

     

    난 웹페이지에 가위, 바위, 보를 이미지를 삽입해줬기 때문에 static file 안에 paper.png, rock.png, scissors.png 파일이 있다.

     


    app.py 전체 코드

     

    from flask import Flask, render_template, request, jsonify, session
    from flask_sqlalchemy import SQLAlchemy
    import random
    
    app = Flask(__name__)
    app.secret_key = 'your_secret_key'  # 세션을 위한 시크릿 키 설정
    
    # SQLite 데이터베이스 설정
    app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///game_history.db'
    app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
    db = SQLAlchemy(app)
    
    option = ["가위", "바위", "보"]
    
    # 데이터베이스 정의
    class GameHistory(db.Model):
        id = db.Column(db.Integer, primary_key=True)
        player_choice = db.Column(db.String(20), nullable=False)
        computer_choice = db.Column(db.String(20), nullable=False)
        result = db.Column(db.String(20), nullable=False)
    
        def __repr__(self):
            return f'<GameHistory {self.id} - {self.player_choice} vs {self.computer_choice}: {self.result}>'
    
    # 데이터베이스 초기화
    with app.app_context():
        db.create_all()
    
    def get_computer_choice():
        return random.choice(option)
    
    def determine_winner(player_choice, computer_choice):
        if player_choice == computer_choice:
            session['draw'] += 1
            result = "무승부!"
        elif (
            (player_choice == "바위" and computer_choice == "가위")
            or (player_choice == "가위" and computer_choice == "보")
            or (player_choice == "보" and computer_choice == "바위")
        ):
            session['win'] += 1
            result = "이겼습니다!"
        else:
            session['lose'] += 1
            result = "졌습니다.."
        return result
    
    # 세션 초기화
    def initialize_session():
        if 'win' not in session:
            session['win'] = 0
        if 'lose' not in session:
            session['lose'] = 0
        if 'draw' not in session:
            session['draw'] = 0
    
    # 웹페이지 보여줌
    @app.route('/')
    def index():
        initialize_session()
        history = GameHistory.query.all()
        return render_template('index.html', history=history, win=session['win'], lose=session['lose'], draw=session['draw'])
    
    
    @app.route('/play', methods=['POST'])
    def play():
        initialize_session()
        player_choice = request.json.get('choice')
        computer_choice = get_computer_choice()
        result = determine_winner(player_choice, computer_choice)
    
        # 데이터베이스에 결과 저장
        new_game = GameHistory(player_choice=player_choice, computer_choice=computer_choice, result=result)
        db.session.add(new_game)
        db.session.commit()
    
        # 결과와 승, 패, 무승부 횟수 반환
        return jsonify({
            'player_choice': player_choice,
            'computer_choice': computer_choice,
            'result': result,
            'win': session['win'],
            'lose': session['lose'],
            'draw': session['draw']
        })
    
    # 기록 초기화
    @app.route('/reset', methods=['POST'])
    def reset():
        session['win'] = 0
        session['lose'] = 0
        session['draw'] = 0
        return jsonify({'status': 'reset'})
    
    if __name__ == '__main__':
        app.run(debug=True)
    

     


    코드 설명

     

    쓸 기능들 import 

    from flask import Flask, render_template, request, jsonify, session
    from flask_sqlalchemy import SQLAlchemy
    import random

     

     

    flask 앱을 만들어주고 

    app = Flask(__name__)

     

    세션을 위한 시크릿 키를 설정해준다.

    app.secret_key = 'your_secret_key'  # 세션을 위한 시크릿 키 설정

     

    근데 이렇게 설정하는 건 개발환경에서는 괜찮지만, 실제로는 보안에 취약하다고 한다. 

     

     

     

    SQLite 데이터베이스 설정

    # SQLite 데이터베이스 설정
    app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///game_history.db'
    app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
    db = SQLAlchemy(app)

     

    먼저 첫번째 app.config는 SQLite 데이터베이스 파일의 위치를 지정해준다. SQLAlchemy가 어떤 데이터베이스와 연결될지를 설정해줘야 하는데, 나는 SQLite를 사용할거고, SQLite 데이터베이스 URI 형식은 sqlite:///파일의 위치 이므로,

    app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///game_history.db'

     

    이렇게 코드를 작성해준다. *슬래시 세 개(///) 뒤에 파일 이름을 지정하면, 현재 디렉토리에 해당 파일이 생성된다.

     

    그리고 내 데이터베이스 세션에는 값이 추가되거나 변경될 일이 없기 때문에 SQLALCHEMY_TRACK_MODIFICATIONS 트랙 수정 기능은 False로 설정해준다. (보통 기본적으로 False로 설정한다.)

    app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False

     

    마지막으로 SQLAlchemy와 app을 연결하여 데이터베이스의 데이터를 주고받을 수 있게 설정해준다.

    db = SQLAlchemy(app)

     

     

     

    그럼 이제 게임의 주요 옵션인 가위 바위 보를 설정해주고 데이터베이스 모델을 정의해줘야 한다.

     

    데이터베이스 모델을 정의해주기 위해 GameHistory 클래스를 생성했다.

    id, player_choice, computer_choice, results웹페이지에서 구현될 표의 컬럼 값을 의마한다. 

    option = ["가위", "바위", "보"]
    
    # 데이터베이스 정의
    class GameHistory(db.Model):
        id = db.Column(db.Integer, primary_key=True)
        player_choice = db.Column(db.String(20), nullable=False)
        computer_choice = db.Column(db.String(20), nullable=False)
        result = db.Column(db.String(20), nullable=False)

     

     

    • id: 내가 구현할 표를 먼저 보면 이렇게 id값은 게임 횟수(정수이기 때문에 Integer, 중복될 수 없고 row값을 식별하는 인덱스와 비슷한 역할을 하는 고유 키니까 primary_key=True 기본 키로 지정)
    • player_choice: 사용자 컬럼 값
    • computer_choice: 컴퓨터 컬럼 값
    • result: 결과 컬럼 값

    (웹페이지 표에서 No., 사용자, 컴퓨터, 결과 로 보여지는 건 html파일에서 th태그 값을 내가 그렇게 지정해줬기 때문이다.)

     

    db.String(20) : 문자열이 최대 20을 넘지 않도록 설정한거다. 사실 길어봐야 6개라 6으로 해도 된다.

    nullable : 빈 값이 있으면 안되므로 False

     

     

    __repr__메서드를 추가하여 GameHistory 클래스의 인스턴스인 id, player_choice, computer_choice, result 의 속성을 문자열로 반환해도록 설정한다.

    def __repr__(self):
        return f'<GameHistory {self.id} - {self.player_choice} vs {self.computer_choice}: {self.result}>'

     

     

    그리고 Flask 앱의 요소들을 가져오고, 실제 데이터베이스에 테이블을 만들어준다.

    with app.app_context():
        db.create_all()

     

     

    이제 게임의 주요 로직 코드.

    컴퓨터가 가위 바위 보 중 하나를 랜덤으로 선택하는 함수 

    둘(사용자, 컴퓨터) 중 위너를 결정해주는 함수

    session을 통해 데이터를 저장하고 결과값을 나타내는 drwa(무승부), win(승), losw(패) 코드를 작성해줬다.

    def get_computer_choice():
        return random.choice(option)
    
    def determine_winner(player_choice, computer_choice):
        if player_choice == computer_choice:
            session['draw'] += 1
            result = "무승부!"
        elif (
            (player_choice == "바위" and computer_choice == "가위")
            or (player_choice == "가위" and computer_choice == "보")
            or (player_choice == "보" and computer_choice == "바위")
        ):
            session['win'] += 1
            result = "이겼습니다!"
        else:
            session['lose'] += 1
            result = "졌습니다.."
        return result

     

     

    그리고 세션을 초기화(승, 패, 무승부 횟수 초기화)하는 함수를 만들어줬다. 사용자가 처음 게임 페이지에 접속할 때나 게임을 다시 시작할 때 쓰면 된다.

    def initialize_session():
        if 'win' not in session:
            session['win'] = 0
        if 'lose' not in session:
            session['lose'] = 0
        if 'draw' not in session:
            session['draw'] = 0

     

     

    @app.route('/') 

    index() 함수는 웹페이지에 접속할 때 실행되는 함수로, 일단 승,패,무승부 횟수를 초기화하고, 데이터베이스에서 게임 히스토리를 가져오고, 게임 결과에 따라 세션의 승, 패, 무승부 횟수를 업데이트하여 index.html에 전달해 웹페이지를 렌더링 해준다.

    @app.route('/')
    def index():
        initialize_session()
        history = GameHistory.query.all()
        return render_template('index.html', history=history, win=session['win'], lose=session['lose'], draw=session['draw'])

     

     

     

    다음은, Post 메소드를 사용해서 게임을 플레이 할 때마다 세션을 초기화 한 후 사용자의 선택을 서버로 전송하고 > 서버는 사용자의 선택과 랜덤으로 생성된 컴퓨터의 선택을 비교 > 게임 결과를 데이터베이스에 기록하고 저장하는 과정 을 설정해준다.

    @app.route('/play', methods=['POST'])
    def play():
        initialize_session()
        player_choice = request.json.get('choice')
        computer_choice = get_computer_choice()
        result = determine_winner(player_choice, computer_choice)
    
        # 데이터베이스에 결과 저장
        new_game = GameHistory(player_choice=player_choice, computer_choice=computer_choice, result=result)
        db.session.add(new_game)
        db.session.commit()
    
        # 결과와 승, 패, 무승부 횟수 반환
        return jsonify({
            'player_choice': player_choice,
            'computer_choice': computer_choice,
            'result': result,
            'win': session['win'],
            'lose': session['lose'],
            'draw': session['draw']
        })

     

     

    @app.route('/reset', methods=['POST'])

    웹페이지에서 (html 코드에서 설정한) '다시 시작' 버튼을 클릭하면(서버에 요청) > /reset 엔드포인트에 포스트 요청이 전송되고 (/reset 라우트에 도달) > flask 앱은 이 요청을 받아서 > reset()함수를 실행하고 세션을 초기화 하여 > JSON 형식으로 값을 반환한다. (요청에 응답)

    # 기록 초기화
    @app.route('/reset', methods=['POST'])
    def reset():
        session['win'] = 0
        session['lose'] = 0
        session['draw'] = 0
        return jsonify({'status': 'reset'})
    
    if __name__ == '__main__':
        app.run(debug=True)

     


    구현된 웹페이지는 아래와 같다.

    *이미지(가위 바위 보 중 하나) 클릭: 사용자의 선택

     

Designed by Tistory.