Understand the complete project structure and goals
Dima - Game logic, sessions, and prize system
Danil - Questions and answers in JSON format
Inna - User interface and game interaction
Artyom - Styling and Russian visual theme
We're creating a "Who Wants to Be a Millionaire?" style quiz game with a Russian cultural theme. Players answer increasingly difficult questions to win virtual prize money.
Flask is a web framework that lets us create web applications with Python. Think of it as a restaurant:
app.py = The restaurant kitchen (prepares everything)
Routes = The menu (different pages/actions)
Templates = The dining area (what customers see)
Static files = Decorations and utensils (CSS, JavaScript, images)
When a user visits our website, Flask serves the appropriate template and handles any requests, like when a player answers a question.
We'll follow this process over 6 lessons:
Lessons 1-2: Setup & foundation - Get basic structure working
Lessons 3-4: Core development - Implement main features
Lessons 5-6: Completion & testing - Polish and fix issues
Each student has a specific role, but we'll integrate all our work at the end to create a complete, functional game!
First, let's set up the prize money levels. Players earn more money for each correct answer.
# 1. This file should contain the game logic for the quiz game # TODO: Import Flask and setup the app # TODO: Define prize levels and guaranteed levels # TODO: Setup game session routes # TODO: Implement question serving functionality # TODO: Add lifeline functionality
What this does: Creates a list of prize amounts that players can win. Each number represents the prize for answering that question correctly. The amounts increase as questions get harder.
GUARANTEED_LEVELS: These are safety nets - if a player gets a question wrong after one of these levels, they still win the prize from that level.
We need to track each player's game session - what question they're on, their prize money, etc.
from flask import Flask, session, redirect, url_for
app = Flask(__name__)
app.secret_key = 'your_secret_key_here' # Needed for sessions
@app.route('/start')
def start_game():
# Initialize a new game session
session['current_question'] = 0
session['score'] = 0
session['lifelines'] = ['fifty_fifty'] # Only one lifeline implemented
return redirect(url_for('game_screen'))
What this does: Creates a "/start" route that begins a new game. It resets the player's progress to zero and gives them one lifeline: fifty_fifty.
Session: Like a digital backpack that remembers your game progress as you play.
Routes: Different web addresses that do different things in our app.
Note: Although the original plan included multiple lifelines, the current implementation only includes the fifty_fifty lifeline for simplicity.
We need to send questions to the player one by one as they progress.
# 2. This file should contain the database connection and data handling # TODO: Load questions from JSON file # TODO: Implement answer checking functionality # TODO: Handle lifeline requests # TODO: Manage game state and sessions
What this does: Reads the questions from the JSON file and sends the appropriate question based on how far the player has progressed.
JSON: A file format that stores data in an organized way, like a digital filing cabinet.
Session.get(): Safely checks what question the player is currently on.
Pro Tip: Test your backend by running python app.py and visiting http://localhost:5000/start in your browser!
Our "database" is a JSON file that stores all the quiz questions, options, and correct answers.
// 1. This file should contain the basic structure of the game page // TODO: Create the main game container // TODO: Add elements for displaying questions and answers // TODO: Include buttons for lifelines // TODO: Add a game over screen // TODO: Link to CSS and JavaScript files
What this does: Creates a list of question objects. Each question has:
Important: The correct_answer uses 0-based indexing, so 0 = first option, 1 = second option, etc.
Create questions about Russian history, culture, geography, and famous people.
{
"question": "What is the name of the famous Russian ballet company?",
"options": [
"Moscow Dance Theater",
"St. Petersburg Ballet",
"Bolshoi Ballet",
"Russian National Ballet"
],
"correct_answer": 2
},
{
"question": "Which Russian ruler was known as 'The Great' and modernized Russia?",
"options": [
"Ivan the Terrible",
"Catherine the Great",
"Peter the Great",
"Alexander II"
],
"correct_answer": 2
},
{
"question": "What is the traditional Russian soup made with beets?",
"options": [
"Shchi",
"Borscht",
"Solyanka",
"Ukha"
],
"correct_answer": 1
}
What this does: Adds culturally relevant questions to our game. Make sure:
We need 15 questions total, with increasing difficulty.
// Example of a harder question for later in the game
{
"question": "In which year did the Soviet Union dissolve?",
"options": [
"1989",
"1991",
"1993",
"1985"
],
"correct_answer": 1
},
{
"question": "What is the name of the Russian equivalent of NASA?",
"options": [
"Russian Space Agency",
"Soviet Space Program",
"Roscosmos",
"Kosmonavtika"
],
"correct_answer": 2
}
What this does: Adds more challenging questions for the higher prize levels. These should require more specific knowledge.
Tip: Use a mix of history, geography, culture, science, and arts questions to make the game interesting!
Pro Tip: Validate your JSON at jsonlint.com to catch any syntax errors!
Create the main game screen where questions will be displayed.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Russian Quiz - Game</title>
<link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
</head>
<body>
<div class="container">
<h1>Russian Quiz</h1>
<div class="score">Prize: <span id="prize">0</span> ₽</div>
<div class="question-box">
<div class="question-number">Question <span id="q-number">1</span>/5</div>
<div class="question" id="question-text">Loading...</div>
<div class="options" id="options">
<!-- Options go here -->
</div>
<div class="result" id="result"></div>
</div>
<button class="lifeline" onclick="useFiftyFifty()">50:50 Lifeline</button>
<div class="game-over" id="game-over" style="display: none;">
<h2>Game Over!</h2>
<p>You won: <span id="final-prize">0</span> ₽</p>
<button onclick="restartGame()">Play Again</button>
</div>
</div>
<script src="{{ url_for('static', filename='script.js') }}"></script>
</body>
</html>
What this does: Creates the basic structure of our game page with:
URL_FOR: A Flask function that creates the correct path to our CSS and JavaScript files.
Create utility functions to avoid repeating code and make our application more maintainable.
// Utility function for making API requests
function apiRequest(url, options = {}) {
return fetch(url, options)
.then(response => response.json())
.catch(error => {
console.error('Error:', error);
throw error;
});
}
// Utility function for updating element text content
function updateElementText(id, text) {
const element = document.getElementById(id);
if (element) {
element.textContent = text;
}
}
// Utility function for showing/hiding elements
function toggleElementVisibility(id, show = true) {
const element = document.getElementById(id);
if (element) {
element.style.display = show ? 'block' : 'none';
}
}
What this does: These utility functions follow the DRY (Don't Repeat Yourself) principle:
DRY Principle: Writing code once and reusing it makes applications easier to maintain and less error-prone.
Use JavaScript to fetch questions from the backend and display them.
let currentQuestion = null;
function loadQuestion() {
apiRequest('/get_question')
.then(data => {
if (data.game_over) {
endGame(data.final_score);
return;
}
currentQuestion = data;
displayQuestion(data);
})
.catch(error => console.error('Error:', error));
}
function displayQuestion(data) {
updateElementText('q-number', data.question_number);
updateElementText('question-text', data.question);
updateElementText('prize', data.current_prize);
const optionsContainer = document.getElementById('options');
optionsContainer.innerHTML = '';
data.options.forEach((option, index) => {
const optionElement = document.createElement('div');
optionElement.className = 'option';
optionElement.textContent = option;
optionElement.onclick = () => selectAnswer(option);
optionsContainer.appendChild(optionElement);
});
// Reset result display
toggleElementVisibility('result', false);
const result = document.getElementById('result');
if (result) {
result.className = 'result';
}
}
What this does:
Event Handling: Makes the answer options clickable by assigning onclick handlers.
Handle what happens when a player selects an answer.
function selectAnswer(answer) {
apiRequest('/answer', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({ answer: answer })
})
.then(data => {
const result = document.getElementById('result');
if (result) {
result.style.display = 'block';
if (data.correct) {
result.textContent = 'Correct!';
result.className = 'result correct';
setTimeout(() => {
if (data.game_over) {
endGame(data.final_score);
} else {
loadQuestion();
}
}, 1500);
} else {
result.textContent = `Wrong! Correct answer: ${data.correct_answer}`;
result.className = 'result incorrect';
setTimeout(() => {
endGame(data.final_score);
}, 2000);
}
}
})
.catch(error => console.error('Error:', error));
}
function endGame(score) {
updateElementText('final-prize', score);
toggleElementVisibility('game-over', true);
toggleElementVisibility('question-box', false);
toggleElementVisibility('lifeline', false);
}
function restartGame() {
window.location.href = '/start';
}
// Start the game when page loads
if (window.location.pathname === '/start') {
loadQuestion();
}
What this does:
setTimeout(): Adds a delay before progressing to give players time to see the result.
Implement the 50:50 lifeline that removes two wrong answers.
// 2. This file should contain the interactive functionality of the game // TODO: Implement functions to load and display questions // TODO: Add event handlers for answer selection // TODO: Implement lifeline functionality // TODO: Add game flow control (next question, game over)
What this does:
Error handling: Gracefully handles errors and re-enables the button if the lifeline fails.
Create a color scheme inspired by the Russian flag and traditional colors.
/* Russian Color Theme */
:root {
--russian-white: #ffffff;
--russian-blue: #1a3b8b;
--russian-red: #d52b1e;
--russian-gold: #daa520;
--russian-dark: #0a1a3a;
}
body {
background: linear-gradient(135deg, var(--russian-blue), var(--russian-dark));
color: var(--russian-white);
font-family: 'Arial', sans-serif;
min-height: 100vh;
margin: 0;
padding: 0;
}
.game-container {
max-width: 800px;
margin: 0 auto;
padding: 20px;
background-color: rgba(255, 255, 255, 0.95);
border-radius: 15px;
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.3);
color: var(--russian-dark);
}
.header {
background: linear-gradient(to right, var(--russian-blue), var(--russian-red));
color: white;
padding: 20px;
border-radius: 10px;
text-align: center;
margin-bottom: 30px;
}
What this does: Establishes a color palette based on the Russian flag colors and applies them to our game:
Style the question display and answer options to be clear and attractive.
.question-container {
margin-bottom: 30px;
}
.question {
font-size: 1.5rem;
font-weight: bold;
text-align: center;
margin-bottom: 25px;
padding: 20px;
background-color: var(--russian-white);
border: 3px solid var(--russian-gold);
border-radius: 10px;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
}
.options {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 15px;
}
.option {
padding: 15px 20px;
background: linear-gradient(to bottom, #f8f9fa, #e9ecef);
border: 2px solid var(--russian-blue);
border-radius: 8px;
font-size: 1.1rem;
cursor: pointer;
transition: all 0.3s ease;
color: var(--russian-dark);
}
.option:hover {
background: linear-gradient(to bottom, #e9ecef, #dee2e6);
transform: translateY(-2px);
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
}
.option:active {
transform: translateY(0);
}
/* Answer feedback styles */
.option.correct {
background: linear-gradient(to bottom, #d4edda, #c3e6cb);
border-color: #28a745;
color: #155724;
}
.option.wrong {
background: linear-gradient(to bottom, #f8d7da, #f1b0b7);
border-color: #dc3545;
color: #721c24;
}
What this does:
CSS Grid: Modern way to create responsive layouts without complex calculations.
Style the lifeline buttons and prize display to match the Russian theme.
.lifelines {
display: flex;
justify-content: center;
gap: 20px;
margin: 20px 0;
}
.lifeline {
padding: 10px 20px;
background: linear-gradient(to bottom, var(--russian-gold), #b8860b);
color: var(--russian-dark);
border: none;
border-radius: 25px;
font-weight: bold;
cursor: pointer;
transition: all 0.3s ease;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
}
.lifeline:hover:not(:disabled) {
transform: translateY(-2px);
box-shadow: 0 6px 12px rgba(0, 0, 0, 0.3);
}
.lifeline:disabled {
background: linear-gradient(to bottom, #6c757d, #495057);
color: #adb5bd;
cursor: not-allowed;
transform: none;
box-shadow: none;
}
.prize-display {
font-size: 1.5rem;
font-weight: bold;
color: var(--russian-gold);
text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.5);
}
/* Responsive design for mobile */
@media (max-width: 768px) {
.options {
grid-template-columns: 1fr;
}
.game-container {
margin: 10px;
padding: 15px;
}
.question {
font-size: 1.2rem;
}
}
What this does:
Media Queries: Apply different styles based on screen size - crucial for mobile users!