diff --git a/Quizzler Using Tkinter and Trivia DB API/README.md b/Quizzler Using Tkinter and Trivia DB API/README.md new file mode 100644 index 00000000000..1efa6c3f350 --- /dev/null +++ b/Quizzler Using Tkinter and Trivia DB API/README.md @@ -0,0 +1,103 @@ +# ๐Ÿง  Quizzler - Python-Based Quiz Application + +## ๐Ÿ“Œ Overview + +**Quizzler** is a Python-based GUI quiz application that fetches trivia questions from an online API and challenges the user with a series of True/False questions. Built using **Tkinter**, the app demonstrates effective use of object-oriented programming, API integration, and interactive UI design in Python. + +--- + +## ๐ŸŽฏ Objective + +The primary goal of Quizzler is to: +- Provide a user-friendly quiz experience. +- Integrate with the Open Trivia DB API for dynamic question fetching. +- Showcase modular and scalable code architecture using Python. + +--- + +## Screenshots + +### Initial Screen and result + + + + + +
Login PageRegister Page
+ +### Response to wrong or correct answer + + + + + +
Profile PageHome Page
+ +--- +## ๐Ÿ› ๏ธ Tech Stack + +| Component | Technology | +|------------------|---------------------| +| Language | Python | +| GUI Framework | Tkinter | +| Data Source | Open Trivia DB API | +| Architecture | Object-Oriented | + +--- + +## ๐Ÿงฉ Project Structure + +
+quizzler/
+โ”‚
+โ”œโ”€โ”€ main.py # Main file to run the application
+โ”œโ”€โ”€ ui.py # Handles the GUI logic with Tkinter
+โ”œโ”€โ”€ quiz_brain.py # Core logic for question handling
+โ”œโ”€โ”€ data.py # Module for API integration
+โ””โ”€โ”€ README.md # Documentation
+
+ + +- `main.py`: Initializes the quiz and GUI components. +- `ui.py`: Manages GUI rendering and button interactions. +- `quiz_brain.py`: Controls quiz logic, answer checking, and scorekeeping. +- `data.py`: Fetches quiz questions from the Open Trivia DB API. + +--- + +## ๐Ÿ”Œ API Integration + +Questions are fetched using a GET request from the [Open Trivia Database API](https://opentdb.com/api_config.php). The app dynamically parses the JSON response and formats it for display. + +Example API endpoint: +> https://opentdb.com/api.php?amount=10&type=boolean + + - You can adjust amount if you want more or less questions. And type also. + +--- + +## ๐Ÿ’ป How to Run + +### โœ… Prerequisites + +- Python 3.x installed on your machine +- `requests` library (install via pip) + +### ๐Ÿงช Installation Steps + +```bash +git clone https://github.com/prashantgohel321/Quizzler-Python.git +cd quizzler +pip install requests +``` + +### Execution +> python main.py + +### Features + - Clean and responsive UI with score tracking + - Instant feedback with visual cues (color-based) + - Real-time data fetching using API + - Modular code architecture for scalability + + diff --git a/Quizzler Using Tkinter and Trivia DB API/data_dynamic.py b/Quizzler Using Tkinter and Trivia DB API/data_dynamic.py new file mode 100644 index 00000000000..df3e705cbc0 --- /dev/null +++ b/Quizzler Using Tkinter and Trivia DB API/data_dynamic.py @@ -0,0 +1,29 @@ + +''' +This file is responsible for fetching quiz questions from the Open Trivia Database API. +''' + +import requests + +parameters = { + "amount": 10, + "type": "multiple", + "category": 18 +} + +error_message = "" + +try: + response = requests.get(url="https://opentdb.com/api.php", params=parameters, timeout=10) + response.raise_for_status() # Raise an exception for HTTP errors + question_data = response.json()["results"] + print("Questions loaded successfully from the API.") +except requests.exceptions.ConnectionError: + error_message = "Network connection is poor. Please check your internet connection." + question_data = [] +except requests.exceptions.Timeout: + error_message = "Request timed out. Internet speed might be too slow." + question_data = [] +except requests.exceptions.RequestException as e: + error_message = f"An error occurred: {e}" + question_data = [] diff --git a/Quizzler Using Tkinter and Trivia DB API/data_static.py b/Quizzler Using Tkinter and Trivia DB API/data_static.py new file mode 100644 index 00000000000..081bc3982a2 --- /dev/null +++ b/Quizzler Using Tkinter and Trivia DB API/data_static.py @@ -0,0 +1,191 @@ +question_data = [ + { + "question": "What is one of the main impacts of progress in hardware technologies on software?", + "correct_answer": "Need for more sophisticated programs", + "incorrect_answers": [ + "Increase in hardware prices", + "Decrease in computational power", + "Less complex problems for software engineers" + ] + }, + { + "question": "How have software engineers coped with the challenges of increasing computational capabilities?", + "correct_answer": "By innovating and building on past experiences", + "incorrect_answers": [ + "By reducing programming efforts", + "By simplifying programming languages", + "By avoiding large and complex problems" + ] + }, + { + "question": "Which of the following is a definition of software engineering according to IEEE?", + "correct_answer": "The application of systematic, disciplined, quantifiable approach to software development, operation, and maintenance", + "incorrect_answers": [ + "The art of writing computer programs", + "An engineering approach to developing software", + "A collection of unorganized programming techniques" + ] + }, + { + "question": "Why is software engineering similar to other engineering disciplines?", + "correct_answer": "It uses well-understood and well-documented principles", + "incorrect_answers": [ + "It makes use of subjective judgement and ill understood principles", + "It often avoids conflicting goals", + "It relies solely on qualitative attributes" + ] + }, + { + "question": "Which statement supports the idea that software engineering is not just an art?", + "correct_answer": "It organizes experiences and provides theoretical bases to experimental observations", + "incorrect_answers": [ + "It makes subjective judgement based on qualitative attributes", + "It avoids systematic and disciplined approaches", + "It does not require tradeoffs in problem solving" + ] + }, + { + "question": "How have software engineering principles evolved over the last sixty years?", + "correct_answer": "From an art form to an engineering discipline", + "incorrect_answers": [ + "From a science to an art form", + "From a craft to an art form", + "From an engineering discipline to a craft" + ] + }, + { + "question": "Which programming style is characterized by quickly developing a program without any specification, plan, or design?", + "correct_answer": "Build and fix", + "incorrect_answers": [ + "Exploratory", + "Code and fix", + "Ad hoc" + ] + }, + { + "question": "According to the text, what has been a symptom of the present software crisis?", + "correct_answer": "Increasing software costs compared to hardware", + "incorrect_answers": [ + "Decrease in software development costs", + "Software products becoming easier to alter and debug", + "Software products being delivered on time" + ] + }, + { + "question": "What is one of the main benefits of adopting software engineering techniques according to the text?", + "correct_answer": "Developing high quality software cost effectively and timely", + "incorrect_answers": [ + "Increasing hardware costs", + "Avoiding the use of scientific principles", + "Making software development more subjective" + ] + }, + { + "question": "What is a key characteristic of toy software?", + "correct_answer": "Lack good user interface and proper documentation", + "incorrect_answers": [ + "Developed by a team of professionals", + "Large in size and highly complex", + "Thoroughly tested and maintained" + ] + } + # { + # "question": "What differentiates professional software from toy software?", + # "correct_answer": "Professional software is systematically designed, carefully implemented, and thoroughly tested", + # "incorrect_answers": [ + # "Professional software is usually developed by a single individual", + # "Professional software lacks supporting documents", + # "Professional software is used by a single user" + # ] + # }, + # { + # "question": "What is a key feature of software services projects?", + # "correct_answer": "They often involve the development of customized software", + # "incorrect_answers": [ + # "They are always largescale projects", + # "They involve the development of off-the-shelf software", + # "They are never outsourced to other companies" + # ] + # }, + # { + # "question": "Why might a company choose to outsource part of its software development work?", + # "correct_answer": "To develop some parts cost effectively or to use external expertise", + # "incorrect_answers": [ + # "To ensure all development work is done internally", + # "Because it has more expertise than the outsourcing company", + # "To avoid completing the project on time" + # ] + # }, + # { + # "question": "What type of software is typically developed in a short time frame and at a low cost?", + # "correct_answer": "Toy software", + # "incorrect_answers": [ + # "Generic software products", + # "Customized software", + # "Professional software" + # ] + # }, + # { + # "question": "What has been a traditional focus of Indian software companies?", + # "correct_answer": "Executing software services projects", + # "incorrect_answers": [ + # "Developing largescale generic software products", + # "Avoiding any type of software development", + # "Developing only toy software" + # ] + # }, + # { + # "question": "What is the primary characteristic of the exploratory style of software development?", + # "correct_answer": "Complete freedom for the programmer to choose development activities", + # "incorrect_answers": [ + # "Strict adherence to development rules and guidelines", + # "Development of software based on detailed specifications", + # "Use of structured and well-documented procedures" + # ] + # }, + # { + # "question": "What typically initiates the coding process in the exploratory development style?", + # "correct_answer": "Initial customer briefing about requirements", + # "incorrect_answers": [ + # "Completion of a detailed design document", + # "Formal approval from a project manager", + # "Completion of a feasibility study" + # ] + # }, + # { + # "question": "What is a major limitation of the exploratory development style for large sized software projects?", + # "correct_answer": "Development time and effort grow exponentially with problem size", + # "incorrect_answers": [ + # "Requires a large team of developers", + # "Results in highly structured and high quality code", + # "Easily allows for concurrent work among multiple developers" + # ] + # }, + # { + # "question": "What difficulty arises when using the exploratory style in a team development environment?", + # "correct_answer": "Difficulty in partitioning work among developers due to lack of proper design and documentation", + # "incorrect_answers": [ + # "Easy partitioning of work among developers", + # "Development work is based on a detailed design", + # "Use of structured and well documented code" + # ] + # }, + # { + # "question": "In what scenario can the exploratory development style be successful?", + # "correct_answer": "Developing very small programs", + # "incorrect_answers": [ + # "Developing largescale enterprise software", + # "Implementing critical safety systems", + # "Managing large, distributed teams" + # ] + # }, + # { + # "question": "What was the primary programming style used in the 1950s?", + # "correct_answer": "Build and fix (exploratory programming) style", + # "incorrect_answers": [ + # "Object-oriented programming", + # "Control flow-based design", + # "Data flow-oriented design" + # ] + # } +] \ No newline at end of file diff --git a/Quizzler Using Tkinter and Trivia DB API/main.py b/Quizzler Using Tkinter and Trivia DB API/main.py new file mode 100644 index 00000000000..37a038c5d60 --- /dev/null +++ b/Quizzler Using Tkinter and Trivia DB API/main.py @@ -0,0 +1,27 @@ + +"""This file processes the fetched questions and prepares them for use in the quiz.""" + +from question_model import Question +from data_dynamic import question_data +from quiz_brain import QuizBrain +from ui import QuizInterface + +# question_bank = [] +# question_text = question["question"] +# question_answer = question["correct_answer"] +# question_options = question["incorrect_answers"] + [question["correct_answer"]] +# new_question = Question(question_text, question_answer, question_options) +# question_bank.append(new_question) + +# list comprehension +question_bank = [ + Question( + question["question"], + question["correct_answer"], + question["incorrect_answers"] + [question["correct_answer"]] + ) + for question in question_data +] + +quiz = QuizBrain(question_bank) +quiz_ui = QuizInterface(quiz) diff --git a/Quizzler Using Tkinter and Trivia DB API/question_model.py b/Quizzler Using Tkinter and Trivia DB API/question_model.py new file mode 100644 index 00000000000..7087cd22968 --- /dev/null +++ b/Quizzler Using Tkinter and Trivia DB API/question_model.py @@ -0,0 +1,5 @@ +class Question: + def __init__(self, q_text, q_answer, q_options): + self.text = q_text + self.answer = q_answer + self.options = q_options diff --git a/Quizzler Using Tkinter and Trivia DB API/quiz_brain.py b/Quizzler Using Tkinter and Trivia DB API/quiz_brain.py new file mode 100644 index 00000000000..53bcf178931 --- /dev/null +++ b/Quizzler Using Tkinter and Trivia DB API/quiz_brain.py @@ -0,0 +1,24 @@ + +"""This file contains the logic that drives the quiz game, including managing the current question, checking answers, and tracking the score.""" + +import html + +class QuizBrain: + def __init__(self, q_list): + self.question_number = 0 + self.score = 0 + self.question_list = q_list + self.current_question = None + + def still_has_questions(self): + return self.question_number < len(self.question_list) + + def next_question(self): + self.current_question = self.question_list[self.question_number] + self.question_number += 1 + q_text = html.unescape(self.current_question.text) + return f"Q.{self.question_number}: {q_text}" + + def check_answer(self, user_answer): + correct_answer = self.current_question.answer + return user_answer.lower() == correct_answer.lower() diff --git a/Quizzler Using Tkinter and Trivia DB API/screenshots/s1.png b/Quizzler Using Tkinter and Trivia DB API/screenshots/s1.png new file mode 100644 index 00000000000..8034d295d2e Binary files /dev/null and b/Quizzler Using Tkinter and Trivia DB API/screenshots/s1.png differ diff --git a/Quizzler Using Tkinter and Trivia DB API/screenshots/s2.png b/Quizzler Using Tkinter and Trivia DB API/screenshots/s2.png new file mode 100644 index 00000000000..96ad3a82ef6 Binary files /dev/null and b/Quizzler Using Tkinter and Trivia DB API/screenshots/s2.png differ diff --git a/Quizzler Using Tkinter and Trivia DB API/screenshots/s3.png b/Quizzler Using Tkinter and Trivia DB API/screenshots/s3.png new file mode 100644 index 00000000000..0e0129fbceb Binary files /dev/null and b/Quizzler Using Tkinter and Trivia DB API/screenshots/s3.png differ diff --git a/Quizzler Using Tkinter and Trivia DB API/screenshots/s4.png b/Quizzler Using Tkinter and Trivia DB API/screenshots/s4.png new file mode 100644 index 00000000000..977a7d38159 Binary files /dev/null and b/Quizzler Using Tkinter and Trivia DB API/screenshots/s4.png differ diff --git a/Quizzler Using Tkinter and Trivia DB API/ui.py b/Quizzler Using Tkinter and Trivia DB API/ui.py new file mode 100644 index 00000000000..42102c20fac --- /dev/null +++ b/Quizzler Using Tkinter and Trivia DB API/ui.py @@ -0,0 +1,145 @@ + +"""This file manages the graphical user interface of the quiz, using Tkinter to display questions, answer options, and the score to the user.""" + +from tkinter import * +from quiz_brain import QuizBrain +from data_dynamic import error_message + +# Normal screen +BACKGROUND = "#608BC1" +CANVAS = "#CBDCEB" +TEXT = "#133E87" + +# If answer is right +R_BACKGROUND = "#859F3D" +R_CANVAS = "#F6FCDF" +R_TEXT = "#31511E" + +# If answer is wrong +W_BACKGROUND = "#C63C51" +W_CANVAS = "#D95F59" +W_TEXT = "#522258" + +FONT = ("Lucida sans", 20) + +class QuizInterface: + + def __init__(self, quiz_brain: QuizBrain): + self.quiz = quiz_brain + self.window = Tk() + self.window.title("Quizzler") + self.window.config(padx=20, pady=20, bg=BACKGROUND) + + self.score_label = Label(text="Score: 0", fg="white", bg=BACKGROUND, font=("Lucida sans", 15, "bold")) + self.score_label.grid(row=0, column=1) + + self.canvas = Canvas(width=1000, height=550, bg=CANVAS) + self.question_text = self.canvas.create_text( + 500, 100, width=800, text="Some question text", fill=TEXT, font=FONT, anchor="center", justify="center" + ) + self.canvas.grid(row=1, column=0, columnspan=2, pady=50) + + self.opt_selected = IntVar() + self.options = self.create_radio_buttons() + + self.submit_button = Button( + text="Submit", command=self.submit_answer, fg=TEXT, font=FONT + ) + self.submit_button.grid(row=3, column=0, columnspan=2) + + if error_message: + self.display_error_message(error_message) + else: + self.get_next_question() + + self.window.mainloop() + + def create_radio_buttons(self): + radio_buttons = [] + y_position = 230 + for i in range(4): + radio_button = Radiobutton( + self.canvas, text="", variable=self.opt_selected, value=i + 1, font=FONT, bg=CANVAS, anchor="w", + justify="left", fg=TEXT, wraplength=900 + ) + radio_buttons.append(radio_button) + self.canvas.create_window(50, y_position, window=radio_button, anchor="w") + y_position += 65 + return radio_buttons + + def get_next_question(self): + if self.quiz.still_has_questions(): + self.opt_selected.set(0) # Reset selection + q_text = self.quiz.next_question() + self.canvas.itemconfig(self.question_text, text=q_text) + self.canvas.config(bg=CANVAS) + self.window.config(bg=BACKGROUND) + for option in self.options: + option.config(bg=CANVAS, fg=TEXT) + self.display_options() + self.score_label.config(bg=BACKGROUND, text=f"Score: {self.quiz.score}") + self.canvas.itemconfig(self.question_text, fill=TEXT) + else: + self.display_result() + + def display_options(self): + current_options = self.quiz.current_question.options + for i, option in enumerate(current_options): + self.options[i].config(text=option) + + def submit_answer(self): + selected_option_index = self.opt_selected.get() - 1 + if selected_option_index >= 0: + user_answer = self.quiz.current_question.options[selected_option_index] + self.quiz.check_answer(user_answer) + + if self.quiz.check_answer(user_answer): + self.quiz.score += 1 + self.canvas.config(bg=R_CANVAS) + self.window.config(bg=R_BACKGROUND) + for option in self.options: + option.config(bg=R_CANVAS, fg=R_TEXT) + self.canvas.itemconfig(self.question_text, fill=R_TEXT) + self.score_label.config(bg=R_BACKGROUND) + else: + self.canvas.config(bg=W_CANVAS) + self.window.config(bg=W_BACKGROUND) + for option in self.options: + option.config(bg=W_CANVAS, fg=W_TEXT) + self.canvas.itemconfig(self.question_text, fill=W_TEXT) + self.score_label.config(bg=W_BACKGROUND) + + self.window.after(1000, self.get_next_question) + + def display_result(self): + for option in self.options: + option.config(bg=CANVAS, fg=TEXT) + option.destroy() + + if self.quiz.score <= 3: + self.result_text = f"You've completed the quiz!\nYour final score: {self.quiz.score}/{self.quiz.question_number}\nBetter luck next time! Keep practicing!" + elif self.quiz.score <= 6: + self.result_text = f"You've completed the quiz!\nYour final score: {self.quiz.score}/{self.quiz.question_number}\nGood job! You're getting better!" + elif self.quiz.score <= 8: + self.result_text = f"You've completed the quiz!\nYour final score: {self.quiz.score}/{self.quiz.question_number}\nGreat work! You're almost there!" + else: + self.result_text = f"You've completed the quiz!\nYour final score: {self.quiz.score}/{self.quiz.question_number}\nExcellent! You're a Quiz Master!" + + self.score_label.config(bg=BACKGROUND, text=f"Score: {self.quiz.score}") + self.canvas.config(bg=CANVAS) + self.window.config(bg=BACKGROUND) + self.canvas.itemconfig(self.question_text, fill=TEXT) + self.score_label.config(bg=BACKGROUND) + + self.canvas.itemconfig(self.question_text, text=self.result_text) + self.canvas.coords(self.question_text, 500, 225) # Centered position + self.submit_button.config(state="disabled") + + def display_error_message(self, message): + for option in self.options: + option.config(bg=CANVAS, fg=TEXT) + option.destroy() + + self.canvas.itemconfig(self.question_text, text=message) + self.canvas.coords(self.question_text, 500, 225) # Centered position + self.submit_button.config(state="disabled")