Skip to content

Commit 658327b

Browse files
committed
bots: port trivia_quiz to game_handler
1 parent 5883b32 commit 658327b

File tree

4 files changed

+229
-245
lines changed

4 files changed

+229
-245
lines changed
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
from zulip_bots.game_handler import BadMoveException
2+
import html
3+
import json
4+
import requests
5+
import random
6+
from copy import deepcopy
7+
from zulip_bots.lib import Any
8+
9+
from typing import Optional, Any, Dict, Tuple
10+
11+
class NotAvailableException(Exception):
12+
def __init__(self, message: str) -> None:
13+
self.message = message
14+
15+
def __str__(self) -> str:
16+
return self.message
17+
18+
class TriviaQuizModel(object):
19+
def __init__(self):
20+
# This could throw an exception. It will be picked up by
21+
# game_handler and the game will end
22+
self.current_board = self.get_trivia_quiz()
23+
self.scores = {} # type: Dict[int, int]
24+
25+
def update_board(self, board):
26+
self.current_board = deepcopy(board)
27+
28+
def validate_move(self, answer):
29+
return answer in "ABCD"
30+
31+
def make_move(self, move, player_number, is_computer=False):
32+
if player_number not in self.scores:
33+
self.scores[player_number] = 0
34+
if not self.validate_move(move):
35+
raise BadMoveException("Move not valid")
36+
self.current_board = self.get_trivia_quiz()
37+
if move == self.current_board['correct_letter']:
38+
self.scores[player_number] += 1
39+
else:
40+
self.scores[player_number] -= 1
41+
if self.scores[player_number] < 0:
42+
self.scores[player_number] = 0
43+
return {
44+
'correct': move == self.current_board['correct_letter'],
45+
'correct_letter': self.current_board['correct_letter'],
46+
'score': self.scores[player_number]
47+
}
48+
49+
def determine_game_over(self, players):
50+
for player_number, score in self.scores.items():
51+
if score > 5:
52+
# Game over
53+
return players[player_number]
54+
return
55+
56+
def get_trivia_quiz(self) -> Dict[str, Any]:
57+
payload = self.get_trivia_payload()
58+
quiz = self.get_quiz_from_payload(payload)
59+
return quiz
60+
61+
def get_trivia_payload(self) -> Dict[str, Any]:
62+
63+
url = 'https://opentdb.com/api.php?amount=1&type=multiple'
64+
65+
try:
66+
data = requests.get(url)
67+
68+
except requests.exceptions.RequestException:
69+
raise NotAvailableException("Uh-Oh! Trivia service is down.")
70+
71+
if data.status_code != 200:
72+
raise NotAvailableException("Uh-Oh! Trivia service is down.")
73+
74+
payload = data.json()
75+
return payload
76+
77+
def get_quiz_from_payload(self, payload: Dict[str, Any]) -> Dict[str, Any]:
78+
result = payload['results'][0]
79+
question = result['question']
80+
letters = ['A', 'B', 'C', 'D']
81+
random.shuffle(letters)
82+
correct_letter = letters[0]
83+
answers = dict()
84+
answers[correct_letter] = result['correct_answer']
85+
for i in range(3):
86+
answers[letters[i+1]] = result['incorrect_answers'][i]
87+
88+
def fix_quotes(s: str) -> Optional[str]:
89+
# opentdb is nice enough to escape HTML for us, but
90+
# we are sending this to code that does that already :)
91+
#
92+
# Meanwhile Python took until version 3.4 to have a
93+
# simple html.unescape function.
94+
try:
95+
return html.unescape(s)
96+
except Exception:
97+
raise Exception('Please use python3.4 or later for this bot.')
98+
answers = {
99+
letter: fix_quotes(answer)
100+
for letter, answer
101+
in answers.items()
102+
}
103+
quiz = dict(
104+
question=fix_quotes(question),
105+
answers=answers,
106+
answered_options=[],
107+
pending=True,
108+
correct_letter=correct_letter,
109+
)
110+
return quiz

zulip_bots/zulip_bots/bots/trivia_quiz/test_trivia_quiz.py

Lines changed: 2 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,7 @@
1515
mock_request_exception,
1616
)
1717

18-
from zulip_bots.bots.trivia_quiz.trivia_quiz import (
19-
get_quiz_from_payload,
20-
fix_quotes,
21-
get_quiz_from_id,
22-
update_quiz,
23-
handle_answer,
24-
)
18+
from zulip_bots.bots.trivia_quiz.controller import TriviaQuizModel
2519

2620
class TestTriviaQuizBot(BotTestCase, DefaultTests):
2721
bot_name = "trivia_quiz" # type: str
@@ -31,7 +25,7 @@ class TestTriviaQuizBot(BotTestCase, DefaultTests):
3125
'* **B** Fish\n' + \
3226
'* **C** Reptiles\n' + \
3327
'* **D** Mammals\n' + \
34-
'**reply**: answer Q001 <letter>'
28+
'**reply**: <letter>'
3529

3630
def get_test_quiz(self) -> Tuple[Dict[str, Any], Any]:
3731
bot_handler = StubBotHandler()
@@ -47,13 +41,6 @@ def _test(self, message: str, response: str, fixture: Optional[str]=None) -> Non
4741
else:
4842
self.verify_reply(message, response)
4943

50-
def test_bot_responds_to_empty_message(self) -> None:
51-
self._test('', 'type "new" for a new question')
52-
53-
def test_bot_new_question(self) -> None:
54-
with patch('random.shuffle'):
55-
self._test('new', self.new_question_response, 'test_new_question')
56-
5744
def test_question_not_available(self) -> None:
5845
self._test('new', 'Uh-Oh! Trivia service is down.', 'test_status_code')
5946

0 commit comments

Comments
 (0)