Début corrections 'obvious values'

This commit is contained in:
Jérôme Henry-Barnaudière - GeeHB 2023-12-08 19:14:36 +01:00
parent 231557ac09
commit 6604915b8e
5 changed files with 344 additions and 27 deletions

View File

@ -6,8 +6,11 @@ int main(void)
sudoku myGame;
myGame.display();
myGame.edit(KEY_CODE_EXIT);
myGame.edit();
myGame.findObviousValues();
myGame.display();
getkey();
return 1;
}

View File

@ -10,6 +10,8 @@
#include "sudoku.h"
#include "shared/bFile.h"
#include <math.h>
// Construction
//
sudoku::sudoku(){
@ -187,15 +189,12 @@ uint8_t sudoku::save(FONTCHARACTER fName){
// edit() : Edit / modify the current grid
//
// @exitKey : key code of exit key
//
// @return : true if grid has been modified or false if left unchanged
//
bool sudoku::edit(uint exitKey){
bool sudoku::edit(){
bool modified(false);
bool cont(true);
uint car(0);
int8_t val(0);
position currentPos(0, false);
position prevPos(0, false);
keyboard keys;
@ -242,39 +241,39 @@ bool sudoku::edit(uint exitKey){
break;
case KEY_CODE_1:
modified =_checkAndSet(currentPos, 1);
modified = _checkAndSet(currentPos, 1);
break;
case KEY_CODE_2:
modified =_checkAndSet(currentPos, 2);
modified = _checkAndSet(currentPos, 2);
break;
case KEY_CODE_3:
modified =_checkAndSet(currentPos, 3);
modified = _checkAndSet(currentPos, 3);
break;
case KEY_CODE_4:
modified =_checkAndSet(currentPos, 4);
modified = _checkAndSet(currentPos, 4);
break;
case KEY_CODE_5:
modified =_checkAndSet(currentPos, 5);
modified = _checkAndSet(currentPos, 5);
break;
case KEY_CODE_6:
modified =_checkAndSet(currentPos, 6);
modified = _checkAndSet(currentPos, 6);
break;
case KEY_CODE_7:
modified =_checkAndSet(currentPos, 7);
modified = _checkAndSet(currentPos, 7);
break;
case KEY_CODE_8:
modified =_checkAndSet(currentPos, 8);
modified = _checkAndSet(currentPos, 8);
break;
case KEY_CODE_9:
modified =_checkAndSet(currentPos, 1);
modified = _checkAndSet(currentPos, 9);
break;
case KEY_CODE_EXE:
@ -287,11 +286,29 @@ bool sudoku::edit(uint exitKey){
} // switch (car)
} // while (cont)
// unselect
_drawSingleElement(currentPos.row(), currentPos.line(), elements_[currentPos.index()].value(), BK_COLOUR, ORIGINAL_COLOUR);
return modified;
}
#endif // #ifdef DEST_CASIO_CALC
// findObviousValues() : Find all the obvious values
//
// @return : #obvious values found
//
uint8_t sudoku::findObviousValues(){
uint8_t found(0);
uint values(0);
do{
values = _findObviousValues();
found += values;
} while(values); // since we put some values, maybe we can guess new ones
return found;
}
//
// Internal methods
//
@ -338,8 +355,11 @@ bool sudoku::_checkRow(position& pos, uint8_t value){
return true;
}
#ifdef DEST_CASIO_CALC
//
// Drawings
//
#ifdef DEST_CASIO_CALC
// _drawBorders() : Draw the grid's borders
//
void sudoku::_drawBorders(){
@ -413,7 +433,250 @@ void sudoku::_drawSingleElement(uint8_t row, uint8_t line, uint8_t value, int bk
dtext_opt(x + dx, y + dy, txtColour, bkColour, DTEXT_LEFT, DTEXT_TOP, sVal, 1);
}
}
#endif // #ifdef DEST_CASIO_CALC
//
// Obvious values
//
// _findObviousValues() :
// Search and set all the possible obvious values in the grid
//
// @return the # of values found (and set)
//
uint8_t sudoku::_findObviousValues(){
uint8_t found(0);
position pos(0, true);
int8_t value;
for (uint8_t index = 0; index <= INDEX_MAX; index++){
if (elements_[pos.index()].isEmpty()){
// Try to set a single value at this empty place
value = _checkObviousValue(pos);
if (value){
// One more obvious value !!!!
elements_[pos.index()].setValue(value, STATUS_OBVIOUS);
found += 1;
}
}
else{
value = elements_[pos.index()].value(); // Current "ORIGINAL" val.
// Can we put this value on another line ?
found += _setObviousValueInLines(pos, value);
// ... or/and put it in another row ?
found += _setObviousValueInRows(pos, value);
}
// Next pos.
pos+=1;
} // for
return found;
}
// _checkObviousValue() : Is there an obvious value for the given position ?
//
// pos : current position in the grid
//
// @returns the value or 0
//
uint8_t sudoku::_checkObviousValue(position& pos){
uint8_t value(0);
for (uint8_t candidate = VALUE_MIN; candidate <= VALUE_MAX; candidate++){
if (_checkValue(pos, candidate)){
// This candidate value can be used
if (value){
// already a possible value at this pos.
// => no unique value can be guessed
return 0;
}
value = candidate;
}
}
return value;
}
// _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 sudoku::_setObviousValueInLines(position& pos, uint8_t value){
// Check for lines in the 3 tinySquares
//
// tinySquares IDs for this line
uint8_t modID(pos.squareID() % 3);
uint8_t firstID, secondID;
if (0 == modID){
// At the left pos
firstID = pos.squareID() + 1;
secondID = pos.squareID() + 2;
}
else{
if (1 == modID){
// centered
firstID = pos.squareID() - 1;
secondID = pos.squareID() + 1;
}
else{
// on the right
firstID = pos.squareID() - 2;
secondID = pos.squareID() - 1;
}
}
// Is the value already in theses tiny squares ?
CPOINT firstPos(tSquares_[firstID].findValue(elements_, value));
CPOINT secondPos(tSquares_[secondID].findValue(elements_, value));
// No for both them or yes for both
if ((-1 == firstPos.line && -1 == secondPos.line) || (-1 != firstPos.line && -1 != secondPos.line)){
return 0;
}
// Just one square misses the value => we'll try to put this value in the correct line
//
// The sum of the 3 lineID is a consts and we know 2 of them ...
//
uint8_t candidate, candidateLine;
if (firstPos.line>=0){
candidate = firstID;
candidateLine = 2 * (tSquares_[firstID].topLine() + 1) - secondPos.line - pos.line() + 1;
}
else{
candidate = secondID;
candidateLine = 2 * (tSquares_[secondID].topLine() + 1) - firstPos.line - pos.line() + 1;
}
// Try to put the value in the line
//
bool found(false);
position candidatePos(0), foundPos;
candidatePos.moveTo(candidateLine, tSquares_[candidate].topRow()); // First row ID
for (uint8_t row = 0; row < TINY_ROW_COUNT; row++){
if (elements_[candidatePos.index()].isEmpty() && _checkValue(candidatePos, value)){
// found a valid pos. in the line for the value
if (found){
// Already a candiate => not obvious
return 0;
}
foundPos.set(candidatePos);
found = true;
}
// Next row
candidatePos+=1;
}
// Did we find a position ?
if (found){
// Yes !!!
elements_[foundPos.index()].setValue(value, STATUS_OBVIOUS); // One more obvious value
return 1;
}
// No ...
return 0;
}
// _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 sudoku::_setObviousValueInRows(position& pos, uint8_t value){
// Check for lines in the 3 tinySquares
//
// tinySquares IDs for this line
uint8_t modID(floor(pos.squareID() / 3));
uint8_t firstID, secondID;
if (0 == modID){
// At the top pos
firstID = pos.squareID() + TINY_ROW_COUNT;
secondID = pos.squareID() + 2 * TINY_ROW_COUNT;
}
else{
if (1 == modID){
// centered
firstID = pos.squareID() - TINY_ROW_COUNT;
secondID = pos.squareID() + TINY_ROW_COUNT;
}
else{
// on the bottom
firstID = pos.squareID() - 2 * TINY_ROW_COUNT;
secondID = pos.squareID() - 1 * TINY_ROW_COUNT;
}
}
// Is the value already in theses tiny squares ?
CPOINT firstPos(tSquares_[firstID].findValue(elements_, value));
CPOINT secondPos(tSquares_[secondID].findValue(elements_, value));
// No for both them or yes for both
if ((-1 == firstPos.row && -1 == secondPos.row) || (-1 != firstPos.row && -1 != secondPos.row)){
return 0;
}
// Just one square misses the value => we'll try to put this value in the correct line
//
// The sum of the 3 lineID is a consts and we know 2 of them
//
uint8_t candidate, candidateRow;
if (firstPos.row == -1){
candidate = firstID;
candidateRow = 2 * (tSquares_[firstID].topRow() + 1) - secondPos.row - pos.row() + 1;
}
else{
candidate = secondID;
candidateRow = 2 * (tSquares_[secondID].topRow() + 1) - firstPos.row - pos.row() + 1;
}
// Try to put the value ...
//
bool found(false);
position candidatePos(0), foundPos;
candidatePos.moveTo(tSquares_[candidate].topLine(), candidateRow);
for (uint8_t line = 0; line < TINY_LINE_COUNT; line++){
if (elements_[candidatePos.index()].isEmpty() && _checkValue(candidatePos, value)){
if (found){
// Already a candiate => not obvious
return 0;
}
foundPos.set(candidatePos);
found = true;
}
// Next line
candidatePos += ROW_COUNT;
}
// Did we find a valid position ?
if (found){
// Yes !!!
elements_[foundPos.index()].setValue(value, STATUS_OBVIOUS);
return 1;
}
// No ...
return 0;
}
// EOF

View File

@ -65,13 +65,17 @@ public:
#ifdef DEST_CASIO_CALC
// edit() : Edit / modify the current grid
//
// @exitKey : key code of exit key
//
// @return : true if grid has been modified or false if left unchanged
//
bool edit(uint exitKey);
bool edit();
#endif // #ifdef DEST_CASIO_CALC
// findObviousValues() : Find all the obvious values
//
// @return : #obvious values found
//
uint8_t findObviousValues();
private:
//
@ -135,6 +139,10 @@ private:
return false;
}
//
// Drawings
//
#ifdef DEST_CASIO_CALC
// _drawBorders() : Draw the grid's borders
//
@ -154,6 +162,43 @@ private:
void _drawSingleElement(uint8_t row, uint8_t line, uint8_t value, int bkColour, int txtColour);
#endif // #ifdef DEST_CASIO_CALC
//
// 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);
// Members
private:
element elements_[LINE_COUNT * ROW_COUNT]; // grid as a one dim. table

View File

@ -55,9 +55,9 @@ bool tinySquare::setIndex(uint8_t index){
// @value : value to search for
// @where : pointer to the position of the value (can be NULL)
//
// returns true if the value is in the current tinySquare
// @return : a CPOINT struct {line, row} if valid or {-1, -1} if not found
//
bool tinySquare::findValue(element* elements, uint8_t value, position* where){
CPOINT tinySquare::findValue(element* elements, uint8_t value, position* where){
// Check all the positions
for (uint8_t line = 0; line < TINY_LINE_COUNT; line++){
for (uint8_t row = 0; row < TINY_ROW_COUNT; row++){
@ -66,13 +66,13 @@ bool tinySquare::findValue(element* elements, uint8_t value, position* where){
if (where){
where->moveTo(line, row);
}
return true;
return {(int8_t)line, (int8_t)row};
}
}
}
// No, this value is not in this square
return false;
return {-1, -1};
}
// _indexes() : Indexes matrix for the tinySquare

View File

@ -24,6 +24,11 @@
extern "C" {
#endif // #ifdef __cplusplus
typedef struct cpoint{
int8_t line;
int8_t row;
}CPOINT;
// tinySquare object
// A tiny-square is one of the 9 3x3 matrix composing the whole grid
//
@ -75,9 +80,9 @@ public:
// @value : value to search for
// @where : pointer to the position of the value (can be NULL)
//
// returns true if the value is in the current tinySquare
// @return : a CPOINT struct {line, row} if valid or {-1, -1} if not found
//
bool findValue(element* elements, uint8_t value, position* where = NULL);
CPOINT findValue(element* elements, uint8_t value, position* where = NULL);
// inMe() : Is the given value "in" the square ?
//
@ -89,7 +94,8 @@ public:
// @return true if found
//
bool inMe(element* elements, uint8_t value){
return (findValue(elements, value));
CPOINT pos = findValue(elements, value);
return (pos.line >=0 && pos.row>=0);
}
private: