Example #1
0
class TestXmlConfig(unittest.TestCase): 

    def setUp(self):
        self.xml_config = XMLConfig()
        self.path_game_settings = os.path.abspath("..\\..\\game_settings.xml")
        shutil.copy2(self.xml_config.path_name, 'copy_config.xml')
        shutil.copy2(self.path_game_settings, 'copy_game_settings.xml')


    def test_read_configuration_file_returns_error_msg_if_file_config_does_not_exist(self):
        expected_message = "Invalid data or file"
        os.remove(self.xml_config.path_name)
        self.assertEquals(expected_message, self.xml_config.read_configuration_file())
        

    def test_read_configuration_file_returns_error_msg_if_file_config_is_empty(self):
        expected_message = "Invalid data or file"
        file_config = open(self.xml_config.path_name, 'w')
        file_config.write('')
        file_config.close()
        self.assertEquals(expected_message, self.xml_config.\
                                                    read_configuration_file())

    def test_read_configuration_file_returns_error_msg_if_file_config_cannot_parse_xml(self):
        expected_message = "Invalid data or file"
        file_config = open(self.xml_config.path_name, 'w')
        file_config.write('<config><level>')
        file_config.close()
        self.assertEquals(expected_message, self.xml_config.read_configuration_file())      

    def test_read_configuration_file_returns_error_msg_if_file_config_without_output_type(self):
        expected_message = "Invalid data or file"
        file_name = "test_xmls\\config_test_no_ouput_type.xml"
        shutil.copy2(file_name, "..\\..\\config_test_no_ouput_type.xml")
        config_test = XMLConfig(file_name)
        self.assertEquals(expected_message, config_test.read_configuration_file())

    def test_read_configuration_file_returns_error_msg_if_file_config_without_algorithm(self):
        expected_message = "Invalid data or file"
        file_name = "test_xmls\\config_test_no_algorithm.xml"
        shutil.copy2(file_name, "..\\..\\config_test_no_algorithm.xml")
        config_test = XMLConfig(file_name)
        self.assertEquals(expected_message, config_test.read_configuration_file())

    def test_read_configuration_file_returns_a_dictionary_of_configuration_if_valid_data(self):
        empty_spot_char = self.xml_config.get_empty_spot_char()
        output_type = self.xml_config.get_output_type()
        algorithm = self.xml_config.get_algorithm()
        level = self.xml_config.get_complexity()
        dict_configuration = {'empty_spot_char': empty_spot_char, 'output-type': output_type, 
                              'algorithm': algorithm, 'output-path': 'results',
                               'level': level}
        self.assertEquals(dict_configuration, self.xml_config.read_configuration_file())

    def test_get_valid_data_game_returns_list_of_levels_if_level_specified(self):
        expected_levels = ['easy', 'medium', 'hard']
        self.assertEquals(expected_levels, self.xml_config.get_valid_data_game(
                                                                    self.path_game_settings,
                                                                    'level', 'name'))

    def test_get_valid_data_game_returns_list_of_algorithms_if_algorithm_specified(self):
        expected_algorithms = ['backtracking', 'norvig', 'brute force']
        self.assertEquals(expected_algorithms, self.xml_config.get_valid_data_game(
                                                            self.path_game_settings,
                                                            'algorithm', 'name'))

    def test_get_complexity_returns_error_message_if_level_tag_does_not_exist(self):
        expected_message = "Tag is missing!"
        file_config = open(self.xml_config.path_name, 'w')
        file_config.write('<config><tessst>')
        file_config.close()
        self.assertEquals(expected_message, self.xml_config.get_complexity())

    def test_get_complexity_returns_complexity_value_if_value_exists(self):
        expected_default_level = 'medium'
        self.xml_config.modify_complexity('medium')
        self.assertEquals(expected_default_level, self.xml_config.get_complexity())        
   
    def test_modify_complexity_returns_error_message_if_level_tag_does_not_exist(self):
        expected_message = "Tag is missing!"
        file_config = open(self.xml_config.path_name, 'w')
        file_config.write('<config><level>')
        file_config.close()
        self.assertEquals(expected_message, self.xml_config.modify_complexity('hard'))
    
    def test_modify_complexity_returns_error_message_if_value_tag_does_not_exist(self):
        expected_message = "Tag is missing!"
        file_config = open(self.xml_config.path_name, 'w')
        file_config.write('<config><level>')
        file_config.close()
        self.assertEquals(expected_message, self.xml_config.modify_complexity('hard'))

    def test_modify_complexity_returns_error_message_if_complexity_is_not_valid(self):
        expected_message = "Invalid complexity parameter"
        self.assertEquals(expected_message, self.xml_config.modify_complexity('not-valid'))

    def test_modify_complexity_saves_new_complexity_in_config_file_if_complexity_is_valid(self):
        expected_complexity = 'hard'
        self.xml_config.modify_complexity('hard')
        current_complexity = self.xml_config.get_complexity()
        self.assertEquals(expected_complexity, current_complexity)        

    def test_get_output_type_returns_error_message_if_level_tag_does_not_exist(self):
        expected_message = "Tag is missing!"
        file_config = open(self.xml_config.path_name, 'w')
        file_config.write('<config><tessst>')
        file_config.close()
        self.assertEquals(expected_message, self.xml_config.get_output_type())

    def test_get_output_type_returns_output_type_value_if_value_exists(self):
        expected_default_output = 'file'
        self.xml_config.modify_output_type('file')
        self.assertEquals(expected_default_output, self.xml_config.get_output_type())        

    def test_modify_output_type_returns_error_message_if_output_type_tag_does_not_exist(self):
        expected_message = "Tag is missing!"
        file_config = open(self.xml_config.path_name, 'w')
        file_config.write('<config><level>')
        file_config.close()
        self.assertEquals(expected_message, self.xml_config.modify_output_type('console'))
    
    def test_modify_output_type_returns_error_message_if_path_tag_does_not_exist(self):
        expected_message = "Tag is missing!"
        file_config = open(self.xml_config.path_name, 'w')
        file_config.write('<config><level>')
        file_config.close()
        self.assertEquals(expected_message, self.xml_config.modify_output_type('console'))

    def test_modify_output_type_returns_error_message_if_out_put_is_not_valid(self):
        expected_message = "Invalid output type parameter"
        self.assertEquals(expected_message, self.xml_config.modify_output_type('not-valid'))

    def test_modify_output_type_saves_console_in_config_file_if_output_type_is_console(self):
        expected_output_type = 'console'
        self.xml_config.modify_output_type('console')
        current_output_type = self.xml_config.get_output_type()
        self.assertEquals(expected_output_type, current_output_type)        
    
    def test_write_value_to_xml_modifies_complexity_to_hard_in_config_file(self):
        expected_complexity = 'hard'
        self.xml_config.write_value_to_xml(self.xml_config.path_name, 'level/value','hard')
        current_complexity = self.xml_config.get_complexity()
        self.assertEquals(expected_complexity, current_complexity)

    def test_get_value_from_xml_recovers_complexity_from_config_file(self):
        expected_complexity = 'medium'
        self.xml_config.write_value_to_xml(self.xml_config.path_name, 'level/value','medium')
        complexity = self.xml_config.get_value_from_xml(self.xml_config.path_name, 'level/value')
        self.assertEquals(expected_complexity, complexity)

    def test_get_algorithm_returns_error_message_if_algorithm_tag_does_not_exist(self):
        expected_message = "Tag is missing!"
        file_config = open(self.xml_config.path_name, 'w')
        file_config.write('<none>')
        file_config.close()
        self.assertEquals(expected_message, self.xml_config.get_algorithm())

    def test_get_algorithm_returns_default_algorithm_value_if_value_exists(self):
        expected_default_algorithm = 'backtracking'
        self.xml_config.modify_algorithm('backtracking')
        self.assertEquals(expected_default_algorithm, self.xml_config.get_algorithm())        

    def test_modify_algorithm_returns_error_message_if_algorithm_tag_does_not_exist(self):
        expected_message = "Tag is missing!"
        file_config = open(self.xml_config.path_name, 'w')
        file_config.write('<config><ss>')
        file_config.close()
        self.assertEquals(expected_message, self.xml_config.modify_algorithm('backtracking'))

    def test_modify_algorithm_returns_error_message_if_algorithm_is_not_valid(self):
        expected_message = "Invalid algorithm parameter"
        self.assertEquals(expected_message, self.xml_config.modify_algorithm('not-valid'))

    def test_modify_algorithm_saves_norvig_in_config_file_if_algorithm_is_norvig(self):
        expected_algorithm = 'norvig'
        self.xml_config.modify_algorithm('norvig')
        current_algorithm = self.xml_config.get_algorithm()
        self.assertEquals(expected_algorithm, current_algorithm) 

    def test_get_empty_spot_char_returns_error_message_if_empty_spot_char_tag_does_not_exist(self):
        expected_message = "Tag is missing!"
        file_config = open(self.xml_config.path_name, 'w')
        file_config.write('<none>')
        file_config.close()
        self.assertEquals(expected_message, self.xml_config.get_empty_spot_char())

    def test_get_empty_spot_char_returns_default_empty_spot_char_value_if_value_exists(self):
        expected_default_empty_spot_char = '0'
        self.xml_config.modify_empty_spot_char('0')
        self.assertEquals(expected_default_empty_spot_char, self.xml_config.get_empty_spot_char())        

    def test_modify_empty_spot_char_returns_error_message_if_empty_spot_char_tag_does_not_exist(self):
        expected_message = "Tag is missing!"
        file_config = open(self.xml_config.path_name, 'w')
        file_config.write('<config><ss>')
        file_config.close()
        self.assertEquals(expected_message, self.xml_config.modify_empty_spot_char('*'))

    def test_modify_empty_spot_char_saves_a_dot_in_config_file_if_a_dot_is_used_as_empty_char(self):
        expected_empty_spot_char = '.'
        self.xml_config.modify_empty_spot_char('.')
        current_empty_spot_char = self.xml_config.get_empty_spot_char()
        self.assertEquals(expected_empty_spot_char, current_empty_spot_char)   

    def test_get_min_holes_by_complexity_when_complexity_is_easy(self):
        expected_min_holes = 20
        self.assertEquals(expected_min_holes, self.xml_config.get_min_holes_by_complexity('easy')) 

    def test_get_min_holes_by_complexity_when_complexity_is_medium(self):
        expected_min_holes = 30
        self.assertEquals(expected_min_holes, self.xml_config.get_min_holes_by_complexity('medium'))

    def test_get_min_holes_by_complexity_when_complexity_is_hard(self):
        expected_min_holes = 40
        self.assertEquals(expected_min_holes, self.xml_config.get_min_holes_by_complexity('hard'))

    def test_get_max_holes_by_complexity_when_complexity_is_easy(self):
        expected_max_holes = 25
        self.assertEquals(expected_max_holes, self.xml_config.get_max_holes_by_complexity('easy')) 

    def test_get_max_holes_by_complexity_when_complexity_is_medium(self):
        expected_max_holes = 40
        self.assertEquals(expected_max_holes, self.xml_config.get_max_holes_by_complexity('medium'))

    def test_get_max_holes_by_complexity_when_complexity_is_hard(self):
        expected_max_holes = 50
        self.assertEquals(expected_max_holes, self.xml_config.get_max_holes_by_complexity('hard'))  

    def tearDown(self):
        shutil.copy2('copy_config.xml', self.xml_config.path_name)
        os.remove('copy_config.xml')

        shutil.copy2('copy_game_settings.xml', self.path_game_settings)
        os.remove('copy_game_settings.xml')
        
        test_output = os.path.abspath("..\\..\\config_test_no_ouput_type.xml")
        if os.path.isfile(test_output):
            os.remove(test_output)

        test_algorithm = os.path.abspath("..\\..\\config_test_no_algorithm.xml")
        if os.path.isfile(test_algorithm):
            os.remove(test_algorithm)
Example #2
0
class Main():
    def __init__(self):
        self.configuration = XMLConfig()
        self.import_data = ImportData()
        self.empty_spot_char = self.configuration.get_empty_spot_char()
        self.export_sudoku = ExportSudoku()
        self.display_main_menu()

    def display_main_menu(self):
        """ Displays the Main Menu and validates the entered values for the required options """

        print self.logo()
        self.print_dictionary_list(self.main_menu_options())

        while True:
            op_main_menu = raw_input("\nPlease enter a number: ")

            if op_main_menu == "1" or op_main_menu == "2" or op_main_menu == "3"\
                                   or op_main_menu == "4" or op_main_menu == "5":
                self.main_menu_options()[op_main_menu]
                break
            else:
                print "Oops!  That was not a valid option number.  Try again...\n"
        self.execute_main_option(op_main_menu)

    def logo(self):
        """ Displays the logo on the menu"""

        logo_str = " _____           _       _             ___\n" + \
                   "/  ___|         | |     | |           / _ \\\n" + \
                   "\ `--. _   _  __| | ___ | | ___   _  / /_\ \\\n" + \
                   " `--. \ | | |/ _` |/ _ \| |/ / | | | |  _  |\n" + \
                   "/\__/ / |_| | (_| | (_) |   <| |_| | | | | |\n" + \
                   "\____/ \__,_|\__,_|\___/|_|\_\\\\__,_| \_| |_/\n"

        return logo_str

    def main_menu_options(self):
        """ Defines the 3 available options for the Sudoku Main Menu """

        main_menu_opts = {'1': 'Configure', '2': 'Solve Sudoku', '3': 'Generate Sudoku',\
                          '4': 'Play online!', '5': 'Exit'}
        return main_menu_opts

    def execute_change_solve_option(self, op_solve_menu):
        """ Executes the Solve Menu for the selected option

            Keyword arguments:
            op_solve_menu -- takes one of the three options to select on the Main Menu
        """

        if op_solve_menu == "1":
            self.solve_sudoku_from_cmd("txt")

        if op_solve_menu == "2":
            self.solve_sudoku_from_file("txt")

        if op_solve_menu == "3":
            self.solve_sudoku_from_file("txt")

        if op_solve_menu == "4":
            self.display_main_menu()

    def solve_sudoku_from_cmd(self, type_file):
        """ Method used for solving the sudoku given the input by command line

            Keyword arguments:
            type_file -- stores the selected cmd option

        """

        cmd_sudoku = raw_input(
            '\nEnter the sudoku to solve in the same line without spaces or'
            'commas, it should have 81 numbers as the following example:\n0'
            '03020600900305001001806400008102900700000008006708200002609500'
            '800203009005010300\n')

        print "\nSolution:\n"
        sudoku_matrix = self.import_data.read_sudoku_data_from_line(cmd_sudoku)
        self.export_sudoku_to(sudoku_matrix, type_file)
        self.display_main_menu()

    def export_sudoku_to(self, sudoku_matrix, type_file):
        """ Method used for exporting the solved sudoku to the default "results" path

            Keyword arguments:
            sudoku_matrix -- stores the sudoku on the valid sudoku matrix to solve
            type_file -- stores the selected file type; file or cmd

        """

        path = "../results/"
        algoritms = self.create_algorith_to_solve_sudoku(
            sudoku_matrix, self.empty_spot_char)
        for algoritm_to_solve in algoritms:
            sudoku_solved = algoritm_to_solve.solve_sudoku()
            if sudoku_solved != []:
                export_to = self.configuration.get_output_type()
                if export_to == 'file':
                    self.export_file(algoritm_to_solve, type_file,
                                     sudoku_solved, path)
                else:
                    self.export_sudoku.export_sudoku(sudoku_solved, "cmd line",
                                                     "", "")
            else:
                print "\nInvalid sudoku, it cannot be solved!\n"

    def file_exists(self):
        """ Method used for verifying whether the entered file exists or not """

        result = ""
        path = "../inputs/"
        while True:
            file_name = raw_input(
                '\nEnter the name of the file to solve or enter quit to exit: '
            )
            file_txt = path + "\\" + file_name
            if os.path.exists(file_txt):
                result = file_txt
                break
            elif file_name == "quit":
                break
            else:
                print "\nThe file provided does not exists, please try again\n"
        return result

    def solve_sudoku_from_file(self, type_file):
        """ Method used for solving the sudoku given a file

            Keyword arguments:            
            type_file -- stores the selected file type, it can be a txt or csv file

        """

        file_ext = self.file_exists()

        if file_ext != "":
            sudoku_matrix = self.import_data.read_sudoku_data_from_file(
                file_ext)
            self.export_sudoku_to(sudoku_matrix, type_file)
            #self.display_main_menu()
        #else:
        self.display_solve_menu()

    def export_file(self, algoritm_to_solve, type_file, sudoku_solved, path):
        """ Method used for create the solved sudoku in a file on the default "results" path

            Keyword arguments:
            algoritm_to_solve -- the selected algorithm to solve the sudoku           
            type_file -- stores the selected file type; file or cmd
            sudoku_solved -- sores the solved sudoku
            path -- stores the default "results" path for the solutions

        """

        file_name = 'sudoku_solved_' + algoritm_to_solve.__class__.__name__ + "_" + \
                    str(algoritm_to_solve.get_time()) + "_" + time.strftime("%Y-%m-%dT%H-%M-%S",
                     time.localtime(time.time())) + "." + type_file
        if self.export_sudoku.export_sudoku(sudoku_solved, type_file, path,
                                            file_name):
            print "\nThe file was created successfully\n"
        else:
            print "\nThere was a error, the file couldn't be created\n"

    def create_algorith_to_solve_sudoku(self, sudoku_matrix, empty_character):
        """ Method used for create the algorithm to solve given the expected sudoku matrix 
            and empty character
            
            Keyword arguments:
            sudoku_matrix -- stores the sudoku in the valid matrix ready to be solved
            empty_character -- stores the selected character for the empty spots 

        """

        algorithm_selected = self.configuration.get_algorithm()
        algoritms = []
        for i in range(0, len(sudoku_matrix)):
            algoritm_to_solve = Algorithm(sudoku_matrix[i][0], empty_character)
            if algorithm_selected == 'norvig':
                algoritm_to_solve = NorvigAlgorithm(sudoku_matrix[i][0],
                                                    empty_character)
            elif algorithm_selected == 'backtracking':
                algoritm_to_solve = BacktrakingAlgorithm(
                    sudoku_matrix[i][0], empty_character)
            elif algorithm_selected == 'brute force':
                algoritm_to_solve = BruteForceAlgorithm(
                    sudoku_matrix[i][0], empty_character)
            algoritms.append(algoritm_to_solve)
        return algoritms

    def display_solve_menu(self):
        """ Displays/validates the selected options for solving the sudoku using one of the 
            three valid input types
            
        """

        self.print_dictionary_list(self.change_solve_menu_options(),
                                   "--- Solve Sudoku Menu ---")

        while True:
            solve_opts = raw_input("\nPlease enter a number: ")

            if solve_opts == "1" or solve_opts == "2" or solve_opts == "3" or solve_opts == "4":
                self.change_solve_menu_options()[solve_opts]
                break
            else:
                print "\nOops!  That was not a valid option number.  Try again...\n"
        self.execute_change_solve_option(solve_opts)

    def change_solve_menu_options(self):
        """ Defines the 3 available options for the inputs type for solving the sudoku """

        solve_opts = {
            '1': 'Solve sudoku entered by command line',
            '2': 'Solve sudoku from a txt file',
            '3': 'Solve sudoku from a csv file',
            '4': 'Back'
        }

        return solve_opts

    def conf_menu_options(self):
        """ Defines the 3 available options for the: "1 . Configure" option """

        conf_opts = {
            '1': 'Change Output format',
            '2': 'Change Level',
            '3': 'Change Algorithm to use',
            '4': 'Change empty spot character',
            '5': 'Back'
        }

        return conf_opts

    def execute_main_option(self, op_main_menu):
        """ Executes the Main Menu for the selected option

            Keyword arguments:
            op_main_menu -- takes one of the four options to select on the Main Menu
        """

        if op_main_menu == "1":
            self.display_configure_menu()

        if op_main_menu == "2":
            self.display_solve_menu()

        if op_main_menu == "3":
            self.display_generate_sudoku_menu()

        if op_main_menu == "4":
            SudokuUI()

        if op_main_menu == "5":
            print "Good bye!"

    def execute_conf_option(self, conf_opts):
        """ Executes the selected option on the "1 . Configure" option 

            Keyword arguments:
            conf_opts -- takes one of the four options available in the option: "1 . Configure"  
        """

        if conf_opts == "1":
            self.display_output_type_menu()

        if conf_opts == "2":
            self.display_level_algorithm_menu()

        if conf_opts == "3":
            self.display_algorithm_menu()

        if conf_opts == "4":
            self.execute_change_empty_spot()

        if conf_opts == "5":
            self.display_main_menu()

    def execute_change_empty_spot(self):
        """ Method that changes the character used as empty spot """

        empty_spot_char = str(
            raw_input('Enter a new character used as empty spot or'
                      ' enter <quit> to go back menu: '))

        if empty_spot_char >= '1' and empty_spot_char <= '9':
            print "\nInvalid empty spot character, please don't use numbers from 1 to 9"

        elif empty_spot_char == ',':
            print "\nInvalid empty spot character, please don't use the comma (,) character"

        elif len(empty_spot_char) == 1:
            print "\n", self.configuration.modify_empty_spot_char(
                empty_spot_char)

        elif empty_spot_char.lower() == 'quit':
            print  "\nDefault empty spot char will be used: "\
                                                    + self.configuration.get_empty_spot_char()

        else:
            print "\nInvalid empty spot character, please use only one character"

        self.display_configure_menu()

    def execute_change_level_option(self, level_opts):
        """ Changes the complexity level for create or solve the sudoku 

            Keyword arguments:
            level_opts -- takes one of the three options for the complexity level
        """

        if level_opts == "1":
            # save Easy level
            print "\n", self.configuration.modify_complexity('Easy')

        if level_opts == "2":
            # save Medium level
            print "\n", self.configuration.modify_complexity('Medium')

        if level_opts == "3":
            # save Hard level
            print "\n", self.configuration.modify_complexity('Hard')

        self.execute_change_algorithm_option('4')

    def execute_change_algorithm_option(self, chng_algorit):
        """ Changes the Algorithm used for create or solve the sudoku 

            Keyword arguments:
            chng_algorit -- takes one of the three options for changing the Algorithm to use
        """

        if chng_algorit == "1":
            # save Norvig algorithm
            print "\n", self.configuration.modify_algorithm('Norvig')

        if chng_algorit == "2":
            # save Backtraking algorithm
            print "\n", self.configuration.modify_algorithm('Backtracking')

        if chng_algorit == "3":
            # save Brute Force algorithm
            print "\n", self.configuration.modify_algorithm("brute force")

        self.display_configure_menu()

    def execute_change_output_option(self, output_opts):
        """ Changes the output format for the solved the sudoku 

            Keyword arguments:
            output_opts -- takes one of the two options, 
                           solved sudoku could be displayed in console, or in a file
        """
        if output_opts == "1":
            # display solved sudoku in console
            print "\n", self.configuration.modify_output_type('console')

        if output_opts == "2":
            # save solved sudoku in a file
            print "\n", self.configuration.modify_output_type('file')

        self.display_configure_menu()

    def execute_generate_sudoku_option(self, generate_opts):
        """Executes the action selected by the user save sudoku on TXT file or diplay in console

            Keyword arguments:
            generate_opts -- takes one of the two options, 
                             generated sudoku could be displayed in console, or in a file
        """
        if generate_opts in ['1', '2']:
            complexity = self.configuration.get_complexity()
            min_holes = self.configuration.get_min_holes_by_complexity(
                complexity)
            max_holes = self.configuration.get_max_holes_by_complexity(
                complexity)
            empty_spot_char = self.configuration.get_empty_spot_char()
            sudoku_generator = SudokuGenerator()
            sudoku_generator.generate_sudoku_pattern_by_complexity(
                min_holes, max_holes, empty_spot_char)

        if generate_opts == "1":
            # save sudoku generated in file
            name_sudoku = "sudoku_generated_" + time.strftime("%Y-%m-%dT%H-%M-%S",\
                                                time.localtime(time.time())) + ".txt"

            if self.export_sudoku.export_sudoku(
                    sudoku_generator.sudoku_pattern, 'txt', "../results/",
                    name_sudoku) is True:
                print "\nSudoku was saved to: '", name_sudoku, "'"
                self.display_main_menu()

            else:
                print "\nFailed to save in TXT file. Try again...!"
                self.display_generate_sudoku_menu()

        if generate_opts == "2":
            # display generate sudoku in console
            print "\nGenerated Sudoku:\n"
            self.export_sudoku.export_sudoku(sudoku_generator.sudoku_pattern,
                                             'cmd line', '', '')
            self.display_main_menu()

        if generate_opts == "3":
            self.display_main_menu()

    def display_algorithm_menu(self):
        """ Displays/validates the selected options for the option: 
                              3 . Change Algorithm to solve sudokus                              
        """

        self.print_dictionary_list(self.change_algorithm_menu_options(),
                                   "--- Change Algorithm Menu ---")

        while True:
            algorit_opts = raw_input("\nPlease enter a number: ")

            if algorit_opts == "1" or algorit_opts == "2" or algorit_opts == "3"\
                                   or algorit_opts == "4":
                self.change_algorithm_menu_options()[algorit_opts]
                break
            else:
                print "Oops!  That was not a valid option number.  Try again..."
        self.execute_change_algorithm_option(algorit_opts)

    def display_level_algorithm_menu(self):
        """ Displays and validates the selected options for the option "2 . Change level" """

        self.print_dictionary_list(self.change_level_menu_options(),
                                   "--- Change Complexity Level Menu ---")

        while True:
            level_opts = raw_input("\nPlease enter a number: ")

            if level_opts == "1" or level_opts == "2" or level_opts == "3" or level_opts == "4":
                self.change_level_menu_options()[level_opts]
                break
            else:
                print "Oops!  That was not a valid option number.  Try again..."
        self.execute_change_level_option(level_opts)

    def display_output_type_menu(self):
        """ Displays/validates the selected options for the option: 1 . Change output format """

        self.print_dictionary_list(self.change_output_type_options(),
                                   "--- Change Output Type Menu ---")

        while True:
            output_opts = raw_input("\nPlease enter a number: ")

            if output_opts == "1" or output_opts == "2" or output_opts == "3":
                self.change_output_type_options()[output_opts]
                break
            else:
                print "Oops!  That was not a valid option number.  Try again..."
        self.execute_change_output_option(output_opts)

    def display_generate_sudoku_menu(self):
        """ Displays and validates the selected options for the option "3. Generate Sudoku" """

        self.print_dictionary_list(self.change_generate_sudoku_options(),
                                   "--- Generate Sudoku Menu ---")

        while True:
            generate_opts = raw_input("\nPlease enter a number: ")

            if generate_opts == "1" or generate_opts == "2" or generate_opts == "3":
                self.change_generate_sudoku_options()[generate_opts]
                break
            else:
                print "Oops!  That was not a valid option number.  Try again..."
        self.execute_generate_sudoku_option(generate_opts)

    def display_configure_menu(self):
        """ Displays and validates the selected options for the option "1 . Configure" """

        self.print_dictionary_list(self.conf_menu_options(),
                                   "--- Configuration Menu ---")

        while True:
            config_opts = raw_input("\nPlease enter a number: ")

            if config_opts == "1" or config_opts == "2" or config_opts == "3"\
                                  or config_opts == "4" or config_opts == "5":
                self.conf_menu_options()[config_opts]
                break
            else:
                print "Oops!  That was not a valid option number.  Try again..."
        self.execute_conf_option(config_opts)

    def change_generate_sudoku_options(self):
        """ Defines the 3 available options for the option "3. Generate Sudoku" """

        generate_opts = {'1': 'Save Sudoku to TXT file', '2': 'Display Sudoku on console',\
                         '3': 'Back to Main menu'}

        return generate_opts

    def change_output_type_options(self):
        """ Defines the 3 available options for the option "1 . Change output format" """

        output_opts = {
            '1': 'Display result in console',
            '2': 'Save result in a file',
            '3': 'Back'
        }
        return output_opts

    def change_algorithm_menu_options(self):
        """ Defines the available Algorithm methods for the sudoku resolution """

        algorit_opts = {
            '1': 'Norvig',
            '2': 'Backtracking',
            '3': 'Brute Force',
            '4': 'Back'
        }
        return algorit_opts

    def change_level_menu_options(self):
        """ Defines the available levels for the option "2 . Change level" """

        level_opts = {'1': 'Easy', '2': 'Medium', '3': 'Hard', '4': 'Back'}
        return level_opts

    def print_dictionary_list(self, dictionary, title_menu=""):
        """ Prints the dictionary list for each value """
        if title_menu != "":
            print "\n" + title_menu + "\n"

        for n in range(1, len(dictionary) + 1):
            for key, value in dictionary.iteritems():
                if str(n) == key:
                    print key, value
Example #3
0
class Main():

    def __init__(self):
        self.configuration = XMLConfig()
        self.display_main_menu()
         
    def display_main_menu(self):
        """ Displays the Main Menu and validates the entered values for the required options 

            Keyword arguments:
            op_main_menu -- stores the selected value of available options in the Main Menu 
        """

        print self.logo()
        self.print_dictionary_list(self.main_menu_options())

        while True:   
            op_main_menu = raw_input("\nPlease enter a number: ")
            print ''

            if op_main_menu == "1" or op_main_menu == "2" or op_main_menu == "3" or op_main_menu == "4":
                self.main_menu_options()[op_main_menu]
                break
            else: 
              print "Oops!  That was no valid option number.  Try again..."
        self.execute_main_option(op_main_menu) 

    def logo(self):
        """ Displays the logo on the menu"""

        res = """--------------------------------------
--------------------------------------
              SUDOKU A
--------------------------------------
--------------------------------------"""

        return res
    
    def main_menu_options(self):
        """ Defines the 3 available options for the Sudoku Main Menu

            Keyword arguments:
            main_menu_opts -- stores the dictionary of available options for the Main Menu 
        """

        main_menu_opts = {'1': 'Configure', '2': 'Solve Sudoku', '3': 'Generate Sudoku', '4': 'Exit'}
        return main_menu_opts

    def conf_menu_options(self):
        """ Defines the 3 available options for the: "1 . Configure" option 

            Keyword arguments:
            config_opts -- stores the dictionary of available options for the option "1 . Configure"  
        """

        conf_opts = {'1': 'Change Output format', '2': 'Change Level',
                    '3': 'Change Algorithm to use', '4': 'Back'}

        return conf_opts
    
    def execute_main_option(self, op_main_menu):
        """ Executes the Main Menu for the selected option

            Keyword arguments:
            op_main_menu -- takes one of the four options to select on the Main Menu
        """

        if (op_main_menu == "1"):
            self.display_configure_menu()

        if (op_main_menu == "2"):
            print 'Not implemented yet'
            self.display_main_menu()

        if (op_main_menu == "3"):
            print 'Not implemented yet'
            self.display_main_menu()

        if (op_main_menu == "4"):
            print "Good bye!"

    def execute_conf_option(self, conf_opts):
        """ Executes the selected option on the "1 . Configure" option 

            Keyword arguments:
            config_opts -- takes one of the three options available in the "1 . Configure" option 
        """

        if (conf_opts == "1"):
            self.display_output_type_menu()
        if (conf_opts == "2"):
            self.display_level_algorithm_menu()
        if (conf_opts == "3"):
            self.display_algorithm_menu()
        if (conf_opts == "4"):
            self.display_main_menu()     

    def execute_change_level_option(self, level_opts):
        """ Changes the complexity level for create or solve the sudoku 

            Keyword arguments:
            level_opts -- takes one of the three options for the complexity level
        """

        if (level_opts == "1"):
            # save Easy level 
            self.configuration.modify_complexity('Easy')
            self.execute_change_algorithm_option('4')
            
        if (level_opts == "2"):
            # save Medium level 
            self.configuration.modify_complexity('Medium')
            self.execute_change_algorithm_option('4')
            
        if (level_opts == "3"):
            # save Hard level
            self.configuration.modify_complexity('Hard')
            self.execute_change_algorithm_option('4')
            
        if (level_opts == "4"):
            self.execute_change_algorithm_option('4')

    def execute_change_algorithm_option(self, chng_algorit):
        """ Changes the Algorithm used for create or solve the sudoku 

            Keyword arguments:
            chng_algorit -- takes one of the three options for changing the Algorithm to use
        """ 

        if (chng_algorit == "1"):
            # save Norvig algorithm  
            #self.configuration.('Norvig')
            self.execute_change_algorithm_option('4')
            pass

        if (chng_algorit == "2"):
            # save Backtraking algorithm
            #self.configuration.('Backtraking')
            self.execute_change_algorithm_option('4')
            pass

        if (chng_algorit == "3"):
            # save Custom algorithm
            #self.save_algorithm("Custom")
            #self.display_main_menu()
            self.execute_change_algorithm_option('4')
            pass

        if (chng_algorit == "4"):
            self.display_configure_menu()

    def execute_change_output_option(self, output_opts): 
        """ Changes the output format for the solved the sudoku 

            Keyword arguments:
            output_opts -- takes one of the two options, 
                            solved sudoku could be displayed in console, or in a file
        """ 

        if (output_opts == "1"):
            # display solved sudoku in console
            self.configuration.modify_output_type('console')
            self.execute_change_output_option('3')

        if (output_opts == "2"):
            # save solved sudoku in a file            
            self.configuration.modify_output_type('file')                       
            self.execute_change_output_option('3')                
            
        if (output_opts == "3"):
            self.display_configure_menu()
            
    def display_algorithm_menu(self):
        """ Displays/validates the selected options for the option "3 . Change Algorithm to solve sudokus"

            Keyword arguments:
            algorit_opts -- stores the dictionary of available options for the option 
                            "3 . Change Algorithm"
        """ 

        self.print_dictionary_list(self.change_algorithm_menu_options())

        while True:   
            algorit_opts = raw_input("\nPlease enter a number: ")
            print ''

            if algorit_opts == "1" or algorit_opts == "2" or algorit_opts == "3" or algorit_opts == "4":
                self.change_algorithm_menu_options()[algorit_opts]
                break
            else:
              print "Oops!  That was no valid option number.  Try again..." 
        self.execute_change_algorithm_option(algorit_opts)    
    
    def display_level_algorithm_menu(self):
        """ Displays and validates the selected options for the option "2 . Change level"

            Keyword arguments:
            level_opts -- stores the dictionary of available options for the option "2 . Change level"
        """ 

        self.print_dictionary_list(self.change_level_menu_options())

        while True:   
            level_opts = raw_input("\nPlease enter a number: ")
            print ''

            if level_opts == "1" or level_opts == "2" or level_opts == "3" or level_opts == "4":
                self.change_level_menu_options()[level_opts]
                break
            else:
              print "Oops!  That was no valid option number.  Try again..." 
        self.execute_change_level_option(level_opts)

    def display_output_type_menu(self):
        """ Displays and validates the selected options for the option "1 . Change output format"

            Keyword arguments:
            output_opts -- stores the dictionary of available options for the option "1 . Change output format"
        """ 

        self.print_dictionary_list(self.change_output_type_options())

        while True:   
            output_opts = raw_input("\nPlease enter a number: ")
            print ''

            if output_opts == "1" or output_opts == "2" or output_opts == "3":
                self.change_output_type_options()[output_opts]
                break
            else:
              print "Oops!  That was no valid option number.  Try again..." 
        self.execute_change_output_option(output_opts)

    def change_output_type_options(self):
        """ Defines the 3 available options for the option "1 . Change output format"

            Keyword arguments:
            output_opts -- stores the dictionary of available options for the "1 . Change output format"
        """

        output_opts = {'1': 'Display result in console', '2': 'Save result in a file', '3': 'Back'}    

        return output_opts
    
    def change_algorithm_menu_options(self):
        """ Defines the available Algorithm methods for the sudoku resolution

            Keyword arguments:
            algorit_opts -- stores the selected value for the available Algorithms to use             
        """

        algorit_opts = {'1': 'Norvig', '2': 'Backtraking', '3': 'Custom', '4': 'Back'}
        return algorit_opts
    
    def change_level_menu_options(self):
        """ Defines the available levels for the option "2 . Change level"

            Keyword arguments:
            level_opts -- stores the dictionary of avilable levels for the "2 . Change level"            
        """

        level_opts = {'1': 'Easy', '2': 'Medium', '3': 'Hard', '4': 'Back'}
        return level_opts
    
    def display_configure_menu(self):
        """ Displays and validates the selected options for the option "1 . Configure"

            Keyword arguments:
            config_opts -- stores the dictionary of avilable options for the option "1 . Configure"
        """ 

        self.print_dictionary_list(self.conf_menu_options())

        while True:   
            config_opts = raw_input("\nPlease enter a number: ")
            print ''

            if config_opts == "1" or config_opts == "2" or config_opts == "3" or config_opts == "4":
                self.conf_menu_options()[config_opts]
                break
            else:
              print "Oops!  That was no valid option number.  Try again..." 
        self.execute_conf_option(config_opts)


    def print_dictionary_list(self, dictionary):
        """ Prints the dictionary list for each value 
            
        """ 

        for n in range (1, len (dictionary) + 1):
            for key, value in dictionary.iteritems() :
                if str(n) == key:
                    print key, value
Example #4
0
class Main():

    def __init__(self):
        self.configuration = XMLConfig()
        self.import_data = ImportData()    
        self.empty_spot_char = self.configuration.get_empty_spot_char()     
        self.export_sudoku = ExportSudoku()
        self.display_main_menu()
         
    def display_main_menu(self):
        """ Displays the Main Menu and validates the entered values for the required options """

        print self.logo()
        self.print_dictionary_list(self.main_menu_options())

        while True:   
            op_main_menu = raw_input("\nPlease enter a number: ")

            if op_main_menu == "1" or op_main_menu == "2" or op_main_menu == "3"\
                                   or op_main_menu == "4" or op_main_menu == "5":
                self.main_menu_options()[op_main_menu]
                break
            else: 
              print "Oops!  That was not a valid option number.  Try again...\n"
        self.execute_main_option(op_main_menu) 

    def logo(self):
        """ Displays the logo on the menu"""

        logo_str = " _____           _       _             ___\n" + \
                   "/  ___|         | |     | |           / _ \\\n" + \
                   "\ `--. _   _  __| | ___ | | ___   _  / /_\ \\\n" + \
                   " `--. \ | | |/ _` |/ _ \| |/ / | | | |  _  |\n" + \
                   "/\__/ / |_| | (_| | (_) |   <| |_| | | | | |\n" + \
                   "\____/ \__,_|\__,_|\___/|_|\_\\\\__,_| \_| |_/\n"
                                                                                       
        return logo_str
    
    def main_menu_options(self):
        """ Defines the 3 available options for the Sudoku Main Menu """

        main_menu_opts = {'1': 'Configure', '2': 'Solve Sudoku', '3': 'Generate Sudoku',\
                          '4': 'Play online!', '5': 'Exit'}
        return main_menu_opts    

    def execute_change_solve_option(self, op_solve_menu):
        """ Executes the Solve Menu for the selected option

            Keyword arguments:
            op_solve_menu -- takes one of the three options to select on the Main Menu
        """

        if op_solve_menu == "1":
            self.solve_sudoku_from_cmd("txt")
            
        if op_solve_menu == "2":
            self.solve_sudoku_from_file("txt")
            
        if op_solve_menu == "3":
            self.solve_sudoku_from_file("txt")

        if op_solve_menu == "4":
            self.display_main_menu()

    def solve_sudoku_from_cmd(self, type_file):
        """ Method used for solving the sudoku given the input by command line

            Keyword arguments:
            type_file -- stores the selected cmd option

        """
        
        cmd_sudoku = raw_input ('\nEnter the sudoku to solve in the same line without spaces or'
                                'commas, it should have 81 numbers as the following example:\n0'
                                '03020600900305001001806400008102900700000008006708200002609500'
                                '800203009005010300\n')

        print "\nSolution:\n"
        sudoku_matrix = self.import_data.read_sudoku_data_from_line(cmd_sudoku)
        self.export_sudoku_to(sudoku_matrix, type_file)        
        self.display_main_menu()

    def export_sudoku_to(self, sudoku_matrix, type_file):
        """ Method used for exporting the solved sudoku to the default "results" path

            Keyword arguments:
            sudoku_matrix -- stores the sudoku on the valid sudoku matrix to solve
            type_file -- stores the selected file type; file or cmd

        """

        path = "../results/"
        algoritms = self.create_algorith_to_solve_sudoku(sudoku_matrix, self.empty_spot_char)        
        for algoritm_to_solve in algoritms:
            sudoku_solved = algoritm_to_solve.solve_sudoku()        
            if sudoku_solved != []:
                export_to = self.configuration.get_output_type()                
                if  export_to == 'file':
                    self.export_file(algoritm_to_solve, type_file, sudoku_solved, path)
                else:
                    self.export_sudoku.export_sudoku(sudoku_solved, "cmd line", "", "")
            else:
                print "\nInvalid sudoku, it cannot be solved!\n" 

    def file_exists(self):
        """ Method used for verifying whether the entered file exists or not """

        result = ""
        path = "../inputs/"
        while True :
            file_name = raw_input('\nEnter the name of the file to solve or enter quit to exit: ')
            file_txt = path + "\\" + file_name
            if os.path.exists(file_txt):
                result = file_txt
                break
            elif file_name == "quit":
                break
            else:
                print "\nThe file provided does not exists, please try again\n"
        return result

    def solve_sudoku_from_file(self, type_file):
        """ Method used for solving the sudoku given a file

            Keyword arguments:            
            type_file -- stores the selected file type, it can be a txt or csv file

        """ 

        file_ext = self.file_exists()
        
        if file_ext != "":            
            sudoku_matrix = self.import_data.read_sudoku_data_from_file(file_ext)            
            self.export_sudoku_to(sudoku_matrix, type_file)              
            #self.display_main_menu()            
        #else:            
        self.display_solve_menu()

    def export_file(self, algoritm_to_solve, type_file, sudoku_solved, path):
        """ Method used for create the solved sudoku in a file on the default "results" path

            Keyword arguments:
            algoritm_to_solve -- the selected algorithm to solve the sudoku           
            type_file -- stores the selected file type; file or cmd
            sudoku_solved -- sores the solved sudoku
            path -- stores the default "results" path for the solutions

        """ 

        file_name = 'sudoku_solved_' + algoritm_to_solve.__class__.__name__ + "_" + \
                    str(algoritm_to_solve.get_time()) + "_" + time.strftime("%Y-%m-%dT%H-%M-%S",
                     time.localtime(time.time())) + "." + type_file  
        if self.export_sudoku.export_sudoku(sudoku_solved, type_file, path, file_name) :
            print "\nThe file was created successfully\n"
        else:
            print "\nThere was a error, the file couldn't be created\n"

    def create_algorith_to_solve_sudoku(self, sudoku_matrix, empty_character):
        """ Method used for create the algorithm to solve given the expected sudoku matrix 
            and empty character
            
            Keyword arguments:
            sudoku_matrix -- stores the sudoku in the valid matrix ready to be solved
            empty_character -- stores the selected character for the empty spots 

        """
         
        algorithm_selected = self.configuration.get_algorithm()
        algoritms = []
        for i in range(0, len(sudoku_matrix)):
            algoritm_to_solve = Algorithm(sudoku_matrix[i][0], empty_character)
            if algorithm_selected == 'norvig':
                algoritm_to_solve = NorvigAlgorithm(sudoku_matrix[i][0], empty_character)                
            elif algorithm_selected == 'backtracking':
                algoritm_to_solve = BacktrakingAlgorithm(sudoku_matrix[i][0], empty_character)
            elif algorithm_selected == 'brute force':
                algoritm_to_solve =  BruteForceAlgorithm(sudoku_matrix[i][0], empty_character)
            algoritms.append(algoritm_to_solve)
        return algoritms
                
    def display_solve_menu(self):
        """ Displays/validates the selected options for solving the sudoku using one of the 
            three valid input types
            
        """ 

        self.print_dictionary_list(self.change_solve_menu_options(), "--- Solve Sudoku Menu ---")

        while True:   
            solve_opts = raw_input("\nPlease enter a number: ")

            if solve_opts == "1" or solve_opts == "2" or solve_opts == "3" or solve_opts == "4":
                self.change_solve_menu_options()[solve_opts]
                break
            else:
              print "\nOops!  That was not a valid option number.  Try again...\n" 
        self.execute_change_solve_option(solve_opts)

    def change_solve_menu_options(self):
        """ Defines the 3 available options for the inputs type for solving the sudoku """

        solve_opts = {'1': 'Solve sudoku entered by command line', 
                      '2': 'Solve sudoku from a txt file', '3': 'Solve sudoku from a csv file',
                      '4': 'Back'}   

        return solve_opts

    def conf_menu_options(self):
        """ Defines the 3 available options for the: "1 . Configure" option """

        conf_opts = {'1': 'Change Output format', '2': 'Change Level',
                     '3': 'Change Algorithm to use', '4': 'Change empty spot character', '5': 'Back'}

        return conf_opts
    
    def execute_main_option(self, op_main_menu):
        """ Executes the Main Menu for the selected option

            Keyword arguments:
            op_main_menu -- takes one of the four options to select on the Main Menu
        """

        if op_main_menu == "1":
            self.display_configure_menu()

        if op_main_menu == "2":
            self.display_solve_menu()              
                        
        if op_main_menu == "3":
            self.display_generate_sudoku_menu()

        if op_main_menu == "4":
            SudokuUI()

        if op_main_menu == "5":
            print "Good bye!"

    def execute_conf_option(self, conf_opts):
        """ Executes the selected option on the "1 . Configure" option 

            Keyword arguments:
            conf_opts -- takes one of the four options available in the option: "1 . Configure"  
        """

        if conf_opts == "1":
            self.display_output_type_menu()

        if conf_opts == "2":
            self.display_level_algorithm_menu()

        if conf_opts == "3":
            self.display_algorithm_menu()

        if conf_opts == "4":
            self.execute_change_empty_spot() 

        if conf_opts == "5":
            self.display_main_menu()

    def execute_change_empty_spot(self):
        """ Method that changes the character used as empty spot """

        empty_spot_char = str(raw_input('Enter a new character used as empty spot or'
                                        ' enter <quit> to go back menu: '))
                            
        if empty_spot_char >= '1' and empty_spot_char <= '9':
            print "\nInvalid empty spot character, please don't use numbers from 1 to 9"

        elif empty_spot_char == ',':
            print "\nInvalid empty spot character, please don't use the comma (,) character"
        
        elif len(empty_spot_char) == 1:
            print "\n", self.configuration.modify_empty_spot_char(empty_spot_char)

        elif empty_spot_char.lower() == 'quit':
            print  "\nDefault empty spot char will be used: "\
                                                    + self.configuration.get_empty_spot_char()

        else:
            print "\nInvalid empty spot character, please use only one character"

        self.display_configure_menu()

    def execute_change_level_option(self, level_opts):
        """ Changes the complexity level for create or solve the sudoku 

            Keyword arguments:
            level_opts -- takes one of the three options for the complexity level
        """

        if level_opts == "1":
            # save Easy level 
            print "\n", self.configuration.modify_complexity('Easy')
            
        if level_opts == "2":
            # save Medium level
            print "\n", self.configuration.modify_complexity('Medium')

        if level_opts == "3":
            # save Hard level
            print "\n", self.configuration.modify_complexity('Hard')

        self.execute_change_algorithm_option('4')

    def execute_change_algorithm_option(self, chng_algorit):
        """ Changes the Algorithm used for create or solve the sudoku 

            Keyword arguments:
            chng_algorit -- takes one of the three options for changing the Algorithm to use
        """ 

        if chng_algorit == "1":
            # save Norvig algorithm              
            print "\n", self.configuration.modify_algorithm('Norvig')

        if chng_algorit == "2":
            # save Backtraking algorithm            
            print "\n", self.configuration.modify_algorithm('Backtracking')

        if chng_algorit == "3":
            # save Brute Force algorithm            
            print "\n", self.configuration.modify_algorithm("brute force")           

        self.display_configure_menu()

    def execute_change_output_option(self, output_opts): 
        """ Changes the output format for the solved the sudoku 

            Keyword arguments:
            output_opts -- takes one of the two options, 
                           solved sudoku could be displayed in console, or in a file
        """ 
        if output_opts == "1":
            # display solved sudoku in console            
            print "\n", self.configuration.modify_output_type('console')            

        if output_opts == "2":
            # save solved sudoku in a file            
            print "\n", self.configuration.modify_output_type('file')       

        self.display_configure_menu()

    def execute_generate_sudoku_option(self, generate_opts): 
        """Executes the action selected by the user save sudoku on TXT file or diplay in console

            Keyword arguments:
            generate_opts -- takes one of the two options, 
                             generated sudoku could be displayed in console, or in a file
        """ 
        if generate_opts in ['1', '2']:
            complexity = self.configuration.get_complexity()
            min_holes = self.configuration.get_min_holes_by_complexity(complexity)
            max_holes = self.configuration.get_max_holes_by_complexity(complexity)
            empty_spot_char = self.configuration.get_empty_spot_char()
            sudoku_generator = SudokuGenerator()
            sudoku_generator.generate_sudoku_pattern_by_complexity(min_holes, max_holes, 
                                                                   empty_spot_char)

        if generate_opts == "1":
            # save sudoku generated in file
            name_sudoku = "sudoku_generated_" + time.strftime("%Y-%m-%dT%H-%M-%S",\
                                                time.localtime(time.time())) + ".txt"

            if self.export_sudoku.export_sudoku(sudoku_generator.sudoku_pattern,
                                                 'txt', "../results/", name_sudoku) is True:
                print "\nSudoku was saved to: '",name_sudoku,"'"                
                self.display_main_menu()

            else:
                print "\nFailed to save in TXT file. Try again...!"                
                self.display_generate_sudoku_menu()              

        if generate_opts == "2":
            # display generate sudoku in console
            print "\nGenerated Sudoku:\n"
            self.export_sudoku.export_sudoku(sudoku_generator.sudoku_pattern, 'cmd line', '', '')
            self.display_main_menu()
            
        if generate_opts == "3":
            self.display_main_menu()
            
    def display_algorithm_menu(self):
        """ Displays/validates the selected options for the option: 
                              3 . Change Algorithm to solve sudokus                              
        """ 

        self.print_dictionary_list(self.change_algorithm_menu_options(), "--- Change Algorithm Menu ---")

        while True:   
            algorit_opts = raw_input("\nPlease enter a number: ")
            
            if algorit_opts == "1" or algorit_opts == "2" or algorit_opts == "3"\
                                   or algorit_opts == "4":
                self.change_algorithm_menu_options()[algorit_opts]
                break
            else:
              print "Oops!  That was not a valid option number.  Try again..." 
        self.execute_change_algorithm_option(algorit_opts)    
    
    def display_level_algorithm_menu(self):
        """ Displays and validates the selected options for the option "2 . Change level" """ 

        self.print_dictionary_list(self.change_level_menu_options(), "--- Change Complexity Level Menu ---")

        while True:   
            level_opts = raw_input("\nPlease enter a number: ")
            
            if level_opts == "1" or level_opts == "2" or level_opts == "3" or level_opts == "4":
                self.change_level_menu_options()[level_opts]
                break
            else:
              print "Oops!  That was not a valid option number.  Try again..." 
        self.execute_change_level_option(level_opts)

    def display_output_type_menu(self):
        """ Displays/validates the selected options for the option: 1 . Change output format """ 

        self.print_dictionary_list(self.change_output_type_options(), "--- Change Output Type Menu ---")

        while True:   
            output_opts = raw_input("\nPlease enter a number: ")
            
            if output_opts == "1" or output_opts == "2" or output_opts == "3":
                self.change_output_type_options()[output_opts]
                break
            else:
              print "Oops!  That was not a valid option number.  Try again..." 
        self.execute_change_output_option(output_opts)

    def display_generate_sudoku_menu(self):
        """ Displays and validates the selected options for the option "3. Generate Sudoku" """

        self.print_dictionary_list(self.change_generate_sudoku_options(), "--- Generate Sudoku Menu ---")

        while True:   
            generate_opts = raw_input("\nPlease enter a number: ")            

            if generate_opts == "1" or generate_opts == "2" or generate_opts == "3":
                self.change_generate_sudoku_options()[generate_opts]
                break
            else:
              print "Oops!  That was not a valid option number.  Try again..." 
        self.execute_generate_sudoku_option(generate_opts)

    def display_configure_menu(self):
        """ Displays and validates the selected options for the option "1 . Configure" """ 

        self.print_dictionary_list(self.conf_menu_options(), "--- Configuration Menu ---")

        while True:   
            config_opts = raw_input("\nPlease enter a number: ")            

            if config_opts == "1" or config_opts == "2" or config_opts == "3"\
                                  or config_opts == "4" or config_opts == "5":
                self.conf_menu_options()[config_opts]
                break
            else:
              print "Oops!  That was not a valid option number.  Try again..." 
        self.execute_conf_option(config_opts)

    def change_generate_sudoku_options(self):
        """ Defines the 3 available options for the option "3. Generate Sudoku" """

        generate_opts = {'1': 'Save Sudoku to TXT file', '2': 'Display Sudoku on console',\
                         '3': 'Back to Main menu'}    

        return generate_opts

    def change_output_type_options(self):
        """ Defines the 3 available options for the option "1 . Change output format" """

        output_opts = {'1': 'Display result in console', '2': 'Save result in a file', '3': 'Back'} 
        return output_opts
    
    def change_algorithm_menu_options(self):
        """ Defines the available Algorithm methods for the sudoku resolution """

        algorit_opts = {'1': 'Norvig', '2': 'Backtracking', '3': 'Brute Force', '4': 'Back'}
        return algorit_opts
    
    def change_level_menu_options(self):
        """ Defines the available levels for the option "2 . Change level" """

        level_opts = {'1': 'Easy', '2': 'Medium', '3': 'Hard', '4': 'Back'}
        return level_opts
    

    def print_dictionary_list(self, dictionary, title_menu = ""):
        """ Prints the dictionary list for each value """ 
        if title_menu != "":
            print "\n" + title_menu + "\n"

        for n in range (1, len (dictionary) + 1):
            for key, value in dictionary.iteritems() :
                if str(n) == key:
                    print key, value
class TestXmlConfig(unittest.TestCase):

    def setUp(self):
        self.xml_config = XMLConfig()
        self.path_game_settings = os.path.abspath("..\\..\\game_settings.xml")
        shutil.copy2(self.xml_config.path_name, 'copy_config.xml')
        shutil.copy2(self.path_game_settings, 'copy_game_settings.xml')

    #################################
    # Tests for: read_configuration_file(self)
    #################################

    def test_read_configuration_file_returns_error_msg_if_file_config_does_not_exist(self):
        expected_message = "Invalid data or file"
        os.remove(self.xml_config.path_name)
        self.assertEquals(expected_message, self.xml_config.read_configuration_file())
        

    def test_read_configuration_file_returns_error_msg_if_file_config_is_empty(self):
        expected_message = "Invalid data or file"
        file_config = open(self.xml_config.path_name, 'w')
        file_config.write('')
        file_config.close()
        self.assertEquals(expected_message, self.xml_config.\
                                                    read_configuration_file())

    def test_read_configuration_file_returns_error_msg_if_file_config_cannot_parse_xml(self):
        expected_message = "Invalid data or file"
        file_config = open(self.xml_config.path_name, 'w')
        file_config.write('<config><level>')
        file_config.close()
        self.assertEquals(expected_message, self.xml_config.read_configuration_file())      

    def test_read_configuration_file_returns_error_msg_if_file_config_without_output_type(self):
        expected_message = "Invalid data or file"
        file_name = "test_xmls\\config_test_no_ouput_type.xml"
        shutil.copy2(file_name, "..\\..\\config_test_no_ouput_type.xml")
        config_test = XMLConfig(file_name)
        self.assertEquals(expected_message, config_test.read_configuration_file())

    def test_read_configuration_file_returns_error_msg_if_file_config_without_algorithm(self):
        expected_message = "Invalid data or file"
        file_name = "test_xmls\\config_test_no_algorithm.xml"
        shutil.copy2(file_name, "..\\..\\config_test_no_algorithm.xml")
        config_test = XMLConfig(file_name)
        self.assertEquals(expected_message, config_test.read_configuration_file())

    def test_read_configuration_file_returns_a_dictionary_of_configuration_if_valid_data(self):
        dict_configuration = {'space_char':'0', 'output-type': 'file', 
                              'algorithm': 'backtracking', 'output-path': 'results',
                               'level': 'medium'}
        self.assertEquals(dict_configuration, self.xml_config.read_configuration_file())

    ########### END read_configuration_file ##############

    #################################
    # Tests for: get_valid_data_game(self, file_path, xml_tag_path, attrib_name)
    #################################

    def test_get_valid_data_game_returns_list_of_levels_if_level_specified(self):
        expected_levels = ['easy', 'medium', 'hard']
        self.assertEquals(expected_levels, self.xml_config.get_valid_data_game(self.path_game_settings, 'level', 'name'))

    def test_get_valid_data_game_returns_list_of_algorithms_if_algorithm_specified(self):
        expected_algorithms = ['backtracking', 'norvig', 'x']
        self.assertEquals(expected_algorithms, self.xml_config.get_valid_data_game(self.path_game_settings, 'algorithm', 'name'))

    ########### END get_valid_data_game ##############

    #################################
    # Tests for: get_complexity(self)
    #################################

    def test_get_complexity_returns_error_message_if_level_tag_does_not_exist(self):
        expected_message = "Tag is missing!"
        file_config = open(self.xml_config.path_name, 'w')
        file_config.write('<config><tessst>')
        file_config.close()
        self.assertEquals(expected_message, self.xml_config.get_complexity())

    def test_get_complexity_returns_complexity_value_if_value_exists(self):
        expected_default_level = 'medium'
        self.assertEquals(expected_default_level, self.xml_config.get_complexity())        

    ########### END get_complexity ##############

    #################################
    # Tests for: modify_complexity(self, complexity)
    #################################
    
    def test_modify_complexity_returns_error_message_if_level_tag_does_not_exist(self):
        expected_message = "Tag is missing!"
        file_config = open(self.xml_config.path_name, 'w')
        file_config.write('<config><level>')
        file_config.close()
        self.assertEquals(expected_message, self.xml_config.modify_complexity('hard'))
    
    def test_modify_complexity_returns_error_message_if_value_tag_does_not_exist(self):
        expected_message = "Tag is missing!"
        file_config = open(self.xml_config.path_name, 'w')
        file_config.write('<config><level>')
        file_config.close()
        self.assertEquals(expected_message, self.xml_config.modify_complexity('hard'))

    def test_modify_complexity_returns_error_message_if_complexity_is_not_valid(self):
        expected_message = "Invalid complexity parameter"
        self.assertEquals(expected_message, self.xml_config.modify_complexity('not-valid'))

    def test_modify_complexity_saves_new_complexity_in_config_file_if_complexity_is_valid(self):
        expected_complexity = 'hard'
        self.xml_config.modify_complexity('hard')
        current_complexity = self.xml_config.get_complexity()
        self.assertEquals(expected_complexity, current_complexity)        

    ########### END modify_complexity ##############

    #################################
    # Tests for: get_output_type(self)
    #################################

    def test_get_output_type_returns_error_message_if_level_tag_does_not_exist(self):
        expected_message = "Tag is missing!"
        file_config = open(self.xml_config.path_name, 'w')
        file_config.write('<config><tessst>')
        file_config.close()
        self.assertEquals(expected_message, self.xml_config.get_output_type())

    def test_get_output_type_returns_output_type_value_if_value_exists(self):
        expected_default_output = 'file'
        self.assertEquals(expected_default_output, self.xml_config.get_output_type())        

    ########### END get_output_type ##############

    #################################
    # Tests for: modify_output_type(self, output_type)
    #################################
    
    def test_modify_output_type_returns_error_message_if_output_type_tag_does_not_exist(self):
        expected_message = "Tag is missing!"
        file_config = open(self.xml_config.path_name, 'w')
        file_config.write('<config><level>')
        file_config.close()
        self.assertEquals(expected_message, self.xml_config.modify_output_type('console'))
    
    def test_modify_output_type_returns_error_message_if_path_tag_does_not_exist(self):
        expected_message = "Tag is missing!"
        file_config = open(self.xml_config.path_name, 'w')
        file_config.write('<config><level>')
        file_config.close()
        self.assertEquals(expected_message, self.xml_config.modify_output_type('console'))

    def test_modify_output_type_returns_error_message_if_out_put_is_not_valid(self):
        expected_message = "Invalid output type parameter"
        self.assertEquals(expected_message, self.xml_config.modify_output_type('not-valid'))

    def test_modify_output_type_saves_console_output_type_in_config_file_if_output_type_is_console(self):
        expected_output_type = 'console'
        self.xml_config.modify_output_type('console')
        current_output_type = self.xml_config.get_output_type()
        self.assertEquals(expected_output_type, current_output_type)        

    ########### END modify_output_type ############## 

    #################################
    # Tests for: write_value_to_xml(file_path, xml_path, new_value)
    #################################
    
    def test_write_value_to_xml_modifies_complexity_to_hard_in_config_file(self):
        expected_complexity = 'hard'
        self.xml_config.write_value_to_xml(self.xml_config.path_name, 'level/value','hard')
        current_complexity = self.xml_config.get_complexity()
        self.assertEquals(expected_complexity, current_complexity)

    ########### END write_value_in_config_file ##############       

    #################################
    # Tests for: get_value_from_xml(file_path, xml_path)
    #################################
    
    def test_get_value_from_xml_recovers_complexity_from_config_file(self):
        expected_complexity = 'medium'
        complexity = self.xml_config.get_value_from_xml(self.xml_config.path_name, 'level/value')
        self.assertEquals(expected_complexity, complexity)

    ########### END get_value_from_xml ############## 

    #################################
    # Tests for: get_algorithm(self)
    #################################

    def test_get_algorithm_returns_error_message_if_algorithm_tag_does_not_exist(self):
        expected_message = "Tag is missing!"
        file_config = open(self.xml_config.path_name, 'w')
        file_config.write('<none>')
        file_config.close()
        self.assertEquals(expected_message, self.xml_config.get_algorithm())

    def test_get_algorithm_returns_default_algorithm_value_if_value_exists(self):
        expected_default_algorithm = 'backtracking'
        self.assertEquals(expected_default_algorithm, self.xml_config.get_algorithm())        

    ########### END get_algorithm ##############

    #################################
    # Tests for: modify_algorithm(self, algorithm):
    #################################

    def test_modify_algorithm_returns_error_message_if_algorithm_tag_does_not_exist(self):
        expected_message = "Tag is missing!"
        file_config = open(self.xml_config.path_name, 'w')
        file_config.write('<config><ss>')
        file_config.close()
        self.assertEquals(expected_message, self.xml_config.modify_algorithm('backtracking'))

    def test_modify_algorithm_returns_error_message_if_algorithm_is_not_valid(self):
        expected_message = "Invalid algorithm parameter"
        self.assertEquals(expected_message, self.xml_config.modify_algorithm('not-valid'))

    def test_modify_algorithm_saves_norvig_in_config_file_if_algorithm_is_norvig(self):
        expected_algorithm = 'norvig'
        self.xml_config.modify_algorithm('norvig')
        current_algorithm = self.xml_config.get_algorithm()
        self.assertEquals(expected_algorithm, current_algorithm)        

    
    ########### END modify_algorithm ##############  


    def tearDown(self):
        shutil.copy2('copy_config.xml', self.xml_config.path_name)
        os.remove('copy_config.xml')

        shutil.copy2('copy_game_settings.xml', self.path_game_settings)
        os.remove('copy_game_settings.xml')
        
        test_output = os.path.abspath("..\\..\\config_test_no_ouput_type.xml")
        if os.path.isfile(test_output):
            os.remove(test_output)

        test_algorithm = os.path.abspath("..\\..\\config_test_no_algorithm.xml")
        if os.path.isfile(test_algorithm):
            os.remove(test_algorithm)
class TestXmlConfig(unittest.TestCase):
    def setUp(self):
        self.xml_config = XMLConfig()
        self.path_game_settings = os.path.abspath("..\\..\\game_settings.xml")
        shutil.copy2(self.xml_config.path_name, 'copy_config.xml')
        shutil.copy2(self.path_game_settings, 'copy_game_settings.xml')

    #################################
    # Tests for: read_configuration_file(self)
    #################################

    def test_read_configuration_file_returns_error_msg_if_file_config_does_not_exist(
            self):
        expected_message = "Invalid data or file"
        os.remove(self.xml_config.path_name)
        self.assertEquals(expected_message,
                          self.xml_config.read_configuration_file())

    def test_read_configuration_file_returns_error_msg_if_file_config_is_empty(
            self):
        expected_message = "Invalid data or file"
        file_config = open(self.xml_config.path_name, 'w')
        file_config.write('')
        file_config.close()
        self.assertEquals(expected_message, self.xml_config.\
                                                    read_configuration_file())

    def test_read_configuration_file_returns_error_msg_if_file_config_cannot_parse_xml(
            self):
        expected_message = "Invalid data or file"
        file_config = open(self.xml_config.path_name, 'w')
        file_config.write('<config><level>')
        file_config.close()
        self.assertEquals(expected_message,
                          self.xml_config.read_configuration_file())

    def test_read_configuration_file_returns_error_msg_if_file_config_without_output_type(
            self):
        expected_message = "Invalid data or file"
        file_name = "test_xmls\\config_test_no_ouput_type.xml"
        shutil.copy2(file_name, "..\\..\\config_test_no_ouput_type.xml")
        config_test = XMLConfig(file_name)
        self.assertEquals(expected_message,
                          config_test.read_configuration_file())

    def test_read_configuration_file_returns_error_msg_if_file_config_without_algorithm(
            self):
        expected_message = "Invalid data or file"
        file_name = "test_xmls\\config_test_no_algorithm.xml"
        shutil.copy2(file_name, "..\\..\\config_test_no_algorithm.xml")
        config_test = XMLConfig(file_name)
        self.assertEquals(expected_message,
                          config_test.read_configuration_file())

    def test_read_configuration_file_returns_a_dictionary_of_configuration_if_valid_data(
            self):
        dict_configuration = {
            'space_char': '0',
            'output-type': 'file',
            'algorithm': 'backtracking',
            'output-path': 'results',
            'level': 'medium'
        }
        self.assertEquals(dict_configuration,
                          self.xml_config.read_configuration_file())

    ########### END read_configuration_file ##############

    #################################
    # Tests for: get_valid_data_game(self, file_path, xml_tag_path, attrib_name)
    #################################

    def test_get_valid_data_game_returns_list_of_levels_if_level_specified(
            self):
        expected_levels = ['easy', 'medium', 'hard']
        self.assertEquals(
            expected_levels,
            self.xml_config.get_valid_data_game(self.path_game_settings,
                                                'level', 'name'))

    def test_get_valid_data_game_returns_list_of_algorithms_if_algorithm_specified(
            self):
        expected_algorithms = ['backtracking', 'norvig', 'x']
        self.assertEquals(
            expected_algorithms,
            self.xml_config.get_valid_data_game(self.path_game_settings,
                                                'algorithm', 'name'))

    ########### END get_valid_data_game ##############

    #################################
    # Tests for: get_complexity(self)
    #################################

    def test_get_complexity_returns_error_message_if_level_tag_does_not_exist(
            self):
        expected_message = "Tag is missing!"
        file_config = open(self.xml_config.path_name, 'w')
        file_config.write('<config><tessst>')
        file_config.close()
        self.assertEquals(expected_message, self.xml_config.get_complexity())

    def test_get_complexity_returns_complexity_value_if_value_exists(self):
        expected_default_level = 'medium'
        self.assertEquals(expected_default_level,
                          self.xml_config.get_complexity())

    ########### END get_complexity ##############

    #################################
    # Tests for: modify_complexity(self, complexity)
    #################################

    def test_modify_complexity_returns_error_message_if_level_tag_does_not_exist(
            self):
        expected_message = "Tag is missing!"
        file_config = open(self.xml_config.path_name, 'w')
        file_config.write('<config><level>')
        file_config.close()
        self.assertEquals(expected_message,
                          self.xml_config.modify_complexity('hard'))

    def test_modify_complexity_returns_error_message_if_value_tag_does_not_exist(
            self):
        expected_message = "Tag is missing!"
        file_config = open(self.xml_config.path_name, 'w')
        file_config.write('<config><level>')
        file_config.close()
        self.assertEquals(expected_message,
                          self.xml_config.modify_complexity('hard'))

    def test_modify_complexity_returns_error_message_if_complexity_is_not_valid(
            self):
        expected_message = "Invalid complexity parameter"
        self.assertEquals(expected_message,
                          self.xml_config.modify_complexity('not-valid'))

    def test_modify_complexity_saves_new_complexity_in_config_file_if_complexity_is_valid(
            self):
        expected_complexity = 'hard'
        self.xml_config.modify_complexity('hard')
        current_complexity = self.xml_config.get_complexity()
        self.assertEquals(expected_complexity, current_complexity)

    ########### END modify_complexity ##############

    #################################
    # Tests for: get_output_type(self)
    #################################

    def test_get_output_type_returns_error_message_if_level_tag_does_not_exist(
            self):
        expected_message = "Tag is missing!"
        file_config = open(self.xml_config.path_name, 'w')
        file_config.write('<config><tessst>')
        file_config.close()
        self.assertEquals(expected_message, self.xml_config.get_output_type())

    def test_get_output_type_returns_output_type_value_if_value_exists(self):
        expected_default_output = 'file'
        self.assertEquals(expected_default_output,
                          self.xml_config.get_output_type())

    ########### END get_output_type ##############

    #################################
    # Tests for: modify_output_type(self, output_type)
    #################################

    def test_modify_output_type_returns_error_message_if_output_type_tag_does_not_exist(
            self):
        expected_message = "Tag is missing!"
        file_config = open(self.xml_config.path_name, 'w')
        file_config.write('<config><level>')
        file_config.close()
        self.assertEquals(expected_message,
                          self.xml_config.modify_output_type('console'))

    def test_modify_output_type_returns_error_message_if_path_tag_does_not_exist(
            self):
        expected_message = "Tag is missing!"
        file_config = open(self.xml_config.path_name, 'w')
        file_config.write('<config><level>')
        file_config.close()
        self.assertEquals(expected_message,
                          self.xml_config.modify_output_type('console'))

    def test_modify_output_type_returns_error_message_if_out_put_is_not_valid(
            self):
        expected_message = "Invalid output type parameter"
        self.assertEquals(expected_message,
                          self.xml_config.modify_output_type('not-valid'))

    def test_modify_output_type_saves_console_output_type_in_config_file_if_output_type_is_console(
            self):
        expected_output_type = 'console'
        self.xml_config.modify_output_type('console')
        current_output_type = self.xml_config.get_output_type()
        self.assertEquals(expected_output_type, current_output_type)

    ########### END modify_output_type ##############

    #################################
    # Tests for: write_value_to_xml(file_path, xml_path, new_value)
    #################################

    def test_write_value_to_xml_modifies_complexity_to_hard_in_config_file(
            self):
        expected_complexity = 'hard'
        self.xml_config.write_value_to_xml(self.xml_config.path_name,
                                           'level/value', 'hard')
        current_complexity = self.xml_config.get_complexity()
        self.assertEquals(expected_complexity, current_complexity)

    ########### END write_value_in_config_file ##############

    #################################
    # Tests for: get_value_from_xml(file_path, xml_path)
    #################################

    def test_get_value_from_xml_recovers_complexity_from_config_file(self):
        expected_complexity = 'medium'
        complexity = self.xml_config.get_value_from_xml(
            self.xml_config.path_name, 'level/value')
        self.assertEquals(expected_complexity, complexity)

    ########### END get_value_from_xml ##############

    #################################
    # Tests for: get_algorithm(self)
    #################################

    def test_get_algorithm_returns_error_message_if_algorithm_tag_does_not_exist(
            self):
        expected_message = "Tag is missing!"
        file_config = open(self.xml_config.path_name, 'w')
        file_config.write('<none>')
        file_config.close()
        self.assertEquals(expected_message, self.xml_config.get_algorithm())

    def test_get_algorithm_returns_default_algorithm_value_if_value_exists(
            self):
        expected_default_algorithm = 'backtracking'
        self.assertEquals(expected_default_algorithm,
                          self.xml_config.get_algorithm())

    ########### END get_algorithm ##############

    #################################
    # Tests for: modify_algorithm(self, algorithm):
    #################################

    def test_modify_algorithm_returns_error_message_if_algorithm_tag_does_not_exist(
            self):
        expected_message = "Tag is missing!"
        file_config = open(self.xml_config.path_name, 'w')
        file_config.write('<config><ss>')
        file_config.close()
        self.assertEquals(expected_message,
                          self.xml_config.modify_algorithm('backtracking'))

    def test_modify_algorithm_returns_error_message_if_algorithm_is_not_valid(
            self):
        expected_message = "Invalid algorithm parameter"
        self.assertEquals(expected_message,
                          self.xml_config.modify_algorithm('not-valid'))

    def test_modify_algorithm_saves_norvig_in_config_file_if_algorithm_is_norvig(
            self):
        expected_algorithm = 'norvig'
        self.xml_config.modify_algorithm('norvig')
        current_algorithm = self.xml_config.get_algorithm()
        self.assertEquals(expected_algorithm, current_algorithm)

    ########### END modify_algorithm ##############

    def tearDown(self):
        shutil.copy2('copy_config.xml', self.xml_config.path_name)
        os.remove('copy_config.xml')

        shutil.copy2('copy_game_settings.xml', self.path_game_settings)
        os.remove('copy_game_settings.xml')

        test_output = os.path.abspath("..\\..\\config_test_no_ouput_type.xml")
        if os.path.isfile(test_output):
            os.remove(test_output)

        test_algorithm = os.path.abspath(
            "..\\..\\config_test_no_algorithm.xml")
        if os.path.isfile(test_algorithm):
            os.remove(test_algorithm)