Skip to content

Commit 59bd01e

Browse files
authored
Merge pull request #768 from isaacwellish/pyportal-trivia-time
PyPortal Trivia Time
2 parents 631d502 + c4e422b commit 59bd01e

4 files changed

Lines changed: 59434 additions & 0 deletions

File tree

PyPortal_Trivia_Time/code.py

Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
"""
2+
This example uses the Open Trivia Database API to display multiple choice trivia questions.
3+
Tap the screen to start, then a question will appear and a 30 second timer will start.
4+
The first player to hit their button will get 10 seconds to answer.
5+
Hit button again to reveal answer. Tap screen to move to next question.
6+
This program assumes two buttons are attached to D3 and D4 on the Adafruit PyPortal.
7+
"""
8+
9+
import time
10+
import random
11+
import board
12+
from adafruit_pyportal import PyPortal
13+
from digitalio import DigitalInOut, Direction, Pull
14+
from adafruit_display_text import label
15+
from adafruit_bitmap_font import bitmap_font
16+
17+
# initialize harware
18+
led = DigitalInOut(board.L) # For debugging
19+
led.direction = Direction.OUTPUT
20+
button1 = DigitalInOut(board.D4)
21+
button2 = DigitalInOut(board.D3)
22+
button1.direction = Direction.INPUT
23+
button2.direction = Direction.INPUT
24+
button1.pull = Pull.UP
25+
button2.pull = Pull.UP
26+
display = board.DISPLAY
27+
28+
# determine the current working directory
29+
# needed so we know where to find files
30+
cwd = ("/"+__file__).rsplit('/', 1)[0]
31+
32+
# Set up where we'll be fetching data from
33+
DATA_SOURCE = "https://opentdb.com/api.php?amount=1&type=multiple"
34+
Q_LOCATION = ['results', 0, 'question']
35+
WA_LOCATION1 = ['results', 0, 'incorrect_answers', 0]
36+
WA_LOCATION2 = ['results', 0, 'incorrect_answers', 1]
37+
WA_LOCATION3 = ['results', 0, 'incorrect_answers', 2]
38+
CA_LOCATION = ['results', 0, 'correct_answer']
39+
40+
# Text info
41+
trivia_font = bitmap_font.load_font("/fonts/Arial-ItalicMT-17.bdf")
42+
43+
loading_color = 0x8080FF
44+
loading_position = (100,120)
45+
loading_text_area = label.Label(trivia_font, max_glyphs=30, color=loading_color,
46+
x=loading_position[0], y=loading_position[1])
47+
48+
q_color = 0x8080FF
49+
q_position = (25, 70)
50+
q_text_area = label.Label(trivia_font, max_glyphs=120,
51+
x=q_position[0], y=q_position[1],
52+
color=q_color, line_spacing = 1)
53+
54+
answer_choices = ("A","B","C","D")
55+
a_positions = ((25, 135), (25, 155), (25, 175), (25, 195))
56+
a_color = 0xFFFFFF
57+
ans_text_areas = []
58+
for answernum in range(4):
59+
ans_text_areas.append(label.Label(trivia_font, max_glyphs=80,
60+
color=a_color, line_spacing = 1.5,
61+
x=a_positions[answernum][0],
62+
y=a_positions[answernum][1]))
63+
64+
reveal_position = (25, 75)
65+
reveal_text_area = label.Label(trivia_font, max_glyphs=120, color=loading_color,
66+
x=reveal_position[0], y=reveal_position[1])
67+
68+
timer_position = (25, 215)
69+
timer_color = 0xFF00FF
70+
timer_text_area = label.Label(trivia_font, max_glyphs=20, color=timer_color,
71+
x=timer_position[0], y=timer_position[1])
72+
73+
# A function to shuffle trivia questions
74+
def shuffle(aList):
75+
for i in range(len(aList)):
76+
j = random.randint(0, len(aList)-1)
77+
# Swap arr[i] with the element at random index
78+
aList[i], aList[j] = aList[j], aList[i]
79+
return aList
80+
81+
# convert html codes to normal text
82+
def unescape(s):
83+
s = s.replace(""", "''")
84+
s = s.replace("'", "'")
85+
s = s.replace("&", "&")
86+
return s
87+
88+
# A function to handle the timer and determine which player answers first
89+
def faceOff(timerLength):
90+
timer_text = str(timerLength) + " seconds!"
91+
timer_text_area.text = ''
92+
timer_text_area.text = str(timer_text)
93+
timerStart = time.monotonic()
94+
while time.monotonic() - timerStart < timerLength:
95+
if button1.value:
96+
led.value = False # For debugging
97+
else: # If button 1 pressed, print player 1 on screen and exit function
98+
led.value = True # For debugging
99+
q_text_area.text = ''
100+
reveal_text_area.text = "Player 1!"
101+
break
102+
if button2.value:
103+
led.value = False # For debugging
104+
else: # If button 2 pressed, print player 2 on screen and exit function
105+
led.value = True # For debugging
106+
q_text_area.text = ''
107+
reveal_text_area.text = "Player 2!"
108+
break
109+
time.sleep(0.05) # debounce delay
110+
else: # Timer runs out
111+
q_text_area.text = ''
112+
reveal_text_area.text = "Times up!"
113+
114+
# PyPortal constructor
115+
pyportal = PyPortal(url=DATA_SOURCE,
116+
json_path=(Q_LOCATION, CA_LOCATION, WA_LOCATION1, WA_LOCATION2, WA_LOCATION3),
117+
status_neopixel=board.NEOPIXEL,
118+
default_bg=cwd+"/trivia_title.bmp")
119+
120+
pyportal.preload_font() # speed things up by preloading font
121+
122+
pyportal.splash.append(loading_text_area) #loading...
123+
pyportal.splash.append(q_text_area)
124+
pyportal.splash.append(reveal_text_area)
125+
pyportal.splash.append(timer_text_area)
126+
for textarea in ans_text_areas:
127+
pyportal.splash.append(textarea)
128+
129+
while True:
130+
# Load new question when screen is touched
131+
while not pyportal.touchscreen.touch_point:
132+
pass
133+
134+
reveal_text_area.text = ''
135+
q_text_area.text = ''
136+
for textarea in ans_text_areas:
137+
textarea.text = ''
138+
timer_text_area.text = ''
139+
140+
pyportal.set_background(cwd+"/trivia.bmp")
141+
loading_text_area.text ="Loading question..."
142+
143+
while True:
144+
try:
145+
value = pyportal.fetch()
146+
break
147+
except RuntimeError as e:
148+
print("Some error occured, retrying! -", e)
149+
continue
150+
print("Response is", value)
151+
question = value[0]
152+
correct_answer = value[1]
153+
answers = shuffle(value[1:5])
154+
loading_text_area.text = ''
155+
156+
# Format text and wrap with display text library
157+
try: # sometimes gives a runtime error: Group full
158+
q_text_area.text = '\n'.join(pyportal.wrap_nicely(unescape(question), 35))
159+
except RuntimeError as e:
160+
print("Group full", e)
161+
continue
162+
for k, answer in enumerate(answers):
163+
ans_text_areas[k].text = answer_choices[k]+") "+unescape(answer)
164+
165+
faceOff(10) # 10 seconds with question
166+
time.sleep(2) # pause for 2 seconds to show which player tapped first
167+
faceOff(5) # 5 seconds to answer
168+
timer_text_area.text = ''
169+
# Show the correct answer
170+
k = answers.index(correct_answer)
171+
reveal_text = ("Correct Answer:\n"+answer_choices[k]+") "
172+
+unescape(answers[k])+"\n(Tap for next question.)")
173+
print(reveal_text)
174+
reveal_text_area.text = reveal_text

0 commit comments

Comments
 (0)