import queue import random import re import string from wonderwords import RandomWord from .text import TextHelper class ExercisesHelper: @staticmethod def divide_number_into_parts(number, parts): if number < parts: return None part_size = number // parts remaining = number % parts q = queue.Queue() for i in range(parts): if i < remaining: q.put(part_size + 1) else: q.put(part_size) return q @staticmethod def fix_exercise_ids(exercise, start_id): # Initialize the starting ID for the first exercise current_id = start_id questions = exercise["questions"] # Iterate through questions and update the "id" value for question in questions: question["id"] = str(current_id) current_id += 1 return exercise @staticmethod def replace_first_occurrences_with_placeholders(text: str, words_to_replace: list, start_id): for i, word in enumerate(words_to_replace, start=start_id): # Create a case-insensitive regular expression pattern pattern = re.compile(r'\b' + re.escape(word) + r'\b', re.IGNORECASE) placeholder = '{{' + str(i) + '}}' text = pattern.sub(placeholder, text, 1) return text @staticmethod def replace_first_occurrences_with_placeholders_notes(notes: list, words_to_replace: list, start_id): replaced_notes = [] for i, note in enumerate(notes, start=0): word = words_to_replace[i] pattern = re.compile(r'\b' + re.escape(word) + r'\b', re.IGNORECASE) placeholder = '{{' + str(start_id + i) + '}}' note = pattern.sub(placeholder, note, 1) replaced_notes.append(note) return replaced_notes @staticmethod def add_random_words_and_shuffle(word_array, num_random_words): r = RandomWord() random_words_selected = r.random_words(num_random_words) combined_array = word_array + random_words_selected random.shuffle(combined_array) result = [] for i, word in enumerate(combined_array): letter = chr(65 + i) # chr(65) is 'A' result.append({"letter": letter, "word": word}) return result @staticmethod def fillblanks_build_solutions_array(words, start_id): solutions = [] for i, word in enumerate(words, start=start_id): solutions.append( { "id": str(i), "solution": word } ) return solutions @staticmethod def remove_excess_questions(questions: [], quantity): count_true = 0 result = [] for item in reversed(questions): if item.get('solution') == 'true' and count_true < quantity: count_true += 1 else: result.append(item) result.reverse() return result @staticmethod def build_write_blanks_text(questions: [], start_id): result = "" for i, q in enumerate(questions, start=start_id): placeholder = '{{' + str(i) + '}}' result = result + q["question"] + placeholder + "\\n" return result @staticmethod def build_write_blanks_text_form(form: [], start_id): result = "" replaced_words = [] for i, entry in enumerate(form, start=start_id): placeholder = '{{' + str(i) + '}}' # Use regular expression to find the string after ':' match = re.search(r'(?<=:)\s*(.*)', entry) # Extract the matched string original_string = match.group(1) # Split the string into words words = re.findall(r'\b\w+\b', original_string) # Remove words with only one letter filtered_words = [word for word in words if len(word) > 1] # Choose a random word from the list of words selected_word = random.choice(filtered_words) pattern = re.compile(r'\b' + re.escape(selected_word) + r'\b', re.IGNORECASE) # Replace the chosen word with the placeholder replaced_string = pattern.sub(placeholder, original_string, 1) # Construct the final replaced string replaced_string = entry.replace(original_string, replaced_string) result = result + replaced_string + "\\n" # Save the replaced word or use it as needed # For example, you can save it to a file or a list replaced_words.append(selected_word) return result, replaced_words @staticmethod def build_write_blanks_solutions(questions: [], start_id): solutions = [] for i, q in enumerate(questions, start=start_id): solution = [q["possible_answers"]] if isinstance(q["possible_answers"], str) else q["possible_answers"] solutions.append( { "id": str(i), "solution": solution } ) return solutions @staticmethod def build_write_blanks_solutions_listening(words: [], start_id): solutions = [] for i, word in enumerate(words, start=start_id): solution = [word] if isinstance(word, str) else word solutions.append( { "id": str(i), "solution": solution } ) return solutions @staticmethod def answer_word_limit_ok(question): # Check if any option in any solution has more than three words return not any( len(option.split()) > 3 for solution in question["solutions"] for option in solution["solution"] ) @staticmethod def assign_letters_to_paragraphs(paragraphs): result = [] letters = iter(string.ascii_uppercase) for paragraph in paragraphs.split("\n\n"): if TextHelper.has_x_words(paragraph, 10): result.append({'paragraph': paragraph.strip(), 'letter': next(letters)}) return result @staticmethod def contains_empty_dict(arr): return any(elem == {} for elem in arr) @staticmethod def fix_writing_overall(overall: float, task_response: dict): grades = [category["grade"] for category in task_response.values()] if overall > max(grades) or overall < min(grades): total_sum = sum(grades) average = total_sum / len(grades) rounded_average = round(average, 0) return rounded_average return overall @staticmethod def build_options(ideas): options = [] letters = iter(string.ascii_uppercase) for idea in ideas: options.append({ "id": next(letters), "sentence": idea["from"] }) return options @staticmethod def build_sentences(ideas, start_id): sentences = [] letters = iter(string.ascii_uppercase) for idea in ideas: sentences.append({ "solution": next(letters), "sentence": idea["idea"] }) random.shuffle(sentences) for i, sentence in enumerate(sentences, start=start_id): sentence["id"] = i return sentences @staticmethod def randomize_mc_options_order(questions): option_ids = ['A', 'B', 'C', 'D'] for question in questions: # Store the original solution text original_solution_text = next( option['text'] for option in question['options'] if option['id'] == question['solution']) # Shuffle the options random.shuffle(question['options']) # Update the option ids and find the new solution id for idx, option in enumerate(question['options']): option['id'] = option_ids[idx] if option['text'] == original_solution_text: question['solution'] = option['id'] return questions