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])
{
}