def _get_question(self, force_refresh=False, cache_for=settings.DEFAULT_WIDGET_CACHE_TIME): search = {'state': PUBLISHED} global _last_question if _last_question and not force_refresh: ts, question_id = _last_question if ts > time.time(): print "Reusing same old question" question = (self.db.Question.collection .one({'_id': question_id})) return dict_plus(question) #'_id':{'$nin': [x._id for x in battle.sent_questions]} count = self.db.Question.find(search).count() while True: skip = random.randint(0, count - 1) for question in (self.db.Question.collection .find(search) .skip(skip) .limit(1)): if (self.db.QuestionImage .one({'question.$id': question['_id']})): if '_id' not in search: search['_id'] = {'$nin': []} search['_id']['$nin'].append(question['_id']) continue question = dict_plus(question) #logging.info("New widget question: %r (%s)"% # (question.text, question._id)) _last_question = (time.time() + cache_for, question._id) return question
def _get_question(self, force_refresh=False, cache_for=settings.DEFAULT_WIDGET_CACHE_TIME): search = {'state': PUBLISHED} global _last_question if _last_question and not force_refresh: ts, question_id = _last_question if ts > time.time(): print "Reusing same old question" question = (self.db.Question.collection.one( {'_id': question_id})) return dict_plus(question) #'_id':{'$nin': [x._id for x in battle.sent_questions]} count = self.db.Question.find(search).count() while True: skip = random.randint(0, count - 1) for question in (self.db.Question.collection.find(search).skip( skip).limit(1)): if (self.db.QuestionImage.one( {'question.$id': question['_id']})): if '_id' not in search: search['_id'] = {'$nin': []} search['_id']['$nin'].append(question['_id']) continue question = dict_plus(question) #logging.info("New widget question: %r (%s)"% # (question.text, question._id)) _last_question = (time.time() + cache_for, question._id) return question
def calculate(user, rules_id): db = user.db search = { 'users.$id': user._id, 'finished': { '$ne': None }, 'rules': rules_id, } from mongokit import MultipleResultsFound try: play_points = db.PlayPoints.one({ 'user.$id': user._id, 'rules': rules_id }) except MultipleResultsFound: # Temporary hack! for pp in db.PlayPoints.find({ 'user.$id': user._id, 'rules': rules_id }).sort('add_date').limit(1): pp.delete() raise Exception("Try again") if not play_points: play_points = db.PlayPoints() play_points.rules = rules_id play_points.user = user # reset all because we're recalculating play_points.points = 0 play_points.wins = 0 play_points.losses = 0 play_points.draws = 0 for play in db.Play.collection.find(search): play = dict_plus(play) if play.winner and play.winner.id == user._id: play_points.wins += 1 elif play.draw: play_points.draws += 1 else: try: assert play.winner assert play.winner.id != user._id except AssertionError: # pragma: no cover # This happens because of a past bug in the game, where a # draw wassn't saved properly. points = defaultdict(int) for u_ref in play.users: u = db.User.one({'_id': u_ref.id}) for pq in (db.PlayedQuestion.collection.find({ 'play.$id': play._id, 'user.$id': u._id })): pq = dict_plus(pq) if pq.right: if pq.alternatives: p = 1 else: p = 3 else: p = 0 points[u.username] += p if sum(points.values()) == 0: for pq in (db.PlayedQuestion.find( {'play.$id': play._id})): pq.delete() play = db.Play.one({'_id': play._id}) play.delete() continue if len(points) == 2 and len(set(points.values())): play = db.Play.one({'_id': play._id}) play.delete() play.draw = True play.save() play_points.draws += 1 continue print "WINNER", repr(play.winner) print "USERS", [x.username for x in play.users] print "DRAW", repr(play.draw) print "FINISHED", repr(play.finished) print "HALTED", repr(play.halted) print "\n" continue play_points.losses += 1 try: for played in (user.db.PlayedQuestion.collection.find({ 'play.$id': play._id, 'user.$id': user._id })): played = dict_plus(played) if played.right: if played.alternatives: play_points.points += 1 else: play_points.points += 3 except: # pragma: no cover print "BROKEN!!!" print user.username, print "Against", play.get_other_user(user).username print "PLAY", play._id print "USER", user._id raise return play_points play_points.save() return play_points
def post(self): _id = self.get_argument('id') try: question = self.db.Question.one({'_id': ObjectId(_id)}) except InvalidId: raise HTTPError(400, "Invalid ID") if not question: raise HTTPError(404, "Question not found") if self.get_argument('answer', ''): answer = self.get_argument('answer') alternatives = False else: answer = self.get_argument('alt_answer', '') alternatives = True right = question.check_answer(answer) qk = (self.db.QuestionKnowledge.collection .one({'question.$id': question._id})) qk_comment = qk_alternatives_comment = None if qk: qk = dict_plus(qk) p_right = min(99, 100 * qk.right * 1.5) p_right = int(p_right) if right: if p_right < 50: qk_comment = TEMPLATES[0] % dict(p_right=p_right) if p_right < 20: qk_comment += "You're really smart!" else: qk_comment += "You're smart!" else: qk_comment = TEMPLATES[2] % dict(p_right=p_right) else: if p_right < 50: qk_comment = TEMPLATES[1] % dict(p_right=p_right) else: qk_comment = TEMPLATES[3] % dict(p_right=p_right) options = self.get_base_options() if answer: if right: if alternatives: options['page_title'] = 'Very good!' else: options['page_title'] = 'Excellent!' else: options['page_title'] = 'Sorry, better luck next time' else: options['page_title'] = 'No answer :(' options['right'] = right options['alternatives'] = alternatives options['question'] = question options['knowledge_comment'] = qk_comment options['qk_alternatives_comment'] = qk_alternatives_comment _log = "Widget answer: %r " % answer if alternatives: _log += ' (alternatives)' if right: _log += ' RIGHT!' else: _log += ' WRONG' _log += ' Question: %r' % question.text _log += ' knowledge_comment: %r' % qk_comment logging.info(_log) self.render('widget/answer.html', **options)
def get(self, play_id): options = self.get_base_options() play = self.must_find_play(play_id, options['user']) play = self.find_play(play_id) options['play'] = play player_names_lookup = {} for user in play.users: player_names_lookup[user._id] = unicode(user) player_names = player_names_lookup.values() def sort_me_first(x, y): if x == unicode(options['user']): return -1 else: return 1 player_names.sort(sort_me_first) options['player_names'] = player_names played_questions = (self.db.PlayedQuestion.collection .find({'play.$id': play._id}).sort('add_date', ASCENDING)) questions = [] outcomes = defaultdict(dict) totals = defaultdict(int) series = defaultdict(list) # to use for the graph for played_question in played_questions: if played_question['question'].id not in questions: questions.append(played_question['question'].id) player_name = player_names_lookup[played_question['user'].id] outcomes[played_question['question'].id][player_name] = \ dict_plus(played_question) if played_question['right']: if played_question['alternatives']: totals[player_name] += 1 else: totals[player_name] += 3 series[player_name].append( totals[player_name] ) # now turn this series dict into a list series = [dict(name=k, data=[0] + v) for (k, v) in series.items()] options['series_json'] = tornado.escape.json_encode(series) questions = [dict_plus(self.db.Question.collection.one({'_id':x})) for x in questions] genres = {} images = {} for q in questions: if q._id in genres: name = genres[q._id] else: genres[q._id] = u'xxx' q.genre = dict_plus(dict(name=genres[q._id])) for question_image in (self.db.QuestionImage .find({'question.$id': {'$in': [x._id for x in questions]}})): images[question_image.question._id] = question_image options['images'] = images options['questions'] = questions options['outcomes'] = outcomes options['totals'] = totals options['page_title'] = ' vs. '.join(player_names) options['message_sent'] = None options['can_send_message'] = not options['user'].anonymous if settings.COMPUTER_USERNAME in player_names: options['can_send_message'] = False options['play_messages'] = (self.db.PlayMessage .find({'play.$id': play._id}) .sort('add_date')) self.render("play/replay.html", **options)
def render(self, question): db = connection[settings.DATABASE_NAME] difficulties = { 0: 0, # about right 1: 0, # easy -1: 0 # hard } ratings = { 0: 0, # ok 1: 0, # good -1: 0 # bad } count = 0 search = {'question.$id': question._id} for review in db.QuestionReview.collection.find(search): review = dict_plus(review) difficulties[review['difficulty']] += 1 rating = review['rating'] if rating == 2: # legacy if isinstance(review.difficulty, float): review.delete() continue review.rating = 1 review.save() rating = 1 ratings[rating] += 1 count += 1 count = rights = alternatives = wrongs = tooslows = 0 for qp in db.PlayedQuestion.collection.find(search): play = db.Play.collection.one({'_id': qp['play'].id}) if not play: db.PlayedQuestion.collection.remove({'play.$id':qp['play'].id}) continue if play['finished']: if qp['answer']: count += 1 if qp['right']: rights += 1 else: wrongs += 1 if qp['alternatives']: alternatives += 1 else: tooslows += 1 answers = { 'right': 0, 'wrong': 0, 'alternatives': 0, } if count: answers['right'] = int(100. * rights /count) answers['wrong'] = int(100. * wrongs /count) answers['alternatives'] = int(100. * alternatives /count) return dict(difficulties=difficulties, ratings=ratings, answers=answers, ) return dict(difficulties_json=tornado.escape.json_encode(difficulties), ratings_json=tornado.escape.json_encode(ratings), )
def get(self, play_id): options = self.get_base_options() play = self.must_find_play(play_id, options['user']) play = self.find_play(play_id) options['play'] = play player_names_lookup = {} for user in play.users: player_names_lookup[user._id] = unicode(user) player_names = player_names_lookup.values() def sort_me_first(x, y): if x == unicode(options['user']): return -1 else: return 1 player_names.sort(sort_me_first) options['player_names'] = player_names played_questions = (self.db.PlayedQuestion.collection.find({ 'play.$id': play._id }).sort('add_date', ASCENDING)) questions = [] outcomes = defaultdict(dict) totals = defaultdict(int) series = defaultdict(list) # to use for the graph for played_question in played_questions: if played_question['question'].id not in questions: questions.append(played_question['question'].id) player_name = player_names_lookup[played_question['user'].id] outcomes[played_question['question'].id][player_name] = \ dict_plus(played_question) if played_question['right']: if played_question['alternatives']: totals[player_name] += 1 else: totals[player_name] += 3 series[player_name].append(totals[player_name]) # now turn this series dict into a list series = [dict(name=k, data=[0] + v) for (k, v) in series.items()] options['series_json'] = tornado.escape.json_encode(series) questions = [ dict_plus(self.db.Question.collection.one({'_id': x})) for x in questions ] genres = {} images = {} for q in questions: if q._id in genres: name = genres[q._id] else: genres[q._id] = u'xxx' q.genre = dict_plus(dict(name=genres[q._id])) for question_image in (self.db.QuestionImage.find( {'question.$id': { '$in': [x._id for x in questions] }})): images[question_image.question._id] = question_image options['images'] = images options['questions'] = questions options['outcomes'] = outcomes options['totals'] = totals options['page_title'] = ' vs. '.join(player_names) options['message_sent'] = None options['can_send_message'] = not options['user'].anonymous if settings.COMPUTER_USERNAME in player_names: options['can_send_message'] = False options['play_messages'] = (self.db.PlayMessage.find({ 'play.$id': play._id }).sort('add_date')) self.render("play/replay.html", **options)
def calculate_knowledge(db, question): bot_ids = [ bot['_id'] for bot in ( db.User.collection.find({'username': settings.COMPUTER_USERNAME})) ] users = defaultdict(set) tally = { 'right': 0, 'wrong': 0, 'alternatives_wrong': 0, 'alternatives_right': 0, 'too_slow': 0, 'timed_out': 0, 'users': 0, } finished_plays = {} for played_question in (db.PlayedQuestion.collection.find({ 'question.$id': question._id, 'user.$id': { '$nin': bot_ids } }).sort('add_date', 1)): played_question = dict_plus(played_question) #print "PQ" #pprint(dict(play=played_question.play.id, # user=played_question.user.id, # right=played_question.right, # question=played_question.question.id, # alternatives=played_question.alternatives, # timed_out=played_question.timed_out, # answer=played_question.answer)) # only bother with played questions in a play that finished play_id = played_question.play.id if play_id not in finished_plays: # need to figure out if it was finished play = db.Play.collection.one({'_id': play_id}) assert play, play_id finished_plays[play_id] = bool(play['finished']) if not finished_plays[play_id]: continue user_id = played_question['user'].id if played_question['question'].id in users[user_id]: continue users[user_id].add(played_question['question'].id) tally['users'] += 1 if played_question.right: # means, this user nailed it! if played_question.alternatives: # ...but had to load alternatives tally['alternatives_right'] += 1 #print "ALTERNATIVES RIGHT" else: # ...by knowing the answer tally['right'] += 1 #print "RIGHT" elif played_question.answer: if played_question.alternatives: tally['alternatives_wrong'] += 1 #print "ALTERNATIVES WRONG" else: tally['wrong'] += 1 #print "WRONG" else: # that means that this user was either # too slow (ie. beaten) or timed out # To find out what happened we need to find out how the other # opponent faired others_right = [] others_wrong = [] others_alternatives = [] others_right_alternatives = [] others_too_slow = [] others_timed_out = [] for other in (db.PlayedQuestion.collection.find({ 'question.$id': question._id, 'play.$id': played_question['play'].id, 'user.$id': { '$ne': user_id } })): # always assume N opponents others_right.append(other['right']) if any(others_right): # in some way, the opponent beat you to it tally['too_slow'] += 1 #print "TOO SLOW" else: # opponent didn't get it right and you no answer tally['timed_out'] += 1 #print "TIMED OUT" if not tally['users']: if options.verbose: print "NO ANSWERS!" print repr(question.text), repr(question.answer) print question.publish_date else: if options.verbose: print repr(question.text), repr(question.answer) pprint(tally) check = (tally['right'] + tally['alternatives_right'] + tally['wrong'] + tally['alternatives_wrong'] + tally['too_slow'] + tally['timed_out']) if check != tally['users']: raise ValueError(tally) # save all of this! knowledge = db.QuestionKnowledge.one({'question.$id': question._id}) if not knowledge: knowledge = db.QuestionKnowledge() knowledge.question = question users = float(tally['users']) knowledge.users = tally['users'] knowledge.right = tally['right'] / users knowledge.wrong = tally['wrong'] / users knowledge.alternatives_right = tally['alternatives_right'] / users knowledge.alternatives_wrong = tally['alternatives_wrong'] / users knowledge.too_slow = tally['too_slow'] / users knowledge.timed_out = tally['timed_out'] / users knowledge.save()
def calculate_knowledge(db, question): bot_ids = [bot["_id"] for bot in (db.User.collection.find({"username": settings.COMPUTER_USERNAME}))] users = defaultdict(set) tally = { "right": 0, "wrong": 0, "alternatives_wrong": 0, "alternatives_right": 0, "too_slow": 0, "timed_out": 0, "users": 0, } finished_plays = {} for played_question in db.PlayedQuestion.collection.find( {"question.$id": question._id, "user.$id": {"$nin": bot_ids}} ).sort("add_date", 1): played_question = dict_plus(played_question) # print "PQ" # pprint(dict(play=played_question.play.id, # user=played_question.user.id, # right=played_question.right, # question=played_question.question.id, # alternatives=played_question.alternatives, # timed_out=played_question.timed_out, # answer=played_question.answer)) # only bother with played questions in a play that finished play_id = played_question.play.id if play_id not in finished_plays: # need to figure out if it was finished play = db.Play.collection.one({"_id": play_id}) assert play, play_id finished_plays[play_id] = bool(play["finished"]) if not finished_plays[play_id]: continue user_id = played_question["user"].id if played_question["question"].id in users[user_id]: continue users[user_id].add(played_question["question"].id) tally["users"] += 1 if played_question.right: # means, this user nailed it! if played_question.alternatives: # ...but had to load alternatives tally["alternatives_right"] += 1 # print "ALTERNATIVES RIGHT" else: # ...by knowing the answer tally["right"] += 1 # print "RIGHT" elif played_question.answer: if played_question.alternatives: tally["alternatives_wrong"] += 1 # print "ALTERNATIVES WRONG" else: tally["wrong"] += 1 # print "WRONG" else: # that means that this user was either # too slow (ie. beaten) or timed out # To find out what happened we need to find out how the other # opponent faired others_right = [] others_wrong = [] others_alternatives = [] others_right_alternatives = [] others_too_slow = [] others_timed_out = [] for other in db.PlayedQuestion.collection.find( {"question.$id": question._id, "play.$id": played_question["play"].id, "user.$id": {"$ne": user_id}} ): # always assume N opponents others_right.append(other["right"]) if any(others_right): # in some way, the opponent beat you to it tally["too_slow"] += 1 # print "TOO SLOW" else: # opponent didn't get it right and you no answer tally["timed_out"] += 1 # print "TIMED OUT" if not tally["users"]: if options.verbose: print "NO ANSWERS!" print repr(question.text), repr(question.answer) print question.publish_date else: if options.verbose: print repr(question.text), repr(question.answer) pprint(tally) check = ( tally["right"] + tally["alternatives_right"] + tally["wrong"] + tally["alternatives_wrong"] + tally["too_slow"] + tally["timed_out"] ) if check != tally["users"]: raise ValueError(tally) # save all of this! knowledge = db.QuestionKnowledge.one({"question.$id": question._id}) if not knowledge: knowledge = db.QuestionKnowledge() knowledge.question = question users = float(tally["users"]) knowledge.users = tally["users"] knowledge.right = tally["right"] / users knowledge.wrong = tally["wrong"] / users knowledge.alternatives_right = tally["alternatives_right"] / users knowledge.alternatives_wrong = tally["alternatives_wrong"] / users knowledge.too_slow = tally["too_slow"] / users knowledge.timed_out = tally["timed_out"] / users knowledge.save()
def calculate(user, rules_id): db = user.db search = { 'users.$id': user._id, 'finished': {'$ne': None}, 'rules': rules_id, } from mongokit import MultipleResultsFound try: play_points = db.PlayPoints.one({'user.$id': user._id, 'rules': rules_id}) except MultipleResultsFound: # Temporary hack! for pp in db.PlayPoints.find({'user.$id': user._id,'rules': rules_id}).sort('add_date').limit(1): pp.delete() raise Exception("Try again") if not play_points: play_points = db.PlayPoints() play_points.rules = rules_id play_points.user = user # reset all because we're recalculating play_points.points = 0 play_points.wins = 0 play_points.losses = 0 play_points.draws = 0 for play in db.Play.collection.find(search): play = dict_plus(play) if play.winner and play.winner.id == user._id: play_points.wins += 1 elif play.draw: play_points.draws += 1 else: try: assert play.winner assert play.winner.id != user._id except AssertionError: # pragma: no cover # This happens because of a past bug in the game, where a # draw wassn't saved properly. points = defaultdict(int) for u_ref in play.users: u = db.User.one({'_id': u_ref.id}) for pq in (db.PlayedQuestion.collection .find({'play.$id': play._id, 'user.$id': u._id})): pq = dict_plus(pq) if pq.right: if pq.alternatives: p = 1 else: p = 3 else: p = 0 points[u.username] += p if sum(points.values()) == 0: for pq in (db.PlayedQuestion .find({'play.$id': play._id})): pq.delete() play = db.Play.one({'_id': play._id}) play.delete() continue if len(points) == 2 and len(set(points.values())): play = db.Play.one({'_id': play._id}) play.delete() play.draw = True play.save() play_points.draws += 1 continue print "WINNER", repr(play.winner) print "USERS", [x.username for x in play.users] print "DRAW", repr(play.draw) print "FINISHED", repr(play.finished) print "HALTED", repr(play.halted) print "\n" continue play_points.losses += 1 try: for played in (user.db.PlayedQuestion.collection .find({'play.$id': play._id, 'user.$id': user._id})): played = dict_plus(played) if played.right: if played.alternatives: play_points.points += 1 else: play_points.points += 3 except: # pragma: no cover print "BROKEN!!!" print user.username, print "Against", play.get_other_user(user).username print "PLAY", play._id print "USER", user._id raise return play_points play_points.save() return play_points
def post(self): _id = self.get_argument('id') try: question = self.db.Question.one({'_id': ObjectId(_id)}) except InvalidId: raise HTTPError(400, "Invalid ID") if not question: raise HTTPError(404, "Question not found") if self.get_argument('answer', ''): answer = self.get_argument('answer') alternatives = False else: answer = self.get_argument('alt_answer', '') alternatives = True right = question.check_answer(answer) qk = (self.db.QuestionKnowledge.collection.one( {'question.$id': question._id})) qk_comment = qk_alternatives_comment = None if qk: qk = dict_plus(qk) p_right = min(99, 100 * qk.right * 1.5) p_right = int(p_right) if right: if p_right < 50: qk_comment = TEMPLATES[0] % dict(p_right=p_right) if p_right < 20: qk_comment += "You're really smart!" else: qk_comment += "You're smart!" else: qk_comment = TEMPLATES[2] % dict(p_right=p_right) else: if p_right < 50: qk_comment = TEMPLATES[1] % dict(p_right=p_right) else: qk_comment = TEMPLATES[3] % dict(p_right=p_right) options = self.get_base_options() if answer: if right: if alternatives: options['page_title'] = 'Very good!' else: options['page_title'] = 'Excellent!' else: options['page_title'] = 'Sorry, better luck next time' else: options['page_title'] = 'No answer :(' options['right'] = right options['alternatives'] = alternatives options['question'] = question options['knowledge_comment'] = qk_comment options['qk_alternatives_comment'] = qk_alternatives_comment _log = "Widget answer: %r " % answer if alternatives: _log += ' (alternatives)' if right: _log += ' RIGHT!' else: _log += ' WRONG' _log += ' Question: %r' % question.text _log += ' knowledge_comment: %r' % qk_comment logging.info(_log) self.render('widget/answer.html', **options)
def render(self, question): db = connection[settings.DATABASE_NAME] difficulties = { 0: 0, # about right 1: 0, # easy -1: 0 # hard } ratings = { 0: 0, # ok 1: 0, # good -1: 0 # bad } count = 0 search = {'question.$id': question._id} for review in db.QuestionReview.collection.find(search): review = dict_plus(review) difficulties[review['difficulty']] += 1 rating = review['rating'] if rating == 2: # legacy if isinstance(review.difficulty, float): review.delete() continue review.rating = 1 review.save() rating = 1 ratings[rating] += 1 count += 1 count = rights = alternatives = wrongs = tooslows = 0 for qp in db.PlayedQuestion.collection.find(search): play = db.Play.collection.one({'_id': qp['play'].id}) if not play: db.PlayedQuestion.collection.remove( {'play.$id': qp['play'].id}) continue if play['finished']: if qp['answer']: count += 1 if qp['right']: rights += 1 else: wrongs += 1 if qp['alternatives']: alternatives += 1 else: tooslows += 1 answers = { 'right': 0, 'wrong': 0, 'alternatives': 0, } if count: answers['right'] = int(100. * rights / count) answers['wrong'] = int(100. * wrongs / count) answers['alternatives'] = int(100. * alternatives / count) return dict( difficulties=difficulties, ratings=ratings, answers=answers, ) return dict( difficulties_json=tornado.escape.json_encode(difficulties), ratings_json=tornado.escape.json_encode(ratings), )