Hi, new to the forum,

I am currently studying the basics of C++ and we have an assignment in which we have to code a Sudoku validator. Basically the validator will ask for a file to be input, it will read the file and the user will be able to input options: 1) check columns, 2) check rows and 3) check minigrids and of course a display option.

I've gotten the check rows and check mini grids right... or at least I think. However, I am really stuck on the minigrids part. I know the code I computed here is wrong. I have searched for assistance online, but always come to a deadend. Can someone just point how the logic behind it (as in the pseudocode [not the actual code]).

Also, another question here is that the program is also supposed to read some files where there are some char, and it will point out where the char is, I think I know the logic behind this, however, if I change all my grid variables to 'char', when I try to compare the columns and rows, it says that the rows and columns all match, when in reality they shouldn't...

EDIT: We can only use 2D arrays here, no pointers, queues, stacks, vectors, etc... (I don't know how to do it because we haven't learn them yet)

// Purpose of program
// Sudoku Validator: checks rows, columns and minigrids to ensure that each row, column
// and minigrid contains no duplicates
// Program written by
// Eric Cheung, 40745708

#include <cstdlib>
#include <iostream>
#include <fstream>
#include <string>

using namespace std;

void printMenu();
bool readGrid(string fName, int grid[9][9]); //function to load and read the input files
int displayGrid(int grid[][9]); //function to display grid
bool checkColumns (int grid[][9]); //function to check columns for duplicates
bool checkRow (int grid[][9]); //function to check rows for duplcates
bool checkMini (int grid[][9]); // function to check minigrids for duplicates



int main()
{
         
     int grid[9][9];  //9X9 grid
    
     string fName;  //file name
     char choice = '*';
     while (choice != 'Q')
     {
         printMenu();
         cin >> choice; 
         switch (toupper(choice))
         {
                case 'L' :  cout << "Enter file name" << endl;
                            cin >> fName;  //enter file name
                            if( !readGrid(fName, grid)) //if function readGrid returns a false scenario
                            cout << "invalid file input!" << endl;
                            break;                            
                case 'D' :  displayGrid (grid);
                            break;
                case 'R' :  if (!checkRow(grid)) //if function checkRow returns a false scenario, it will output the required message as coded in the function
                            break;
                            else
                            cout << "All Rows are correct." << endl; //message to ouput for the true scenario
                            break;
                case 'C' :  if(!checkColumns(grid))  ////if function checkColumnsreturns a false scenario, it will output the required message as coded in the function
                            break;
                            else
                            cout << "All Columns are correct." << endl;  //message to output for the true scenario
                            break;
                case 'M' :  if (!checkMini(grid))
                            break;
                            else
                            cout << "All Minigrids are correct."<< endl;  //message to output for the true scenario
                case 'Q' : break;
                default :  cout << "Invalid option " << endl; cin.ignore(100,'\n');
         }

     }     
         
    return 0;
}


void printMenu()
{
     cout << "\n\tSudoku Checker " << endl << endl;
     cout << "\t L\t Load file " << endl;
     cout << "\t D\t Display " << endl;
     cout << "\t C \t Check columns " << endl;
     cout << "\t R \t Check rows " << endl;
     cout << "\t M \t Check minigrids" << endl;
     cout << "\t Q\t Quit " << endl;
     cout << " Rows and columns are labelled from 0 to 8 " << endl;
     cout << endl;
}

bool readGrid(string fName, int grid[9][9])
{
     ifstream fileName;
     
     fileName.open(fName.c_str());
     
     if (! fileName)  //if file doesn't not exist
        return false;
        
     while (! fileName.eof())  //if file is detected, fill in the array for grid
     {
           for (int i = 0; i < 9; i++)
           for (int j = 0; j < 9; j++)                        
           fileName >> grid[i][j];
     }
     return true;
}

      
int displayGrid(int grid[][9])
{
	for (int row = 0; row < 9; row++)  //2D array to go through both rows and columns
	{
		for (int col = 0; col < 9; col++)
		{
			cout << grid[row][col] << " "; //fill in the sudoku grid (seperated by a space)
        }
		cout << endl;
	}
}

bool checkRow (int grid[][9])
{
     bool status = true;  //a status check
     for (int row = 0; row<9; row++) // go through the rows of the 9X9 grid)
     {
         for (int check =1; check <9; check++) //a check variable to compare the rows
         {
             int occurance = 0;  // a flag
             for (int column = 0; column <9; column++) //go through each column of the 9X9 grid)
             {
                 if (grid[row][column] == check) // if the cell matches the number in the check variable
                 {
                    occurance++;  //increase the occurance flag to output the result
                 }
             }
             if (occurance > 1)  //if there are more than one occurances
             {
                 cout << "Row " << row << " is incorrect!" << endl;
                 status = false;
             }
         }
       
     }
     return status; 
}


bool checkColumns (int grid[][9])
{
     bool status2 = true;  //a status check
     for (int column = 0; column<9; column++)  // go through the columns of the 9X9 grid)
     {
         for (int check =1; check <9; check++)  //a check variable to compare the columns
         {
             int occurance = 0;
             for (int row = 0; row<9; row++)  // go through the rows of the 9X9 grid)
             {
                 if (grid[row][column] == check)  // if the cell matches the number in the check variable
                 {
                    occurance++;
                 }
             }
             if (occurance > 1)
             {
                 cout << "Column " << column << " is incorrect!" << endl;
                 status2 = false;
             }
         }
       
     }
     return status2; 
}


bool checkMini (int grid[][9])
{
     bool status3= true;
     int container[9];

     for (int row = 0; row < 9; row++)
     {
           for (int column = 0; column < 9; column ++)
          {
                
                {
                    int occurances = 0;
                    int MiniCol = (column/3)*3;  //calculates the minigrids for column (the 3 cells)
                    int MiniRow = (row/3)*3;  // calculates the minigrids for the row (the 3 cells)
             
                    for (int nextRow = 0; nextRow < MiniRow +3; nextRow++)  //loop to go through the 3X3 minigrids
                    {
                       for (int nextCol = 0; nextCol < MiniCol + 3; nextCol++)
                          {
                             container[9] == grid[row][column];                             
                             {
                                       if (grid[nextRow][nextCol] == container[9])
                                       {
                                          occurances++;
                                       }
                             }
                          }
                         
                        if (occurances > 1)
                    {
                       cout << "Incorrect minigrid starting at row " << row << " column " << column << "."<< endl;
                       status3 = false;
                    }    

                }
             
          }
      
     return status3;
     }
}
}

Please assist... very urgent! Been working on it for some time.

Thanks a lot.

I think I have also confirmed that confirm columns and rows are both incorrect... which was strange because I tried to output on one file and it worked, whereas another file checked that there was no similar rows or columns.... I will upload the files we were required to upload to the program...

in1.txt

5 8 9 6 4 7 2 1 3
6 2 4 3 1 9 5 7 8
1 3 7 5 8 2 9 6 4
9 5 8 7 3 1 4 2 6
2 7 1 4 6 8 3 5 9
4 6 3 9 2 5 1 8 7
3 1 2 8 7 4 6 9 5
8 4 5 2 9 6 7 3 1
7 9 6 1 5 3 8 4 2


in2.txt (this is the one that worked for the aforementioned program)
5 8 9 6 4 7 2 1 3
6 2 4 3 1 9 5 7 8
1 3 7 5 8 2 9 6 4
9 5 8 7 3 1 4 2 6
2 7 1 4 6 8 3 5 9
4 6 3 9 2 5 1 8 7
3 1 2 8 7 4 6 9 5
8 4 5 2 9 6 7 3 1
7 9 6 1 5 7 8 4 2

int.txt this is the one that was used by the marker to check my first checkpoint...

5 8 9 6 4 7 2 1 3
6 2 4 3 1 9 5 7 8
1 3 7 5 8 2 9 6 4
9 5 8 7 3 1 4 2 6
2 7 1 4 6 8 3 5 9
4 6 3 9 2 5 1 8 7
3 1 2 8 7 4 6 9 5
8 4 5 2 9 6 7 3 1
7 9 6 1 5 7 8 4 2

^ this is the one that did not work

Here is my suggestion for how to handle this. Regardless of if you are checking a column, row, or minigrid, you will always have 9 chars/ints/whatever to compare. I would make a char/int/whatever array of size 9, copy the contents of whatever I'm checking into that array, and then run through that array to make sure that there are no duplicates chars/ints/whatevers (meaning check 0 against 1-8; 1 against 2-8; 2 against 3-8, etc).

By doing it the way I have it, people could use ! @ # $ % ^ & * ( and make a sudoku using those symbols and still be able to tell if it was right or not simply because I'm checking using whatever I was given, not a hardcoded set. It would look similar to what you have, except you would probably just add another function that runs through that array and have all your check functions call it. But, yeah, that's just my suggestion.

For handling the mini grid, you can make your life easier on yourself. For simplicity, I'm have an image and I'm going across the top three grids. The first grid will deal with 0-2, the second with 3-5, and the third with 6-8. If you look at that, and mod every number by three, it leaves you with 0-2 (3%3 = 0, 7%3=1, etc). By using this, you could number your mini grids, and access the correct numbers in those mini grids just by adding 3 or 6 depending.

http://i21.photobucket.com/albums/b272/DemonGal711/Program%20Pic/1.png

The grid in image above shows my numbering and how that affects the position in the grid.

Mini grid: What to add (denotes row positions, denotes column positions)

Grid 1: Add nothing (0-2, 0-2)
Grid 2: Add 3 to row (3-5, 0-2)
Grid 3: Add 6 to row (6-8, 0-2)
Grid 4: Add 3 to col (0-2, 3-5)
Grid 5: Add 3 to col and 3 to row (3-5, 3-5)
Grid 6: Add 3 to col, 6 to row (6-8, 3-5)
Grid 7: Add 6 to col (0-2, 6-8)
Grid 8: Add 6 to col and 3 to row (3-5, 6-8)
Grid 9: Add 6 to col, 6 to row (6-8, 6-8)

See how it just repeats. It makes it nice for you cause all you tell the program is, if we are in grid 7, add 6 to the row number and 3 to the column number and your in the right grid. It would be something like this.

for (int z = 1; z < 10; z++)
{ int x = 0, y = 0;
  findMiniGrid(z, x, y);  // z is grid; x and y are either 0, 3, or 6.
  for (int i = 0; i < 3; i++)
      {  for (int j = 0; j < 3; j++)
              { grid[i+x][j+y] /*do something with this spot*/ ; } } }

That should visit every mini grid, and go through every position on said mini grid. You still have to code the findMiniGrid function, but I gave you the list above so, if you followed my madness, it's practically done.

That's excellent! I'll give it ago...

BTW I found out why I was getting some outputs wrong and some outputs right when I was comparing columns and rows of different sudoku files. Apparently, some files are really extended... for example:

7 1 9 8 3 5 2 4 6
4 2 8 7 1 6 9 5 3
3 5 6 2 9 4 7 1 9
5 7 2 4 6 8 1 3 9
6 3 1 9 7 2 5 8 4
8 9 4 3 5 1 6 7 2
2 4 7 1 8 9 3 6 5
1 8 5 6 2 3 4 9 7
9 6 3 5 4 7 8 2 1
5 8 9 6 4 7 2 1 3
6 2 4 3 1 9 5 7 8
1 3 7 5 8 2 9 6 4
9 5 8 7 3 1 4 2 6
2 7 1 4 6 8 3 5 9
4 6 3 9 2 5 1 8 7
3 1 2 8 7 4 6 9 5
8 4 5 2 9 6 7 3 1
7 9 6 1 5 3 8 4 2

This is more than 81... I think that I need to include an if case in my printGrid function so that if a situation as such arises, it will print from the beginning and not half way through... but I'm not sure how to arrange my loop and my if case... any help there? I really can't think of anything.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.