示例#1
0
    def _chooseFile(self):
        """_chooseFile internal function
		Presents the user with a list of flashcard files in the current directory and asks
		them to select one of them. It then loads that file into a FlashcardSet and sets
		that internal variable.
		"""
        # Find all the flashcard files in the current directory
        validfilepattern = re.compile(setnameToFilename('(.*)'))
        allfiles = os.listdir()
        validfiles = []
        for f in allfiles:
            match = validfilepattern.match(f)
            if match:
                validfiles.append(match.group(1))
        filechoices = dict(enumerate(validfiles, 1))

        # Ask the user which file to load, providing an option for adding a new file
        choice = ConsoleMenu.static_quickChoice(
            filechoices, {
                'manual': True,
                'manual_value': 'Create new file',
                'manual_prompt': 'New file name: '
            })
        setname = choice[1]
        filename = setnameToFilename(setname)

        # Now unpickle the file, or initialize a default flashcard set
        if setname not in validfiles:
            self._set = FlashcardSet(setname)
        else:
            with open(filename, 'rb') as pickledfile:
                self._set = pickle.load(pickledfile)
示例#2
0
    def _chooseAnswer(self):
        """_chooseAnswer internal function
		Helper function to clean up run function. Lets user choose answer to change,
		rearrange answers, or add new answer.
		"""
        choices = dict(enumerate(self._card._valid_answers, 1))
        choices['c'] = 'Change correct answer'
        choices['d'] = 'Delete an answer'
        options = {
            'manual': True,
            'manual_key': 'a',
            'manual_value': 'Add new answer',
            'manual_prompt': 'Enter new answer: ',
            'abstain': True,
            'abstain_key': 'q',
            'abstain_value': 'Return to edit card menu',
            'intro_text':
            'Choose one of the answers, or change the correct answer'
        }
        choice = ConsoleMenu.static_quickChoice(choices, options)

        # If the user chooses to return to the edit card menu, nothing needs be done
        if choice == None:
            pass
        # If the user wants to add a new answer, just add it to the list
        elif choice[0] == 'a':
            self._card._valid_answers.append(choice[1])
        # If the user wants to change the correct answer, convert to int and rearrange list
        elif choice[0] == 'c':
            inputtext = input('Enter key for correct answer (integer between 1 and ' \
             +str(len(self._card._valid_answers))+'): ')
            # By default, do nothing (if the user entered an invalid value, screw 'em)
            newcorrect = None
            try:
                newcorrect = int(inputtext) - 1
            except:
                pass
            # Move the new index to the front of the list, if it's a valid index
            if newcorrect != None and newcorrect >= 0 \
             and newcorrect < len(self._card._valid_answers):
                self._card._valid_answers.insert(
                    0, self._card._valid_answers.pop(newcorrect))
        # If the user wants to delete an answer, remove it from the list
        elif choice[0] == 'd':
            inputtext = input('Enter key for the answer to delete: ')
            deleteindex = None
            try:
                deleteindex = int(inputtext) - 1
            except:
                pass
            # Delete the item, if it's a valid index
            if deleteindex != None and deleteindex >= 0 \
             and deleteindex < len(self._card._valid_answers):
                del self._card._valid_answers[deleteindex]
        # If the user picked one of the answers, allow them to edit it
        else:
            answerindex = int(choice[0]) - 1
            self._changeAnswer(answerindex)
示例#3
0
    def run(self):
        """run function
		Displays a menu of a few possible options and allows the user to pick among them.
		Includes importing a CSV, manually editing cards, running the cards, and displaying
		stats.
		"""
        choices = {
            'i': "Import Cards",
            'e': "Export Cards",
            'c': "Edit cards",
            'o': "Edit options",
            'r': "Run cards",
            's': "Show stats"
        }
        options = {
            'abstain': True,
            'abstain_key': 'q',
            'abstain_value': "Quit"
        }

        choice = ConsoleMenu.static_quickChoice(choices, options)

        # If the user wants to exit, set the next to None and do nothing else
        if choice == None:
            self.next = None
        else:
            # Call the appropriate state, based on the user's choice
            if choice[0] == 'i':
                self.next = FCStateImportCSV(self._set, self)
            elif choice[0] == 'e':
                self._exportCSV()
            elif choice[0] == 'c':
                self.next = FCStateEditCardsMain(self._set, self)
            elif choice[0] == 'o':
                print('Go to ' + choice[1])
            elif choice[0] == 'r':
                self.next = FCStateRunCardsMenu(self._set, self)
            elif choice[0] == 's':
                self._showStats()
示例#4
0
    def run(self):
        """run function
		Displays a menu of a few possible attributes to edit. Question, answers, confirm override,
		and answer type.
		"""
        choices = {
            'u':
            'Change question text (current: "' + self._card._question + '")',
            'a':
            'Change answers (current: "' + str(self._card._valid_answers) +
            '")',
            't':
            'Change answer type (current: "' + self._card._answer_type + '")',
            'c':
            'Change confirm override (current: "' +
            str(self._card._override_confirms) + '")'
        }
        options = {
            'abstain': True,
            'abstain_key': 'q',
            'abstain_value': "Return to edit cards main menu",
        }

        choice = ConsoleMenu.static_quickChoice(choices, options)

        # If the user wants to return to main menu, set the next and do nothing else
        if choice == None:
            self.next = self._editcardsmain
        else:
            # Run a helper function based on the user choice
            if choice[0] == 'u':
                self._changeQuestionText()
            elif choice[0] == 'a':
                self._chooseAnswer()
            elif choice[0] == 't':
                self._changeAnswerType()
            elif choice[0] == 'c':
                self._changeOverrideConfirm()
示例#5
0
    def _changeOverrideConfirm(self):
        """_changeOverrideConfirm internal function
		Helper function to clean up run function. Lets user change override confirm.
		"""
        choices = {'1': True, '2': False}
        options = {
            'abstain':
            True,
            'abstain_key':
            'q',
            'abstain_value':
            'Return to edit card menu',
            'intro_text':
            'Choose an override confirm setting (current: ' +
            str(self._card._override_confirms) + ')'
        }
        choice = ConsoleMenu.static_quickChoice(choices, options)

        # If the user wants to quit, nothing needs be done
        if choice == None:
            pass
        # Otherwise, set the new override confirm
        else:
            self._card._override_confirms = choice[1]
示例#6
0
    def _changeAnswerType(self):
        """_changeAnswerType internal function
		Helper function to clean up run function. Lets user change answer type.
		"""
        choices = dict(enumerate(FlashcardSet.ANSWER_TYPES, 1))
        options = {
            'abstain':
            True,
            'abstain_key':
            'q',
            'abstain_value':
            'Return to edit card menu',
            'intro_text':
            'Choose an answer type (current: ' + self._card._answer_type + ')'
        }
        choice = ConsoleMenu.static_quickChoice(choices, options)

        # If the user wants to quit, nothing needs be done
        if choice == None:
            pass
        # Otherwise, set the new answer type
        else:
            self._card._answer_type = FlashcardSet.ANSWER_TYPES[int(choice[0])
                                                                - 1]
示例#7
0
    def _askMultipleChoice(self, question, answers):
        """_askMultipleChoice internal function
		Simply presents the user with the question and a choice menu for an answer.
		Returns the answer the user chose.
		"""
        print("Question: " + question)
        # If the question is boolean, generate a choices dict of just True and False
        if len(answers) == 1 and answers[0] in ('True', 'False'):
            choices = {'1': 'True', '2': 'False'}
        # Otherwise, the answers are just what was passed to us
        # Make sure to randomize the order
        else:
            choices = dict(
                enumerate(sorted(answers, key=lambda k: random.random()), 1))
        options = {
            'abstain': True,
            'abstain_key': 'q',
            'abstain_value': 'Return to menu'
        }
        choice = ConsoleMenu.static_quickChoice(choices, options)

        if choice == None:
            return 'q'
        return choice[1]
示例#8
0
    def run(self):
        """run function
		Displays a menu of a few possible options and allows the user to pick among them.
		Includes a list of cards (shows question), an option to add a new card, and an option
		to jump back to the main menu.
		"""
        questionlist = []
        cardlist = []
        for card in self._set.getAllCards():
            questionlist.append(card._question)
            cardlist.append(card)
        choices = dict(enumerate(questionlist, 1))
        options = {
            'abstain': True,
            'abstain_key': 'q',
            'abstain_value': "Return to main menu",
            'manual': True,
            'manual_key': 'n',
            'manual_value': "Enter a new question",
            'manual_prompt': "Enter the new question: "
        }

        choice = ConsoleMenu.static_quickChoice(choices, options)

        # If the user wants to return to main menu, set the next and do nothing else
        if choice == None:
            self.next = self._mainmenu
        else:
            # If they entered a new question
            if choice[0] == 'n':
                # Grab the new question
                question = choice[1]
                # Grab the answers from the user
                valid_answers = []
                while len(valid_answers) == 0:
                    print("For freeform questions, enter the correct answer.")
                    print(
                        "For True/False questions, enter 'True' or 'False' (case/spelling sensitive!)."
                    )
                    print(
                        "For multiple-choice questions, enter all possible answers, starting with the correct answer."
                    )
                    print(
                        "To stop entering answers, hit enter without typing text."
                    )
                    inputtext = None
                    while inputtext != "":
                        inputtext = input("Enter answer: ")
                        if inputtext != "":
                            valid_answers.append(inputtext)
                    # If the user did not enter any answers, yell at them
                    if len(valid_answers) == 0:
                        print("ERROR: At least one answer must be entered.")
                # From those two, we can guess the rest of the attributes to create a new card
                card = FlashcardCard(question, valid_answers)
                # Replace any existing card with the same question
                self._set.addCard(card, True)
                # We've added the card, so let's jump back to the menu again
                self.next = self
            # They chose one of the existing cards
            else:
                # Pull the card from the cardlist; note that the choice key is int by design;
                # We also need to subtract 1 because we added 1 for the choice menu
                card = cardlist[int(choice[0]) - 1]
                # Send the user to the Edit Card state
                self.next = FCStateEditCard(self, card)
示例#9
0
    def run(self):
        """run function
		Displays the number of cards in the set. Displays a menu of possible runs, with an
		option to customize. Then switches to the RunCardList state to actually run.
		"""
        choices = {
            '1': "Run the lowest-scoring card",
            '5': "Run 5 lowest-scoring cards",
            '10': "Run 10 lowest-scoring cards",
            '10r': "Run 10 random cards",
            '15': "Run 10 lowest-scoring cards with 5 random cards",
            'third': "Run the lowest-scoring 1/3rd of the cards",
            'half': "Run the lowest-scoring 1/2 of the cards",
            'all': "Run all the cards in the order they were added",
            'endless': "Run the lowest-ranking card in the set until you quit",
            'custom': "Define a custom run of the cards"
        }
        options = {
         'abstain':True, 'abstain_key':'q', 'abstain_value':'Return to main menu',
         'intro_text':str(len(self._set.getAllCards()))+" cards in set. " \
          +"Choose a run from the list below"
        }
        choice = ConsoleMenu.static_quickChoice(choices, options)

        if choice == None:
            self.next = self._mainmenu
            return

        # Put together a list of cards to run, based on the user choice
        cardlist = []
        if choice[0] == '1':
            cardlist = self._set.getSortedCards()
        elif choice[0] == '5':
            cardlist = self._set.getSortedCards(5)
        elif choice[0] == '10':
            cardlist = self._set.getSortedCards(10)
        elif choice[0] == '10r':
            cardlist = self._set.getSortedCards(0, 10)
        elif choice[0] == '15':
            cardlist = self._set.getSortedCards(10, 5)
        elif choice[0] == 'third':
            cardlist = self._set.getSortedCards(
                int(len(self._set.getAllCards()) / 3))
        elif choice[0] == 'half':
            cardlist = self._set.getSortedCards(
                int(len(self._set.getAllCards()) / 2))
        elif choice[0] == 'all':
            cardlist = self._set.getAllCards()[:]
        elif choice[0] == 'endless':
            # Endless starts with just one card
            cardlist = self._set.getSortedCards()
        elif choice[0] == 'custom':
            inputranked = input(
                "Enter the number of lowest-scoring cards to run: ")
            inputrandom = input("Enter the number of random cards to run: ")
            numranked = None
            numrandom = None
            try:
                numranked = int(inputranked)
                numrandom = int(inputrandom)
            except:
                print(
                    "ERROR: One of the inputs above was not an integer. Returning to run menu."
                )
                return
            cardlist = self._set.getSortedCards(numranked, numrandom)

        # Randomize the order of the cards, so we're not always going by rank
        cardlist.sort(key=lambda k: random.random())

        # We now have a cardlist, so kick off the run
        # If in endless mode, pass in the full flashcard set as well, to indicate so
        if choice[0] == 'endless':
            self.next = FCStateRunCardList(cardlist, self._mainmenu, self._set,
                                           endless)
        else:
            self.next = FCStateRunCardList(cardlist, self._mainmenu, self._set)
示例#10
0
    def run(self):
        """run function
		Displays a list of .csv files in the directory, allows the user to choose one of them,
		and then imports the questions from that .csv.
		"""
        # Provide the user with instructions
        print(
            "This process imports a list of questions and valid/correct answers from a CSV"
        )
        print(
            "file. Columns should be separated by the ~ symbol. The first column is the"
        )
        print(
            "question. The second column is the correct answer. For multiple-choice questions,"
        )
        print(
            "you can specify the other choices in the 3rd, 4th, 5th, etc. columns."
        )
        print(
            "The question type (boolean, word, freeform, multiple-choice, etc.) is"
        )
        print(
            "automatically determined based on the form of the answers, but it can be manually"
        )
        print("changed later by editing the cards.")
        print()

        # Find all the CSV files in the current directory
        validfilepattern = re.compile('.*\.[Cc][Ss][Vv]')
        allfiles = os.listdir()
        validfiles = []
        for f in allfiles:
            match = validfilepattern.match(f)
            if match:
                validfiles.append(f)
        filechoices = dict(enumerate(validfiles, 1))

        # Ask the user which file to load, providing an option to cancel
        choice = ConsoleMenu.static_quickChoice(
            filechoices, {
                'abstain': True,
                'abstain_key': 'q',
                'abstain_value': 'Cancel Card Import'
            })
        if choice == None:
            self.next = self._mainmenu
            return

        # Now that we have a filename, let's read it in
        filename = choice[1]
        with open(filename, 'r') as csvfile:
            csvreader = csv.reader(csvfile, delimiter='~')
            linenumber = 0
            questionsimported = 0
            for row in csvreader:
                linenumber += 1
                if len(row) < 2:
                    print("Error on line "+str(linenumber)+": Not enough fields. Need at " \
                     +"least 2 (question and correct answer).")
                    continue
                else:
                    question = row[0].strip()
                    valid_answers = []
                    for answer in row[1:]:
                        if answer.strip() != "":
                            valid_answers.append(answer.strip())
                    cardadded = self._set.addCard(
                        FlashcardCard(question, valid_answers))
                    if cardadded:
                        questionsimported += 1
                    else:
                        print("Warning on line "+str(linenumber)+": Question already exists " \
                         +"in flashcard set: "+question)
            print(str(questionsimported) + " questions successfully imported")

        # We're done importing, return to the main menu
        self.next = self._mainmenu