172 lines
6.1 KiB
Python
Executable file
172 lines
6.1 KiB
Python
Executable file
"""
|
|
This example uses the Open Trivia Database API to display multiple choice trivia questions.
|
|
Tap the screen to start, then a question will appear and a 30 second timer will start.
|
|
The first player to hit their button will get 10 seconds to answer.
|
|
Hit button again to reveal answer. Tap screen to move to next question.
|
|
This program assumes two buttons are attached to D3 and D4 on the Adafruit PyPortal.
|
|
"""
|
|
|
|
import time
|
|
import random
|
|
import board
|
|
from adafruit_pyportal import PyPortal
|
|
from digitalio import DigitalInOut, Direction, Pull
|
|
from adafruit_display_text import label
|
|
from adafruit_bitmap_font import bitmap_font
|
|
|
|
# initialize harware
|
|
led = DigitalInOut(board.L) # For debugging
|
|
led.direction = Direction.OUTPUT
|
|
button1 = DigitalInOut(board.D4)
|
|
button2 = DigitalInOut(board.D3)
|
|
button1.direction = Direction.INPUT
|
|
button2.direction = Direction.INPUT
|
|
button1.pull = Pull.UP
|
|
button2.pull = Pull.UP
|
|
display = board.DISPLAY
|
|
|
|
# determine the current working directory
|
|
# needed so we know where to find files
|
|
cwd = ("/"+__file__).rsplit('/', 1)[0]
|
|
|
|
# Set up where we'll be fetching data from
|
|
DATA_SOURCE = "https://opentdb.com/api.php?amount=1&type=multiple"
|
|
Q_LOCATION = ['results', 0, 'question']
|
|
WA_LOCATION1 = ['results', 0, 'incorrect_answers', 0]
|
|
WA_LOCATION2 = ['results', 0, 'incorrect_answers', 1]
|
|
WA_LOCATION3 = ['results', 0, 'incorrect_answers', 2]
|
|
CA_LOCATION = ['results', 0, 'correct_answer']
|
|
|
|
# Text info
|
|
trivia_font = bitmap_font.load_font("/fonts/Arial-ItalicMT-17.bdf")
|
|
|
|
loading_color = 0x8080FF
|
|
loading_position = (100,120)
|
|
loading_text_area = label.Label(trivia_font, color=loading_color,
|
|
x=loading_position[0], y=loading_position[1])
|
|
|
|
q_color = 0x8080FF
|
|
q_position = (25, 70)
|
|
q_text_area = label.Label(trivia_font, x=q_position[0], y=q_position[1],
|
|
color=q_color, line_spacing = 1)
|
|
|
|
answer_choices = ("A","B","C","D")
|
|
a_positions = ((25, 145), (25, 165), (25, 185), (25, 205))
|
|
a_color = 0xFFFFFF
|
|
ans_text_areas = []
|
|
for answernum in range(4):
|
|
ans_text_areas.append(label.Label(trivia_font, color=a_color,
|
|
line_spacing = 1.5, x=a_positions[answernum][0],
|
|
y=a_positions[answernum][1]))
|
|
|
|
reveal_position = (25, 45)
|
|
reveal_text_area = label.Label(trivia_font, color=loading_color,
|
|
x=reveal_position[0], y=reveal_position[1])
|
|
|
|
timer_position = (25, 215)
|
|
timer_color = 0xFF00FF
|
|
timer_text_area = label.Label(trivia_font, color=timer_color,
|
|
x=timer_position[0], y=timer_position[1])
|
|
|
|
# A function to shuffle trivia questions
|
|
def shuffle(aList):
|
|
for i in range(len(aList)):
|
|
j = random.randint(0, len(aList)-1)
|
|
# Swap arr[i] with the element at random index
|
|
aList[i], aList[j] = aList[j], aList[i]
|
|
return aList
|
|
|
|
# convert html codes to normal text
|
|
def unescape(s):
|
|
s = s.replace(""", "''")
|
|
s = s.replace("'", "'")
|
|
s = s.replace("&", "&")
|
|
return s
|
|
|
|
# A function to handle the timer and determine which player answers first
|
|
def faceOff(timerLength):
|
|
timer_text = str(timerLength) + " seconds!"
|
|
timer_text_area.text = ''
|
|
timer_text_area.text = str(timer_text)
|
|
timerStart = time.monotonic()
|
|
while time.monotonic() - timerStart < timerLength:
|
|
if button1.value:
|
|
led.value = False # For debugging
|
|
else: # If button 1 pressed, print player 1 on screen and exit function
|
|
led.value = True # For debugging
|
|
q_text_area.text = ''
|
|
reveal_text_area.text = "Player 1!"
|
|
break
|
|
if button2.value:
|
|
led.value = False # For debugging
|
|
else: # If button 2 pressed, print player 2 on screen and exit function
|
|
led.value = True # For debugging
|
|
q_text_area.text = ''
|
|
reveal_text_area.text = "Player 2!"
|
|
break
|
|
time.sleep(0.05) # debounce delay
|
|
else: # Timer runs out
|
|
q_text_area.text = ''
|
|
reveal_text_area.text = "Times up!"
|
|
|
|
# PyPortal constructor
|
|
pyportal = PyPortal(url=DATA_SOURCE,
|
|
json_path=(Q_LOCATION, CA_LOCATION, WA_LOCATION1, WA_LOCATION2, WA_LOCATION3),
|
|
status_neopixel=board.NEOPIXEL,
|
|
default_bg=cwd+"/trivia_title.bmp")
|
|
|
|
pyportal.preload_font() # speed things up by preloading font
|
|
|
|
pyportal.splash.append(loading_text_area) #loading...
|
|
pyportal.splash.append(q_text_area)
|
|
pyportal.splash.append(reveal_text_area)
|
|
pyportal.splash.append(timer_text_area)
|
|
for textarea in ans_text_areas:
|
|
pyportal.splash.append(textarea)
|
|
|
|
while True:
|
|
# Load new question when screen is touched
|
|
while not pyportal.touchscreen.touch_point:
|
|
pass
|
|
|
|
reveal_text_area.text = ''
|
|
q_text_area.text = ''
|
|
for textarea in ans_text_areas:
|
|
textarea.text = ''
|
|
timer_text_area.text = ''
|
|
|
|
pyportal.set_background(cwd+"/trivia.bmp")
|
|
loading_text_area.text ="Loading question..."
|
|
|
|
while True:
|
|
try:
|
|
value = pyportal.fetch()
|
|
break
|
|
except RuntimeError as e:
|
|
print("Some error occured, retrying! -", e)
|
|
continue
|
|
print("Response is", value)
|
|
question = value[0]
|
|
correct_answer = value[1]
|
|
answers = shuffle(value[1:5])
|
|
loading_text_area.text = ''
|
|
|
|
# Format text and wrap with display text library
|
|
try: # sometimes gives a runtime error: Group full
|
|
q_text_area.text = '\n'.join(pyportal.wrap_nicely(unescape(question), 35))
|
|
except RuntimeError as e:
|
|
print("Group full", e)
|
|
continue
|
|
for k, answer in enumerate(answers):
|
|
ans_text_areas[k].text = answer_choices[k]+") "+unescape(answer)
|
|
|
|
faceOff(10) # 10 seconds with question
|
|
time.sleep(2) # pause for 2 seconds to show which player tapped first
|
|
faceOff(5) # 5 seconds to answer
|
|
timer_text_area.text = ''
|
|
# Show the correct answer
|
|
k = answers.index(correct_answer)
|
|
reveal_text = ("Correct Answer:\n"+answer_choices[k]+") "
|
|
+unescape(answers[k])+"\n(Tap for next question.)")
|
|
print(reveal_text)
|
|
reveal_text_area.text = reveal_text
|