Our Project
Group
The purpose of our group’s program is to create a multiplayer drawing and guessing game inspired by Scribble.io. This program allows players to take turns drawing while others guess the word or phrase being illustrated. The goal is to provide an entertaining and interactive way for people to engage in creative gameplay, fostering collaboration, quick thinking, and creativity.
Individual
My individual feature focuses on implementing the real-time guessing system. This feature enables players to submit guesses while others draw, providing instant feedback on whether the guess is correct. The purpose of this feature is to ensure smooth and engaging gameplay by allowing seamless interaction between players and keeping the game dynamic and competitive.
List Requests
In our program, we make use of lists, dictionaries, and a database to handle the application’s data. Specifically:
- Lists are used to store rows of guesses
- Dictionaries are used to handle the JSON api requests and responses
- Database (SQLite) is used to store the user data(the guesses)
The Guess function uses the following requests;
- Post: add new guesses
- Get: Retrieveing new entries
- Put: To update existing guesses
- Delete: deleting guesses
We use lists to handle guesses and dictionaires to represent individual entries.Those database rows are then coverted for JSON Responses
Formatting JSON Response from API to DOM
@token_required() # Require authentication before accessing this route
def get(self):
"""
Return the guesses of the authenticated user as a JSON object.
"""
# Get the current authenticated user from the token.
# This ensures that only the logged-in user's data is accessed.
current_user = g.current_user
# Query the database to find all guesses associated with the current user.
guesses = Guess.query.filter_by(user_id=current_user.id).all()
# If the user has no recorded guesses, return a 404 response with a JSON message.
# This prevents returning an empty list and provides meaningful feedback.
if not guesses:
return {'message': 'No guesses found for this user'}, 404
# Format the retrieved guesses into a list of dictionaries.
# Each dictionary represents a single guess and contains:
# - 'guess': the actual guessed word
# - 'is_correct': a boolean indicating if the guess was correct or not
guesses_data = [{'guess': guess.guess, 'is_correct': guess.is_correct} for guess in guesses]
# Convert the list of dictionaries into a JSON response.
# This ensures that the frontend receives structured data that can be easily parsed.
return jsonify(guesses_data)
Database queries
Query the database using SQLAlchemy to find all guesses for the current user - SQLAlchemy is a third-party library that allows us to interact with the database using Python objects instead of raw SQL queries.
@token_required() # Require authentication before accessing this route
def get(self):
"""
Return the guesses of the authenticated user as a JSON object.
"""
# Get the current authenticated user from the token
current_user = g.current_user
# Query the database to find all guesses that match the current user's ID
guesses = Guess.query.filter_by(user_id=current_user.id).all()
# If the user has no guesses recorded, return a 404 response with a message
if not guesses:
return {'message': 'No guesses found for this user'}, 404
# Iterate through each guess object and create a list of dictionaries
# Each dictionary contains the guess and whether it was correct
guesses_data = [{'guess': guess.guess, 'is_correct': guess.is_correct} for guess in guesses]
# Convert the list into a JSON response and return it
return jsonify(guesses_data)
Methods in Class to Work with Columns:
class GuessesAPI:
class _CRUD(Resource):
@token_required()
def post(self):
"""
Add a new guess for the authenticated user.
"""
current_user = g.current_user # Get the current authenticated user
body = request.get_json() # Get the request body as JSON
guess_value = body.get('guess') # Extract the 'guess' field from the request body
if not guess_value:
return {'message': 'No guess provided'}, 400 # Return an error if no guess is provided
# Create a new Guess object and assume it's incorrect initially
new_guess = Guess(user_id=current_user.id, guess=guess_value, is_correct=False)
# Add the new guess to the database session and commit it
db.session.add(new_guess)
db.session.commit()
return jsonify({'message': 'Guess added successfully', 'guess': new_guess.guess}), 201
@token_required()
def get(self):
"""
Retrieve all guesses made by the authenticated user.
"""
current_user = g.current_user # Get the authenticated user
# Fetch all guesses associated with the current user from the database
guesses = Guess.query.filter_by(user_id=current_user.id).all()
if not guesses:
return {'message': 'No guesses found for this user'}, 404 # Handle case where no guesses exist
# Convert guesses into a structured JSON response
guesses_data = [{'id': guess.id, 'guess': guess.guess, 'is_correct': guess.is_correct} for guess in guesses]
return jsonify(guesses_data) # Return the JSON response
@token_required()
def put(self):
"""
Update an existing guess's correctness status.
"""
current_user = g.current_user # Get the authenticated user
body = request.get_json() # Parse the request body
guess_id = body.get('id') # Get the guess ID
is_correct = body.get('is_correct') # Get the new correctness status
if guess_id is None or is_correct is None:
return {'message': 'Guess ID and correctness status are required'}, 400 # Validate input
# Find the guess entry belonging to the user
guess = Guess.query.filter_by(id=guess_id, user_id=current_user.id).first()
if not guess:
return {'message': 'Guess not found'}, 404 # Return error if guess doesn't exist
# Update the correctness status
guess.is_correct = bool(is_correct)
db.session.commit() # Save changes to the database
return jsonify({'message': 'Guess updated successfully', 'id': guess.id, 'is_correct': guess.is_correct})
@token_required()
def delete(self):
"""
Delete a guess made by the authenticated user.
"""
current_user = g.current_user # Get the authenticated user
body = request.get_json() # Parse the request body
guess_id = body.get('id') # Get the ID of the guess to be deleted
if not guess_id:
return {'message': 'Guess ID is required'}, 400 # Ensure ID is provided
# Find the guess entry that belongs to the user
guess = Guess.query.filter_by(id=guess_id, user_id=current_user.id).first()
if not guess:
return {'message': 'Guess not found'}, 404 # Handle case where guess doesn't exist
# Delete the guess and commit changes to the database
db.session.delete(guess)
db.session.commit()
return jsonify({'message': 'Guess deleted successfully', 'id': guess_id})
Algorithmic code request.
Definition of Code Blocks to Handle Requests
Api CRUD Methods:
class GuessesAPI:
class _CRUD(Resource):
@token_required()
def post(self):
"""
Add a new guess for the authenticated user.
"""
current_user = g.current_user # Get the authenticated user
body = request.get_json() # Extract JSON data from request
new_guess = body.get('guess') # Retrieve 'guess' value from request body
if not new_guess:
return {'message': 'No guess provided'}, 400 # Validate input
# Create a new Guess object with the provided guess value
new_guess_obj = Guess(user_id=current_user.id, guess=new_guess, is_correct=False)
# Add and commit the new guess to the database
db.session.add(new_guess_obj)
db.session.commit()
return jsonify({'message': 'Guess added successfully', 'guess': new_guess_obj.guess}), 201
@token_required()
def get(self):
"""
Retrieve all guesses made by the authenticated user.
"""
current_user = g.current_user # Get the authenticated user
# Fetch all guesses associated with the user
guesses = Guess.query.filter_by(user_id=current_user.id).all()
if not guesses:
return {'message': 'No guesses found for this user'}, 404 # Handle case where no guesses exist
# Convert guesses into a structured JSON response
guesses_data = [{'id': guess.id, 'guess': guess.guess, 'is_correct': guess.is_correct} for guess in guesses]
return jsonify(guesses_data) # Return the JSON response
@token_required()
def put(self):
"""
Update an existing guess for the authenticated user.
"""
current_user = g.current_user # Get the authenticated user
body = request.get_json() # Extract JSON data from request
updated_guess = body.get('guess') # Retrieve updated guess value
guess_id = body.get('guess_id') # Retrieve ID of the guess to be updated
if not updated_guess or not guess_id:
return {'message': 'No guess or guess_id provided'}, 400 # Validate input
# Find the guess by ID and ensure it belongs to the current user
guess = Guess.query.filter_by(id=guess_id, user_id=current_user.id).first()
if not guess:
return {'message': 'Guess not found or does not belong to the user'}, 404
# Update the guess value
guess.guess = updated_guess
db.session.commit() # Save changes to the database
return jsonify({'message': 'Guess updated successfully', 'guess': guess.guess}), 200
@token_required()
def delete(self):
"""
Delete a specified guess of the authenticated user.
"""
body = request.get_json() # Extract JSON data from request
if not body or 'guess_id' not in body:
return {'message': 'No guess_id provided'}, 400 # Validate input
current_user = g.current_user # Get the authenticated user
guess_id = body.get('guess_id') # Retrieve ID of the guess to be deleted
# Find the guess by ID and ensure it belongs to the current user
guess = Guess.query.filter_by(id=guess_id, user_id=current_user.id).first()
if not guess:
return {'message': 'Guess not found or does not belong to the user'}, 404
# Delete the guess and commit changes to the database
db.session.delete(guess)
db.session.commit()
return {'message': 'Guess deleted successfully'}, 200
Method/Procedure in Class with Sequencing, Selection, and Iteration
@token_required()
def update_guess():
"""
API endpoint to update a user's guess. This function follows:
- **Sequencing**: Each step is executed in a logical order.
- **Selection**: Decisions are made based on input validity and conditions.
- **Iteration**: Updates are applied to stored guesses iteratively.
"""
try:
# ========== SEQUENCING: Step 1 - Parse JSON input ==========
data = request.json # Extract the JSON request body
if not data:
return jsonify({"error": "Invalid or missing JSON payload."}), 400 # Selection: Handle missing data
print("Incoming update request:", data) # Debugging output
# ========== SEQUENCING: Step 2 - Validate required keys ==========
required_keys = {'user', 'guess_id', 'new_guess', 'is_correct'}
is_valid, error_message = validate_request_data(data, required_keys)
if not is_valid:
print("Validation failed:", error_message) # Debugging
return jsonify({"error": error_message}), 400 # Selection: Handle invalid data
# ========== SEQUENCING: Step 3 - Extract values from JSON ==========
user = data['user']
guess_id = data['guess_id']
new_guess = data['new_guess']
is_correct = data['is_correct']
# ========== SEQUENCING: Step 4 - Validate data types ==========
if not isinstance(user, str) or not isinstance(new_guess, str) or not isinstance(is_correct, bool):
return jsonify({"error": "Invalid data types for user, guess, or is_correct."}), 400 # Selection
# ========== SEQUENCING: Step 5 - Find and update the guess ==========
existing_guess = Guess.query.filter_by(id=guess_id, guesser_name=user).first() # Selection: Locate the guess
if not existing_guess:
return jsonify({"error": "Guess not found or does not belong to the user."}), 404 # Selection
# ========== SEQUENCING: Step 6 - Update the guess in the database ==========
existing_guess.guess = new_guess # Modify guess value
existing_guess.is_correct = is_correct # Modify correctness status
db.session.commit() # Save changes
# ========== SEQUENCING: Step 7 - Update user stats ==========
if user in user_stats:
user_stats[user]["guesses"] = [ # Iteration: Modify guess list
{"guess": new_guess, "is_correct": is_correct} if g["guess"] == existing_guess.guess else g
for g in user_stats[user]["guesses"]
]
# Recalculate correctness statistics
user_stats[user]["correct"] = sum(1 for g in user_stats[user]["guesses"] if g["is_correct"]) # Iteration
user_stats[user]["wrong"] = sum(1 for g in user_stats[user]["guesses"] if not g["is_correct"]) # Iteration
# ========== SEQUENCING: Step 8 - Return response ==========
response_data = {
"User": user,
"Updated Guess": {
"Guess": new_guess,
"Is Correct": is_correct
},
"Updated Stats": {
"Correct Guesses": user_stats[user]["correct"],
"Wrong Guesses": user_stats[user]["wrong"],
"Total Guesses": len(user_stats[user]["guesses"]) # Iteration: Count guesses
}
}
return jsonify(response_data), 200 # Return success response
except Exception as e:
print("General Exception:", str(e)) # Debugging
return jsonify({"error": f"Internal server error: {str(e)}"}), 500 # Selection: Handle unexpected errors
Parameters and Return Type
-
Parameters The body of the request is in JSON format, which contains fields like:
guesser_name: Name of the guesser (string). guess: The guessed value (string). is_correct: Whether the guess is correct (boolean).
-
Return Type The functions return a JSON response, created using jsonify(), which ensures the response is in proper JSON format.
{ “id”: 1, “guesser_name”: “JohnDoe”, “guess”: “apple”, “is_correct”: true }
Call to Algorithm request
Definition of Code Block to Make a Request
Frontend Fetch to Endpoint:
async function fetchGuesses() {
try {
// Step 1: Make a GET request to the server to fetch the list of guesses
const response = await fetch('http://127.0.0.1:8887/api/guesses', { method: 'GET' });
// Step 2: Check if the response is successful (status code 200-299)
if (!response.ok) throw new Error('Failed to fetch guesses'); // If not, throw an error
// Step 3: Parse the response body as JSON
const guesses = await response.json(); // The server is expected to respond with an array of guesses
// Step 4: Update the UI with the fetched guesses
updateGuessTable(guesses); // Call the function to update the guesses table in the UI
} catch (error) {
// Step 5: Handle any errors that occurred during the request or processing
console.error('Error fetching guesses:', error); // Log the error to the console
messageArea.textContent = `Error fetching guesses: ${error.message}`; // Display the error message to the user
}
}
Discuss the Call/Request to the Method with Algorithim
- Call/Request:
- The delete CRUD method sends delete request to api/guesses endpoint for guess deletion
@token_required() # Ensures the user is authenticated before accessing this endpoint
def delete(self):
"""
Delete a specified guess of the authenticated user.
"""
# Step 1: Retrieve JSON body from the request
body = request.get_json()
# Step 2: Check if the request contains a 'guess_id'
if not body or 'guess_id' not in body:
return {'message': 'No guess_id provided'}, 400 # Return error if missing
# Step 3: Get the authenticated user (provided by token_required)
current_user = g.current_user
# Step 4: Extract the 'guess_id' from the JSON body
guess_id = body.get('guess_id')
# Step 5: Query the database using SQLAlchemy to find the guess
# This query is provided by SQLAlchemy (a third-party ORM) and translates to:
# SELECT * FROM guesses WHERE id = <guess_id> AND user_id = <current_user.id>;
guess = Guess.query.filter_by(id=guess_id, user_id=current_user.id).first()
# Step 6: If no guess is found (either it doesn't exist or doesn't belong to the user), return an error
if not guess:
return {'message': 'Guess not found or does not belong to the user'}, 404
# Step 7: Delete the guess from the database
db.session.delete(guess) # SQLAlchemy ORM handles the deletion
db.session.commit() # Commit the transaction to make changes permanent
# Step 8: Return a success response
return {'message': 'Guess deleted successfully'}, 200
- Return/Response:
- The response from the backend is handled by checking the status code and updating the UI accordingly.
Success Response: 200 OK
{
"message": "Guess deleted successfully"
}
Error response: 400 Missing guess_id
{
"message": "No guess_id provided"
}
Error Response: 404 guess not found
{
"message": "Guess not found or does not belong to the user"
}
Handling Data and Error Conditions
- Normal Conditions:
- The guess is successfully deleted, and the UI is updated to reflect the change.
- 200 OK: Guess successfully deleted
- The guess is successfully deleted, and the UI is updated to reflect the change.
- Error Conditions:
- If the guess is not found or the request fails, an error message is displayed.
- error 404: Guess not found
- error 400: missing guess_id provided
- If the guess is not found or the request fails, an error message is displayed.