def get_sampled_num(handler_input) -> tuple:
        """Returns tuples of times table question for the user.

      Uses random.gaus() to take two randomly selected numbers.
      numbers are capped at sm_upper.
      """
        @log_func_name
        def get_rand_gauss_num(upper: int) -> int:
            """Returns integer sampled from normal distribution.
         
         Uses a center at 2/3 the max number."""
            sm_center = (upper / 1.1)
            variation = (sqrt(upper) - 1) * 1.5

            gauss_dist_num = float('inf')
            while (gauss_dist_num > upper) or (gauss_dist_num < 0):
                gauss_dist_num = int(random.gauss(sm_center, variation))

                if (gauss_dist_num < sm_center // 2.5) and (random.random() <
                                                            0.33):
                    ## norm dist with variation showing high chance of low nums...
                    ## still want wide spread, so chance to re-roll.
                    gauss_dist_num = float('inf')

            return gauss_dist_num

        attr = handler_input.attributes_manager.session_attributes
        sm_upper = attr.get('sm_upper', 5)
        num_1, num_2 = (get_rand_gauss_num(sm_upper) for _ in range(2))

        log_all(sm_upper, num_1, num_2)
        return (num_1, num_2)
    def get_ms_average_score_welcome(player_obj: object) -> str:
        """Returns welcome message telling the player's average time."""

        average_records = None
        for difficulty in speed_challenge.data.SC_DIFFICULTIES:
            average_records = player_obj.get_sc_average_records(difficulty)
            if average_records is not None:
                break

        if (difficulty is None) or (average_records is None):
            log_all(difficulty, average_records, log_level=40)
            logger.error(
                "get_ms_high_score_welcome: Found no difficulty or average_records."
            )
            return SC_WelcomeUtils.get_ms_short_welcome()

        avg_score = int(mean(average_records))
        avg_score = SC_EndGame.format_score_as_minutes_seconds(avg_score)

        ms_average_score = random.choice(
            speed_challenge.data.MT_AVERAGE_SCORE).format(
                difficulty, avg_score)
        ms_beat_it = random.choice(speed_challenge.data.MT_BEAT_IT)

        speech_list = (ms_average_score, 1, ms_beat_it)
        return get_linear_nlg(speech_list)
 def get_sc_high_score(self, difficulty: str) -> int:
    """Returns the user's high score for the speed challenge difficulty.
    
    Returns None if no high score is found for that difficulty."""
    sc_hs_dict = self._sc_high_score_dict
    log_all(sc_hs_dict)
    return sc_hs_dict.get(difficulty, None)
    def get_oldest_date(wrong_quest_by_date: dict) -> str:
        """Returns the oldest date key for wrong_questions_by_date."""
        date_keys = list(wrong_quest_by_date.keys())
        date_keys.sort()

        log_all(date_keys)
        return date_keys[-1]  # most recent dates 1st.
Beispiel #5
0
 def format_score_as_minutes_seconds(sc_score_time: int) -> str:
     """Returns score as string in proper MM:SS format."""
     minutes, seconds = int(sc_score_time) // 60, int(sc_score_time) % 60
     log_all(minutes, seconds)
     if minutes != 0:
         return f"{minutes} minutes and {seconds} seconds"
     else:
         return f"{seconds} seconds"
    def check_same_question(handler_input, new_question: tuple) -> bool:
        """Returns boolean representing if same question asked to the user."""
        old_question_1, old_question_2 = QuestionAttr.get_question_tables(
            handler_input, integers=True)
        log_all(old_question_1, old_question_2, new_question[0],
                new_question[1])

        return (new_question[0] == old_question_1
                and new_question[1] == old_question_2)
 def enforce_allowed_answered_tables(answered_tables: list) -> list:
    """Enforces the allowed length of answered_tables."""
    table_overflow = len(answered_tables) - players.data.ALLOWED_ANSWERED_TABLES
    if table_overflow <= 0:
       return answered_tables
    
    log_all(table_overflow, answered_tables)
    del answered_tables[0 : table_overflow]
    logger.debug(answered_tables)
    return answered_tables
   def enforce_table_data_size(table_data: list) -> list:
      """Enforces the allowed length of the table data.

      If data exceeds the length of the allowed data, 
      removes excess elements."""
      table_overflow = len(table_data) - players.data.ALLOWED_TABLE_DATA
      if table_overflow <= 0:
         return table_data

      log_all(table_overflow, table_data)
      del table_data[0 : table_overflow]
      logger.debug(table_data)

      return table_data
Beispiel #9
0
    def get_sc_total_time(handler_input) -> int:
        """Returns the difference in seconds between start and end of sc.

        Also saves the float number as a session attribute."""
        attr = handler_input.attributes_manager.session_attributes

        start_time_dict = attr['sc_start_time'] 
        end_time_dict = attr['sc_end_time']
        start_time = TimeEncoder.convert_dict_to_datetime( start_time_dict)
        end_time = TimeEncoder.convert_dict_to_datetime( end_time_dict)

        time_difference = (end_time - start_time).seconds
        attr['sc_time_score'] = time_difference

        log_all(start_time, end_time, time_difference)
        return time_difference
   def set_sc_high_score(self, difficulty: str, user_score: int) -> None:
      """Sets the highscore for speed challenge's difficulty."""
      sc_hs_dict = self._sc_high_score_dict
      log_all(sc_hs_dict)
      
      if difficulty not in sc_hs_dict.keys():
         sc_hs_dict[difficulty] = user_score
         self._sc_high_score_dict = sc_hs_dict
         return None

      high_score = sc_hs_dict[difficulty]
      if (user_score < high_score):
         sc_hs_dict[difficulty] = user_score
         self._sc_high_score_dict = sc_hs_dict
      
      return
    def get_ms_question_intro(handler_input,
                              first_question: bool,
                              player_obj: object = None) -> str:
        """Returns message for the question introduction.
      
      NOTE: No confirmation in this mode."""
        attr = handler_input.attributes_manager.session_attributes

        flag_double_digits = attr.get('flag_double_digits', False)
        flag_upper_hit_avg = attr.get('flag_upper_hit_avg', False)
        flag_cntr_hit_avg = attr.get('flag_cntr_hit_avg', False)

        sm_upper = int(attr.get('sm_upper', 0))
        sm_center = int(sm_upper / 1.1)
        questions_answered = attr.get('questions_answered', 0)

        if first_question:
            return AllQuestionIntros.get_first_question_intro()

        elif (sm_upper == 10) and flag_double_digits:
            attr['flag_double_digits'] = False
            return SMQuestions.get_ms_upper_as_ten()

        ## Load objs to avoid repetitive loads.
        if not player_obj:
            player_obj = PlayerDict.load_player_obj(handler_input)
        answered_tables = player_obj.get_answered_tables(integers=True)
        inflated_average_table = int(
            mean(answered_tables)) + 2  ## Note a truth average

        log_all(sm_upper, sm_center, inflated_average_table,
                questions_answered)

        if (sm_upper == inflated_average_table - 2
            ) and flag_upper_hit_avg:  ## when sm_upper is uninflated_average.
            attr['flag_upper_hit_avg'] = False
            return SMQuestions.get_ms_upper_as_average_table()

        elif (sm_center == inflated_average_table) and flag_cntr_hit_avg:
            attr['flag_cntr_hit_avg'] = False
            return SMQuestions.get_ms_freq_average_table()

        return SMQuestions.get_ms_relative_difficulty(
            handler_input,
            player_obj=player_obj,
            answered_tables=answered_tables)
   def update_sc_average_record(self, difficulty: str, user_score: int) -> None:
      """Updates the average records for speed challenge's difficulty."""
      sc_average_record_dict = self._sc_average_record_dict
      log_all(sc_average_record_dict)

      if difficulty not in sc_average_record_dict.keys():
         sc_average_record_dict[difficulty] = [user_score]
         self._sc_average_record_dict = sc_average_record_dict
         return None
      
      average_records = sc_average_record_dict[difficulty]
      average_records.append(user_score)

      if len(average_records) > players.data.ALLLOWED_AVG_RECORDS:
         del average_records[0]
      
      sc_average_record_dict[difficulty] = average_records
      self._sc_average_record_dict = sc_average_record_dict
      log_all(sc_average_record_dict)
      return None
    def get_ms_high_score_welcome(player_obj: object) -> str:
        """Returns welcome message that includes user's highscore."""
        mode_hs = None
        for difficulty in speed_challenge.data.SC_DIFFICULTIES:
            mode_hs = player_obj.get_sc_high_score(difficulty)
            if mode_hs is not None:
                break
        if (difficulty is None) or (mode_hs is None):
            log_all(difficulty, mode_hs, log_level=40)
            logger.error(
                "get_ms_high_score_welcome: Found no difficulty or hs.")
            return SC_WelcomeUtils.get_ms_short_welcome()

        mode_hs = SC_EndGame.format_score_as_minutes_seconds(mode_hs)

        ms_high_score = random.choice(
            speed_challenge.data.MT_HIGH_SCORE).format(difficulty, mode_hs)
        ms_beat_it = random.choice(speed_challenge.data.MT_BEAT_IT)

        speech_list = (ms_high_score, 1, ms_beat_it)
        return get_linear_nlg(speech_list)
    def record_wrong_question(handler_input) -> None:
        """Saves the question as a session attribute.

        Implementation NOTE:
        Currently using series of get statements
        May be able to use a while loop instead that checks if data type is dict.
        May also like to change to try-except statement.
        """
        attr = handler_input.attributes_manager.session_attributes

        ## Keys
        wrong_quest_by_date = attr['wrong_quest_by_date']
        today = attr['today']
        table_1, table_2 = QuestionAttr.get_question_tables(handler_input,
                                                            integers=False)
        log_all(wrong_quest_by_date, today, table_1, table_2)

        ## Get Dicts
        incorrect_today_dict = wrong_quest_by_date.get(today, {})
        tbl_1_incorrect_dict = incorrect_today_dict.get(table_1, {})
        tbl_2_val = tbl_1_incorrect_dict.get(table_2, 0)
        log_all(incorrect_today_dict, tbl_1_incorrect_dict, tbl_2_val)

        ## Val
        tbl_2_val += 1

        ## Update dicts
        tbl_1_incorrect_dict[table_2] = tbl_2_val
        incorrect_today_dict[table_1] = tbl_1_incorrect_dict
        wrong_quest_by_date[today] = incorrect_today_dict
        attr['wrong_quest_by_date'] = wrong_quest_by_date

        log_all(incorrect_today_dict, tbl_1_incorrect_dict, tbl_2_val)
        return
    def update_last_question_attr(handler_input, correct: bool) -> None:
        """Updates last question boolean session attribute.
        
        NOTE: Only call when question is correct."""
        attr = handler_input.attributes_manager.session_attributes
        if attr.get('mode', None) != 'custom':
            return None
        
        practice_type = attr.get('practice_type', None)
        if practice_type == custom_practice.data.PRACT_TYPES[0] and correct:
            attr['last_question'] = (not CP_Attr.check_more_than_one_incorrect_question(handler_input))
        
        elif practice_type != custom_practice.data.PRACT_TYPES[0]:
            CP_Attr.adjust_cp_consec_correct(handler_input, correct)
            
            next_consec_correct = int(attr['cp_consecutive_correct']) + 1
            max_questions = custom_practice.data.QUESTIONS_PER_MODE
            log_all( next_consec_correct, max_questions)
            
            attr['last_question'] = next_consec_correct == max_questions  

        return None
Beispiel #16
0
    def get_last_prompt(handler_input) -> str:
        """Returns the prompt used in the previous response.
        
        first checks if existing question to be asked. If so, asks the question.

        If function saved, uses function.
        Elif str prompt saved, uses cached from response interceptor.
        Else, uses HelpUtils.get_corresponding_message.
        """
        attr = handler_input.attributes_manager.session_attributes

        ## Free Play Questions
        question = attr.get('question', None)
        flag_in_game = attr.get(
            'mode', None) in aux_data.skill_data.MODE_ACT_DICT.keys()
        log_all(question, flag_in_game)
        if (question and flag_in_game):
            prompt_user = GenQuestions.get_same_question(handler_input)

        ## Don't repeat help
        elif is_intent_name("AMAZON.HelpIntent")(handler_input):
            prompt_user = HelpUtils.get_q_what_todo()

        ## Standard questions
        ## NOTE: May like to save function references in the future.
        # saving functions may create more variety.
        # elif attr.get('prompt_func', False):
        #     prompt_user = attr['prompt_func']
        #     attr['prompt_func'] = None
        # elif attr.get('prompt_ms', False):
        #     prompt_user = attr['prompt_ms']
        #     attr['prompt_ms'] = None
        # else:
        #     prompt_user = HelpUtils.get_ms_corresponding_help(handler_input)

        else:
            prompt_user = HelpUtils.get_q_what_todo()

        return CardFuncs.format_prompt(prompt_user)
   def update_times_tables_info_dict(self, tables: tuple, correct: bool):
      """Updates the times_table dict mean & correct/incorrect answer.
      
      Passes times tables (str, str). """
      times_tables_info = self._times_tables_info
      tables = Player.check_not_duplicate_tables(tables)

      for table in tables:
         table = str(table)      # dict keys saved as str in json?
         table_dict = times_tables_info.get(table, dict())

         log_all(table, table_dict)

         if table_dict == dict():
            table_dict = Player.init_times_table_dict(correct)
         else:
            table_dict = Player.get_updated_table_dict(table_dict, correct)
           
            
         times_tables_info[ table] = table_dict
      
      self._times_tables_info = times_tables_info
def calc_z_score(
    data_point: float,
    data_mean: float = None,
    data_stdev: float = None,
    data: list = None,
    required_data_length: int = 2,
) -> float:
    """Returns z_score for data list.
    
    data_point: (required) float. Returns z_score.
    data_mean: (optional) float.
    data_stdev: (optional) float. 
    data: (optional) list. 
    required_data_length: int - minimum data to calculate z_score.


    NOTE: User must prvoide either mean & stdev, or data. Otherwise,
    insufficient data to calculate z-score.
    """
    if (data is not None) and (len(data) < required_data_length):
        logger.info(f"calc_z_score - list length {data}")
        return 0

    elif data_mean is None:
        data_mean = mean(data)

    elif data_stdev is None:
        data_stdev = stdev(data, xbar=data_mean)

    try:
        z_score = (data_point - data_mean) / data_stdev
    except ZeroDivisionError:
        logger.info("calc_z_score - 0 stdev")
        z_score = 0

    log_all(data_mean, data_stdev, z_score)
    return z_score
Beispiel #19
0
    def update_player_mode_statistics(handler_input,
                                      player_obj: object) -> None:
        """Updates relevant mode statistics."""
        attr = handler_input.attributes_manager.session_attributes
        mode = attr.get('mode', None)

        if mode:
            correct, _ = ModeStats.get_mode_stats(handler_input, mode)
        else:
            correct = 0

        MODE_FUNC_DICT = {
            'free_play': UserStats.update_player_fp_stats,
            'custom': UserStats.update_player_cp_stats,
            'speed': UserStats.update_player_sc_stats,
            'survival': UserStats.update_player_sm_stats,
        }
        update_stats_func = MODE_FUNC_DICT.get(mode, None)
        log_all(update_stats_func, correct)

        if (update_stats_func) and (correct > 4):
            update_stats_func(handler_input, player_obj)

        return None
Beispiel #20
0
    def get_ms_score_results(handler_input,
                             sc_score_time: int,
                             player_obj: object = None) -> str:
        """Returns message about the user's Speed Challenge score."""
        attr = handler_input.attributes_manager.session_attributes
        sc_difficulty = attr['sc_difficulty']
        high_score = player_obj.get_sc_high_score(sc_difficulty)

        log_all(sc_score_time, high_score, sc_difficulty)

        if SC_EndGame.check_new_sc_highscore(high_score, sc_score_time):

            if SC_EndGame.check_first_highscore(high_score):
                return SC_EndGame.get_ms_first_highscore(
                    sc_difficulty, sc_score_time)

            return SC_EndGame.get_ms_new_highscore(sc_difficulty, high_score,
                                                   sc_score_time)

        elif SC_EndGame.check_tie_sc_highscore(high_score, sc_score_time):
            return SC_EndGame.get_ms_tied_highscore(sc_score_time)

        return SC_EndGame.get_ms_relative_record(player_obj, sc_difficulty,
                                                 sc_score_time)
    def remove_question_from_incorrect_questions(handler_input) -> None:
        """Removes the question from the incorrect questions.
        
        Also checks if dictionary is empty and deletes.
        """
        attr = handler_input.attributes_manager.session_attributes
        wrong_quest_by_date = attr['wrong_quest_by_date']

        date_key = CP_Utils.get_oldest_date(wrong_quest_by_date)
        date_dict = wrong_quest_by_date[date_key]

        table_1, table_2 = QuestionAttr.get_question_tables(handler_input, integers = False)
        
        log_all( date_dict, table_1, table_2)
        
        table_1_dict = date_dict[table_1]
        num_incorrect = table_1_dict[table_2]
        log_all(table_1_dict, num_incorrect)

        ## Reduce counts of incorrect.
        num_incorrect = CP_Utils.reduce_num_incorrect(num_incorrect)

        ## Resave dictionaries.
        table_1_dict[table_2] = num_incorrect
        date_dict[table_1] = table_1_dict
        wrong_quest_by_date[date_key] = date_dict

        log_all(table_1_dict, date_dict, wrong_quest_by_date)

        ## Should refactor into many different methods.
        logger.debug(num_incorrect)
        if num_incorrect == 1:      # already asked, so delete & any unnecessary dicts
            CP_Attr.del_dict_key(table_1_dict, key = table_2)

            if len(table_1_dict.keys()) == 0:
                CP_Attr.del_dict_key(date_dict, table_1)
            
                if len(date_dict.keys()) == 0:
                    CP_Attr.del_dict_key(wrong_quest_by_date, key = date_key)
                    
        logger.debug(wrong_quest_by_date)
        attr['wrong_quest_by_date'] = wrong_quest_by_date
        return
Beispiel #22
0
    def handle(self, handler_input):
        logger.info("HAN  FP_StartHandler")
        attr = handler_input.attributes_manager.session_attributes
        speech_list = []

        ## Set attr & get slots
        FreePlayAttr.set_attr_free_play(handler_input)

        ## Get table_input to start game.
        lower_table, upper_table, tables_query = (
            FreePlayAttr.get_times_table_input_slots(handler_input))
        FreePlayAttr.set_attr_times_tables(handler_input, lower_table,
                                           upper_table, tables_query)

        ## Logic check
        retry_query = attr.get('inform_query_tables_format', False)
        tables_provided = FreePlayLogic.check_tables_provided(
            lower_table, upper_table, tables_query)
        tables_exist = FreePlayLogic.check_tables_exist(handler_input)

        log_all(retry_query, tables_exist)

        ## Confirmation
        if tables_provided or tables_exist:

            if retry_query:
                ms_potential_mistake = FPTimesTables.get_ms_potential_mistake_parsing_query(
                )
                speech_list += Pauser.make_ms_pause_level_list(
                    ms_potential_mistake, 2)
            else:
                ms_confirm = ConfirmUtils.get_confirmation(punct=True)
                speech_list += Pauser.make_ms_pause_level_list(ms_confirm, 1)

            if tables_provided:
                ms_using_tables = (
                    FPTimesTables.get_ms_using_tables_from_input(
                        lower_table, upper_table, tables_query))
            elif tables_exist:
                ms_using_tables = None  # Create method to use existing tables.
            speech_list += Pauser.make_ms_pause_level_list(ms_using_tables, 2)

            if retry_query:
                ms_retry_query = FPTimesTables.get_ms_can_retry_query_format()
                speech_list += Pauser.make_ms_pause_level_list(
                    ms_retry_query, 3.5)
                FreePlayAttr.reset_attr_query_format(handler_input)

            ms_first_problem = FPQuestions.get_question(handler_input,
                                                        first_question=True)
            speech_list.append(ms_first_problem)

            reprompt = FPQuestions.get_rephrased_question(handler_input)

        if not tables_provided:
            ms_welcome = FPSpeech.get_ms_welcome(handler_input)
            q_times_tables, reprompt = (
                FPTimesTables.get_q_times_tables_input() for _ in range(2))
            q_times_tables = CardFuncs.format_prompt(q_times_tables)

            speech_list += Pauser.make_ms_pause_level_list(
                ms_welcome, 1.5, q_times_tables)

        ModeStats.translate_mode_stats_to_sesh(handler_input)

        speech = ' '.join(speech_list)
        card_title, card_text = CardFuncs.get_card_info(handler_input, speech)
        return (handler_input.response_builder.speak(speech).ask(
            reprompt).set_card(SimpleCard(card_title, card_text)).response)
 def get_sc_average_records(self, difficulty: str) -> list:
    """Returns list of average records for appropriate speed challenge difficulty."""
    sc_average_record_dict = self._sc_average_record_dict
    log_all(sc_average_record_dict)
    return sc_average_record_dict.get(difficulty, None)