Skip to content

Commit

Permalink
Add CmpE487 final project
Browse files Browse the repository at this point in the history
  • Loading branch information
enescakir committed Dec 31, 2018
1 parent e6fd535 commit 986d5c7
Show file tree
Hide file tree
Showing 22 changed files with 687 additions and 4 deletions.
5 changes: 2 additions & 3 deletions cmpe436/final-project/README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
## Auction App
### [Server](/cmpe436/final-project/Server) `Java`
### [Android App](/cmpe436/final-project/Auctioner) `Java`
|||||
:-------------------------:|:-------------------------:|:-------------------------:|:-------------------------:
<a href="https://raw.githubusercontent.com/EnesCakir/university-projects/master/cmpe436/final-project/screenshots/ss1.png"><img src="https://raw.githubusercontent.com/EnesCakir/university-projects/master/cmpe436/final-project/screenshots/ss1.png"></a> | <a href="https://raw.githubusercontent.com/EnesCakir/university-projects/master/cmpe436/final-project/screenshots/ss2.png"><img src="https://raw.githubusercontent.com/EnesCakir/university-projects/master/cmpe436/final-project/screenshots/ss2.png"></a> | <a href="https://raw.githubusercontent.com/EnesCakir/university-projects/master/cmpe436/final-project/screenshots/ss3.png"><img src="https://raw.githubusercontent.com/EnesCakir/university-projects/master/cmpe436/final-project/screenshots/ss3.png"></a> | <a href="https://raw.githubusercontent.com/EnesCakir/university-projects/master/cmpe436/final-project/screenshots/ss4.png"><img src="https://raw.githubusercontent.com/EnesCakir/university-projects/master/cmpe436/final-project/screenshots/ss4.png"></a>
<a href="https://raw.githubusercontent.com/EnesCakir/university-projects/master/cmpe436/final-project/screenshots/ss5.png"><img src="https://raw.githubusercontent.com/EnesCakir/university-projects/master/cmpe436/final-project/screenshots/ss5.png"></a> | <a href="https://raw.githubusercontent.com/EnesCakir/university-projects/master/cmpe436/final-project/screenshots/ss6.png"><img src="https://raw.githubusercontent.com/EnesCakir/university-projects/master/cmpe436/final-project/screenshots/ss6.png"></a> | <a href="https://raw.githubusercontent.com/EnesCakir/university-projects/master/cmpe436/final-project/screenshots/ss7.png"><img src="https://raw.githubusercontent.com/EnesCakir/university-projects/master/cmpe436/final-project/screenshots/ss7.png"></a> |

### [Server](/cmpe436/final-project/Server) `Java`
### [Android App](/cmpe436/final-project/Auctioner) `Java`
Binary file modified cmpe436/final-project/screenshots/ss1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified cmpe436/final-project/screenshots/ss3.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified cmpe436/final-project/screenshots/ss4.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified cmpe436/final-project/screenshots/ss5.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified cmpe436/final-project/screenshots/ss6.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified cmpe436/final-project/screenshots/ss7.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 0 additions & 1 deletion cmpe487/final-project
Submodule final-project deleted from d3a72a
Binary file added cmpe487/final-project/Presentation.pdf
Binary file not shown.
56 changes: 56 additions & 0 deletions cmpe487/final-project/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# CmpE 487 Final Project
## Network-Based Realtime Multiple-Choice Quiz Application
<p align="center">
<img src="https://github.com/CMPE487/final-project-quizapp/raw/master/logo.png" width="50%" height="auto" align="center">
</p>

- Moderator creates quizzes manually or imports from prepared text files.
- Participants connect to the quiz room that is on the server.
- When moderator starts session, participants compete for correct answers.
- Participants have 10 seconds for each question
#### [Final Presentation PDF](https://github.com/CMPE487/final-project-quizapp/blob/master/Presentation.pdf)

### Usage
Run following command for both Server or Client
```
$ python3 main.py
```
![Main Menu](main_menu.png)

**IMPORTANT NOTE:** Please don't press any key if it's not prompted. Especially when waiting for new questions.
#### Create Quiz
`QuizServer` class handles server operations.
1) Select `Start new quiz`
2) Enter quiz name
3) Select quiz creation method
- **Import file:** We have samples quizzes. Enter file path. (i.e: `samples/network.txt` `samples/general.txt`)
- **Manually:** Enter number of the questions in the quiz. Then enter question body and options as prompted.
4) Review questions, enter to continue
5) Wait for participants. Participants can't enter after you sent first question.
![Participants](server.png)
6) Send first question, so quiz is started.
7) Wait answers from participants (12 seconds)
8) When you see scores after 12 seconds, you can send simply next question by pressing `Enter`
9) End of the quiz, scores are sent to all participants automatically.

#### Enter a Quiz
`QuizClient` class handles client operations.
1) Select `Enter a quiz`. Discovery sent to network automatically.
- If you are not in the same subnet with the server, first discover manually with `Manual quiz discovery` option then `Enter a quiz`
2) Select a quiz to enter
3) Enter your username and wait for the first question
4) When question is appeared, enter your answer and press `Enter`.
![Question](client.png)
5) Wait for the next questions and give your answer when it is prompted.
6) Repeat this process until all questions is done
7) When the all questions are answered, you will see the scoreboard.
8) Highlighted row is your score :)

### Contributors:
- [Mustafa Enes Çakır](https://github.com/EnesCakir)
- [Oğuzhan Yetimoğlu](https://github.com/oguzhanyetimoglu)

(We did pair programming)

### License
Quiz App is an open-sourced software licensed under the [BSD-2 license](https://opensource.org/licenses/BSD-2-Clause).
Binary file added cmpe487/final-project/client.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
34 changes: 34 additions & 0 deletions cmpe487/final-project/config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import socket


def get_ip():
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
try:
s.connect(('10.255.255.255', 1))
IP = s.getsockname()[0]
except:
IP = '127.0.0.1'
finally:
s.close()
return IP


SELF_IP = get_ip()
SUBNET = SELF_IP[:SELF_IP.rfind('.')]

DISCOVERY_PORT = 5000 # TCP
QUIZ_PORT = 5001 # TCP

QUESTION_TIME = 10

MESSAGE_TYPES = {
"request": 0,
"response": 1,
"enter": 2,
"success": 3,
"error": 4,
"question": 5,
"answer": 6,
"answer_response": 7,
"result": 8
}
Binary file added cmpe487/final-project/logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
80 changes: 80 additions & 0 deletions cmpe487/final-project/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
from quizClient import *
from quizServer import *
from quizUtils import *
from utils import *

quiz_server = None
quiz_client = QuizClient()

clear()
while True:
option = select_option([
"Start new quiz",
"Enter a quiz",
"Manual quiz discovery",
"Quit"
], header="AVAILABLE COMMANDS")


if option == "1":
clear()
print_header("Start New Quiz")
quiz_name = input("\n" + change_style("Enter quiz name", 'underline') + ": ")
quiz = Quiz(quiz_name)
clear()
quiz_option = select_option(["Import from file", "Enter questions manually"], header="Quiz Create Methods")
if quiz_option == "1":
clear()
print_header("Import Quiz")
filename = input("Enter file name: ")
while not os.path.isfile(filename):
print(change_style("\nPlease enter valid filename\n", "red"))
filename = input("Enter file name: ")
quiz.import_file(filename)
else:
clear()
print_header("Create Quiz")
question_count = input("How many questions your quiz has? ")
for i in range(int(question_count)):
question = Question.from_input(i + 1)
quiz.add_question(question)

clear()
quiz.print()
enter_continue()
quiz_server = QuizServer(quiz)
quiz_server.listen()
print_header("QUIZ: " + quiz.name)
print(change_style("QUIZ IP: " + change_style(SELF_IP, 'bold'), 'green'))
print(change_style("\n\nWAITING FOR NEW PARTICIPANTS\n\n", 'bold'))
tmp = input("Enter for start quiz")
quiz_server.start()
elif option == "2":
quiz_client.broadcast_quiz(True)
clear()
id = select_option(quiz_client.available_quizzes.values(), prompt="Enter quiz ID", header="Enter a Quiz")

if id is "":
clear()
else:
username = input("\nEnter username: ")
quiz_ip = list(quiz_client.available_quizzes.keys())[int(id) - 1]
quiz_client.enter(quiz_ip, username)

elif option == "3":
clear()
print_header("Manual Quiz Discovery")
quiz_client.broadcast_quiz(False)
quiz_ip = input(change_style("Enter quiz server IP address (i.e: 192.168.6.150)", "underline") + ": ")
start_new_thread(quiz_client.send_discovery_packet, (quiz_ip, False))
clear()
print_notification("Discovery request sent to " + quiz_ip)

elif option == "4":
clear()
print_notification("Good bye \n\n")
os.system("pkill -9 \"python3 main.py\"")
sys.exit(0)
else:
clear()
print_error("Invalid option")
Binary file added cmpe487/final-project/main_menu.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
119 changes: 119 additions & 0 deletions cmpe487/final-project/quizClient.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
from config import *
from utils import *


class QuizClient():
def __init__(self):
self.username = None
self.active_quiz = None
self.score = 0
self.available_quizzes = {}

def start(self):
self.broadcast_quiz()

def broadcast_quiz(self, print=False):
for i in range(1, 255):
target_ip = SUBNET + "." + str(i)
# if target_ip != SELF_IP:
start_new_thread(self.send_discovery_packet, (target_ip, print))

def send_discovery_packet(self, target_ip, print):
message = "{}|{}".format(MESSAGE_TYPES["request"], SELF_IP)
try:
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.settimeout(5)
s.connect((target_ip, DISCOVERY_PORT))
s.send(message.encode('utf-8'))
data = s.recv(1024)
if data:
type, source, quiz_name = data.decode().split('|')
if int(type) == MESSAGE_TYPES["response"]:
print_notification("New quiz: {}".format(quiz_name))
self.available_quizzes[source] = quiz_name
if print:
clear()
select_option(self.available_quizzes.values(), prompt="Enter quiz ID",
header="Enter a Quiz", is_active=False)

s.close()
except Exception as ex:
# print("Error while sending packet: " + message)
# print(ex.__str__() + " " + str(port))
pass

def enter(self, quiz_ip, username):
self.username = username
self.active_quiz = self.available_quizzes[quiz_ip]

print("Entering: " + quiz_ip)
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.connect((quiz_ip, QUIZ_PORT))
message = "{}|{}|{}".format(MESSAGE_TYPES["enter"], SELF_IP, username)
s.send(message.encode('utf-8'))
while True:
data = s.recv(1024)
if not data:
break

type, *parts = data.decode().split("|")
type = int(type)
if type == MESSAGE_TYPES["error"]:
print(parts[0])
break
elif type == MESSAGE_TYPES["success"]:
clear()
print("\n\n" + parts[0])
print_header("PLEASE WAIT TO START QUIZ")
elif type == MESSAGE_TYPES["question"]:
clear()
number = parts[0]
body = parts[1]
options = parts[2:]
self.print_status()
print(change_style("\n\nQuestion {}: ".format(number), "question") + change_style(body, "bold"))
start_timer(QUESTION_TIME)
answer = select_option(options, prompt="Your answer", timeout=QUESTION_TIME)
if answer:
if int(answer) > 4 or int(answer) < 0:
print(change_style("\nInvalid answer\n", "red"))
else:
print("\nSubmitted answer is \"{}\"".format(options[int(answer) - 1]))

message = "{}|{}|{}".format(MESSAGE_TYPES["answer"], number, answer)
s.send(message.encode())
else:
print("\nTime is up. You got {} point".format(change_style("ZERO", "bold")))
elif type == MESSAGE_TYPES["answer_response"]:
clear()
self.score = int(parts[0])
message = parts[1]
self.print_status()
print(change_style(message, "bold"))
print_header("PLEASE WAIT NEXT QUESTION")
elif type == MESSAGE_TYPES["result"]:
clear()
print_header("SCOREBOARD")
for rank, result in enumerate(parts):
username, score = result.split(":")
if username == self.username:
print(change_style(
"{} {} {}".format((str(rank + 1) + ")").ljust(10), username.ljust(30),
score + " points"),
"sender"))
else:
print("{} {} {}".format((str(rank + 1) + ")").ljust(10), username.ljust(30),
score + " points"))

enter_continue()
break
else:
print(type, parts)
s.close()

def print_status(self):
print("\n\n")
print("{}: {}".format(change_style("Username", "green").ljust(30), change_style(self.username, "bold")))
print("{}: {}".format(change_style("Quiz Name", "green").ljust(30), change_style(self.active_quiz, "bold")))
print("{}: {}".format(change_style("Current Score", "green").ljust(30), change_style(self.score, "bold")))
print("\n\n")
Loading

0 comments on commit 986d5c7

Please sign in to comment.