-
Notifications
You must be signed in to change notification settings - Fork 3
/
run.py
347 lines (313 loc) · 12.7 KB
/
run.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
import os
import ast
import math
import sys
from flask import Markup
from datetime import datetime
from riddlesList import content
from operator import itemgetter
from flask import Flask, render_template, request, flash, redirect, url_for,\
session, current_app
riddles = content()
app = Flask(__name__)
app.debug = False
if app.debug:
from config import config
app.secret_key = config()
else:
app.secret_key = os.environ.get('SECRET_KEY')
usernames = []
leaderboard = [{"username": "Player 1", "score": 8, "timestamp": "01-09-2018"},
{"username": "Player 2", "score": 3, "timestamp": "02-09-2018"}]
player_info = []
riddle = {}
@app.route('/', methods=["GET", "POST"])
def index():
'''
Get username from form
'''
# session.pop('username', None)
session.pop('_flashes', None)
length = len(riddles)
try:
if request.method == "POST":
username_from_form = request.form['addUsername']
if check_username(username_from_form):
# start the game
return redirect(url_for('start_game'))
except: # Exception as e:
return render_template("500.html")
return render_template("index.html", page_title="Riddle-Me-This - Home",
length=length, player_info=player_info,
usernames=usernames,
leaderboard=leaderboard)
def check_username(username):
'''
check if username is already taken or in session so that user can
start/restart/resume Session takes precedence over the usernames
List. If a person is in the usernames list but does not have an
active session they are asked to choose a different username
'''
in_usernames_list = username in usernames
in_session = session.get('username') == username
in_both = in_usernames_list and in_session
in_neither = not in_usernames_list and not in_session
# if user has an active session but is not in the list
if not in_usernames_list and in_session or in_both:
if not in_usernames_list:
usernames.append(username)
for player in player_info:
if (player['username'] == username and
player['riddle_number'] == len(riddles)):
flash("You have already completed the 10 riddles.\
You can try again")
player.update({"restart": True, "resume": False,
"riddle_number": 0, "score": 0,
"attempt_total": 0, "wrong": 0, "attempts": 0})
elif (player['username'] == username and
player['riddle_number'] != len(riddles)):
player.update({"resume": True, "restart": False})
return True
elif in_usernames_list and not in_session:
# username taken try again until username is not in usernames[]
message_false = Markup("{}, this name has already been taken. \
<br>Enter a different player \
name".format(username))
flash(message_false)
return False
elif in_neither:
# if its a new unique username, add to usernames[]
usernames.append(username)
# add username to flask session
session['username'] = username
return True
else:
return render_template("index.html",
page_title="Riddle-Me-This - Home",
usernames=usernames,
leaderboard=leaderboard)
@app.route('/start_game', methods=["GET", "POST"])
def start_game():
'''
Intialise 'riddle' dictionary. Checks if user is
starting/restarting/resuming a game.
Populate 'player' with player info to track their progress.
Get the first riddle to start the game,
or get the current riddle a player is on if resuming a game
or get the first riddle if a player is resuming
'''
global riddle
for player in player_info:
if player['resume'] is True:
# returns NEXT riddle for that player
riddle = get_riddle(player['riddle_number'])
player.update({"resume": False})
return redirect(url_for('play'))
if player['restart'] is True:
# returns FIRST riddle
riddle = get_riddle(0)
player.update({"restart": False})
return redirect(url_for('play'))
else:
create_player(session['username'])
# returns FIRST riddle
riddle = get_riddle(0)
return redirect(url_for('play'))
@app.route('/play')
def play():
'''
If no session is running this page can't be accessed.
User is redirected to index page
'''
try:
if session.get('username'):
for player in player_info:
if (player['username'] == session['username'] and
player['restart'] is False or
player['username'] == session['username'] and
player['restart'] is True):
length_of_riddles = len(riddles)
return render_template("play.html",
page_title="Riddle-Me-This - Play",
username=session['username'],
leaderboard=leaderboard,
player_info=player_info,
player=player,
usernames=usernames,
riddle=riddle,
session=session,
length_of_riddles=length_of_riddles)
else:
return redirect(url_for('index'))
except: # Exception as e:
return render_template("500.html")
@app.route('/checkPlayerInput', methods=["GET", "POST"])
def check():
'''
The player answer is read from the form.
The answer, the correct answer and the current riddle index is sent to
check_answer(). The returned riddle index is checked that it is not more
than the number of riddles available. If the last riddle is complete,
player is redirected to end() end.html. If not the last riddle the index
is passed to get_next_riddle() to get the next riddle from riddleList[]
'''
global riddle
if request.method == "POST":
# get player answer from form
player_answer = request.form['riddleAnswer']
# get player current riddle number from form
player_current_riddle_number = int(request.form
['player_current_riddle_number'])
# check if answer is a digit instead of text e.g. 7 instead of seven
if player_answer.isdigit():
# send to helper function
checked_player_answer = number_to_string(int(player_answer))
else:
# reset player_answer var with checked answer
checked_player_answer = player_answer
# get the correct riddle for that player
current_riddle = get_riddle(player_current_riddle_number)
# check_answer() called. Index of next riddle returned.
player = check_answer(checked_player_answer.lower(), current_riddle)
# check for last riddle
if player['riddle_number'] < len(riddles):
riddle = get_riddle(player['riddle_number'])
else:
# set Riddle Number to length of riddles list
riddle = {'Number': len(riddles)}
# date now
date_completed = datetime.now().strftime("%d-%m-%Y")
leaderboard.append({"username": session['username'],
"score": player['score'],
"timestamp": date_completed})
redirect(url_for('play'))
return redirect(url_for('play'))
def check_answer(answerInputByPlayer, riddle):
'''
Based on the username in session the inputed answer is compared against the
actual riddle answer. If the answer is correct, the score is increased by
1, the leaderboard is updated.
The index is increased by one to find next riddle in riddle list []
If the answer is incorrect, the attempt is increased by 1.
The user two attempts.
The index is increased by one to find next riddle in riddle list []
The next riddle index is returned
'''
for player in player_info:
if player['username'] == session['username']:
if riddle['Answer'] == answerInputByPlayer:
# flash - player told answer is correct
flash("Correct! The answer was: {}.".format(riddle['Answer']))
player['attempt'] = 0
# increase score by 1
player['score'] += 1
# increase riddle number by 1
player['riddle_number'] += 1
# check for last riddle
if (player['riddle_number'] < len(riddles)):
return player # player
else:
# flash - player told answer is incorrect
flash("{} is incorrect.".format(answerInputByPlayer))
# increase attempt by 1
player['attempt'] += 1
# increase attempt_total by 1
player['attempt_total'] += 1
# max of 2 attempts reached
if player['attempt'] == 2:
# increase wrong count by 1
player['wrong'] += 1
# flash - player told the correct answer
flash("{} was the correct\
answer.".format(riddle['Answer']))
# reset attempts back to 0
player['attempt'] = 0
# increase riddle number by 1
player['riddle_number'] += 1
# check for last riddle
if (player['riddle_number'] < len(riddles)):
return player
return player
@app.route('/end')
def end():
'''
User is told the game is over. Their score is added to the LeaderBoad List.
The leader board list is sorted by Score and rendered to the browser.
The session is cleared. Else the leaderboard is still rendered to the
broswer if there are games in session at the same time.
'''
try:
# show leader board list sorted by score
sorted_leaderboard_list = sorted(leaderboard, key=itemgetter('score'),
reverse=True)
return render_template("end.html",
page_title="Riddle-Me-This - Game Over",
session=session, leaderboard=leaderboard,
players=player_info,
sorted_leaderboard_list=sorted_leaderboard_list)
except: # Exception as e:
return render_template("500.html")
@app.context_processor
def debug_on_off():
return dict(debug=app.debug)
def get_riddle(riddleIndex):
'''
If answer is correct or attempts are more than two,
get the next riddle from the riddle List, based on the riddle number
'''
# get next riddle by passing index to riddles[]
# and return the riddle {} dictionary
nextRiddle = riddles[riddleIndex]
return nextRiddle
def create_player(username):
'''
Creates a player dict{} in player_info List to track the players; score,
attempts, wrong, current riddle number,
total attempts, whether they are resuming a game or restarting
after completeing the game.
'''
# creates a player dict{}
player_info.append({"username": username,
"score": 0,
"attempt": 0,
"wrong": 0,
"riddle_number": 0,
"attempt_total": 0,
"restart": False,
"resume": False})
return player_info
def number_to_string(number):
'''
Helper function - to change a digit to the word
version of a number e.g. 7 to seven
'''
switcher = {
1: "one",
2: "two",
3: "three",
4: "four",
5: "five",
6: "six",
7: "seven",
8: "eight",
9: "nine",
10: "ten",
18: "eighteen"
}
return switcher.get(number, str(number))
@app.errorhandler(404)
def page_not_found(error):
'''
404 error is redirected to 404.html
'''
return render_template('404.html')
@app.errorhandler(500)
def internal_error(error):
'''
500 error is redirected to 500.html
'''
session.pop('_flashes', None)
session.pop('username', None)
return render_template('500.html')
if __name__ == '__main__':
app.run(host=os.getenv('IP'), port=int(os.getenv('PORT')))