0

So, I'm working on a project for my Intro to Software Development course; it's a sudoku puzzle program. So far, I've encountered two big bugs:
1.) When I wrote the code in Visual C++, the display worked fine(it showed up on the
screen as a normal puzzle), but when I copied it over to linux, it displays an
entire line of the input file where only a single digit should go...Can anybody
help me out with that?
2.) At the main menu, after selecting 'e' to edit a square, it tells me that the input
coordinate is not valid. I'm not sure where the problem is there, either

Besides those two major bugs, it appears that everything else is working just fine for the time being. I'd very much appreciate any help that anyone can offer! Thanks a bunch!

(I have yet to develop the algorithms for solving the puzzle, so the last few function definitions are left empty intentionally)

#include <iostream>
#include <iomanip>
#include <fstream>
#include <cstdlib>
#include <cassert>

using namespace std;

void getFileName(char fileName[], bool read);
void readFile(char fileName[], int sudokuBoard[][9]);
void fileError(int error, int sudokuBoard[][9]);
void errorOptions(int sudokuBoard[][9]);
void validateBoard(int sudokuBoard[][9]);
void solutionAlgorithm(int sudokuBoard[][9]);
void display(int sudokuBoard[][9]);
void interact(int sudokuBoard[][9]);
void writeFile(int sudokuBoard[][9]);
void randomSudokuBoard(int sudokuBoard[][9]);
void editSquare(int sudokuBoard[][9]);
void possibleValues(int sudokuBoard[][9]);
void setSquareValue(int sudokuBoard[][9], char option[2], int value);
void quit();

/**********************************************************************
* the main function. lean and efficient
*
* PSUEDOCODE
*
*	FUNCTION main
*		RUN getFileName
*		RUN readFile
*		RUN interact
*	END FUNCTION
***********************************************************************/
int main()
{
	// set the filename and sudokuBoard variables to be used in the
	// program
	char fileName[256];
	int sudokuBoard[9][9];
	
	// get the filename with the read file parameter
	getFileName(fileName, true);
	
	// read the file
	readFile(fileName, sudokuBoard);
	
	// interact with the board
	interact(sudokuBoard);
	
   return 0;
}

/**********************************************************************
* this is the function i use to get all file names. a simple bool will
* decide whether or not it is reading the file or writing the file
*
* PSUEDOCODE ::
*
*	FUNCTION getFileName
*		IF read
*			DISPLAY board location prompt
*		ELSE
*			DISPLAY file save prompt
*		GET fileName
*	END FUNCTION
***********************************************************************/
void getFileName(char fileName[], bool read)
{
	// if the read parameter is true display a message geared towards
	// getting the file name to be read in
	if (read)
		cout << "Where is your board located? ";
	
	// if the read parameter is false display a message geared towards
	// getting the file name the users wants the program to write the
	// board to
	else
		cout << "What would you like to save your file as? ";
		
	// get the file name
	cin >> fileName;
}

/**********************************************************************
* this function will check whether or not the file is a sudoku board 
* and then if it is, it reads it into a 2D array.
*
* Psueadocode
*
*	FUNCTION readFile
*		OPEN fileName
*		IF fin.fail
*			RUN fileError :: 1
*		ELSE IF empty file
*			RUN fileError :: 2
*		ELSE
*			FOR :: row IS 0; row LESS THAN 9; ADD 1 TO row
*				FOR :: column IS 0; column LESS THAN 9; ADD 1 TO column
*					SET sudokuBoard[row][column] TO next number in file
*				END FOR
*			END FOR
*		END IF
*		CLOSE fileName
*	END FUNCTION
***********************************************************************/
void readFile(char fileName[], int sudokuBoard[][9])
{
	// open the file
	ifstream fin(fileName);
	
	// create a test buffer
	int test = NULL;
	
	// if the file opening fails
	if (fin.fail())
	{
		// run the fileError function with the parameter 1
		fileError(1, sudokuBoard);
	}
	
	// if the file is empty
	else if (!fin >> test)
	{
		// run the fileError function with the parameter 2
		fileError(2, sudokuBoard);
	}
	
	// otherwise
	else
	{
		// write each item in the file to the 2D sudoku array
		for (int row = 0; row < 9; row++)
			for (int column = 0; column < 9; column++)
				fin >> sudokuBoard[row][column];
	}
	
	// close the file
	fin.close();
}

/**********************************************************************
* handles my file error display
*
* PSUEDOCODE
*
*	FUNCTION fileError
*		ASSERT error IS 1 OR 2
*		IF error IS 1
*			DISPLAY bad load message
*			RUN errorOptions
*		ELSE
*			DISPLAY empty file message
*			RUN errorOptions
*		END IF
*	END FUNCTION
***********************************************************************/
void fileError(int error, int sudokuBoard[][9])
{
	// i want to have an assert to make sure the value being brought
	// in is what i wrote the other functions to send... a 1 or a 2
	assert(error == 1 || error == 2);
	
	// if the error equals 1, it is the first type of error which is a
	// corrupt file error
	if (error == 1)
	{
		cout << "It seems that there was a problem opening the file.\n";
		
		// go to the errorOptions function after i have displayed what
		// error occurred
		errorOptions(sudokuBoard);
	}
	
	// otherwise it must be error 2 and thus is the second type of
	// error, an empty file error
	else
	{
		cout << "It seems that your file is empty.\n";
		
		// go to the errorOptions function after i have displayed what
		// error occurred
		errorOptions(sudokuBoard);
	}
}

/**********************************************************************
* handles the error options screen choices. this is to humor myself. 
*
* PSUEDOCODE
*
*	FUNCTION errorOptions
*		DISPLAY error options
*		GET choice
*		WHILE choice IS INVALID
*			DISPLAY invalid choice message
*			GET choice
*		END WHILE
*		IF choice IS n OR N
*			RUN main
*		ELSE IF choice IS c OR C
*			RUN randomSudokuBoard(sudokuBoard)
*		ELSE
*			RUN quit
*		END IF
*	END FUNCTION
***********************************************************************/
void errorOptions(int sudokuBoard[][9])
{
	// create an empty choice variable to store the users choice in
	char choice;
	
	// display the options available to the user
	cout << "Error options\n"
		 << "\tN  Enter a new filename\n"
		 << "\tC  Create a random sudoku board\n"
		  << "\tQ  Quit the application\n"
		  << "> ";
	
	// get the choice
	cin >> choice;
	
	// if the choice is invalid (aka it's not one of the predefined
	// options) ask the user to choose again
	while (choice != 'n' || choice != 'N' 
		|| choice != 'c' || choice != 'C' 
		|| choice != 'q' || choice != 'Q')
	{
		cout << "Invalid choice. Please choose again.\n";
		cout << "> ";
		cin >> choice;
	
	// now that we know it is a valid choice we need to act upon that
	// choice
	
	// if choice is a n we want to get a new filename. the most simple
	// way to do this is to call the main function and start all over
	if (choice == 'n' || choice == 'N')
		main();
		
	// if the choice is c we want to create a new random sudoku board
	else if (choice == 'c' || choice == 'C')
		randomSudokuBoard(sudokuBoard);
	else
		quit();
	}
}

/**********************************************************************
* quits the program using the exit hack
*
* PSUEDOCODE
*
*	FUNCTION quit
*		RUN exit(1)
*	END FUNCTION
***********************************************************************/
void quit()
{
	// exit the entire program
	exit(1);
}

/**********************************************************************
* interaction screen. used to edit, view, and solve the sudoku board
*
* PSUEDOCODE
*
*	FUNCTION interact
*		DISPLAY options
*		GET choice
*		WHILE choise IS INVALID
*			DISPLAY options
*			GET choice
*		END WHILE
*		IF choice IS ?
*			RUN interact
*		ELSE IF choice IS d OR D
*			RUN display
*		ELSE IF choice IS e OR E
*			RUN editSquare
*		ELSE IF choice IS s OR S
*			RUN possibleValues
*		ELSE
*			RUN writeFile
*			RUN quit
*		END IF
*	END FUNCTION
***********************************************************************/
void interact(int sudokuBoard[][9])
{
	while(true) 
	{ // loop forever, it's simplest
		char choice;
		cout << "Options: \n"
			 << "   ?  Show these instructions\n"
			 << "   D  Display the board\n"
			 << "   E  Edit one square\n"
			 << "   S  Show the possible values for a square\n"
			 << "   Q  Save and quit\n"
			  << "   > ";
		cin >> choice;
		
		// there's no need to validate here, if the choice doesn't match
		// any valid ones, we tell them then
		
		if (choice == '?') 
			;
		 else if (choice == 'd' || choice == 'D' )
			display(sudokuBoard);
		 else if (choice == 'e' || choice == 'E' )
			editSquare(sudokuBoard);
		 else if (choice == 's' || choice == 'S' )
			possibleValues(sudokuBoard);
		 else if (choice == 'q' || choice == 'Q' )
			break; // we can leave the eternal loop
		 else 
			cout << "ERROR: Invalid command\n";
	}
	
	writeFile(sudokuBoard);
	quit();

	return;
}



/**********************************************************************
* displays the sudoku board in the proper format
*
* PSUEDOCODE
*
*	FUNCTION display
*		DISPLAY A - I
*		FOR :: row IS 0; row < 9; ADD 1 TO row
*			DISPLAY 1 more than row
*			FOR :: column IS 0; column < 9; ADD 1 TO column
*				IF sudokuBoard[row][column] IS 0
*					DISPLAY spacing
*				ELSE
*					DISPLAY sudokuBoard[row][column]
*				END IF
*				IF column IS 2 OR column IS 5
*					DISPLAY |
*				ELSE 
*					DISPLAY spacing
*				END IF
*			END FOR
*			IF row IS 2 OR row IS 5
*				DISPLAY breaker
*			ELSE
*				DISPLAY new line
*			END IF
*		END FOR
*	END FUNCTION
***********************************************************************/
void display(int sudokuBoard[][9])
{
	// the columns
	cout << "   " << "A B C D E F G H I\n";
	
	// for loops to display each and every value in sudokuBoard
	for (int row = 0; row < 9; row++)
	{
		// display the rows as the come up
		cout << row + 1 << "  ";
		for (int column = 0; column < 9; column++)
		{
			// if the value in sudokuBoard[row][column] is 0 display a
			// space instead
			if (sudokuBoard[row][column] == 0)
				cout << " ";
				
			// otherwise display the value in sudokuBoard[row][column]
			else
				cout << sudokuBoard[row][column];
			
			// if it is at the end of the first box or the second box
			// we need a breaker to distinguish parts of the grid from
			// eachother
			if (column == 2 || column == 5)
				cout << "|";
			
			// however if it is not a simple space will suffice
			else
				cout << " ";
		}
		
		// if it is at the end of the first row of boxes or the
		// second row of boxes a line will be displayed
		if (row == 2 || row == 5)
			cout << "\n   -----+-----+-----\n";
		
		// otherwise lets go to the next line
		else
			cout << endl;
	}
}

/**********************************************************************
* edits the square the user wants
*
* PSUEDOCODE
*
* FUNCTION editSquare
*		DISPLAY what cooridnates
*		GET coordinate
*		IF coordinate IS INVALID
*			DISPLAY error message
*		ELSE
*			DISPLAY what value
*			GET value
*			IF value < 1 OR > 9
*				DISPLAY error message
*			ELSE
*				IF coordinate[0] > 9
*					SET first TO coordinate[0]
*					SET last TO coordinate[1]
*					SET bCoordinate TO first
*					SET first TO last
*					SET coordinate[0] TO last
*					SET coordinate[1] TO bCoordinate
*				END IF
*				LOWERCASE coordinate[1]
*				SET sudokuBoard[coordinate[0] - 48][coordinate[1] - 87]
*					TO value
*			END IF
*		END IF
*	END FUNCTION
***********************************************************************/
void editSquare(int sudokuBoard[][9])
{
	// coordinate variable.
	char coordinate[2];

	// a message to get the users input
	cout << "What are the coordinates of the square: ";
	
	// getline is used because two items are being entered at once
	cin >> coordinate[2];
	
	// this is self explanitory if you just look at it. basically what
	// it does is checks if the items entered by the user are a valid
	// coordinate or not. it checks for all variations of a coordinate
	// also
	if (((coordinate[0] < '1' || coordinate[0] > '9') ||
		(coordinate[0] < 'a' || coordinate[0] > 'i') ||
		(coordinate[0] < 'A' || coordinate[0] > 'I'))
		||
		(coordinate[1] < '1' || coordinate[1] > '9') ||
		(coordinate[1] < 'a' || coordinate[1] > 'i') ||
		(coordinate[1] < 'A' || coordinate[1] > 'I'))

		// if it is invalid an error must be displayed
		cout << "ERROR: Square '" << coordinate << "' is invalid\n";
	
	// if it is valid however, lets keep goin
	else
	{
		// a buffer variable to hold the new value
		int value;
		cout << "What is the value at '" << coordinate << "': ";
		
		// get the value from the user
		cin >> value;
		
		// if the value is not valid (10, 50, -1, 99, etc) an
		// error message will be displayed
		if (value < 1 || value > 9)
		{
			cout << "ERROR: Value '" 
				 << value 
				 << "' in square '" 
				 << coordinate 
				 << "' is invalid";
		}
		
		// if it is a valid number we must now save it to the proper
		// place in the sudokuBoard
		else
		{
			// it is easiest to convert the users inputed value into a
			// format that i define. this makes it so there is less code
			// for me to type when setting the value to its spot in the
			// sudoku board. the format that i want to end up with is 1a
			// not a1 or A1 or 1A
			
			// if the first item in the coordinate is greater than '9'
			// aka a letter i want to switch the items, thus flipping
			// the date around.
			if (coordinate[0] > '9')
			{
				// coordinate buffers
				int first = coordinate[0];
				int last = coordinate[1];
				
				// setting this to first is the same as setting it to
				// coordinate[0]
				int bCoordinate = first;
                                int aCoordinate = last;
				
				coordinate[0] = last;
                                coordinate[1] = first;
			}
			
			// now that we have the proper formatting lets set the last
			// item to lowercase
			coordinate[1] = tolower(coordinate[1]);
			
			// now setting the value is simple. the first item is a
			// number in char for so we cast it as an int (returning 
			// the ansi value for it) and then subtract the ansi value
			// for 0 (48) to get the number we want in numberical form
			// the same is done for the letter, however it uses the ansi
			// value for a (97) to get the numerical equivilent of the
			// letter. questions?
			sudokuBoard[(int)coordinate[0] - 48]
					   [(int)coordinate[1] - 97] = value;
		}
	}
}

/**********************************************************************
* write the file to a file
*
* PSUEDOCODE
*
*	FUNCTION writeFile
*		RUN getFileName :: write version
*		OPEN fileName
*		IF writing to file FAILS
*			DISPLAY error message
*			RUN writeFile
*		ELSE
*			FOR :: row IS 0; row < 9; ADD 1 TO row
*				FOR :: column IS 0; column < 9; ADD 1 TO column
*					WRITE sudokuBoard[row][column]
*				END FOR
*				WRITE new line
*			END FOR
*			DISPLAY write success
*		END IF
*		CLOSE fileName
*	END FUNCTION
***********************************************************************/
void writeFile(int sudokuBoard[][9])
{
	// create a fileName container
	char fileName[256];
	
	// get the file name with the write file parameter (!read)
	getFileName(fileName, false);
	
	// open the file
	ofstream fout(fileName);
	
	// if file opening failed
	if (fout.fail())
	{
		cout << "File writing failed.\n";
		// run writeFile again
		writeFile(sudokuBoard);
	}
	
	// otherwise the file opened so lets write to it
	else
	{
		// write each item in sudokuBoard to the file with a new line
		// every 9 numbers so that we end up with a 9 X 9 board in the
		// file
		for (int row = 0; row < 9; row++)
		{
			for (int column = 0; column < 9; column++)
				fout << sudokuBoard[row][column];
			fout << endl;
		}
		
		// display a message telling the user the board was written
		cout << "Board written successfully";
	}
	
	// close the file connection
	fout.close();
}

/**********************************************************************
* 
***********************************************************************/
void solutionAlgorithm(int sudokuBoard[][9])
{
	
}

/**********************************************************************
* 
***********************************************************************/
void randomSudokuBoard(int sudokuBoard[][9])
{
	
}

/**********************************************************************
* 
***********************************************************************/
void possibleValues(int sudokuBoard[][9])
{
	
}
2
Contributors
1
Reply
4
Views
7 Years
Discussion Span
Last Post by StuXYZ
0

Well I can't repeat the first error. the board looks fine.

The problem with the second error is a simple mistake, so no problem. You wrote this

char coordinate[2];
cout << "What are the coordinates of the square: ";
	
cin >> coordinate[2];  // ERROR HERE:

You input the value into the THIRD coordinate of the char array. There is NO boundary
checking and there is obviously for any input a buffer overflow.

Your conditional test for coordinate[0] and coordinate[1] looks wrong.
Test that with "11" "AA" entries and I think you will quickly find the problem.

Finally: If I get this to mark, I would be deducting serious marks for the excessive comments. Do you really really need to write the functions in peudo-code and then write the same function? Please unless you absolutely HAVE to have such a pointless comment, write a comment that says what the function is going to do e.g.

/*
  editSquare:
     
     Param sudokoBoard : sudoku board 9x9 array
   
   - Takes text entry of a coordinate square from the user
   - Set the value to be text entered value from the user.
   - Simple error checking (none based on sudoku rules).
*/

The code and the pseudo code are nearly the same, it doesn't help to say i++; // add one to i .

The principle is don't repeat code, and don't repeat code in the comments.

Obviously this is broken by every C++ book because they are trying to teach what the code means, but you know what the code means. Comment should be for the why and what, not how. e.g. Why do I want an to smooth this data, and that I am using a quadratic summation smoothing, but the code tells me that I am looping over all the points in the data, so no comment is necessary.

Sorry about the rant, had a bad code review today, with a junior dev. who has more than enough ability to have known better by now!

Edited by StuXYZ: n/a

This topic has been dead for over six months. Start a new discussion instead.
Have something to contribute to this discussion? Please be thoughtful, detailed and courteous, and be sure to adhere to our posting rules.