Compare commits

...

26 commits
master ... dev

Author SHA1 Message Date
Jérôme Henry-Barnaudière - GeeHB cd6acf4958 BUG : disparition du nom du fichier 2024-03-07 15:25:12 +01:00
Jérôme Henry-Barnaudière - GeeHB 0824259d48 Syntaxe et corrections mineures 2024-03-06 17:11:21 +01:00
Jérôme Henry-Barnaudière - GeeHB 53f34c2fd2 Corrections HYPOTHESE::firstPos 2024-03-05 17:12:27 +01:00
Jérôme Henry-Barnaudière - GeeHB 9d177189b6 ID du premier élément d'une hypothèse 2024-03-05 11:37:50 +01:00
Jérôme Henry-Barnaudière - GeeHB bd177252e3 Unification (et simplification) des affichages de texte 2024-03-04 16:51:35 +01:00
Jérôme Henry-Barnaudière - GeeHB 7ce9d0ead2 Edition manuelle - Sortie losque la grille est complète 2024-03-03 18:46:51 +01:00
Jérôme Henry-Barnaudière - GeeHB 8ff5270f9c Grille completée 2024-03-03 15:27:56 +01:00
Jérôme Henry-Barnaudière - GeeHB af8d745452 Alignement des textes 2024-03-03 10:21:52 +01:00
Jérôme Henry-Barnaudière - GeeHB 83ebfdc61b Ajout d'un message pendant la résolution 2024-03-01 09:35:56 +01:00
Jérôme Henry-Barnaudière - GeeHB cebf3e9e9f Ajout du mode pause 2024-02-29 10:19:57 +01:00
Jérôme Henry-Barnaudière - GeeHB c81e62311c 'petite' image pour le mode pause 2024-02-28 18:10:34 +01:00
Jérôme Henry-Barnaudière - GeeHB 0bb633a33d BUG : dépilement des hypothèses 2024-02-28 13:47:22 +01:00
Jérôme Henry-Barnaudière - GeeHB b1099a9d78 Nouvel algo. gestion des couleurs 2024-02-27 12:31:52 +01:00
Jérôme Henry-Barnaudière - GeeHB 8dd6669e0d BUG : onManualAccept - mauvaise couleur 'précédente' 2024-02-23 12:00:19 +01:00
Jérôme Henry-Barnaudière - GeeHB 4ae0a26418 BUG : gestion de la pile des hypothèses 2024-02-23 11:29:33 +01:00
Jérôme Henry-Barnaudière - GeeHB 9220d80535 BUG : Erreur indice Help si plus de 3 appels 2024-02-23 10:16:28 +01:00
Jérôme Henry-Barnaudière - GeeHB 68e7c2f6a1 Images incluses 2024-02-22 16:58:55 +01:00
Jérôme Henry-Barnaudière - GeeHB ab9c236d37 BUG : Erreur de type pour les items des submenus 2024-02-22 15:31:06 +01:00
Jérôme Henry-Barnaudière - GeeHB 6655f33381 Simplification de la gestion des ID des menus pour les checkbox 2024-02-22 11:04:25 +01:00
Jérôme Henry-Barnaudière - GeeHB 65fd555ade BUG : Aide - Mauvais indice de l'élément 2024-02-22 10:02:04 +01:00
Jérôme Henry-Barnaudière - GeeHB 02e498db6b BUG : Mauvaise valeur proposée pour l'aide 2024-02-21 18:02:40 +01:00
Jérôme Henry-Barnaudière - GeeHB 58a90f0268 Empilement des hypothèses colorées pour la résolution 2024-02-21 16:17:08 +01:00
Jérôme Henry-Barnaudière - GeeHB 0c72b11c02 Aide en mode résolution manuelle 2024-02-20 11:47:41 +01:00
Jérôme Henry-Barnaudière - GeeHB 53dbe87e0a Hyp. colorées - Gestion des acceptations et rejets 2024-02-20 09:37:48 +01:00
Jérôme Henry-Barnaudière - GeeHB 1fb10351ca Conservation (au choix) d'une solution 2024-02-19 19:20:08 +01:00
Jérôme Henry-Barnaudière - GeeHB 76e7066da6 BUG : Textes non centrés avec window::drawText 2024-02-19 11:29:17 +01:00
23 changed files with 906 additions and 298 deletions

2
.gitignore vendored
View file

@ -4,6 +4,8 @@
/src/tests.cpp
/assets-cg/base
.DS_Store
*-base.*
*.xcf
# Outputs
/build-cg

View file

@ -25,9 +25,10 @@ set(ASSETS
# ...
)
set(ASSETS_cg
assets-cg/about.png
assets-cg/menu.png
)
assets-cg/menuBar.png
assets-cg/about.png
assets-cg/pause.png
)
fxconv_declare_assets(${ASSETS} ${ASSETS_cg} WITH_METADATA)

View file

@ -1,6 +1,6 @@
MIT License
Copyright (c) 2023 Jérôme Henry-Barnaudière
Copyright (c) 2024 Jérôme Henry-Barnaudière
Permission is hereby granted, free of charge, to any person obtaining a copy
@ -30,4 +30,4 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
SOFTWARE.

View file

@ -1,11 +1,13 @@
# *sudoSolver*
### Présentation
![Accueil](assets/accueil.png)
`sudoSolver` est un *addin* pour Graph 90+E ecrit en C++ pour créer, éditer des grilles de Sudoku puis leur trouver une solution.
L'application est organisée autour d'une barre de menu horizontale; la navigation s'effectuant en appuyant sur les touches de contrôle situées "sous" les items.
* *File* permet d'accéder au sous-menu de gestion des fichiers
* *Edit* permet de modifier une grille
* *Solve* donne accès aux fonctions de recherche automatisée des solutions et permet aussi à l'utilisateur de chercher par lui même une solution.
@ -13,12 +15,13 @@ L'application est organisée autour d'une barre de menu horizontale; la navigati
### Informations de version
| Dépôt  | https://gitea.planet-casio.com/Jhb/sudoSolv |
|----- |-------------------------------------|
| **Date** | 9 février 2024 |
| **Version stable** | **0\.3.2** - branche `master` |
| Dépôt | https://gitea.planet-casio.com/Jhb/sudoSolv |
|----------------|---------------------------------------------|
| **Date** | 5 mars 2024 |
| **Version stable** | **0\.4.14** - branche `master` |
### Gestion des fichiers
Le menu *File* permet de gérer les grilles de sodoku : création d'une nouvelle grille, navigation dans le dossier, sauvegarde, suppression.
Les grilles sont toutes enregistrées et chargées à partir du dossier `fls0\grids`. Si le dossier n'existe pas, il sera crée au lancement de l'application.
@ -28,6 +31,7 @@ Le sous-dossier `grids` dans le dépôt propose quelques grilles.
Dans ce dossier, chaque grille est enregistrée dans un fichier au format texte dont le nom est automatiquement incrémenté.
Le menu propose les options suivantes:
* *New* : Création d'une nouvelle grille
* *Prev* : Chargement du fichier précédent dans le dossier
* *Next* : Ouverture du fichier suivant
@ -37,8 +41,8 @@ Le menu propose les options suivantes:
![Browse](assets/browse.png)
### Modification d'une grille
Le menu *Edit* permet de modifier une grille existante ou de générer une nouvelle grille à partir d'une matrice vierge.
Les touches de navigation déplacent le curseur dans la grille.
@ -48,26 +52,24 @@ La touche '0' supprime la valeur en place.
![Edit](assets/edit.png)
### Résolution
Le menu *Solve* permet, au choix, de rechercher par soi même une solution ou de demander au programme d'en trouver une.
Le menu *Solve* permet, au choix, de rechercher par soi même une solution ou de demander au programme d'en trouver une.
#### Résolution manuelle
L'item *Manual* permet à l'utilisateur de chercher une solution par lui même. Dans ce cas les éléments "posés" sur la grille sont ajoutés avec la couleur noire.
Le système offre néanmoins la possiblité de poser des hypothèses. Cela passe par le choix d'une couleur. Dès lors qu'une couleur est choisie, tous les éléments liés sont affichés avec une pastille colorée. Cela permet d'un coup d'oeil de voir tous les éléments liés à une hypothèse.
Le système offre néanmoins la possiblité de poser des hypothèses. Cela passe par le choix d'une couleur. Dès lors qu'une couleur est choisie, tous les éléments liés sont affichés avec une pastille colorée. Cela permet d'un coup d'oeil de voir tous les éléments liés à une hypothèse.
La couleur utilisée est aussi reprise dans l'affichage du menu.
Par exemple, avec le choix de la couleur verte :
![Hypothèse](assets/hypothese.png)
Le sous-menu offre les possiblités suivantes :
* *Col.* : Choix d'une hypothèse, marquée par une couleur.
En choisissant cette option, un sous menu-menu est affiché (encore un ...) permettant de choisir une couleur en cochant la case associée. Lorsque toutes les cases sont décochées (position par défaut), aucune hypothèse n'est en place.
* *Col.* : Choix d'une hypothèse, marquée par une couleur. En choisissant cette option, un sous menu-menu est affiché (encore un ...) permettant de choisir une couleur en cochant la case associée. Lorsque toutes les cases sont décochées (position par défaut), aucune hypothèse n'est en place.
* *Accept* : Tous les éléments d'une hypothèse (ie. tous les éléments marqués par la couleur) sont intégrés à la grille et donc se voient retirer leur couleur,
* 'Reject' : Tous les éléments d'une hypothèse sont rejetés. Ces éléments sont donc retirés de la grille.
* *End* permet de sortir du mode résolution manuelle et de retourner au msous-menu *Solve*.
![Couelurs](assets/chooseCol.png)

23
TODO.md
View file

@ -1,7 +1,24 @@
#### Ajouts
- [x] Création / génération d'une grille avec choix du niveau / complexité
- [ ] Résolution manuelle : mode "help" avec proposition d'une ou plusieurs valeurs
- [ ] Mode "pause" (cacher la grille)
- [x] Résolution manuelle :
- [x] mode "help" avec proposition d'une ou plusieurs valeurs
- [x] Compter les éléments restants à découvrir
- [x] Féliciter !
- [x] Liste ordonnée des hypothèses
- [x] Popup 'Résolution en cours' lors de la résolution du Sudoku
- [x] Mode "pause" (cacher la grille)
- [x] : "petite" image
- [x] : avec sudoSolver et sudoku
- [ ] menuBar
- [x] Gestion des cases à cocher inactives
- [ ] get/findItem retourne une copie !!!
- [ ] methode menuBar::freeItem
- [ ] set/getItem => mask (Text, status, state)
- [x] Affichage de textes
- [x] Aligner tous les affichages
- [x] Centraliser les affichages des textes
#### Corrections
- [ ] Text centré dans les objets de type 'window'
- [x] Texte centré dans les objets de type 'window'

BIN
assets-cg/app.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

View file

@ -1,7 +1,11 @@
about.png:
type: bopti-image
name: g_homeScreen
name: g_about
pause.png:
type: bopti-image
name: g_pause
menu.png:
menuBar.png:
type: bopti-image
name: g_menuImgs

View file

Before

Width:  |  Height:  |  Size: 991 B

After

Width:  |  Height:  |  Size: 991 B

BIN
assets-cg/pause.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

View file

@ -19,6 +19,8 @@
#endif // DEST_CASIO_CALC
#include <cstring>
#include <cstdlib>
#include <ctime>
#ifdef __cplusplus
extern "C" {
@ -27,7 +29,7 @@ extern "C" {
// App. infos
//
#define APP_NAME "sudoSolver"
#define APP_VERSION "0.4.5"
#define APP_VERSION "0.4.14"
#define APP_AUTHOR "GeeHB"
// Grids folder
@ -46,11 +48,13 @@ extern "C" {
#define ROW_COUNT 9
#define LINE_COUNT ROW_COUNT
#define VALUES_COUNT ROW_COUNT * LINE_COUNT
#define INDEX_MIN 0
#define INDEX_MAX (ROW_COUNT * LINE_COUNT - 1)
#define INDEX_MAX (VALUES_COUNT - 1)
#define VALUE_MIN 1
#define VALUE_MAX 9
#define VALUE_MAX ROW_COUNT
// Blinking
//
@ -68,9 +72,14 @@ extern "C" {
#define FILE_LINE_SIZE ROW_COUNT * 2 // (value & separator) * ROW_COUNT
#define FILE_SIZE LINE_COUNT * FILE_LINE_SIZE
// Grid's solution(s)
// Grid's solution(s) and help
//
#define WIN_SOL_TITLE "Check"
#define WIN_GEN_TXT "Generating..."
#define WIN_SEARCH_TXT "Resolving in progress..."
#define WIN_FOUND_TXT "Congratultation"
// Window size & pos.
#define WIN_SOL_Y 30
#define WIN_SOL_W 200
@ -81,21 +90,73 @@ extern "C" {
#define STR_ONE_SOL "A unique sol."
#define STR_MULTIPLE_SOL "More than one sol."
#define MIN_CLUE_COUNT 10 // No help if fewer items to find
#define MAX_HELP_CLUES 3 // # of help clues
// Display
//
// Dimensions in pixels
#define GRID_HORZ_OFFSET 20
#define SQUARE_SIZE 20
#define INT_SQUARE_SIZE (SQUARE_SIZE - 2 * BORDER_THICK)
#define GRID_SIZE SQUARE_SIZE * ROW_COUNT
#define BORDER_THICK 2 // Thickness of external border
// "Internal" images
#define IMG_ABOUT_W 202
#define IMG_ABOUT_H 216 // Menu is visible !
#define TEXT_X (2*GRID_HORZ_OFFSET + GRID_SIZE)
#define TEXT_Y 30
#define IMG_PAUSE_W CASIO_WIDTH
#define IMG_PAUSE_H 70
#define IMG_PAUSE_COPY_Y 46
#define IMG_PAUSE_LINES (CASIO_HEIGHT - IMG_PAUSE_H)
// Grid dimensions in pixels
#define GRID_HORZ_OFFSET 20
#define SQUARE_SIZE 20
#define INT_SQUARE_SIZE (SQUARE_SIZE - 2 * BORDER_THICK)
#define GRID_SIZE SQUARE_SIZE * ROW_COUNT
#define BORDER_THICK 2 // Thickness of external border
// Texts (stats and hypotheses)
//
#define TEXT_V_BASE 10
#define TEXT_V_OFFSET 20
#define HYP_SQUARE_SIZE 5
#define TEXT_BASE_X (2*GRID_HORZ_OFFSET + GRID_SIZE)
#define TEXT_BASE_Y (TEXT_V_OFFSET + TEXT_V_BASE)
// File
#define FILE_TEXT "File : %s"
#define FILE_ERROR_SAVE_TEXT "Error saving : %d"
#define FILE_ERROR_LOAD_TEXT "Error loading : %d"
#define FILE_TEXT_X TEXT_BASE_X
#define FILE_TEXT_Y TEXT_BASE_Y
#define FILE_TEXT_ERROR_Y TEXT_V_BASE
// Obvious values
#define OBV_TEXT "%d obvious values"
#define OBV_NONE_TEXT "No obvious value"
#define OBV_TEXT_X TEXT_BASE_X
#define OBV_TEXT_Y (TEXT_BASE_Y + TEXT_V_OFFSET)
// Solution
#define SOL_TEXT "Solved in %d ms"
#define SOL_NONE_TEXT "No solution found"
#define SOL_X TEXT_BASE_X
#define SOL_Y (TEXT_BASE_Y + 2 * TEXT_V_OFFSET)
// # values
#define VALUES_TEXT "Val. %d / %d "
#define VALUES_X TEXT_BASE_X
#define VALUES_Y (TEXT_BASE_Y + 3 * TEXT_V_OFFSET)
// Hypotheses
#define HYP_SQUARE_SIZE 5 // Square over element
#define HYP_H_OFFSET 50
#define HYP_LIST_OFFSET 4 // dx and dy
#define HYP_LIST_TEXT "Hyp. :"
#define HYP_LIST_TEXT_X TEXT_BASE_X
#define HYP_LIST_TEXT_Y (TEXT_BASE_Y + 4 * TEXT_V_OFFSET)
#define HYP_LIST_X (HYP_LIST_TEXT_X + HYP_H_OFFSET)
#define HYP_LIST_Y HYP_LIST_TEXT_Y
#define HYP_LIST_W 20
#define HYP_LIST_H (HYP_SQUARE_SIZE + 1)
// Colours
//
@ -129,6 +190,7 @@ enum GAME_KEY{
KEY_CODE_8 = KEY_8,
KEY_CODE_9 = KEY_9,
KEY_CODE_CAPTURE = KEY_7,
KEY_CODE_PAUSE = KEY_OPTN,
KEY_CODE_EXIT = KEY_EXIT,
KEY_CODE_EXE = KEY_EXE
};

View file

@ -23,6 +23,9 @@
// Element's coloured hypothese
//
#define HYP_COUNT 4 // Max. count of hyp.
#ifdef DEST_CASIO_CALC
enum HYP_COLOUR{
HYP_NO_COLOUR = GRID_BK_COLOUR,

View file

@ -73,14 +73,16 @@ extern "C" {
//
#define IDS_MANUAL_HYP_SUBMENU "Col."
#define IDM_MANUAL_HYP_SUBMENU 311
#define IDS_MANUAL_ACCEPT "Accept"
#define IDM_MANUAL_ACCEPT 312
#define IDS_MANUAL_REJECT "Reject"
#define IDM_MANUAL_REJECT 313
#define IDS_MANUAL_END "End"
#define IDM_MANUAL_END IDM_EDIT_OK
#define IDS_MANUAL_ACCEPT "Accept"
#define IDM_MANUAL_ACCEPT 312
#define IDS_MANUAL_REJECT "Reject"
#define IDM_MANUAL_REJECT 313
#define IDS_MANUAL_HELP "Help"
#define IDM_MANUAL_HELP 314
#define IDS_MANUAL_END "End"
#define IDM_MANUAL_END IDM_EDIT_OK
#define IDM_MANUAL_COLOUR_FIRST 3111 // MANUAL_HYP submenu
#define IDM_MANUAL_COLOUR_FIRST 3111 // MANUAL_HYP submenu
#define IDS_MANUAL_NO_COLOUR "None" // maybe in a future version
#ifdef __cplusplus

View file

@ -170,7 +170,7 @@ private:
uint8_t status_;
uint8_t row_, line_; // Position in the "matrix"
uint8_t squareID_; //tiny-square ID
uint8_t squareID_; // tiny-square ID
bool gameMode_; // In game mode ?
}; // class position

View file

@ -30,7 +30,7 @@
#ifndef DEST_CASIO_CALC
// 24 bits RGB (for tests only on Windows and Linux)
#define C_RGB(r,g,b) ((uint32_t)(((uint8_t)(r)|((uint16_t)((uint8_t)(g))<<8))|(((uint32_t)(uint8_t)(b))<<16)))
#define C_RGB(r,g,b) ((uint32_t)(((uint8_t)(r)|((uint16_t)((uint8_t)(g))<<8))|(((uint32_t)(uint8_t)(b))<<16)))
#endif // #ifndef DEST_CASIO_CALC
#ifdef FX9860G
@ -48,7 +48,7 @@ enum DEF_COLOUR{
COLOUR_LT_GREY = C_LIGHT,
COLOUR_GREY = C_WHITE,
COLOUR_DK_GREY = C_DARK,
NO_COLOR = -1
NO_COLOR = -1
};
#else
enum DEF_COLOUR{
@ -65,7 +65,7 @@ enum DEF_COLOUR{
COLOUR_LT_GREY = C_RGB(29, 29, 29),
COLOUR_GREY = C_RGB(16, 16, 16),
COLOUR_DK_GREY = C_RGB(8, 8, 8),
NO_COLOR = -1
NO_COLOR = -1
};
#endif // #ifdef FX9860G

View file

@ -17,11 +17,10 @@
using namespace std;
#else
// Background image
//
extern bopti_image_t g_menuImgs;
// Images index in the image
enum IMAGE_INDEXES{
enum MENU_IMG_INDEX{
MENU_IMG_BACK_ID = 0,
MENU_IMG_CHECKED_ID = 1,
MENU_IMG_UNCHECKED_ID = 2
@ -76,7 +75,6 @@ int menuBar::setColour(uint8_t index, int colour){
return actual;
}
//
// Dimensions
//
@ -175,6 +173,18 @@ bool menuBar::activateItem(int searchedID, int searchMode, bool activated){
return false;
}
// isMenuItemActivated() : Check wether an item is activated or not
//
// @id : item id
// @searchMode : type of search (SEARCH_BY_ID or SEARCH_BY_INDEX)
//
// return : true if the item is activted
//
bool menuBar::isMenuItemActivated(int id, int searchMode){
PMENUITEM item(_findItem(&current_, id, searchMode));
return (item && !isBitSet(item->state, ITEM_STATE_INACTIVE));
}
// freeMenuItem() : Free memory used by a menu item
//
// @item : Pointer to the menu item to be released
@ -200,7 +210,7 @@ MENUACTION menuBar::handleKeyboard(){
uint8_t kID(0);
keyboard kb;
PMENUITEM item(NULL);
MENUACTION ret = {0, MOD_NONE, ACTION_KEYBOARD};
MENUACTION ret = {0, ITEM_STATE_DEFAULT, MOD_NONE, ACTION_KEYBOARD};
bool readKeyboard(true);
if (readKeyboard){
@ -227,11 +237,6 @@ MENUACTION menuBar::handleKeyboard(){
showParentBar();
}
else{
// a selectable item ...
ret.value = item->id;
ret.type = ACTION_MENU;
readKeyboard = false;
// select the item
if (kID != visible_->selIndex){
_selectByIndex(kID, true, true);
@ -246,6 +251,12 @@ MENUACTION menuBar::handleKeyboard(){
setBit(item->state, ITEM_STATE_CHECKED);
}
}
// a selectable item ...
ret.value = item->id;
ret.type = ACTION_MENU;
ret.state = item->state;
readKeyboard = false;
}
}
}
@ -422,12 +433,6 @@ bool menuBar::defDrawItem(PMENUBAR const bar, PMENUITEM const item,
cout << "[no text]";
}
/*
if (item->ownerData){
cout << "[" << (int)item->ownerData << "]";
}
*/
cout << (isBitSet(item->state,ITEM_STATE_SELECTED)?"<" : " ");
cout << "|";
}
@ -443,13 +448,15 @@ bool menuBar::defDrawItem(PMENUBAR const bar, PMENUITEM const item,
// @id : checkbox item id
// @searchMode : type of search (SEARCH_BY_ID or SEARCH_BY_INDEX)
//
// return : ITEM_CHECKED if the item is checked, ITEM_UNCHECKED if the item is not cheched
// ITEM_ERROR on error (invalid id, not a check box, ...)
// return : ITEM_CHECKED if the item is checked, ITEM_UNCHECKED
// if the item is not cheched ITEM_ERROR
// on error (invalid id, not a check box, ...)
//
int menuBar::isMenuItemChecked(int id, int searchMode){
PMENUITEM item(_findItem(&current_, id, searchMode));
if (item && isBitSet(item->status, ITEM_STATUS_CHECKBOX)){
return (isBitSet(item->state, ITEM_STATE_CHECKED)?ITEM_CHECKED:ITEM_UNCHECKED);
return (isBitSet(item->state,
ITEM_STATE_CHECKED)?ITEM_CHECKED:ITEM_UNCHECKED);
}
// Not found or not a checkbox
@ -462,13 +469,13 @@ int menuBar::isMenuItemChecked(int id, int searchMode){
// @searchMode : type of search (SEARCH_BY_ID or SEARCH_BY_INDEX)
// @checkState : ITEM_CHECKED if item should be checked or ITEM_UNCHECKED
//
// return : ITEM_CHECKED it item is checked, ITEM_UNCHECKED if not checked
// return : ITEM_CHECKED if item is checked, ITEM_UNCHECKED if not checked
// and ITEM_ERROR on error
//
int menuBar::checkMenuItem(int id, int searchMode, int check){
int menuBar::checkMenuItem(int id, int searchMode, int checkState){
PMENUITEM item(_findItem(&current_, id, searchMode));
if (item && isBitSet(item->status, ITEM_STATUS_CHECKBOX)){
if (1 == check){
if (ITEM_CHECKED == checkState){
setBit(item->state, ITEM_STATE_CHECKED);
}
else{
@ -476,7 +483,8 @@ int menuBar::checkMenuItem(int id, int searchMode, int check){
}
// return tatus of bit
return (isBitSet(item->state, ITEM_STATE_CHECKED)?ITEM_CHECKED:ITEM_UNCHECKED);
return (isBitSet(item->state,
ITEM_STATE_CHECKED)?ITEM_CHECKED:ITEM_UNCHECKED);
}
// Not found or not a checkbox
@ -614,6 +622,22 @@ void menuBar::_freeMenuBar(PMENUBAR bar, bool freeAll){
}
}
// _unSelectItems() : Unselect item(s)
//
// @bar : Pointer to the bar
//
void menuBar::_unSelectItems(PMENUBAR bar){
if (bar){
PMENUITEM item;
for (uint8_t index(0); index < MENU_MAX_ITEM_COUNT; index++){
if ((item = bar->items[index])){
removeBit(item->state, ITEM_STATE_SELECTED);
}
}
}
}
//
// Menu items
//
@ -634,7 +658,7 @@ PMENUITEM menuBar::_addItem(PMENUBAR const bar, uint8_t index, int id,
if (!bar ||
index >= MENU_MAX_ITEM_COUNT ||
NULL != bar->items[index] ||
_findItem(bar, id, SEARCH_BY_ID) || // this ID is already handled
_findItem(bar, id, SEARCH_BY_ID) || // already handled
current_.itemCount >= MENU_MAX_ITEM_COUNT /*||
!text || !(len = strlen(text))*/){
return NULL;
@ -869,13 +893,16 @@ bool menuBar::_selectByIndex(int8_t index, bool selected, bool redraw){
}
if (selected){
setBit(item->state, ITEM_STATE_SELECTED);
visible_->selIndex = index;
// unselect prev.
/*
if (-1 != sel && (item = visible_->items[sel])){
removeBit(item->state, ITEM_STATE_SELECTED);
}
*/
_unSelectItems(visible_);
setBit(item->state, ITEM_STATE_SELECTED);
visible_->selIndex = index;
}
else{
removeBit(item->state, ITEM_STATE_SELECTED);

View file

@ -12,7 +12,7 @@
#include "casioCalcs.h"
#include "keyboard.h"
#define _GEEHB_MENU_VER_ "0.5.2"
#define _GEEHB_MENU_VER_ "0.5.6"
#define MENU_MAX_ITEM_COUNT 6 // ie. "F" buttons count
@ -28,7 +28,7 @@
#define MENU_IMG_WIDTH 12
#define MENU_IMG_HEIGHT 12
#define ITEM_ROUNDED_DIM 4
#define ITEM_ROUNDED_DIM 4
//
// Item pos is a menu bar
@ -118,7 +118,7 @@ typedef struct _menuItem{
int status;
char text[ITEM_NAME_LEN + 1];
void* subMenu; // if item is a submenu, points to the submenu
int ownerData; // Can ba anything ...
int ownerData; // Can be anything ...
} MENUITEM,* PMENUITEM;
// A menu bar
@ -136,10 +136,18 @@ typedef struct _menuBar{
//
typedef struct _menuAction{
int value;
int state;
uint modifier;
uint8_t type;
} MENUACTION;
// Types of actions
//
enum MENU_ACTION{
ACTION_MENU = 0, // value is a menu ID
ACTION_KEYBOARD = 1 // value is a keycode
};
// Ownerdraw's function prototype
//
typedef bool (*MENUDRAWINGCALLBACK)(
@ -148,12 +156,6 @@ typedef bool (*MENUDRAWINGCALLBACK)(
RECT* const, // Drawing rect for item
int style); // Elements (in item) to draw
// Types of actions
//
enum MENU_ACTION{
ACTION_MENU = 0, // value is a menu ID
ACTION_KEYBOARD = 1 // value is a keycode
};
// Types of search modes
//
@ -375,11 +377,11 @@ public:
// @searchMode : type of search (SEARCH_BY_ID or SEARCH_BY_INDEX)
// @checkState : ITEM_CHECKED if item should be checked or ITEM_UNCHECKED
//
// return : ITEM_CHECKED it item is checked, ITEM_UNCHECKED if not checked
// return : ITEM_CHECKED if item is checked, ITEM_UNCHECKED if not checked
// and ITEM_ERROR on error
//
int checkMenuItem(int id, int searchMode = SEARCH_BY_ID,
int check = ITEM_CHECKED);
int checkState = ITEM_CHECKED);
// removeItem() : Remove an item from the current menu bar
// Remove the item menu or the submenu
@ -398,6 +400,12 @@ public:
// Selection & activation
//
// _unSelectItems() : Unselect item(s)
//
void unSelectItems(){
_unSelectItems(visible_);
}
// selectByIndex() : Select an item by index in the current bar
//
// @index : index of menu item to select or unselect
@ -409,7 +417,7 @@ public:
//
bool selectByIndex(int8_t index, bool selected = true,
bool redraw = false){
return _selectByIndex(index, selected, redraw); // Redraw items
return _selectByIndex(index, selected, redraw);
}
// getSelectedIndex() : Index of selected item in the current bar
@ -444,18 +452,23 @@ public:
return activateItem(searchedID, searchMode, activated);
}
// isMenuItemActivated() : Check wether an item is activated or not
//
// @id : item id
// @searchMode : type of search (SEARCH_BY_ID or SEARCH_BY_INDEX)
//
// return : true if the item is activted
//
bool isMenuItemActivated(int id, int searchMode = SEARCH_BY_ID);
//
// Item access and modifications
//
bool getItem(int searchID, int searchMode, PMENUITEM* pItem);
bool setItem(int searchID, int searchMode, PMENUITEM pItem, int Mask);
// findItem() : Find an item in the menu bar and its submenus
// getItem() : Find an item in the menu bar and its submenus
//
// @searchedID : id or index of the searched item
// @searchMode : Type of search (SEARCH_BY_ID or SEARCH_BY_INDEX)
//
// @containerBar : pointer to a PMENUBAR. when not NULL,
// if item is found, containerBar will point to the bar
// containing the item
@ -463,13 +476,34 @@ public:
//
// @return : pointer to the item if found or NULL
//
PMENUITEM findItem(int searchedID, int searchMode,
PMENUITEM getItem(int searchedID, int searchMode,
PMENUBAR* containerBar = NULL,
uint8_t* pIndex = NULL){
return _findItem(&current_, searchedID, searchMode,
containerBar, pIndex);
}
// setItem() : Modify an item in the menu bar and its submenus
//
// @pItem : Pointer to the modified menu item
// @searchedID : id or index of the searched item
// @searchMode : Type of search (SEARCH_BY_ID or SEARCH_BY_INDEX)
// @mask : Mask to identify modified fields in the MENUITEM struct
//
// @return : true if successfully applied
//
bool setItem(PMENUITEM pItem, int searchID, int searchMode, int Mask);
// findItem() : Find an item in the menu bar and its submenus
//
// Use getItem
//
PMENUITEM findItem(int searchedID, int searchMode,
PMENUBAR* containerBar = NULL,
uint8_t* pIndex = NULL){
return getItem(searchedID, searchMode, containerBar, pIndex);
}
// freeMenuItem() : Free memory used by a menu item
//
// @item : Pointer to the menu item to be released
@ -569,6 +603,12 @@ private:
//
void _freeMenuBar(PMENUBAR bar, bool freeAll);
// _unSelectItems() : Unselect item(s)
//
// @bar : Pointer to the bar
//
void _unSelectItems(PMENUBAR bar);
//
// menu items management
//

View file

@ -204,7 +204,7 @@ void window::update(){
// the default ground colour will be used
//
void window::drawText(const char* text, int x, int y, int tCol, int bCol){
if (activated_){
if (activated_ && text && text[0]){
#ifdef DEST_CASIO_CALC
POINT dest;
int w(0), h(0);
@ -213,21 +213,17 @@ void window::drawText(const char* text, int x, int y, int tCol, int bCol){
}
// Center text (or not ...)
dest.x = (x<0)?(client_.x + (client_.w - w)/2):x;
dest.y = (y<0)?(client_.y + (client_.h - h)/2):y;
win2Screen(dest); // Change origin
#endif // #ifdef DEST_CASIO_CALC
dest.x = client_.x + ((x<0)?((client_.w - w)/2):x);
dest.y = client_.y + ((y<0)?((client_.h - h)/2):y);
if (text && text[0]){
#ifdef DEST_CASIO_CALC
dtext_opt(dest.x, dest.y, (
tCol==-1)?infos_.textColour:tCol, (bCol==-1)?
infos_.bkColour:bCol, DTEXT_LEFT, DTEXT_TOP, text);
dtext_opt(dest.x, dest.y,
(tCol==-1)?infos_.textColour:tCol,
(bCol==-1)?infos_.bkColour:bCol,
DTEXT_LEFT, DTEXT_TOP,
text);
#else
std::cout << "\t- " << text << std::endl;
std::cout << "\t- " << text << std::endl;
#endif // #ifdef DEST_CASIO_CALC
}
} // if (activated_)
}

View file

@ -18,7 +18,7 @@
#include <iostream>
#endif // #ifdef DEST_CASIO_CALC
#define _GEEHB_WINDOW_VER_ "0.1.3"
#define _GEEHB_WINDOW_VER_ "0.1.4"
#define WIN_BORDER_WIDTH 2
@ -99,7 +99,7 @@ public:
// @bCol : background colour. If is equal to -1,
// the default ground colour will be used
//
void drawText(const char* text, int x, int y,
void drawText(const char* text, int x = -1, int y = -1,
int tCol = -1, int bCol = -1);
// win2Screen() : Convert window (x, y) into screen (x,y)

View file

@ -11,7 +11,7 @@
#include "sudoSolver.h"
#include "shared/window.h"
extern bopti_image_t g_homeScreen; // Background image
extern bopti_image_t g_about;
// Construction
//
@ -19,7 +19,7 @@ sudoSolver::sudoSolver(){
_initStats();
}
// Create app. menu bar
// createMenu() : Create app. menu bar
//
void sudoSolver::createMenu(){
@ -60,7 +60,7 @@ void sudoSolver::createMenu(){
//
void sudoSolver::showHomeScreen(){
drect(0, 0, CASIO_WIDTH, CASIO_HEIGHT - menu_.getHeight(), C_WHITE);
dimage(0, 0, &g_homeScreen);
dimage(0, 0, &g_about);
char copyright[255];
strcpy(copyright, APP_NAME);
@ -193,6 +193,13 @@ void sudoSolver::run(void)
end = true;
break;
// Pause
case KEY_CODE_PAUSE:
game_.pause();
game_.display();
menu_.update();
break;
// Activate or deactivate screen capture
case KEY_CODE_CAPTURE:
//if (MOD_SHIFT == (action.modifier & MOD_SHIFT)){
@ -239,13 +246,12 @@ void sudoSolver::_onNewSudoku(uint8_t complexity){
wInf.pos.h = WIN_SOL_H;
wInf.bkColour = COLOUR_LT_GREY;
waitWindow.create(wInf);
waitWindow.drawText("Generating ...", 40, 25);
waitWindow.drawText(WIN_GEN_TXT); // Centered
waitWindow.update();
game_.create(complexity); // do the job ...
waitWindow.close(); // Close the window
waitWindow.close(); // Close the window
game_.display();
_initStats();
@ -275,7 +281,7 @@ void sudoSolver::_onFileNext(){
// _onFileSave() : Save current grid
//
void sudoSolver::_onFileSave(){
bool fileExists(sFileName_[0]);
bool fileExists(!FC_ISEMPTY(fileName_));
int uid(-1);
int error(FILE_NO_ERROR);
@ -299,8 +305,8 @@ void sudoSolver::_onFileSave(){
_updateFileItemsState();
} // save
else{
dprint(TEXT_X, TEXT_V_OFFSET, C_RED,
"Error saving : %d", error);
dprint(FILE_TEXT_X, FILE_TEXT_ERROR_Y, C_RED,
FILE_ERROR_SAVE_TEXT, error);
dupdate();
}
}
@ -428,7 +434,7 @@ bool sudoSolver::_loadFile(FONTCHARACTER fName){
return true;
}
dprint(TEXT_X, TEXT_V_OFFSET, C_RED, "Error loading file : %d",
dprint(FILE_TEXT_X, FILE_TEXT_ERROR_Y, C_RED, FILE_ERROR_LOAD_TEXT,
(int)error);
dupdate();
return false;
@ -445,7 +451,6 @@ void sudoSolver::_initStats(bool whole){
FC_EMPTY(fileName_);
}
sFileName_[0] = '\0';
obviousVals_ = -1;
duration_ = -1;
}
@ -482,8 +487,6 @@ void sudoSolver::_newFileName(FONTCHARACTER fName){
bFile::FC_cpy(fileName_, fName);
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();
@ -493,29 +496,24 @@ void sudoSolver::_newFileName(FONTCHARACTER fName){
// the solution if found any
//
void sudoSolver::_displayStats(){
if (sFileName_[0]){
dprint(TEXT_X, TEXT_Y, C_BLACK, "File : %s", sFileName_);
}
game_.displayFileName();
if (obviousVals_ != -1){
if (obviousVals_){
dprint(TEXT_X, TEXT_Y + TEXT_V_OFFSET, C_BLACK,
"%d obvious values", obviousVals_);
dprint(OBV_TEXT_X, OBV_TEXT_Y, C_BLACK,
OBV_TEXT, obviousVals_);
}
else{
dtext(TEXT_X, TEXT_Y + TEXT_V_OFFSET, C_BLACK,
"No obvious value");
dtext(OBV_TEXT_X, OBV_TEXT_Y, C_BLACK, OBV_NONE_TEXT);
}
}
if (duration_ != -1){
if (duration_){
dprint(TEXT_X, TEXT_Y + 2*TEXT_V_OFFSET, C_BLACK,
"Solved in %d ms", duration_);
dprint(SOL_X, SOL_Y, C_BLACK, SOL_TEXT, duration_);
}
else{
dprint(TEXT_X, TEXT_Y + 2*TEXT_V_OFFSET, C_BLACK,
"No solution found");
dprint(SOL_X, SOL_Y, C_BLACK, SOL_NONE_TEXT);
}
}

View file

@ -27,7 +27,7 @@ public:
// Destruction
~sudoSolver(){}
// Create app. menu bar
// createMenu() : Create app. menu bar
//
void createMenu();
@ -136,7 +136,6 @@ private:
// Current file name
uint16_t fileName_[BFILE_MAX_PATH + 1];
char sFileName_[BFILE_MAX_PATH + 1]; // short filename as char*
// Resolution stats.
int8_t obviousVals_;

View file

@ -20,6 +20,9 @@
#ifdef DEST_CASIO_CALC
#include <gint/timer.h>
#include <gint/clock.h>
extern bopti_image_t g_pause;
#else
using namespace std;
#endif // #ifdef DEST_CASIO_CALC
@ -28,18 +31,29 @@ using namespace std;
//
sudoku::sudoku(){
// Initializes tinySquares
for (uint8_t index=0; index<TINY_COUNT; index++){
uint8_t index;
for (index = 0; index < TINY_COUNT; index++){
tSquares_[index].setIndex(index);
}
empty(); // Start with an empty grid
soluce_ = NULL; // No soluce
empty(); // Start with an empty grid
// No hypothese
for (index = 0; index < HYP_COUNT; index++){
hypotheses_[index] = {0, HYP_NO_COLOUR, -1};
}
hypID_ = -1;
// No help (yet)
helpClues_ = MAX_HELP_CLUES;
}
// Copy constructor
//
sudoku::sudoku(sudoku& original)
:sudoku(){
setElements(original.elements_);
setElements(original.elements_); // copy the grid
}
// setElments() : set elements of the grid
@ -78,6 +92,8 @@ void sudoku::display(bool update){
#ifdef DEST_CASIO_CALC
_drawBackground();
_drawContent();
displayFileName();
_drawHypotheses();
if (update){
dupdate();
}
@ -121,12 +137,64 @@ void sudoku::display(bool update){
#endif // #ifdef DEST_CASIO_CALC
}
// displayFileName() : display current filename
//
void sudoku::displayFileName(){
if (sFileName_[0]){
#ifdef DEST_CASIO_CALC
dprint(FILE_TEXT_X, FILE_TEXT_Y, C_BLACK, FILE_TEXT, sFileName_);
#endif // #ifdef DEST_CASIO_CALC
}
}
// empty() : Empties the grid
//
void sudoku::empty(){
_freeSoluce();
for (uint8_t index(INDEX_MIN); index <= INDEX_MAX ; index++){
elements_[index].empty();
}
emptyFileName();
}
// pause() : Show pause screen
//
void sudoku::pause(){
#ifdef DEST_CASIO_CALC
// Top of image
dsubimage(0, 0, &g_pause,
0, 0, IMG_PAUSE_W, IMG_PAUSE_COPY_Y, DIMAGE_NOCLIP);
// "middle"
uint16_t y;
for (y = IMG_PAUSE_COPY_Y;
y < (IMG_PAUSE_COPY_Y + IMG_PAUSE_LINES); y++){
dsubimage(0, y, &g_pause,
0, IMG_PAUSE_COPY_Y,
IMG_PAUSE_W, 1, DIMAGE_NOCLIP);
}
// bottom
y = CASIO_HEIGHT - IMG_PAUSE_H + IMG_PAUSE_COPY_Y - 1;
dsubimage(0, y, &g_pause,
0, IMG_PAUSE_COPY_Y + 1,
IMG_PAUSE_W, IMG_PAUSE_H - IMG_PAUSE_COPY_Y - 1,
DIMAGE_NOCLIP);
dupdate();
uint car(KEY_CODE_NONE);
keyboard myKeyboard;
do{
car = myKeyboard.getKey();
}while (KEY_CODE_PAUSE != car && KEY_CODE_EXIT != car);
if (KEY_CODE_EXIT == car){
// Close app.
gint_osmenu();
}
#endif // #ifdef DEST_CASIO_CALC
}
// create() : Create a new sudoku
@ -157,6 +225,7 @@ int sudoku::create(uint8_t complexity){
// @return : 0 on success or an error code
//
uint8_t sudoku::load(const FONTCHARACTER fName){
emptyFileName();
if (!fName || !fName[0]){
return FILE_NO_FILENAME;
}
@ -201,6 +270,7 @@ uint8_t sudoku::load(const FONTCHARACTER fName){
}
// The new grid is valid
_newFileName(fName);
return FILE_NO_ERROR;
}
@ -214,6 +284,7 @@ uint8_t sudoku::load(const FONTCHARACTER fName){
// @return : 0 on success or an error code
//
int sudoku::save(const FONTCHARACTER fName){
emptyFileName();
if (!fName || !fName[0]){
return FILE_NO_FILENAME; // No valid file name
}
@ -251,7 +322,12 @@ int sudoku::save(const FONTCHARACTER fName){
oFile.close();
// Done ?
return (done?FILE_NO_ERROR:error);
if (done){
_newFileName(fName);
return FILE_NO_ERROR;
}
return error;
}
#ifdef DEST_CASIO_CALC
@ -274,15 +350,13 @@ bool sudoku::edit(uint8_t mode){
bool showSelected(true);
bool reDraw(false);
int eStatus;
int hypID(-1); // No hypothese
int hypColour(HYP_NO_COLOUR);
int index;
int8_t index;
position currentPos(0, false);
position prevPos(0, false);
if (EDIT_MODE_CREATION == mode){
revert(); // Remove obious and found values (if any)
revert(); // Remove obvious and found values (if any)
display();
}
@ -297,13 +371,14 @@ bool sudoku::edit(uint8_t mode){
_elementTxtColour(currentPos, mode, false));
dupdate();
// # elements in the grid
uint8_t elements(0);
for (uint8_t index(INDEX_MIN); index<=INDEX_MAX ; index++){
// # Values in the grid
uint8_t values(0), oValues(0);
for (index = INDEX_MIN; index<=INDEX_MAX ; index++){
if (!elements_[index].isEmpty()){
elements++;
values++;
}
}
oValues = values;
// Timer for blinking effect
int tickCount(BLINK_TICKCOUNT);
@ -323,7 +398,7 @@ bool sudoku::edit(uint8_t mode){
tick = 0;
// Time to blink ?
if (!(tickCount--)){
if (!(--tickCount)){
// Blink
showSelected = !showSelected;
tickCount = BLINK_TICKCOUNT;
@ -363,90 +438,114 @@ bool sudoku::edit(uint8_t mode){
case KEY_CODE_0:
// Remove the value
if (elements_[currentPos].empty()){
elements--; // one less element
values--; // one less element
modified = true;
// First colored element ?
if (hypID_ && hypotheses_[hypID_].firstPos == currentPos){
hypotheses_[hypID_].firstPos = -1;
}
}
break;
case KEY_CODE_1:
if ((eStatus = _checkAndSet(currentPos, 1, hypColour, mode)) >= 0){
if ((eStatus = _checkAndSet(currentPos, 1, mode)) >= 0){
modified = true;
elements+=eStatus;
values+=eStatus;
}
break;
case KEY_CODE_2:
if ((eStatus = _checkAndSet(currentPos, 2, hypColour, mode)) >= 0){
if ((eStatus = _checkAndSet(currentPos, 2, mode)) >= 0){
modified = true;
elements+=eStatus;
values+=eStatus;
}
break;
case KEY_CODE_3:
if ((eStatus = _checkAndSet(currentPos, 3, hypColour, mode)) >= 0){
if ((eStatus = _checkAndSet(currentPos, 3, mode)) >= 0){
modified = true;
elements+=eStatus;
values+=eStatus;
}
break;
case KEY_CODE_4:
if ((eStatus = _checkAndSet(currentPos, 4, hypColour, mode)) >= 0){
if ((eStatus = _checkAndSet(currentPos, 4, mode)) >= 0){
modified = true;
elements+=eStatus;
values+=eStatus;
}
break;
case KEY_CODE_5:
if ((eStatus = _checkAndSet(currentPos, 5, hypColour, mode)) >= 0){
if ((eStatus = _checkAndSet(currentPos, 5, mode)) >= 0){
modified = true;
elements+=eStatus;
values+=eStatus;
}
break;
case KEY_CODE_6:
if ((eStatus = _checkAndSet(currentPos, 6, hypColour, mode)) >= 0){
if ((eStatus = _checkAndSet(currentPos, 6, mode)) >= 0){
modified = true;
elements+=eStatus;
values+=eStatus;
}
break;
case KEY_CODE_7:
if ((eStatus = _checkAndSet(currentPos, 7, hypColour, mode)) >= 0){
if ((eStatus = _checkAndSet(currentPos, 7, mode)) >= 0){
modified = true;
elements+=eStatus;
values+=eStatus;
}
break;
case KEY_CODE_8:
if ((eStatus = _checkAndSet(currentPos, 8, hypColour, mode)) >= 0){
if ((eStatus = _checkAndSet(currentPos, 8, mode)) >= 0){
modified = true;
elements+=eStatus;
values+=eStatus;
}
break;
case KEY_CODE_9:
if ((eStatus = _checkAndSet(currentPos, 9, hypColour, mode)) >= 0){
if ((eStatus = _checkAndSet(currentPos, 9, mode)) >= 0){
modified = true;
elements+=eStatus;
values+=eStatus;
}
break;
// Pause
case KEY_CODE_PAUSE:
pause();
display();
menu.update();
break;
//
// Hyptoheses
// Hyptoheses & manual solving
//
case IDM_MANUAL_ACCEPT:
if (_acceptHypothese(hypColour)){
// At least one element's colour has changed => redraw
if (_onManualAccept()){
display();
}
break;
case IDM_MANUAL_HELP:
if (-1 != (index = _onManualHelp(menu))){
// Select added-element
currentPos = index;
}
break;
case IDM_MANUAL_REJECT:
{
uint8_t count;
if ((count = _rejectHypothese(hypColour))){
elements-=count;
if ((count = _onManualReject())){
values-=count;
if (-1 != hypotheses_[hypID_].firstPos){
// Move to element at 'first' pos.
currentPos = hypotheses_[hypID_].firstPos;
}
hypotheses_[hypID_].firstPos = -1; // No longer needed
// At least one element's colour has changed => redraw
display();
@ -463,7 +562,7 @@ bool sudoku::edit(uint8_t mode){
// Check grid
//
case IDM_EDIT_CHECK:
_onEditCheck();
_onEditCheckSudoku();
break;
// Exit from "edit" mode
@ -475,22 +574,17 @@ bool sudoku::edit(uint8_t mode){
// Other messages
default:
if ((index = (action.value - IDM_MANUAL_COLOUR_FIRST)) >=0 &&
index <= (IDM_MANUAL_COLOUR_FIRST+3) &&
_onChangeHypothese(menu, index, hypID, hypColour)){
menu.showParentBar(false); // Return to "manual" menubar
PMENUITEM item = menu.findItem(IDM_MANUAL_HYP_SUBMENU, SEARCH_BY_ID);
if (item){
item->ownerData = hypColour; // Update col in menu
}
menu.update();
if (action.value >= IDM_MANUAL_COLOUR_FIRST &&
action.value < (IDM_MANUAL_COLOUR_FIRST + HYP_COUNT)){
// User choose a checkbox
_onHypChanged(menu, action.value,
menuBar::isBitSet(action.state, ITEM_STATE_CHECKED));
}
break;
} // switch (action.value)
if (reDraw || (prevPos != currentPos)){
if (reDraw || prevPos != currentPos){
// if sel. changed, erase previously selected element
if (prevPos != currentPos){
_drawSingleElement(prevPos,
@ -511,27 +605,56 @@ bool sudoku::edit(uint8_t mode){
_elementTxtColour(currentPos, mode, false));
}
// # values
if (oValues != values){
/*
drect(VALUES_X, VALUES_Y,
CASIO_WIDTH - 1,
VALUES_Y + TEXT_V_OFFSET - 1,
SCREEN_BK_COLOUR);
*/
dprint_opt(VALUES_X, VALUES_Y,
C_BLACK, SCREEN_BK_COLOUR,
DTEXT_LEFT, DTEXT_TOP,
VALUES_TEXT, values, ROW_COUNT * LINE_COUNT);
oValues = values;
if (values >= VALUES_COUNT){
cont = false; // No more value to find
}
}
dupdate();
prevPos = currentPos;
reDraw = false;
}
/*
if (modified){
dprint_opt(CASIO_WIDTH - 100, CASIO_HEIGHT - 12 - MENUBAR_DEF_HEIGHT,
C_BLACK, SCREEN_BK_COLOUR,
DTEXT_LEFT, DTEXT_TOP,
" Elements : %d ", elements);
dupdate();
}
*/
} // while (cont)
if (timerID >= 0){
timer_stop(timerID); // stop the timer
}
// Completed ?
if (values >= VALUES_COUNT){
window popup;
window::winInfo wInf;
wInf.style = WIN_STYLE_DBORDER | WIN_STYLE_HCENTER;
wInf.pos.y = WIN_SOL_Y;
wInf.pos.w = WIN_SOL_W;
wInf.pos.h = WIN_SOL_H;
wInf.bkColour = COLOUR_LT_GREY;
popup.create(wInf);
popup.drawText(WIN_FOUND_TXT);
popup.update();
getkey(); // Wait for any key to be pressed
popup.close();
display();
}
// Remove all coloured hyp.
if (EDIT_MODE_MANUAL == mode){
for (uint8_t index(INDEX_MIN); index<=INDEX_MAX ; index++){
@ -576,10 +699,12 @@ uint8_t sudoku::findObviousValues(){
//
// @mDuration : points to an int that will receive duration
// of solving process in ms. Can be NULL
// @soluce : Pointer to a table to copy the solution into. If NULL
// or if no soluce is found no copy is done
//
// @return : true if a solution was found
//
bool sudoku::resolve(int* mDuration){
bool sudoku::resolve(int* mDuration, int8_t** soluce){
clock_t start(0);
if (mDuration){
@ -587,12 +712,38 @@ bool sudoku::resolve(int* mDuration){
start = clock();
}
#ifdef DEST_CASIO_CALC
window waitWindow;
window::winInfo wInf;
wInf.style = WIN_STYLE_DEFAULT;
wInf.pos.y = WIN_SOL_Y;
wInf.pos.w = WIN_SOL_W;
wInf.pos.h = WIN_SOL_H;
wInf.bkColour = COLOUR_LT_GREY;
waitWindow.create(wInf);
waitWindow.drawText(WIN_SEARCH_TXT);
waitWindow.update();
#endif // #ifdef DEST_CASIO_CALC
bool found(_resolve(INDEX_MIN)); // Try to find the first solution
// Copy duration
if (mDuration){
(*mDuration) = ((clock() - start) * 1000 / CLOCKS_PER_SEC);
}
// Copy soluce ?
if (found && soluce){
(*soluce) = (int8_t*)malloc(sizeof(int8_t) * LINE_COUNT * ROW_COUNT);
if ((*soluce)){
_copyElements(*soluce);
}
}
#ifdef DEST_CASIO_CALC
waitWindow.close(); // Close the window
#endif // #ifdef DEST_CASIO_CALC
return found;
}
@ -828,14 +979,12 @@ bool sudoku::_checkValue(position& pos, uint8_t value){
//
// @pos : position
// @value : value to put
// @hypoCol : Hypothese's colour
// @mode : edition mode
//
// @return : -1 if can't be changed, 0 if changed an existing value,
// 1 if new value set
//
int sudoku::_checkAndSet(position& pos, uint8_t value,
int hypColour, uint8_t mode){
int sudoku::_checkAndSet(position& pos, uint8_t value, uint8_t mode){
uint8_t status(elements_[pos].status());
bool editGrid(true);
if (EDIT_MODE_MANUAL == mode){
@ -850,7 +999,8 @@ int sudoku::_checkAndSet(position& pos, uint8_t value,
uint8_t oValue(elements_[pos].value()); // current val
// Check value at the given pos.
// New allowed value or same value with diff. hyp. colour
// New allowed value or same value with different hyp. colour
int hypColour(_hypColour(hypID_));
if ((oValue == value && elements_[pos.index()].hypColour() != hypColour)
||
(_checkLine(pos, value) && _checkRow(pos, value) &&
@ -858,22 +1008,28 @@ int sudoku::_checkAndSet(position& pos, uint8_t value,
// Set new value and colour
elements_[pos.index()].setValue(value, editGrid);
elements_[pos.index()].setHypColour(hypColour);
// First value with this hyp ?
if (-1 == hypotheses_[hypID_].firstPos){
hypotheses_[hypID_].firstPos = pos.index();
}
return (oValue?0:1);
}
return -1; // Not set
}
// _onEditCheck() : Check wether grid can be solved
// _onEditCheckSudoku() : Check wether grid can be solved
//
void sudoku::_onEditCheck(){
void sudoku::_onEditCheckSudoku(){
sudoku tester(*this);
int count = tester.multipleSolutions();
int count = tester.multipleSolutions(); // try to find solution(s)
#ifdef DEST_CASIO_CALC
window output;
window::winInfo wInf;
wInf.title = (char*)"Check";
wInf.title = (char*)WIN_SOL_TITLE;
wInf.style = WIN_STYLE_DBORDER | WIN_STYLE_HCENTER;
wInf.pos.y = WIN_SOL_Y;
wInf.pos.w = WIN_SOL_W;
@ -886,8 +1042,8 @@ void sudoku::_onEditCheck(){
output.drawText(STR_MULTIPLE_SOL, -1, -1, COLOUR_RED);
break;
case 1:
output.drawText(STR_ONE_SOL, -1, -1, COLOUR_RED);
case 1:
output.drawText(STR_ONE_SOL);
break;
case 0:
@ -898,9 +1054,8 @@ void sudoku::_onEditCheck(){
output.update();
// Wait for any key to be pressed
// Wait for any key to be pressed
getkey();
output.close();
display();
@ -1027,6 +1182,32 @@ void sudoku::_drawSingleElement(position pos, int bkColour, int txtColour){
#endif // #ifdef DEST_CASIO_CALC
}
// _drawHypotheses() : Draw hypotheses list
//
void sudoku::_drawHypotheses(){
#ifdef DEST_CASIO_CALC
// Erase previous list
drect(HYP_LIST_X, HYP_LIST_Y,
HYP_LIST_X + HYP_LIST_W + HYP_COUNT * HYP_LIST_OFFSET,
HYP_LIST_Y + HYP_LIST_H + HYP_COUNT * HYP_LIST_OFFSET,
SCREEN_BK_COLOUR);
// Draw hypotheses' stack
if (hypID_ >= 0){
dtext(HYP_LIST_TEXT_X, HYP_LIST_TEXT_Y, C_BLACK, HYP_LIST_TEXT);
int x(HYP_LIST_X), y(HYP_LIST_Y);
for (uint8_t index(0); index <= hypID_; index++){
drect(x, y, x + HYP_LIST_W, y + HYP_LIST_H,
hypotheses_[index].colour);
x+=HYP_LIST_OFFSET;
y+=HYP_LIST_OFFSET;
}
}
#endif // #ifdef DEST_CASIO_CALC
}
//
// Search for obvious values
//
@ -1359,6 +1540,65 @@ bool sudoku::_resolve(position* sPos){
return (POS_END_OF_LIST == status);
}
// _onManualHelp() : Help the user to solve the current grid
//
// A new clue element is shown
//
// @menu : Edit sub-menu
//
// @return : index of added element or -1 if none were added
//
int8_t sudoku::_onManualHelp(menuBar& menu){
if (!helpClues_){
// Already helped, ... too many times
return -1;
}
// No sol. in memory ?
if (NULL == soluce_){
srand((unsigned int)clock()); // Set root
sudoku solver(*this);
if (!solver.resolve(NULL, &soluce_)){
// Unable to find a solution (???)
return -1;
}
}
// # of free items
uint8_t freeItems(ROW_COUNT * LINE_COUNT);
int8_t index;
for (index = INDEX_MIN; index < INDEX_MIN; index++){
if (elements_[index].isEmpty()){
freeItems--;
}
}
if (freeItems <= MIN_CLUE_COUNT){
return -1; // No need to help the use, the grid is nearly full
}
// Randomly select an item in the free ones
uint8_t clueID(1 + (rand() % freeItems));
index = -1;
while (clueID){
if (elements_[++index].isEmpty()){
clueID--;
}
}
// Found one !
int8_t helpValue(soluce_[index] * -1); // found value is < 0
elements_[index].setValue(helpValue, true);
display();
if (!(--helpClues_)){
menu.activateItem(IDM_MANUAL_HELP, SEARCH_BY_ID, false);
}
return index;
}
// _findFirstEmptyPos() : Find the first empty pos.
//
// @start : position where to start the search
@ -1419,6 +1659,7 @@ int sudoku::__callbackTick(volatile int *pTick){
//
void sudoku::_createEditMenu(menuBar& menu, uint8_t editMode){
if (EDIT_MODE_CREATION == editMode){
// Just 3 buttons on edit mode
menu.appendItem(IDM_EDIT_OK, IDS_EDIT_OK);
menu.appendItem(IDM_EDIT_CHECK, IDS_EDIT_CHECK);
menu.addItem(MENU_POS_RIGHT - 1, IDM_EDIT_CANCEL, IDS_EDIT_CANCEL);
@ -1431,9 +1672,9 @@ void sudoku::_createEditMenu(menuBar& menu, uint8_t editMode){
// Coloured hyp. submenu
// each colour is stored in the ownerData member ot item struct
menuBar hypMenu;
PMENUITEM item = hypMenu.appendCheckbox(IDM_MANUAL_COLOUR_FIRST,
PMENUITEM item(hypMenu.appendCheckbox(IDM_MANUAL_COLOUR_FIRST,
NULL, ITEM_STATE_DEFAULT,
ITEM_STATUS_OWNERDRAWN);
ITEM_STATUS_OWNERDRAWN));
item->ownerData = HYP_COLOUR_YELLOW;
item = hypMenu.appendCheckbox(IDM_MANUAL_COLOUR_FIRST + 1,
@ -1459,14 +1700,18 @@ void sudoku::_createEditMenu(menuBar& menu, uint8_t editMode){
ITEM_STATE_DEFAULT, ITEM_STATUS_OWNERDRAWN);
item->ownerData = HYP_NO_COLOUR;
menu.appendItem(IDM_MANUAL_ACCEPT, IDS_MANUAL_ACCEPT);
item = menu.appendItem(IDM_MANUAL_ACCEPT, IDS_MANUAL_ACCEPT,
ITEM_STATE_DEFAULT, ITEM_STATUS_OWNERDRAWN);
item->ownerData = HYP_NO_COLOUR;
menu.appendItem(IDM_MANUAL_REJECT, IDS_MANUAL_REJECT);
menu.appendItem(IDM_MANUAL_HELP, IDS_MANUAL_HELP);
menu.addItem(MENU_POS_RIGHT, IDM_MANUAL_END, IDS_MANUAL_END);
}
}
//
// Coloured hypotheses
// Coloured hypotheses & manual solving process
//
// _elementTxtColour() : Get element's text colour for edition
@ -1505,7 +1750,7 @@ int sudoku::_elementTxtColour(position& pos, uint8_t editMode, bool selected){
//
// @return : False on error(s)
//
bool sudoku::_ownMenuItemsDrawings(PMENUBAR const bar,
bool sudoku::_ownMenuItemsDrawings(PMENUBAR const bar,
PMENUITEM const item, RECT* const anchor, int style){
#ifdef DEST_CASIO_CALC
if (item){
@ -1520,7 +1765,8 @@ int sudoku::_elementTxtColour(position& pos, uint8_t editMode, bool selected){
drect(x, y,
anchor->x + anchor->w -3, y + HYP_SQUARE_SIZE - 1,
item->ownerData);
menuBar::isBitSet(item->state, ITEM_STATE_INACTIVE)?
GRID_BK_COLOUR:item->ownerData);
}
else{
// Draw background
@ -1552,100 +1798,198 @@ int sudoku::_elementTxtColour(position& pos, uint8_t editMode, bool selected){
return true;
}
// _acceptHypothese() : Accept all the hypothese's values
// _onManualReject() : Reject all the hypothese's values
//
// When accepted, all elements with the given hyp. colour
// will be merged with non coloured elements
// and have their hyp. colour removed.
//
// @colour : Hypothese's colour
// When rejected, all elements with the given hyp. colour
// will be cleared
//
// @return : Count of elements concerned
//
uint8_t sudoku::_acceptHypothese(int colour){
int count(0);
if (colour != HYP_NO_COLOUR){
uint8_t sudoku::_onManualReject(){
uint8_t count(0);
if (hypID_>=0){
count = _hypReject(hypotheses_[hypID_].colour);
}
return count;
}
// _hypAccept() : Accept all the hypothese's values
//
// All elements with the @colFrom colour
// will have their colour changed to the @colTo colour
//
// @colFrom : Original hyp. col.
// @colTo : Drest. hyp. colour
//
// @return : Count of elements whose colour have changed
//
uint8_t sudoku::_hypAccept(int colFrom, int colTo){
uint8_t count(0);
if (colFrom != colTo){
for (uint8_t index(INDEX_MIN); index <= INDEX_MAX; index++){
if (colour == elements_[index].hypColour()){
elements_[index].setHypColour(HYP_NO_COLOUR);
if (colFrom == elements_[index].hypColour()){
elements_[index].setHypColour(colTo);
count++;
}
}
}
#ifdef DEST_CASIO_CALC
display();
#endif // #ifdef DEST_CASIO_CALC
return count;
}
// _rejectHypothese() : Reject all the hypothese's values
// _hypReject() : Reject all the hypothese's values
//
// When rejectedted, all elements with the given hyp. colour
// will be cleared (emptied with no more hyp. colour)
// When rejected, all elements with the @colFrom hyp. colour
// will be cleared
//
// @colour : Hypothese's colour
// @colFrom : Colour of rejected elements
//
// @return : Count of elements concerned
//
uint8_t sudoku::_rejectHypothese(int colour){
int count(0);
if (colour != HYP_NO_COLOUR){
uint8_t sudoku::_hypReject(int colFrom){
uint8_t count(0);
if (colFrom != HYP_NO_COLOUR){
for (uint8_t index(INDEX_MIN); index <= INDEX_MAX; index++){
if (colour == elements_[index].hypColour()){
if (colFrom == elements_[index].hypColour()){
elements_[index].empty();
count++;
}
}
}
#ifdef DEST_CASIO_CALC
display();
#endif // #ifdef DEST_CASIO_CALC
return count;
}
// _onChangeHypothese() : Change coloured hyp.
// _hypPush() : Push a new coloured hypthese on top of stack
//
// @menu : Hyp. colours menu
// @newHypID : New colour index (in menu)
// @currentID : Current colour index
// @currentCol : Current col. value
// @menuID : ID of menu colour
// @newColour : new colour
//
// @return : true if successfully changed the hyp. colour
// @return : previous ID (or -1 on error)
//
bool sudoku::_onChangeHypothese(menuBar& menu, int newHypID,
int& currentID, int& currentCol){
PMENUITEM item = menu.findItem(newHypID + IDM_MANUAL_COLOUR_FIRST,
SEARCH_BY_ID);
if (item){
// Unselect previous col.
if (currentID >= 0){
menu.checkMenuItem(currentID + IDM_MANUAL_COLOUR_FIRST,
SEARCH_BY_ID, ITEM_UNCHECKED);
}
int sudoku::_hypPush(menuBar& menu, int menuID, int newColour){
int8_t prev(hypID_);
/* (menu.isMenuItemChecked(newHypID + IDM_MANUAL_COLOUR_FIRST,
SEARCH_BY_ID) == ITEM_CHECKED) */
if (menu.isBitSet(item->state, ITEM_STATE_CHECKED)){
currentCol = item->ownerData;
currentID = newHypID;
}
else{
currentCol = HYP_NO_COLOUR; // No hyp.
currentID = -1;
}
// Add to stack
hypotheses_[++hypID_].colour = newColour;
hypotheses_[hypID_].menuID = menuID;
return true;
// Update menus
_hypUpdateMenu(menu, newColour, _hypColour(hypID_-1));
return hypotheses_[prev].menuID;
}
// _hypPop() : Remove the hypothese from the top of the stack
//
// @return : previous ID
//
int sudoku::_hypPop(menuBar& menu){
int prev(-1);
if (hypID_ >= 0){
prev = (hypID_?hypotheses_[hypID_-1].menuID:-1);
// remove from top
hypotheses_[hypID_--] = {0, HYP_NO_COLOUR, -1};
// Update menus
_hypUpdateMenu(menu, _hypColour(hypID_), _hypColour(hypID_-1));
}
return false;
return prev;
}
// _hypUpdateMenu() : Update menu according to new selected colour
//
// @menu : menubar
// @curCol : New 'currrent' colour
// @prevCol : previous col
//
void sudoku::_hypUpdateMenu(menuBar& menu, int curCol, int prevCol){
if (curCol == prevCol){
return;
}
// Update menus
PMENUITEM item(menu.getItem(IDM_MANUAL_HYP_SUBMENU, SEARCH_BY_ID));
if (item){
item->ownerData = curCol; // Current hyp's col.
}
if ((item = menu.getItem(IDM_MANUAL_ACCEPT, SEARCH_BY_ID))){
// Previous hyp's col
item->ownerData = prevCol;
}
}
// _onHypChanged() : Change coloured hyp.
//
// @menu : Hyp. colours menu
// @newHypID : Menu ID
// @checked : true if item is checked
//
// @return : current col.
//
int sudoku::_onHypChanged(menuBar& menu, int newHypID, bool checked){
if (newHypID == hypID_){
return hypotheses_[hypID_].colour; // No change
}
PMENUITEM item(menu.findItem(newHypID, SEARCH_BY_ID));
if (item){
int prev;
if (checked){
prev = _hypPush(menu, newHypID, item->ownerData);
}
else{
// Reject values associated with the previous colour
// ie. accept with the prev. colour
_hypAccept(_hypColour(hypID_), _hypColour(hypID_-1));
prev = _hypPop(menu);
}
// "previous" item's state
if (prev >= 0){
menu.activateItem(prev, SEARCH_BY_ID, !checked);
}
// Activate current hyp. col in menu
menu.selectByIndex(checked?hypotheses_[hypID_].menuID:prev, true);
// menu.showParentBar(false); // Return to "manual" menubar
menu.update();
display();
return item->ownerData;
}
// error ?
return HYP_NO_COLOUR;
}
//
// Utilities
//
// _newFileName() : Set current file name
//
// @fName : New FQN
//
void sudoku::_newFileName(FONTCHARACTER fName){
if (!FC_ISEMPTY(fName)){
char sName[BFILE_MAX_PATH + 1];
bFile::FC_FC2str(fName, sName); // convert to char*
char* name = strrchr(sName, CHAR_PATH_SEPARATOR);
strcpy(sFileName_, (name?++name:sName)); // No path ?
}
else{
emptyFileName();
}
}
// _revertFrom : Return to the original state
//
// All values "after" @from prosition will be set to 0 if
@ -1676,4 +2020,13 @@ void sudoku::_copyElements(int8_t* dest){
}
}
// _freeSoluce() : Free the memory allocated for a solution
//
void sudoku::_freeSoluce(void){
if (soluce_){
free(soluce_);
soluce_ = NULL;
}
}
// EOF

View file

@ -47,7 +47,7 @@ enum GRID_COMPLEXITTY{
COMPLEXITY_HARD = 22
};
#define COMPLEXITY_BLOCKED_MAX 5
#define COMPLEXITY_BLOCKED_MAX 4
#ifdef __cplusplus
extern "C" {
@ -63,7 +63,9 @@ public:
sudoku(sudoku& original);
// Destruction
~sudoku(){}
~sudoku(){
_freeSoluce();
}
// setElments() : set elements of the grid
//
@ -83,6 +85,10 @@ public:
//
void display(bool update = true);
// displayFileName() : display current filename
//
void displayFileName();
// empty() : Empties the grid
//
void empty();
@ -91,7 +97,11 @@ public:
//
void revert(){
_revertFrom(INDEX_MIN);
}
}
// pause() : Show pause screen
//
static void pause();
// create() : Create a new sudoku
//
@ -105,6 +115,12 @@ public:
// io
//
// emptyFileName() : Empty current file name
//
void emptyFileName(){
sFileName_[0] = '\0';
}
// load() : Load a new grid
//
// @fName : file to load
@ -150,15 +166,17 @@ public:
//
// @mDuration : points to an int that will receive duration
// of solving process in ms. Can be NULL
// @soluce : Pointer to a table to copy the solution into. If NULL
// or if no soluce is found no copy is done
//
// @return : true if a solution was found
//
bool resolve(int* mDuration = NULL);
bool resolve(int* mDuration = NULL, int8_t** soluce = NULL);
// multipleSolutions() : Check wether a grid has one or many solutions
//
// This method doesn't seek for all possible solutions since it stops
// when no soluce is found or at the second one
// when no soluce is found or at the second one
//
// @return : 0 if the grid has no solution, 1 if a unique solution has
// been found -1 if many solutions may be founded (2 at least)
@ -234,12 +252,11 @@ private:
//
// @pos : position
// @value : value to put
// @hypoCol : Hypothese's colour
// @mode : edition mode
//
// @return : -1 if can't be changed, 0 if changed an existing value,
// 1 if new value set
int _checkAndSet(position& pos, uint8_t value, int hypColour, uint8_t mode);
int _checkAndSet(position& pos, uint8_t value, uint8_t mode);
//
// Drawings
@ -263,6 +280,10 @@ private:
//
void _drawSingleElement(position pos, int bkColour, int txtColour);
// _drawHypotheses() : Draw hypotheses list
//
void _drawHypotheses();
//
// Search for obvious values
//
@ -315,14 +336,24 @@ private:
//
uint8_t _setObviousValueInRows(position& pos, uint8_t value);
// _onEditCheck() : Check wether grid can be solved
// _onEditCheckSudoku() : Check wether grid can be solved
//
void _onEditCheck();
void _onEditCheckSudoku();
//
// Resolving
//
// _onHelp() : Help the user to solve the current grid
//
// A new clue element is shown
//
// @menu : Edit sub-menu
//
// @return : index of added element or -1 if none were added
//
int8_t _onManualHelp(menuBar& menu);
// _findFirstEmptyPos() : Find the first empty pos.
//
// @start : position where to start the search
@ -362,7 +393,7 @@ private:
void _createEditMenu(menuBar& menu, uint8_t editMode);
//
// Coloured hypotheses
// Coloured hypotheses & manual solving process
//
// _elementTxtColour() : Get element's text colour for edition
@ -388,45 +419,94 @@ private:
static bool _ownMenuItemsDrawings(PMENUBAR const bar,
PMENUITEM const item, RECT* const anchor, int style);
// _acceptHypothese() : Accept all the hypothese's values
// _onManualAccept() : Accept all the hypothese's values
//
// When accepted, all elements with the given hyp. colour
// will be merged with non coloured elements
// and have their hyp. colour removed.
//
// @colour : Hypothese's colour
// When accepted, all elements with the current hyp. colour
// will have their colour changed to the previous selected col.
//
// @return : Count of elements concerned
//
uint8_t _acceptHypothese(int colour);
uint8_t _onManualAccept(){
// Change selected col. to previous hyp. (if any)
return _hypAccept(_hypColour(hypID_), _hypColour(hypID_-1));
}
// _rejectHypothese() : Reject all the hypothese's values
// _onManualReject() : Reject all the hypothese's values
//
// When rejectedted, all elements with the given hyp. colour
// will be cleared (emptied with no more hyp. colour)
//
// @colour : Hypothese's colour
// When rejected, all elements with the given hyp. colour
// will be cleared
//
// @return : Count of elements concerned
//
uint8_t _rejectHypothese(int colour);
uint8_t _onManualReject();
// _onChangeHypothese() : Change coloured hyp.
// _hypAccept() : Accept all the hypothese's values
//
// All elements with the @colFrom colour
// will have their colour changed to the @colTo colour
//
// @colFrom : Original hyp. col.
// @colTo : Drest. hyp. colour
//
// @return : Count of elements whose colour have changed
//
uint8_t _hypAccept(int colFrom, int colTo);
// _hypReject() : Reject all the hypothese's values
//
// When rejected, all elements with the @colFrom hyp. colour
// will be cleared
//
// @colFrom : Colour of rejected elements
//
// @return : Count of elements concerned
//
uint8_t _hypReject(int colFrom);
// _hypPush() : Push a new coloured hypothese on top of stack
//
// @menu : Hyp. colours menu
// @newHypID : New colour index (in menu)
// @currentID : Current colour index
// @currentCol : Current col. value
// @menuID : ID of menu colour
// @newColour : new colour
//
// @return : true if successfully changed the hyp. colour
// @return : previous menu ID (or -1 on error)
//
bool _onChangeHypothese(menuBar& menu, int newHypID,
int& currentID, int& currentCol);
int _hypPush(menuBar& menu, int menuID, int newColour);
// _hypPop() : Remove the hypothese from the top of the stack
//
// @return : previous menu ID
//
int _hypPop(menuBar& menu);
// _hypUpdateMenu() : Update menu according to new selected colour
//
// @menu : menubar
// @curCol : New 'currrent' colour
// @prevCol : previous col
//
void _hypUpdateMenu(menuBar& menu, int curCol, int prevCol);
// _onHypChanged() : Change coloured hyp.
//
// @menu : Hyp. colours menu
// @newHypID : Menu ID
// @checked : true if item is checked
//
// @return : current col.
//
int _onHypChanged(menuBar& menu, int newHypID, bool checked);
//
// Utilities
//
// _newFileName() : Set current file name
//
// @fName : New FQN
//
void _newFileName(FONTCHARACTER fName);
// _revertFrom : Return to the "original" state
//
// All values "after" @from prosition will be set to 0 if
@ -443,16 +523,41 @@ private:
//
// @dest : destination table
//
void _copyElements(int8_t* dest);
void _copyElements(int8_t* dest);
// _freeSoluce() : Free the memory allocated for a solution
//
void _freeSoluce(void);
// Helper ...
int _hypColour(int hypID){
return (hypID < 0? HYP_NO_COLOUR:hypotheses_[hypID].colour);
}
// Members
private:
element elements_[LINE_COUNT * ROW_COUNT]; // grid as a one-dim. table
tinySquare tSquares_[TINY_COUNT]; // Access to elements in tinySquares
element elements_[LINE_COUNT * ROW_COUNT];
tinySquare tSquares_[TINY_COUNT]; // Access to elements in tinySquares
int8_t *soluce_; // A solution for the current grid
char sFileName_[BFILE_MAX_PATH + 1]; // current short filename
// Position & dims of screen
// {x Grid, yGrid, "screen" width , "screen" height}
RECT screen_;
// Hypotheses & help
//
typedef struct{
int menuID; // ID in the menu
int colour; // Associated colour
int8_t firstPos; // Index of the first value
}HYPOTHESE;
HYPOTHESE hypotheses_[HYP_COUNT]; // Hyps' stack
int8_t hypID_; // Current hyp. index
uint8_t helpClues_; // # of possible help clues left
};
#ifdef __cplusplus

View file

@ -10,9 +10,6 @@
#include "sudokuShuffler.h"
#include "position.h"
#include <cstdlib>
#include <ctime>
// Construction
//
sudokuShuffler::sudokuShuffler(element* source){