Ajout de sudoSolver.cpp - Simplification de la gestion des menus

This commit is contained in:
Jérôme Henry-Barnaudière - GeeHB 2024-01-09 15:27:42 +01:00
parent 72170f0e96
commit b0d79c4184
5 changed files with 649 additions and 649 deletions

View File

@ -13,6 +13,7 @@
- [ ] pour FX9680G ... ?
- [ ] getItem / setItem
- [x] _homeScreen()
- [ ] "Fermeture" après x sec.
- [x] icones
- [x] grids
- [x] Copie d'écran - *fxlink*

View File

@ -51,12 +51,12 @@ extern "C" {
// "Solve" sub-menu bar
//
#define IDS_SOLVE_OBVIOUS "Obvious"
#define IDS_SOLVE_FIND "Resolve"
#define IDS_SOLVE_RESOLVE "Resolve"
#define IDS_SOLVE_REVERT "Revert"
#define IDM_SOLVE_SUBMENU 300
#define IDM_SOLVE_OBVIOUS 301
#define IDM_SOLVE_FIND 302
#define IDM_SOLVE_RESOLVE 302
#define IDM_SOLVE_REVERT 303
#ifdef __cplusplus

View File

@ -1,373 +1,373 @@
//----------------------------------------------------------------------
//--
//-- sudoSolver.cpp
//--
//-- Implementation of sudoSolver object
//--
//----------------------------------------------------------------------
#include "sudoSolver.h"
#include "sudoku.h"
extern bopti_image_t g_homeScreen; // Background image
// Construction
//
sudoSolver::sudoSolver(){
// Initialize members
_initStats();
}
// Destruction
//
sudoSolver::~sudoSolver(){
#ifndef NO_CAPTURE
if (_capture.isSet()){
_capture.remove(); // stop "capture" on exit
}
#endif // #ifndef NO_CAPTURE
}
// Create app. menu bar
//
void sudoSolver::createMenu(){
// "File" sub menu
menuBar fileMenu;
fileMenu.appendItem(IDM_FILE_NEW, IDS_FILE_NEW);
fileMenu.appendItem(IDM_FILE_PREV, IDS_FILE_PREV, ITEM_STATE_INACTIVE);
fileMenu.appendItem(IDM_FILE_NEXT, IDS_FILE_NEXT, ITEM_STATE_INACTIVE);
fileMenu.appendItem(IDM_FILE_SAVE, IDS_FILE_SAVE, ITEM_STATE_INACTIVE);
fileMenu.appendItem(IDM_FILE_DELETE, IDS_FILE_DELETE, ITEM_STATE_INACTIVE);
menu_.appendSubMenu(&fileMenu, IDM_FILE_SUBMENU, IDS_FILE_SUBMENU);
menu_.appendItem(IDM_EDIT, IDS_EDIT);
// "Solve" sub menu
menuBar sMenu;
sMenu.appendItem(IDM_SOLVE_OBVIOUS, IDS_SOLVE_OBVIOUS);
sMenu.appendItem(IDM_SOLVE_FIND, IDS_SOLVE_FIND);
sMenu.addItem(MENU_POS_RIGHT - 1, IDM_SOLVE_REVERT, IDS_SOLVE_REVERT);
menu_.appendSubMenu(&sMenu, IDM_SOLVE_SUBMENU, IDS_SOLVE_SUBMENU);
menu_.addItem(MENU_POS_RIGHT, IDM_QUIT, IDS_QUIT);
menu_.update();
}
// showHomeScreen() : Display home screen
//
void sudoSolver::showHomeScreen(){
drect(0, 0, CASIO_WIDTH, CASIO_HEIGHT - menu_.getHeight(), C_WHITE);
dimage(0, 0, &g_homeScreen);
char copyright[255];
strcpy(copyright, APP_NAME);
strcat(copyright, " par ");
strcat(copyright, APP_AUTHOR);
strcat(copyright, " v");
strcat(copyright, APP_VERSION);
int w, h;
dsize(copyright, NULL, &w, &h);
dtext(CASIO_WIDTH - w - 5,
CASIO_HEIGHT - menu_.getHeight() - h - 10, C_BLACK,
copyright);
dupdate();
}
// browseGridFolder() : Browse the folder containing grid files
//
void sudoSolver::browseGridFolder(){
// List of grid files
if (files_.browse() > 0){
_updateFileItemsState();
}
}
// run() : Edit / solve sudoku(s)
//
void sudoSolver::run(void)
{
// Start sudoku solver object
RECT mainRect;
menu_.getRect(mainRect);
mainRect = {0, 0, mainRect.w, CASIO_HEIGHT - mainRect.h};
sudoku game(&mainRect);
// Handle user's choices
bool end(false);
int error(FILE_NO_ERROR);
MENUACTION action;
while (!end){
// A menu action ?
action = menu_.handleKeyboard();
// push a menu key ?
if (ACTION_MENU == action.type){
switch (action.value){
// (re)start with a new empty grid
case IDM_FILE_NEW:
game.empty();
game.display();
_initStats();
break;
// Load previous file
case IDM_FILE_PREV:
if (files.prevFile(fileName)){
_updateFileItemsState();
// Update grid on screen
if (FILE_NO_ERROR == (error = game.load(fileName))){
game.display(false);
_getShortFileName();
_displayStats(sFileName, -1, -1);
}
else{
dprint(TEXT_X, TEXT_V_OFFSET, C_RED, "Error loading file : %d", (int)error);
dupdate();
}
}
break;
// Load next file
case IDM_FILE_NEXT:
if (files.nextFile(fileName)){
_updateFileItemsState();
// Update grid on screen
if (FILE_NO_ERROR == (error = game.load(fileName))){
game.display(false);
_getShortFileName();
_displayStats(sFileName, -1, -1);
}
else{
dprint(TEXT_X, TEXT_V_OFFSET, C_RED, "Error loading file : %d", (int)error);
dupdate();
}
}
break;
// Save the grid
case IDM_FILE_SAVE:
{
bool fileExists(sFileName[0]);
int uid;
// Use current name or new name if none
if (fileExists || (!fileExists && files.getNewFileName(fileName, &uid))){
if (FILE_NO_ERROR == (error = game.save(fileName))){
if (!fileExists){
_setFileName(fileName, sFileName);
_displayStats(sFileName, -1, -1);
// Update internal list
files.browse();
files.setPos(files.findPos(uid)); // select the file
menu.activate(IDM_FILE_NEXT, SEARCH_BY_ID, false);
menu.activate(IDM_FILE_PREV, SEARCH_BY_ID, files.size()>1);
}
menu.activate(IDM_FILE_SAVE, SEARCH_BY_ID, false);
menu.activate(IDM_FILE_DELETE, SEARCH_BY_ID, true);
menu.update();
} // save
else{
dprint(TEXT_X, TEXT_V_OFFSET, C_RED, "Error saving : %d", error);
dupdate();
}
}
break;
}
// Remove current file
case IDM_FILE_DELETE:
if (files.deleteFile()){
bool file(true);
if (!files.prevFile(fileName)){
menu.activate(IDM_FILE_PREV, SEARCH_BY_ID, false);
if (!files.nextFile(fileName)){
menu.activate(IDM_FILE_NEXT, SEARCH_BY_ID, false);
menu.activate(IDM_FILE_DELETE, SEARCH_BY_ID, false);
game.empty();
file = false; // No filename
}
menu.update();
}
_setFileName(file?fileName:NULL, sFileName);
_displayStats(sFileName, -1, -1);
}
break;
// Modify current grid
case IDM_EDIT:{
game.display();
if (game.edit()){
menu.activate(IDM_FILE_SAVE, SEARCH_BY_ID, true);
_displayStats(sFileName, -1, -1);
}
menu.selectByIndex(-1);
menu.update(); // redraw the whole menu bar
break;
}
// Search for obvious values
case IDM_SOLVE_OBVIOUS:{
obviousVals = game.findObviousValues();
game.display(false);
_displayStats(sFileName, obviousVals, -1);
break;
}
// Try to find a solution
case IDM_SOLVE_FIND:
game.display();
if (!game.resolve(&duration)){
// No soluce found ...
// ... return to original grid
game.revert();
}
game.display(false);
_displayStats(sFileName, obviousVals, duration);
break;
// Return to "original" grid
case IDM_SOLVE_REVERT:
game.revert();
game.display(false);
obviousVals = -1;
_displayStats(sFileName, -1, -1);
break;
// Quit the application
case IDM_QUIT:
end = true;
break;
default:
break; // ???
} // switch
}else{
// From keyboard (and not handled by the menu)
if (ACTION_KEYBOARD == action.type){
switch (action.value){
// Return to main menu
case KEY_MENU:
end = true;
break;
// Activate or deactivate screen capture
#ifndef NO_CAPTURE
case KEY_CODE_CAPTURE:
if (action.modifier == MOD_SHIFT){
if (!_capture.isSet()){
_capture.install();
}
else{
_capture.remove();
}
}
break;
#endif // #ifndef NO_CAPTURE
default:
break;
} // switch (action.value)
}
}
}
}
//
// Internal methods
//
// _initStats() : initialize grid stats
//
void sudoSolver::_initStats(){
fileName_[0] = 0x0000;
sFileName_[0] = '\0';
obviousVals_ = -1;
duration_ = -1;
}
// _updateFileItemsState() : Item's state
//
// @modified : Has the grid been edited (changed) ?
//
void sudoSolver::_updateFileItemsState(bool modified){
int count(files_.size());
int pos(files_.pos());
bool bPrev, bNext, bSave, bDelete;
if (!count){
bPrev = bNext = bSave = bDelete = false;
}
else{
bPrev = (pos>0); // Not the first in list ?
bNext = (pos < (count - 1)); // Not the last in list
bSave = modified;
bDelete = (sFileName_[0]);
}
menu_.activate(IDM_FILE_PREV, SEARCH_BY_ID, bPrev);
menu_.activate(IDM_FILE_NEXT, SEARCH_BY_ID, bNext);
menu_.activate(IDM_FILE_SAVE, SEARCH_BY_ID, bSave);
menu_.activate(IDM_FILE_DELETE, SEARCH_BY_ID, bDelete);
menu_.update();
}
// _getShortFileName() : Get short filename from FQN
//
void sudoSolver::_getShortFileName(){
if (bFile::FC_len(fileName_)){
char fName[BFILE_MAX_PATH + 1];
bFile::FC_FC2str(fileName_, fName);
char* name = strrchr(fName, CHAR_PATH_SEPARATOR);
strcpy(sFileName_, (name?++name:fName)); // No path ?
}
else{
sFileName_[0] = '\0'; // No filename
}
}
// _displayStats() : Display grid's stats
//
void sudoSolver::_displayStats(const char* fName, int8_t obvious, int elapse){
if (fName && fName[0]){
dprint(TEXT_X, TEXT_Y, C_BLACK, "File : %s", fName);
}
if (obvious != -1){
if (obvious){
dprint(TEXT_X, TEXT_Y + TEXT_V_OFFSET, C_BLACK, "%d obvious values", obvious);
}
else{
dtext(TEXT_X, TEXT_Y + TEXT_V_OFFSET, C_BLACK, "No obvious value");
}
}
if (elapse != -1){
if (elapse){
dprint(TEXT_X, TEXT_Y + 2*TEXT_V_OFFSET, C_BLACK, "Solved in %d ms", elapse);
}
else{
dprint(TEXT_X, TEXT_Y + 2*TEXT_V_OFFSET, C_BLACK, "No solution found");
}
}
dupdate();
}
// EOF
//----------------------------------------------------------------------
//--
//-- sudoSolver.cpp
//--
//-- Implementation of sudoSolver object
//--
//----------------------------------------------------------------------
#include "sudoSolver.h"
#include "sudoku.h"
extern bopti_image_t g_homeScreen; // Background image
// Construction
//
sudoSolver::sudoSolver(){
// Initialize members
_initStats();
}
// Destruction
//
sudoSolver::~sudoSolver(){
#ifndef NO_CAPTURE
if (_capture.isSet()){
_capture.remove(); // stop "capture" on exit
}
#endif // #ifndef NO_CAPTURE
}
// Create app. menu bar
//
void sudoSolver::createMenu(){
// "File" sub menu
menuBar fileMenu;
fileMenu.appendItem(IDM_FILE_NEW, IDS_FILE_NEW);
fileMenu.appendItem(IDM_FILE_PREV, IDS_FILE_PREV, ITEM_STATE_INACTIVE);
fileMenu.appendItem(IDM_FILE_NEXT, IDS_FILE_NEXT, ITEM_STATE_INACTIVE);
fileMenu.appendItem(IDM_FILE_SAVE, IDS_FILE_SAVE, ITEM_STATE_INACTIVE);
fileMenu.appendItem(IDM_FILE_DELETE, IDS_FILE_DELETE, ITEM_STATE_INACTIVE);
menu_.appendSubMenu(&fileMenu, IDM_FILE_SUBMENU, IDS_FILE_SUBMENU);
menu_.appendItem(IDM_EDIT, IDS_EDIT);
// "Solve" sub menu
menuBar sMenu;
sMenu.appendItem(IDM_SOLVE_OBVIOUS, IDS_SOLVE_OBVIOUS);
sMenu.appendItem(IDM_SOLVE_RESOLVE, IDS_SOLVE_RESOLVE);
sMenu.addItem(MENU_POS_RIGHT - 1, IDM_SOLVE_REVERT, IDS_SOLVE_REVERT);
menu_.appendSubMenu(&sMenu, IDM_SOLVE_SUBMENU, IDS_SOLVE_SUBMENU);
menu_.addItem(MENU_POS_RIGHT, IDM_QUIT, IDS_QUIT);
menu_.update();
}
// showHomeScreen() : Display home screen
//
void sudoSolver::showHomeScreen(){
drect(0, 0, CASIO_WIDTH, CASIO_HEIGHT - menu_.getHeight(), C_WHITE);
dimage(0, 0, &g_homeScreen);
char copyright[255];
strcpy(copyright, APP_NAME);
strcat(copyright, " par ");
strcat(copyright, APP_AUTHOR);
strcat(copyright, " v");
strcat(copyright, APP_VERSION);
int w, h;
dsize(copyright, NULL, &w, &h);
dtext(CASIO_WIDTH - w - 5,
CASIO_HEIGHT - menu_.getHeight() - h - 10, C_BLACK,
copyright);
dupdate();
}
// browseGridFolder() : Browse the folder containing grid files
//
void sudoSolver::browseGridFolder(){
// List of grid files
if (files_.browse() > 0){
_updateFileItemsState();
}
}
// run() : Edit / solve sudoku(s)
//
void sudoSolver::run(void)
{
// Start sudoku solver object
RECT mainRect;
menu_.getRect(mainRect);
mainRect = {0, 0, mainRect.w, CASIO_HEIGHT - mainRect.h};
sudoku game(&mainRect);
// Handle user's choices
bool end(false);
int error(FILE_NO_ERROR);
MENUACTION action;
while (!end){
// A menu action ?
action = menu_.handleKeyboard();
// push a menu key ?
if (ACTION_MENU == action.type){
switch (action.value){
// (re)start with a new empty grid
case IDM_FILE_NEW:
game.empty();
game.display();
_initStats();
break;
// Load previous file
case IDM_FILE_PREV:
if (files_.prevFile(fileName_)){
_updateFileItemsState();
// Update grid on screen
if (FILE_NO_ERROR == (error = game.load(fileName_))){
game.display(false);
_newFileName();
}
else{
dprint(TEXT_X, TEXT_V_OFFSET, C_RED, "Error loading file : %d", (int)error);
dupdate();
}
}
break;
// Load next file
case IDM_FILE_NEXT:
if (files_.nextFile(fileName_)){
_updateFileItemsState();
// Update grid on screen
if (FILE_NO_ERROR == (error = game.load(fileName_))){
game.display(false);
_newFileName();
}
else{
dprint(TEXT_X, TEXT_V_OFFSET, C_RED, "Error loading file : %d", (int)error);
dupdate();
}
}
break;
// Save the grid
case IDM_FILE_SAVE:
{
bool fileExists(sFileName_[0]);
int uid;
// Use current name or new name if none
if (fileExists || (!fileExists && files_.getNewFileName(fileName_, &uid))){
if (FILE_NO_ERROR == (error = game.save(fileName_))){
if (!fileExists){
// It's a new file
_newFileName();
// Update internal list
files_.browse();
files_.setPos(files_.findPos(uid)); // select the file
}
_updateFileItemsState();
} // save
else{
dprint(TEXT_X, TEXT_V_OFFSET, C_RED, "Error saving : %d", error);
dupdate();
}
}
break;
}
// Remove current file
case IDM_FILE_DELETE:
if (files_.deleteFile()){
bool file(true);
if (!files_.prevFile(fileName_)){
menu_.activate(IDM_FILE_PREV, SEARCH_BY_ID, false);
if (!files_.nextFile(fileName_)){
_updateFileItemsState();
game.empty();
file = false; // No filename
}
}
if (!file){
fileName_[0] = 0x0000;
}
_newFileName();
}
break;
// Modify current grid
case IDM_EDIT:{
game.display();
if (game.edit()){
_displayStats();
}
else{
game.revert();
}
menu_.selectByIndex(-1);
_updateFileItemsState();
break;
}
// Search for obvious values
case IDM_SOLVE_OBVIOUS:{
obviousVals_ = game.findObviousValues();
duration_ = -1;
game.display(false);
_displayStats();
break;
}
// Try to find a solution
case IDM_SOLVE_RESOLVE:
game.display();
if (!game.resolve(&duration_)){
// No soluce found ...
// ... return to original grid
game.revert();
}
game.display(false);
_displayStats();
break;
// Return to "original" grid
case IDM_SOLVE_REVERT:
game.revert();
game.display(false);
obviousVals_ = -1;
duration_ = -1;
_displayStats();
break;
// Quit the application
case IDM_QUIT:
end = true;
break;
default:
break; // ???
} // switch
}else{
// From keyboard (and not handled by the menu)
if (ACTION_KEYBOARD == action.type){
switch (action.value){
// Return to main menu
case KEY_MENU:
end = true;
break;
// Activate or deactivate screen capture
#ifndef NO_CAPTURE
case KEY_CODE_CAPTURE:
if (action.modifier == MOD_SHIFT){
if (!_capture.isSet()){
_capture.install();
}
else{
_capture.remove();
}
}
break;
#endif // #ifndef NO_CAPTURE
default:
break;
} // switch (action.value)
}
}
}
}
//
// Internal methods
//
// _initStats() : initialize grid stats
//
void sudoSolver::_initStats(bool whole){
if (whole){
fileName_[0] = 0x0000;
}
sFileName_[0] = '\0';
obviousVals_ = -1;
duration_ = -1;
}
// _updateFileItemsState() : Item's state
//
// @modified : Has the grid been edited (changed) ?
//
void sudoSolver::_updateFileItemsState(bool modified){
int count(files_.size());
int pos(files_.pos());
bool bPrev, bNext, bSave, bDelete;
if (!count){
bPrev = bNext = bSave = bDelete = false;
}
else{
bPrev = (pos>0); // Not the first in list ?
bNext = (pos < (count - 1)); // Not the last in list
bSave = modified;
bDelete = (sFileName_[0]);
}
menu_.activate(IDM_FILE_PREV, SEARCH_BY_ID, bPrev);
menu_.activate(IDM_FILE_NEXT, SEARCH_BY_ID, bNext);
menu_.activate(IDM_FILE_SAVE, SEARCH_BY_ID, bSave);
menu_.activate(IDM_FILE_DELETE, SEARCH_BY_ID, bDelete);
menu_.update();
}
// _newFileName() : Notifies FQN has changed
//
void sudoSolver::_newFileName(){
_initStats(false);
if (bFile::FC_len(fileName_)){
char fName[BFILE_MAX_PATH + 1];
bFile::FC_FC2str(fileName_, fName);
char* name = strrchr(fName, CHAR_PATH_SEPARATOR);
strcpy(sFileName_, (name?++name:fName)); // No path ?
}
_displayStats();
}
// _displayStats() : Display grid's stats
//
void sudoSolver::_displayStats(){
if (sFileName_[0]){
dprint(TEXT_X, TEXT_Y, C_BLACK, "File : %s", sFileName_);
}
if (obviousVals_ != -1){
if (obviousVals_){
dprint(TEXT_X, TEXT_Y + TEXT_V_OFFSET, C_BLACK, "%d obvious values", obviousVals_);
}
else{
dtext(TEXT_X, TEXT_Y + TEXT_V_OFFSET, C_BLACK, "No obvious value");
}
}
if (duration_ != -1){
if (duration_){
dprint(TEXT_X, TEXT_Y + 2*TEXT_V_OFFSET, C_BLACK, "Solved in %d ms", duration_);
}
else{
dprint(TEXT_X, TEXT_Y + 2*TEXT_V_OFFSET, C_BLACK, "No solution found");
}
}
dupdate();
}
// EOF

View File

@ -44,7 +44,7 @@ private:
// _initStats() : initialize grid stats
//
void _initStats();
void _initStats(bool whole = true);
// _updateFileItemsState() : Item's state
//
@ -53,11 +53,10 @@ private:
void _updateFileItemsState(bool modified = false);
// _updateShortFileName() : Get short filename from FQN
// _newFileName() : Notifies FQN has changed
//
void _updateShortFileName();
void _displayStats(const char* fName, int8_t obvious, int elapse);
void _newFileName();
void _displayStats();
private:
menuBar menu_; // Application menu

View File

@ -1,269 +1,269 @@
//----------------------------------------------------------------------
//--
//-- sudoku.h
//--
//-- Definition of sudoku object - Edition and resolution
//-- of a sudoku grid
//--
//----------------------------------------------------------------------
#ifndef __S_SOLVER_SUDOKU_h__
#define __S_SOLVER_SUDOKU_h__ 1
#include "consts.h"
#include "element.h"
#include "position.h"
#include "tinySquare.h"
#include "shared/bFile.h"
// Error codes
//
#define FILE_NO_ERROR BFILE_NO_ERROR
#define FILE_INVALID_FILENAME (BFILE_LAST_ERROR_CODE + 1) // File doesn't exist
#define FILE_INVALID_FILESIZE (BFILE_LAST_ERROR_CODE + 2)
#define FILE_NO_FILENAME (BFILE_LAST_ERROR_CODE + 3)
#define FILE_IO_ERROR (BFILE_LAST_ERROR_CODE + 4)
#define FILE_INVALID_LINE (BFILE_LAST_ERROR_CODE + 11)
#define FILE_INVALID_FORMAT (BFILE_LAST_ERROR_CODE + 12)
// The value can't be set at this position
#define FILE_VALUE_ERROR (BFILE_LAST_ERROR_CODE + 13)
#ifdef __cplusplus
extern "C" {
#endif // #ifdef __cplusplus
// sudoku : Edition and/or resolution of a single sudoku grid
//
class sudoku{
public:
// Construction & destruction
sudoku(RECT* scr = NULL);
~sudoku(){}
// display() : Display the grid and it's content
//
// @update : update screen ?
//
void display(bool update = true);
// empty() : Empties the grid
//
void empty();
// revert : Return to the original state
//
void revert();
// io
//
// load() : Load a new grid
//
// @fName : file to load
//
// @return : 0 on success or an error code
//
uint8_t load(const FONTCHARACTER fName);
// save() : Save the grid on a file
//
// In the given grid, only "original" values
// will be saved
//
// @fName : File name to use
//
// @return : 0 on success or an error code
//
int save(const FONTCHARACTER fName);
#ifdef DEST_CASIO_CALC
// edit() : Edit / modify the current grid
//
// @return : true if grid has been modified or false if unchanged
//
bool edit();
#endif // #ifdef DEST_CASIO_CALC
// findObviousValues() : Find all the obvious values
//
// @return : #obvious values found
//
uint8_t findObviousValues();
// resolve() : Find a solution for the current grid
//
// mDuration : points to an int that will receive duration
// of solving process in ms. Can be NULL
//
// @return : true if a solution was found
//
bool resolve(int* mDuration = NULL);
private:
//
// Checks
//
// _checkValue() : Can we put the value at the current position ?
//
// @pos : position
// @value : Check the given value at this 'position'
//
// @return : true if the given value is valid at the given position
//
bool _checkValue(position& pos, uint8_t value);
// _checkLine() : Can we put the value at the current position ?
//
// @pos : position
// @value : Check this value at this position's line
//
// @return : true if the given value is valid in the given line
//
bool _checkLine(position& pos, uint8_t value);
// _checkRow() : Can we put the value at the current row ?
//
// @pos : position
// @value : Check this value at this position's row
//
// @return : true if the given value is valid in the given row
//
bool _checkRow(position& pos, uint8_t value);
// _checTinySquare() : Can we put the value in this tinySquare ?
//
// @pos : position
// @value : Check this value
//
// @return : true if the given value is valid in the tinySquare
//
bool _checkTinySquare(position& pos, uint8_t value){
return (false == tSquares_[pos.squareID()].inMe(elements_, value));
}
// _checkAndSet() : Try to put the value at the current position
//
// @pos : position
// @value : value to put
//
// @return : true if value is set
//
bool _checkAndSet(position& pos, uint8_t value);
//
// Drawings
//
#ifdef DEST_CASIO_CALC
// _drawBackground() : Draw background and the grid's borders
//
void _drawBackground();
// _drawContent() : : Draw all the elements
//
void _drawContent();
// _drawSingleElement : draw a single element of the grid
//
// @row, @line : coordinate of the element in the grid
// @value : value of the element in [1..9]
// @bkColour : background colour
// @txtColour : text colour
//
void _drawSingleElement(uint8_t row, uint8_t line, uint8_t value,
int bkColour, int txtColour);
#endif // #ifdef DEST_CASIO_CALC
//
// Search for obvious values
//
// _findObviousValues() :
// Search and set all the possible obvious values in the grid
//
// @return the # of values found (and set)
//
uint8_t _findObviousValues();
// _checkObviousValue() : Is there an obvious value
// for the given position ?
//
// pos : current position in the grid
//
// @returns the value or 0
//
uint8_t _checkObviousValue(position& pos);
// _setObviousValueInLines() : Try to put the value in another line
//
// @pos : start position
// @value : value to "put"
//
// @return : count (0 or 1) of value set
//
uint8_t _setObviousValueInLines(position& pos, uint8_t value);
// _setObviousValueInRows() : Try to put the value in another row
//
// @pos : start position
// @value : value to "put"
//
// @return : count (0 or 1) of value set
//
uint8_t _setObviousValueInRows(position& pos, uint8_t value);
//
// Resolving
//
// _findFirstEmptyPos() : Find the first empty pos.
//
// @start : position where to start the search
//
// @return : status of position (POS_VALID or POS_END_OF_LIST)
//
uint8_t _findFirstEmptyPos(position &start);
// _previousPos() : Returns to the previous position
//
// Go backward in the grid to find a valid position.
// If position index is -1, the method will return POS_INDEX_ERROR
// ie. no solution for this grid
//
// @current : current position
//
// @return the status of the position (POS_VALID or POS_INDEX_ERROR)
//
uint8_t _previousPos(position& current);
#ifdef DEST_CASIO_CALC
// __callbackTick() : Call back function for timer
// This function is used during edition to make selected item blink
//
// @pTick : pointer to blinking state indicator
//
// @return : TIMER_CONTINUE if valid
//
static int __callbackTick(volatile int *pTick);
#endif // #ifdef DEST_CASIO_CALC
// Members
private:
element elements_[LINE_COUNT * ROW_COUNT]; // grid as a one dim. table
tinySquare tSquares_[TINY_COUNT]; // Elements IDs in tinySquares
RECT screen_; // Position & dims of screen : {x Grid, yGrid, "screen" width , "screen" height}
};
#ifdef __cplusplus
}
#endif // #ifdef __cplusplus
#endif // __S_SOLVER_SUDOKU_h__
// EOF
//----------------------------------------------------------------------
//--
//-- sudoku.h
//--
//-- Definition of sudoku object - Edition and resolution
//-- of a sudoku grid
//--
//----------------------------------------------------------------------
#ifndef __S_SOLVER_SUDOKU_h__
#define __S_SOLVER_SUDOKU_h__ 1
#include "consts.h"
#include "element.h"
#include "position.h"
#include "tinySquare.h"
#include "shared/bFile.h"
// Error codes
//
#define FILE_NO_ERROR BFILE_NO_ERROR
#define FILE_INVALID_FILENAME (BFILE_LAST_ERROR_CODE + 1) // File doesn't exist
#define FILE_INVALID_FILESIZE (BFILE_LAST_ERROR_CODE + 2)
#define FILE_NO_FILENAME (BFILE_LAST_ERROR_CODE + 3)
#define FILE_IO_ERROR (BFILE_LAST_ERROR_CODE + 4)
#define FILE_INVALID_LINE (BFILE_LAST_ERROR_CODE + 11)
#define FILE_INVALID_FORMAT (BFILE_LAST_ERROR_CODE + 12)
// The value can't be set at this position
#define FILE_VALUE_ERROR (BFILE_LAST_ERROR_CODE + 13)
#ifdef __cplusplus
extern "C" {
#endif // #ifdef __cplusplus
// sudoku : Edition and/or resolution of a single sudoku grid
//
class sudoku{
public:
// Construction & destruction
sudoku(RECT* scr = NULL);
~sudoku(){}
// display() : Display the grid and it's content
//
// @update : update screen ?
//
void display(bool update = true);
// empty() : Empties the grid
//
void empty();
// revert : Return to the original state
//
void revert();
// io
//
// load() : Load a new grid
//
// @fName : file to load
//
// @return : 0 on success or an error code
//
uint8_t load(const FONTCHARACTER fName);
// save() : Save the grid on a file
//
// In the given grid, only "original" values
// will be saved
//
// @fName : File name to use
//
// @return : 0 on success or an error code
//
int save(const FONTCHARACTER fName);
#ifdef DEST_CASIO_CALC
// edit() : Edit / modify the current grid
//
// @return : true if grid has been modified or false if unchanged
//
bool edit();
#endif // #ifdef DEST_CASIO_CALC
// findObviousValues() : Find all the obvious values
//
// @return : #obvious values found
//
uint8_t findObviousValues();
// resolve() : Find a solution for the current grid
//
// mDuration : points to an int that will receive duration
// of solving process in ms. Can be NULL
//
// @return : true if a solution was found
//
bool resolve(int* mDuration = NULL);
private:
//
// Checks
//
// _checkValue() : Can we put the value at the current position ?
//
// @pos : position
// @value : Check the given value at this 'position'
//
// @return : true if the given value is valid at the given position
//
bool _checkValue(position& pos, uint8_t value);
// _checkLine() : Can we put the value at the current position ?
//
// @pos : position
// @value : Check this value at this position's line
//
// @return : true if the given value is valid in the given line
//
bool _checkLine(position& pos, uint8_t value);
// _checkRow() : Can we put the value at the current row ?
//
// @pos : position
// @value : Check this value at this position's row
//
// @return : true if the given value is valid in the given row
//
bool _checkRow(position& pos, uint8_t value);
// _checTinySquare() : Can we put the value in this tinySquare ?
//
// @pos : position
// @value : Check this value
//
// @return : true if the given value is valid in the tinySquare
//
bool _checkTinySquare(position& pos, uint8_t value){
return (false == tSquares_[pos.squareID()].inMe(elements_, value));
}
// _checkAndSet() : Try to put the value at the current position
//
// @pos : position
// @value : value to put
//
// @return : true if value is set
//
bool _checkAndSet(position& pos, uint8_t value);
//
// Drawings
//
#ifdef DEST_CASIO_CALC
// _drawBackground() : Draw background and the grid's borders
//
void _drawBackground();
// _drawContent() : : Draw all the elements
//
void _drawContent();
// _drawSingleElement : draw a single element of the grid
//
// @row, @line : coordinate of the element in the grid
// @value : value of the element in [1..9]
// @bkColour : background colour
// @txtColour : text colour
//
void _drawSingleElement(uint8_t row, uint8_t line, uint8_t value,
int bkColour, int txtColour);
#endif // #ifdef DEST_CASIO_CALC
//
// Search for obvious values
//
// _findObviousValues() :
// Search and set all the possible obvious values in the grid
//
// @return the # of values found (and set)
//
uint8_t _findObviousValues();
// _checkObviousValue() : Is there an obvious value
// for the given position ?
//
// pos : current position in the grid
//
// @returns the value or 0
//
uint8_t _checkObviousValue(position& pos);
// _setObviousValueInLines() : Try to put the value in another line
//
// @pos : start position
// @value : value to "put"
//
// @return : count (0 or 1) of value set
//
uint8_t _setObviousValueInLines(position& pos, uint8_t value);
// _setObviousValueInRows() : Try to put the value in another row
//
// @pos : start position
// @value : value to "put"
//
// @return : count (0 or 1) of value set
//
uint8_t _setObviousValueInRows(position& pos, uint8_t value);
//
// Resolving
//
// _findFirstEmptyPos() : Find the first empty pos.
//
// @start : position where to start the search
//
// @return : status of position (POS_VALID or POS_END_OF_LIST)
//
uint8_t _findFirstEmptyPos(position &start);
// _previousPos() : Returns to the previous position
//
// Go backward in the grid to find a valid position.
// If position index is -1, the method will return POS_INDEX_ERROR
// ie. no solution for this grid
//
// @current : current position
//
// @return the status of the position (POS_VALID or POS_INDEX_ERROR)
//
uint8_t _previousPos(position& current);
#ifdef DEST_CASIO_CALC
// __callbackTick() : Call back function for timer
// This function is used during edition to make selected item blink
//
// @pTick : pointer to blinking state indicator
//
// @return : TIMER_CONTINUE if valid
//
static int __callbackTick(volatile int *pTick);
#endif // #ifdef DEST_CASIO_CALC
// Members
private:
element elements_[LINE_COUNT * ROW_COUNT]; // grid as a one dim. table
tinySquare tSquares_[TINY_COUNT]; // Elements IDs in tinySquares
RECT screen_; // Position & dims of screen : {x Grid, yGrid, "screen" width , "screen" height}
};
#ifdef __cplusplus
}
#endif // #ifdef __cplusplus
#endif // __S_SOLVER_SUDOKU_h__
// EOF