Resolve "Fragentyp: Ort suchen" #270
@@ -205,53 +205,96 @@ class GameConsumer(AsyncWebsocketConsumer):
|
||||
current_question = quiz_game.quiz_id.questions.all()[quiz_game.current_question_index]
|
||||
question_data = json.loads(current_question.data)
|
||||
target_location = question_data['target_location']
|
||||
tolerance_radius = question_data['tolerance_radius']
|
||||
print(f"target_location: {target_location}")
|
||||
print(f"answer_location: {answer_location}")
|
||||
tolerance_radius = question_data.get('tolerance_radius', 1000) # Default 1km if not set
|
||||
|
||||
print(f"Raw target_location: {target_location}")
|
||||
print(f"Raw answer_location: {answer_location}")
|
||||
print(f"tolerance_radius: {tolerance_radius}")
|
||||
|
||||
# Configuration - Make these easily adjustable
|
||||
MAX_DISTANCE_KM = 1000 # Maximum distance for scoring (in km)
|
||||
DIRECT_HIT_BONUS = 200 # Extra points for direct hit within tolerance
|
||||
# Parse coordinates if they are strings
|
||||
def parse_coords(coord):
|
||||
if isinstance(coord, str):
|
||||
try:
|
||||
# Handle both comma and space separated coordinates
|
||||
if ',' in coord:
|
||||
lat, lng = map(float, [x.strip() for x in coord.split(',')])
|
||||
else:
|
||||
# Try splitting by space if no comma
|
||||
parts = coord.strip().split()
|
||||
if len(parts) >= 2:
|
||||
lat, lng = map(float, parts[:2])
|
||||
else:
|
||||
raise ValueError("Invalid coordinate format")
|
||||
return (lat, lng)
|
||||
except (ValueError, AttributeError) as e:
|
||||
print(f"Error parsing coordinates {coord}: {e}")
|
||||
return None
|
||||
elif isinstance(coord, (list, tuple)) and len(coord) >= 2:
|
||||
return (float(coord[0]), float(coord[1]))
|
||||
return None
|
||||
|
||||
# Calculate base score
|
||||
distance_km = geodesic(answer_location, target_location).kilometers
|
||||
tolerance_km = int(tolerance_radius) / 1000 # Convert meters to kilometers
|
||||
# Parse the coordinates
|
||||
target_location = parse_coords(target_location)
|
||||
answer_location = parse_coords(answer_location)
|
||||
|
||||
# Calculate base score with non-linear decrease
|
||||
if distance_km <= tolerance_km:
|
||||
# Direct hit - full points + bonus
|
||||
base_score = 1000 + DIRECT_HIT_BONUS # 1000 + 200 bonus
|
||||
is_correct = True
|
||||
if not target_location or not answer_location:
|
||||
print("Invalid coordinates, cannot calculate score")
|
||||
is_correct = False
|
||||
score = 0
|
||||
else:
|
||||
if distance_km > MAX_DISTANCE_KM:
|
||||
# Beyond max distance - 0 points
|
||||
base_score = 0
|
||||
print(f"Parsed target_location: {target_location}")
|
||||
print(f"Parsed answer_location: {answer_location}")
|
||||
|
||||
# Configuration - Make these easily adjustable
|
||||
MAX_DISTANCE_KM = 1000 # Maximum distance for scoring (in km)
|
||||
DIRECT_HIT_BONUS = 200 # Extra points for direct hit within tolerance
|
||||
|
||||
try:
|
||||
# Calculate distance
|
||||
distance_km = geodesic(answer_location, target_location).kilometers
|
||||
tolerance_km = float(tolerance_radius) / 1000 # Convert meters to kilometers
|
||||
|
||||
print(f"Distance: {distance_km} km, Tolerance: {tolerance_km} km")
|
||||
|
||||
# Calculate base score with non-linear decrease
|
||||
if distance_km <= tolerance_km:
|
||||
# Direct hit - full points + bonus
|
||||
base_score = 1000 + DIRECT_HIT_BONUS
|
||||
is_correct = True
|
||||
else:
|
||||
if distance_km > MAX_DISTANCE_KM:
|
||||
# Beyond max distance - 0 points
|
||||
base_score = 0
|
||||
is_correct = False
|
||||
else:
|
||||
# Non-linear decrease using exponential falloff
|
||||
progress = (distance_km - tolerance_km) / (MAX_DISTANCE_KM - tolerance_km)
|
||||
falloff = progress ** 1.5 # 1.5 makes the falloff steeper at the beginning
|
||||
base_score = 1000 * (1 - falloff)
|
||||
is_correct = True
|
||||
|
||||
# Apply time penalty (reduces score based on time taken)
|
||||
if is_correct and base_score > 0:
|
||||
# Calculate time taken as a fraction of total time (0-1)
|
||||
time_taken_sec = (int(current_question.time_per_question) * 1000 - time_remaining) / 1000
|
||||
max_time_sec = int(current_question.time_per_question)
|
||||
time_fraction = min(1.0, time_taken_sec / max_time_sec) if max_time_sec > 0 else 1.0
|
||||
|
||||
# Reduce points based on time taken (up to 50% reduction for answering at the last second)
|
||||
time_penalty = base_score * 0.5 * time_fraction # Up to 50% penalty
|
||||
final_score = max(1, base_score - time_penalty) # At least 1 point if correct
|
||||
else:
|
||||
final_score = base_score # 0 points for incorrect answers
|
||||
|
||||
# Apply max score limit after all calculations (including bonus)
|
||||
final_score = min(final_score, 1200) # Cap at 1200 (1000 + 200 bonus)
|
||||
|
||||
score = int(round(final_score))
|
||||
|
||||
except Exception as e:
|
||||
print(f"Error calculating score: {e}")
|
||||
is_correct = False
|
||||
else:
|
||||
# Non-linear decrease using exponential falloff
|
||||
# This creates a steeper drop-off at the beginning
|
||||
progress = (distance_km - tolerance_km) / (MAX_DISTANCE_KM - tolerance_km)
|
||||
# Using a power function to create non-linear falloff
|
||||
falloff = progress ** 1.5 # 1.5 makes the falloff steeper at the beginning
|
||||
base_score = 1000 * (1 - falloff)
|
||||
is_correct = True
|
||||
base_score = max(0, min(1000, int(base_score)))
|
||||
|
||||
# Apply time penalty (reduces score based on time taken)
|
||||
if is_correct and base_score > 0:
|
||||
# Calculate time taken as a fraction of total time (0-1)
|
||||
time_taken_sec = (int(current_question.time_per_question) * 1000 - time_remaining) / 1000
|
||||
max_time_sec = int(current_question.time_per_question)
|
||||
time_fraction = min(1.0, time_taken_sec / max_time_sec) if max_time_sec > 0 else 1.0
|
||||
|
||||
# Reduce points based on time taken (up to 50% reduction for answering at the last second)
|
||||
time_penalty = base_score * 0.5 * time_fraction # Up to 50% penalty
|
||||
final_score = max(1, base_score - time_penalty) # At least 1 point if correct
|
||||
else:
|
||||
final_score = base_score # 0 points for incorrect answers
|
||||
|
||||
score = int(round(final_score))
|
||||
score = 0
|
||||
|
||||
# Save the answer
|
||||
answer_obj, created = QuizAnswer.objects.get_or_create(
|
||||
|
||||
Reference in New Issue
Block a user