-
파이썬, 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)
구현된 웹페이지는 아래와 같다.
*이미지(가위 바위 보 중 하나) 클릭: 사용자의 선택
'Python' 카테고리의 다른 글
[파이썬, 자료구조 알고리즘] Stack (2) 2024.07.12 파이썬, 알고리즘... 뭔말이야.. (0) 2024.07.11 flask 파이참 템플릿, code snippets이 안불러와질때 (0) 2024.07.09 파이썬, class로 sns platform 코드2 input으로 객체 생성 (0) 2024.07.06 python, class, 인스턴스 생성 - 간단한 sns platform 코딩 (2) 2024.07.05