|
Trouver une ressource
Vous ne trouvez pas de réponse à votre problème ? Alors posez la question dans le forum. Souvenez-vous qu'il n'y a jamais de question bête, mais rester dans l'ignorance parce que l'on n'ose pas poser une question, ça c'est une erreur !
[PHP5][POO][JEUX] SUDOKU
Information sur la source
Description
Bonjour, Voici mon Sudoku que j'ai mis en ligne depuis maintenant un mois. (http://nifhell.free.fr) Aussi vu qu'il ne présente pas de bug majeur, je me permets de le publier. Des exemples d'utilisation sont dans le ZIP, ainsi que le code complet. Quelques unes des fonctionnalités: - Export en XML - Import XML - Export HTML - Export texte brut - Génération de grilles - Résolution de grilles - 7 niveaux de difficulté - 2 types de grille: en chiffre ou en lettre (vous pouvez en rajouter: facilement customisable) - Potentiellement peut créer des grilles de 25*25, 36*36, etc... cases => dépend des ressources système Sur mon site FREE: est limité à des grilles de 9*9 cases - Javascript de controle de saisie incorporé lors de l'export HTML - Un mode tutoriel, affichant, lors de l'export HTML, des listes déroulantes contenant les possibilités aulieu de zones de saisie de texte vide - Serialisable (pour se passser le sudoku dans les session) car Orienté Objet Defaut: - Les grilles ne sont pas forcément à solution unique D'ailleur si quelqu'un à un tuyau, pour faire des grille à coup sur à solution unique, matheux de préférence, car j'aime pas les solutions toute faites... Ci dessous une explication de l'algorithme de génération/résolution: Définitions: Un Sudoku est une grille dont la racine carré du nombre total de cases est un chiffre entier. Soit T le nombre total de cases. Soit N le nombre de symboles uniques (le plus souvent des chiffres) avec lesquel on remplira ces cases. N est égale à la racine carré du nombre total de case: N=sqrt(T). Soit V l'ensemble des symboles uniques choisis (ex: 1 2 3 4 5 6 7 8 9) La grille du Sudoku définit un repère, R1, dont l'origine, O1, est la case la plus en haut à gauche de la grille. La grille du Sudoku est donc composée de N lignes, de N colonnes et de N boîtes, composées elle-même de N cases. Chaque case se définit par son abscisse, I, et son ordonnée, J, définis par rapport à l'origine O1. Une boîte est un ensemble de N cases disposées en carré, et se définit par une abscisse, X, et une ordonnée, Y, relative à O1. Une boîte définie donc elle aussi un repère, R2, relatif à R1, dontl'origine, O2, est la case la plus en haut à gauche de cette boîte: Si I, J sont respectivement l'abscisse et l'ordonnée dans le repère R1 de la case la plus en haut à gauche de la boîte, alors O2 à pour coordonnées (X, Y) relatives à O1: (X, Y) = (entier(I/N), entier(J/N)) Aussi chaque case possède des coordonnées (A,B) relatives au repère de leur boîte respective, R2, définies par: (A, B) = (I-N*X, J-N*Y) Le but étant de remplir la grille avec les symboles choisit parmi les N symboles uniques. Les cases se remplissent suivant les contraintes suivantes: Toutes les cases d'une même ligne doivent comporter un symbole différent Toutes les cases d'une même colonne doivent comporter un symbole différent Toutes les cases d'une même boîte doivent comporter un symbole différent Aussi une case se définit donc également par la liste, L, des symboles possibles, i.e. qui ne contredisent pas les contraintes d'unicité ci-dessus. Une case se définit également par 3 états: On a attribué définitivement un symbole à la case. On a attribué temporairement un symbole à la case (uniquement utilisé lors des saisies du joueur). La case est incertaine, si on ne lui a pas attribué définitivement de symbole. Lorsque l'on attribue définitivement un symbole à une case, on va en informer les cases de la ligne, colonne et boîte à laquel cette case appartient, et aussi vérifier les contraintes d'unicité. Alors que lorsque que l'on attribue temporairement un symbole à une case, les contraintes d'unicité ne sont pas vérifiées, mais on prévient aussi les cases de la ligne, colonne et boîte à laquel cette case appartient. Algorithme de création de grille: A l'initialisation on créé les cases, les lignes, les colonnes et les boîtes, et on asssocie à chaque case la ligne, la colonne et la boîte à laquelle elle appartient et réciproquement. Aussi au départ lorsque la grille est vide, la liste L de chaque case est égale à V. Tant que toute les case ne sont pas à l'état "attribuer définitivement": On choisit la case, C, dont le nombre de symboles possibles est le plus faible et dont l'état est incertain et on lui attribue définitivement un symbole au hasard, S, choisi parmi la liste L. En conséquence, on prévient les autres cases, i.e. la ligne, la colonne, et la boîte de cette case vont retirer le symbole S de la liste L de chacune de leurs cases à l'état incertain: Si les contraintes d'unicité ne sont pas vérifiés, i.e. si une liste, L, de ces cases ne comporte plus de symbole, i.e. L est vide, cele signifie que la grille ne possède pas de solution: On désattribue S à C et on rétabli la précédente liste L de chacune des cases à l'état incertain de la ligne , colonne et boîte concernée. Si S était le dernier symbole possible de L, on revient à la case précédente. Sinon, on réattribue définitivement à C un autre symbole S parmi L. Sinon on rechoisit une case, C, dont le nombre de symboles possibles est le plus faible et dont l'état est incertain et on lui attribue définitivement un symbole au hasard, S, choisi parmi la liste L. etc... Fin tant que Une fois la gille remplie, on définit un nombre, P, de cases, déterminé par la difficulté du Sudoku choisi. Tant qu'il n'y a pas P cases à l'état incertain on choisit une case, C, au hasard, et on désattribue son symbole S. Fin tant que Algorithme de résolution: C'est exactement le même que celui de création sauf que la grille posséde un état initiale différent: A l'initialisation on créé les cases, les lignes, les colonnes et les boîtes, et on asssocie à chaque case la ligne, la colonne et la boîte à laquelle elle appartient et réciproquement. Aussi au départ lorsque la grille est vide, la liste L de chaque case est égale à V. On attribue définitivement à chaque case déja remplie le symbole prédéterminé. Tant que toute les case ne sont pas à l'état "attribuer définitivement": On choisit la case, C, dont le nombre de symboles possibles est le plus faible et dont l'état est incertain et on lui attribue définitivement un symbole au hasard, S, choisi parmi la liste L. En conséquence, on prévient les autres cases, i.e. la ligne, la colonne, et la boîte de cette case vont retirer le symbole S de la liste L de chacune de leurs cases à l'état incertain: Si les contraintes d'unicité ne sont pas vérifiés, i.e. si une liste, L, de ces cases ne comporte plus de symbole, i.e. L est vide, cele signifie que la grille ne possède pas de solution: On désattribue S à C et on rétabli la précédente liste L de chacune des cases à l'état incertain de la ligne , colonne et boîte concernée. Si S était le dernier symbole possible de L, on revient à la case précédente. Sinon, on réattribue définitivement à C un autre symbole S parmi L. Sinon on rechoisit une case, C, dont le nombre de symboles possibles est le plus faible et dont l'état est incertain et on lui attribue définitivement un symbole au hasard, S, choisi parmi la liste L. etc... Fin tant que Les avantages de cet algo: On ne recalcule pas sytèmatiquement pour chaque case la liste des symboles possibles: on lit un tableau => gain de temps On ne teste pas, pour chaque case, L'ensemble des symboles (V), on ne teste que les symboles possibles (L) vérifiant déja les contraintes d'unicités définie par l'attribution des cases précédentes => gain de temps. Lors de la résoltuion, on ne choisi pas les cases "au hasard", ou dans un orde établi, on prend celle qui statistiquemet posséde le moins de possibilités. Les contraintes de cet algo: Necessite des ressources en mémoire: car avant de la modifier, on sauvegarde systématiquement la liste, L, des symboles possibles des cases concernées par l'attribution d'une autre case.
Source
- <?php
- /**
- * @desc Generateur et solveur de grille de Sudoku *
- * @author Nifhell
- * @package sudoku
- * @version 1.0
- */
- include_once($_SERVER['DOCUMENT_ROOT']."cobject.php");
- /**
- * @desc Classe CSudoku
- *
- */
- class CSuDoKu extends CObject {
- private $m_oDebug;
- private static $m_oInstance;
- protected $m_iNb;
- protected $m_sType;
- protected $m_aLines;
- protected $m_aCols;
- protected $m_aCases;
- protected $m_aSquare;
- protected $m_iLevel;
- protected $m_iCache;
- protected $m_bTutorial=false;
- protected $m_iTime;
- protected $m_iIter=-1;
- /**
- * @desc Constructeur par valeur
- * @return CSuDoKu
- * @param int $nb
- * @param string $type
- * @param int $level
- * @param bool $tuto
- **/
- public function CSuDoKu() {
- //$this->m_oDebug=CDebug::getInstance(false,true);
- $start=microtime(true);
- if(func_num_args()>1 and func_num_args()<=4) {
- func_get_arg(0)?$nb=func_get_arg(0):$nb=9;
- func_get_arg(1)?$type=func_get_arg(1):$type='numeric';
- func_get_arg(2)?$level=func_get_arg(2):$level=4;
- func_get_arg(3)?$tuto=func_get_arg(3):$tuto=false;
- $this->m_bTutorial=$tuto;
- $this->CSuDoKuGrille($nb,$type);
- $this->CSuDoKuLevel($level);
- }
- elseif (func_num_args()==1 and $param=func_get_arg(0)) {
- $this->XML2CSuDoKu($param);
- }
- $this->m_iTime=microtime(true)-$start;
- //$this->m_oDebug->addTrace(1,$this->getObjectID(),"CSuDoKu","Constructor","($this->m_iNb,$this->m_sType,$this->m_iLevel,$this->m_bTutorial)","Sudoku initialisé: ".$this->m_iTime."s");
- }
- /**
- * @desc Détermine le nombre de cases a cacher
- * @return CSuDoKu
- * @param int $nb
- * @param string $type
- **/
- private function CSuDoKuGrille($nb,$type) {
- if(4<=$nb and $nb<=25
- and intval($sqrt=sqrt($nb))*10==$sqrt*10) {
- $this->m_iNb=$nb;
- $this->m_sType=$type;
- //$this->m_oDebug->addTrace(1,$this->getObjectID(),"CSuDoKu","CSuDoKuGrille","($nb,$type)","Racine: $sqrt.");
- $this->m_aLines=array();
- $this->m_aCols=array();
- $this->m_aCases=array();
- $this->m_aSquare=array();
- for($i=0;$i<$nb;$i++) {
- if(!($this->m_aLines[$i] instanceof CSuDoKuLine)){
- $this->m_aLines[$i]=new CSuDoKuLine($i);
- }
- if(!($i%$sqrt)) {
- $this->m_aSquare[$i/$sqrt]=array();
- }
- $this->m_aCases[$i]=array();
- for($j=0;$j<$nb;$j++) {
- if(!($this->m_aCols[$j] instanceof CSuDoKuColumn)){
- $this->m_aCols[$j]=new CSuDoKuColumn($j);
- }
- $this->m_aCases[$i][$j]=new CSuDoKuCase($i,$j,$nb,$type);
- $this->m_aLines[$i]->addCase($this->m_aCases[$i][$j]);
- $this->m_aCols[$j]->addCase($this->m_aCases[$i][$j]);
- if(!($j%$sqrt) and !($i%$sqrt)) {
- $this->m_aSquare[$i/$sqrt][$j/$sqrt]=new CSuDoKuSquare($i/$sqrt,$j/$sqrt);
- }
- $this->m_aSquare[intval($i/$sqrt)][intval($j/$sqrt)]->addCase($this->m_aCases[$i][$j],$i-($sqrt*intval($i/$sqrt)),$j-($sqrt*intval($j/$sqrt)));
- $this->m_aCases[$i][$j]->square($this->m_aSquare[intval($i/$sqrt)][intval($j/$sqrt)]);
- $this->m_aCases[$i][$j]->line($this->m_aLines[$i]);
- $this->m_aCases[$i][$j]->column($this->m_aCols[$j]);
- }
- }
- }
- return $this;
- }
- /**
- * @desc Détermine le nombre de cases a cacher
- * @return CSuDoKu
- * @param int $level
- **/
- public function CSuDoKuLevel($level) {
- switch ($level){
- case 1:
- $this->m_iLevel=1;
- $base=mt_rand(30,35);
- break;
- case 2:
- $this->m_iLevel=2;
- $base=mt_rand(36,41);
- break;
- case 3:
- $this->m_iLevel=3;
- $base=mt_rand(42,47);
- break;
- case 4:
- $this->m_iLevel=4;
- $base=mt_rand(48,53);
- break;
- case 5:
- $this->m_iLevel=5;
- $base=mt_rand(54,59);
- break;
- case 6:
- $this->m_iLevel=6;
- $base=mt_rand(60,65);
- break;
- case 7:
- $this->m_iLevel=7;
- $base=mt_rand(66,71);
- break;
- default:
- $this->m_iLevel=4;
- $base=mt_rand(48,53);
- }
- $this->m_iCache=intval($base/100*pow($this->m_iNb,2));
- //$this->m_oDebug->addTrace(1,$this->getObjectID(),"CSuDoKu","CSuDoKuLevel","($level)","Niveau: $this->m_iLevel, Caches: $this->m_iCache");
- return $this;
- }
- /**
- * @desc XML => CSuDoKu
- * @return CSuDoKu
- * @param string $xml_source
- **/
- private function XML2CSuDoKu($xml_source) {
- if(isset($xml_source)){
- if(!is_file($xml_source)){
- $xml=simplexml_load_string($xml_source);
- $this->CSuDoKu((int)$xml['nbr'],(string)$xml['type'],(int)$xml['level'],($xml['tuto']=='true'?true:false));
- foreach ($xml->cell as $cell) {
- $case=$this->m_aCases[(int)$cell['x']][(int)$cell['y']];
- if((string)$cell) $case->attribuer((string)$cell);
- if((string)$cell['test']) $case->test((string)$cell['test']);
- }
- ////$this->m_oDebug->addTrace(1,$this->getObjectID(),"CSuDoKu","XML2SuDoKu","($path)","XML => Chargement OK");
- return $this;
- }
- elseif(is_file($xml_source)) {
- $xml=simplexml_load_file($xml_source);
- $this->CSuDoKu((int)$xml['nbr'],(string)$xml['type'],(int)$xml['level'],($xml['tuto']=='true'?true:false));
- foreach ($xml->cell as $cell) {
- $case=$this->m_aCases[(int)$cell['x']][(int)$cell['y']];
- if((string)$cell) $case->attribuer((string)$cell);
- if((string)$cell['test']) $case->test((string)$cell['test']);
- }
- ////$this->m_oDebug->addTrace(1,$this->getObjectID(),"CSuDoKu","XML2SuDoKu","($path)","XML => Chargement OK");
- return $this;
- }
- }
- else {
- //$this->m_oDebug->addTrace(1,$this->getObjectID(),"CSuDoKu","XML2SuDoKu","($path)","XML => Chargement ECHEC (Le fichier n'existe pas)");
- return null;
- }
- }
- /**
- * @desc Cache les cases de la grille de SuDoKu en cours
- * @return bool
- * @param void
- **/
- private function cache() {
- for($i=0;$i<$this->m_iCache;$i++) {
- do {
- $x=mt_rand(0,$this->m_iNb-1);
- $y=mt_rand(0,$this->m_iNb-1);
- $case=$this->m_aCases[$x][$y];
- }while(!$case->isDone());
- $case->reSet();
- //$this->m_oDebug->addTrace(2,$this->getObjectID(),"CSuDoKu","cache","($i)",$case->__toString()." cachée");
- }
- for($x=0;$x<$this->m_iNb;$x++) {
- for($y=0;$y<$this->m_iNb;$y++) {
- $case=$this->m_aCases[$x][$y];
- if($case->isDone()) {
- $case->attribuer($case->getSymbols(0));
- }
- }
- }
- }
- /**
- * @desc Résoud la grille de SuDoKu en cours
- * @return bool
- * @param int $i
- **/
- private function resoudre($i) {
- $tab="";
- $this->m_iIter++;
- //$this->m_oDebug->addTrace(2,$this->getObjectID(),"CSuDoKu","resoudre","($i)",$this->toStrTable());
- if(is_array($coord=$this->best2solve())) {
- $case=$this->m_aCases[$coord['x']][$coord['y']];
- //$this->m_oDebug->addTrace(2,$this->getObjectID(),"CSuDoKu","resoudre","($i)",$tab.$case->__toString()." choisie.");
- foreach($case->getSymbols() as $s) {
- //$this->m_oDebug->addTrace(2,$this->getObjectID(),"CSuDoKu","resoudre","($i)",$tab."Symboles possibles de la ".$case->__toString().": ".join(", ",$case->getSymbols()));
- //$this->m_oDebug->addTrace(2,$this->getObjectID(),"CSuDoKu","resoudre","($i)",$tab."\t Test du symbole $s: ");
- if($case->attribuer($s)) {
- //$this->m_oDebug->addTrace(2,$this->getObjectID(),"CSuDoKu","resoudre","($i)",$tab."\t $s valider provisoirement.");
- if($this->resoudre($i+1)){
- //$this->m_oDebug->addTrace(2,$this->getObjectID(),"CSuDoKu","resoudre","($i)",$tab."\t $s enterriner.");
- return true;
- }
- else {
- //$this->m_oDebug->addTrace(2,$this->getObjectID(),"CSuDoKu","resoudre","($i)",$tab."\t $s ne convient pas au case d'ordre inférieur => on réinitialise la case symbole suivant.");
- $case->desattribuer();
- }
- }
- else {
- //$this->m_oDebug->addTrace(2,$this->getObjectID(),"CSuDoKu","resoudre","($i)",$tab."\t $s ne convient au case de la même ligne, colonne ou boite => symbole suivant.");
- $case->desattribuer();
- }
- }
- return false;
- }
- else return true;
- }
- /**
- * @desc Renvoie les coordonnées de la case qui a le moins de possibilité
- * @return array
- * @param
- **/
- public function best2solve() {
- $min=$this->m_iNb+1;
- $min_x=$min_y=-1;
- for($x=0;$x<$this->m_iNb;$x++) {
- for($y=0;$y<$this->m_iNb;$y++) {
- if(!$this->m_aCases[$x][$y]->isDone()){
- $tmp=count($this->m_aCases[$x][$y]->getSymbols());
- if($tmp<$min) {
- $min=$tmp;
- $min_x=$x;
- $min_y=$y;
- }
- }
- }
- }
- if($min>0 and $min!=$this->m_iNb+1) {
- //$this->m_oDebug->addTrace(4,$this->getObjectID(),"CSuDoKu","best2solve","()","Case best2solve: ".$this->m_aCases[$min_x][$min_y]->__toString()." minimum => $min.");
- return array('x' => $min_x, 'y' => $min_y, 0 => $min_x, 1 => $min_y);
- }
- else {
- //$this->m_oDebug->addTrace(4,$this->getObjectID(),"CSuDoKu","best2solve","()","Case best2solve: ".($this->m_aCases[$min_x][$min_y]?$this->m_aCases[$min_x][$min_y]->__toString():"")." | minimum => $min");
- return null;
- }
- }
- /**
- * @desc Génere une grille
- * @return CSuDoKu
- * @param
- **/
- public function genererGrille() {
- $start=microtime(true);
- $this->reSet();
- $bOK=$this->resoudre(0);
- $bOK=$bOK*$this->isValid();
- $this->cache();
- $bOK=$bOK*$this->isValid();
- $this->m_iTime=microtime(true)-$start;
- //$this->m_oDebug->addTrace(1,$this->getObjectID(),"CSuDoKu","genererGrille","()","Grille initialisé (".$this->m_iTime."s): ".($bOK?"OK":"ECHEC"));
- return $bOK;
- }
- /**
- * @desc Résoud une grille non résolu
- * @return CSuDoKu
- * @param
- **/
- public function resoudreGrille() {
- $start=microtime(true);
- $bOK=$this->resoudre(0);
- $bOK=$bOK*$this->isValid();
- $this->m_iTime=microtime(true)-$start;
- //$this->m_oDebug->addTrace(1,$this->getObjectID(),"CSuDoKu","resoudreGrille","()","Grille résolue (".$this->m_iTime."s): ".($bOK?"OK":"ECHEC"));
- return $bOK;
- }
- /**
- * @desc Renvoie le nombre d'itération que l'algo de résolution a effectuer
- * @return int
- * @param
- **/
- public function getIter() {
- return $this->m_iIter-pow($this->m_iNb,2);
- }
- /**
- * @desc Renvoie le nombre de case par ligne
- * @return int
- * @param
- **/
- public function getNbr() {
- return $this->m_iNb;
- }
- /**
- * @desc Renvoie le nombre de case par ligne
- * @return int
- * @param
- **/
- public function getLevel() {
- return $this->m_iLevel;
- }
- /**
- * @desc Résoud une grille non résolu
- * @return CSuDoKu
- * @param string $mode
- **/
- public function getTime($mode) {
- switch($mode){
- case 's':
- return round($this->m_iTime,2);
- break;
- case 'cs':
- return round($this->m_iTime*10,2);
- break;
- case 'ms':
- return round($this->m_iTime*100,2);
- break;
- case '_s':
- return round($this->m_iTime*1000,2);
- break;
- default:
- return round($this->m_iTime,2);
- }
- }
- /**
- * @desc Vide la grille.
- * Si $shuffle est à vrai, alors le prochain appel de résoudre(), générera une nouvelle grille (par défaut)
- * Si $shuffle est à faux, alors la grille est simplement vidé, mais le prochain appel de resoudre() générera la même grille que précédemment. Pratique, si vous souhiatez avoir la même grille mais avec des niveaux de difficulté différents.
- * @return CSuDoKu
- * @param bool $shuffle = true
- **/
- public function reSet($shuffle=true) {
- //$this->m_oDebug->addTrace(4,$this->getObjectID(),"CSuDoKu","reSet","()","initialisation");
- $this->m_iIter=-1;
- for($i=0;$i<count($this->m_aCases);$i++){
- for($j=0;$j<count($this->m_aCases[$i]);$j++){
- $this->m_aCases[$i][$j]->reSet($shuffle);
- }
- }
- return $this;
- }
- /**
- * @desc (Static) Renvoie l'instance en cours de la classe CSuDoKu
- * @return CSuDoKu
- * @param int $nb
- * @param string $type
- * @param int $level
- * @param bool $tuto
- **/
- public static function getInstance($nb,$type, $level, $tuto) {
- if (empty(self::$m_oInstance)) {
- self::$m_oInstance = new CSuDoKu($nb,$type, $level, $tuto);
- }
- return self::$m_oInstance;
- }
- /**
- * @desc CSuDoKu => SimpleXMLElement
- * @return SimpleXMLElement
- * @param string $path
- **/
- public function toXML($path=false) {
- $xml_string="<?xml version=\"1.0\" standalone=\"yes\"?>\n";
- $xml_string.="<sudoku type=\"".$this->m_sType."\" nbr=\"".$this->m_iNb."\" level=\"".$this->m_iLevel."\" tuto=\"".($this->m_bTutorial?'true':'false')."\">\n";
- for($i=0;$i<$this->m_iNb;$i++){
- for($j=0;$j<$this->m_iNb;$j++){
- if($this->getCase($i,$j)->getTest()) $test=$this->getCase($i,$j)->getTest();
- else $test="";
- $xml_string.="<cell x=\"".$i."\" y=\"".$j."\" test=\"".$test."\">";
- if($this->m_aCases[$i][$j]->isDone()) $xml_string.=$this->m_aCases[$i][$j]->getSymbols(0);
- $xml_string.="</cell>\n";
- }
- }
- $xml_string.="</sudoku>";
- //$this->m_oDebug->addTrace(1,$this->getObjectID(),"CSuDoKu","toXML","($path)","Chargement de la grille: ".$xml_string);
- $xml=simplexml_load_string($xml_string);
- if((!isset($path) and $path!=false) or !$xml->asXML($path)) {
- //$this->m_oDebug->addTrace(1,$this->getObjectID(),"CSuDoKu","toXML","($path)","XML => Enregistrement du fichier XML ECHEC");
- }
- return $xml_string;
- }
- /**
- * @desc Transforme le SuDoKu en Table HTML
- * @return string
- * @param
- **/
- public function toHTMLTable() {
- $table="<table>\n\t";
- for($i=1;$i<=$this->m_iNb;$i++){
- $table.="<tr>";
- for($j=1;$j<=$this->m_iNb;$j++){
- $absc=$i-1;
- $ord=$j-1;
- $symbols=$this->getCase($absc,$ord)->getSymbols();
- $table.="<td>";
- if($this->getCase($absc,$ord)->isDone()){
- $table.=$symbols[0];
- }
- else {
- if($this->m_bTutorial) {
- $table.="<select name=\"case_".$i."_".$j."\" size=1>";
- $table.="<option value=\"null\">";
- natcasesort($symbols);
- foreach ($symbols as $sym) {
- $b="";
- if($this->getCase($absc,$ord)->getTest()) {
- if($sym==$this->getCase($absc,$ord)->getTest()) $b="selected";
- }
- $table.="<option value=\"".$sym."\" ".$b." >".$sym."";
- }
- }
- else {
- if($this->getCase($absc,$ord)->getTest()) $default=$this->getCase($absc,$ord)->getTest();
- else $default="";
- $table.="<input type=\"text\" name=\"case_".$i."_".$j."\" size=\"1\" maxlength=\"1\" onchange=\"check_sudoku_input(this)\" value=\"".$default."\">";
- }
- }
- $table.="</td>";
- }
- $table.="</tr>\n";
- }
- $table.="</table>\n";
- $table.="<script type=\"Javascript\">";
- $table.="function check_sudoku_input(nCase) {
- var Symbols=/^\s|".join("|",$this->getCase(0,0)->getOriginalSymbols())."$/;
- var bOk=false;
- if(nCase.value && !Symbols.test(nCase.value)) {
- alert('Arrrg! Vous devez saisir un caractère parmi ceux-ci: ".join(", ",$this->getCase(0,0)->getOriginalSymbols())."');
- nCase.value='';
- nCase.focus();
- }
- return bOk;
- }
- </script>\n";
- $this->setHTML($table);
- return $table;
- }
- /**
- * @desc Transforme le SuDoKu en Table
- * @return string
- * @param
- **/
- public function toStrTable() {
- $str="\n";
- for($i=0;$i<$this->m_iNb;$i++){
- if (!($i%sqrt($this->m_iNb))){
- for($j=1;$j<=$this->m_iNb;$j++){
- $str.="\t-";
- }
- $str.="\n";
- }
- for($j=0;$j<$this->m_iNb;$j++){
- if(!($j%sqrt($this->m_iNb))) {
- $str.="\t|";
- }
- $symbols=$this->getCase($i,$j)->getSymbols();
- if($this->getCase($i,$j)->isDone()){
- $str.="\t".$symbols[0];
- }
- else {
- $str.="\t ";
- }
- }
- $str.="\n";
- }
- return $str;
- }
- /**
- * @desc Transforme le SuDoKu en tableau HTML
- * @return string
- * @param void
- **/
- public function __toString() {
- return $this->toHTMLTable();
- }
- /**
- * @desc Accesseur
- * @return CSuDoKuCase
- * @param int $i
- * @param int $j
- **/
- public function getCase($i,$j) {
- if($i<$this->m_iNb and $j<$this->m_iNb){
- return $this->m_aCases[$i][$j];
- }
- else {
- echo "<hr>Fatal error: CSudoku:getCase($i,$j):: out of range";
- return null;
- }
- }
- /**
- * @desc Vérifie si le mod tutoriel est activé
- * @return bool
- * @param
- **/
- public function isEasy() {
- return $this->m_bTutorial;
- }
- /**
- * @desc Vérifie les contraintes d'unicité
- * @return bool
- * @param
- **/
- public function isValid() {
- $bRet=array();
- for($x=0;$x<$this->m_iNb;$x++) {
- for($y=0;$y<$this->m_iNb;$y++) {
- if($this->m_aCases[$x][$y]->isEmpty()){
- $bRet[]=false;
- break;
- }
- }
- }
- foreach ($this->m_aLines as $obj) {
- $bRet[]=$obj->isValid();
- }
- foreach ($this->m_aCols as $obj) {
- $bRet[]=$obj->isValid();
- }
- foreach ($this->m_aSquare as $tmp) {
- foreach ($tmp as $obj) {
- $bRet[]=$obj->isValid();
- }
- }
- if(in_array(false,$bRet)) {
- //$this->m_oDebug->addTrace(2,$this->getObjectID(),"CSuDoKu","isValid","","Cette grille est fausse.");
- return false;
- }
- else {
- //$this->m_oDebug->addTrace(2,$this->getObjectID(),"CSuDoKu","isValid","","Cette grille est valide.");
- return true;
- }
- }
- }
- class CSuDoKuLine extends CObject {
- private $m_oDebug;
- protected $m_iOrd;
- protected $m_aCases;
- /**
- * @desc Constructeur par défaut
- * @return CSuDoKuLine
- * @param int $i
- **/
- public function CSuDoKuLine($i) {
- //$this->m_oDebug=CDebug::getInstance(false,true);
- if(intval($i)*10==$i*10){
- //$this->m_oDebug->addTrace(7,$this->getObjectID(),"CSuDoKuLine","Constructor","($i)","$this");
- $this->m_iOrd=$i;
- }
- }
- /**
- * @desc Add a case
- * @return CSuDoKuLine
- * @param CSuDoKuCase $case
- **/
- public function addCase(CSuDoKuCase $case) {
- if($case instanceof CSuDoKuCase) {
- //$this->m_oDebug->addTrace(7,$this->getObjectID(),"CSuDoKuLine","addCase","($case)","Ligne($this->m_iOrd)<=Case: (".$case->getAbsc().",".$case->getOrd().")");
- $this->m_aCases[]=$case;
- return $this;
- }
- else {
- echo "<hr>Fatal error: CSuDoKuLine::addCase(\$case) shouldn't be empty.";
- return null;
- }
- }
- /**
- * @desc Accesseur
- * @return array
- * @param
- **/
- public function getCases() {
- return $this->m_aCases;
- }
- /**
- * @desc Accesseur
- * @return CSuDoKuCase
- * @param int $i
- **/
- public function getCase($i) {
- if($i>=0 and $i<count($this->m_aCases)) {
- return $this->m_aCases[$i];
- }
- else {
- echo "<hr>Fatal Error: \$i out of range.";
- return null;
- }
- }
- /**
- * @desc Accesseur
- * @return int
- * @param
- **/
- public function getOrd() {
- return $this->m_iOrd;
- }
- /**
- * @desc Vérifie les contraintes d'unicité
- * @return bool
- * @param
- **/
- public function isValid() {
- $bRet=true;
- $tmp=array();
- foreach ($this->m_aCases as $case) {
- if($case->isDone()) $tmp[]=$case;
- }
- foreach ($tmp as $case1) {
- $sym1=$case1->getSymbols();
- foreach ($tmp as $case2) {
- $sym2=$case2->getSymbols();
- if(($sym1[0]==$sym2[0] or !strcasecmp($sym1[0],$sym2[0])) and strcasecmp($case1->__toString(),$case2->__toString())) {
- //$this->m_oDebug->addTrace(4,$this->getObjectID(),"CSudoKuLine","isValid","","Violation de contrainte d'unicité de la ligne ".$this->m_iOrd.": ".$case1->__toString()."=".$case2->__toString()."=".$sym1[0]);
- $bRet=false;
- }
- }
- }
- return $bRet;
- }
- /**
- * @desc Propage le fait qu'une case a été découverte
- * @return CSuDoKuLine
- * @param mixed $symbole
- * @param CSuDoKuCase $cCase
- **/
- public function propagate($symbole,CSuDoKuCase $cCase) {
- $bOK=true;
- foreach ($this->m_aCases as $case) {
- if(!$case->isDone() and $case!==$cCase and $case->getSquare()!==$cCase->getSquare()){
- $case->delSymbols($symbole,true,$cCase->getObjectID());
- if($case->isEmpty()) {
- //$this->m_oDebug->addTrace(4,$this->getObjectID(),"CSuDoKuLine","propagate","($symbole,$cCase)",$this->__toString().": ".$case->__toString()." est vide.");
- $bOK=false;
- }
- }
- }
- //$bOK?//$this->m_oDebug->addTrace(4,$this->getObjectID(),"CSuDoKuLine","propagate","($symbole,$absc,$ord)",$this->__toString().": propagation réussie.")://$this->m_oDebug->addTrace(4,$this->getObjectID(),"CSuDoKuLine","propagate","($symbole,$absc,$ord)",$this->__toString().": propagation échouée.");
- return $bOK;
- }
- /**
- * @desc déPropage le fait qu'une case n'est plus découverte
- * @return CSuDoKuLine
- * @param CSuDoKuCase $cCase
- **/
- public function unpropagate(CSuDoKuCase $cCase) {
- ////$this->m_oDebug->addTrace(4,$this->getObjectID(),"CSuDoKuLine","unpropagate","(".$cCase->__toString().")",$this->__toString().": dépropagation");
- foreach ($this->m_aCases as $case) {
- if($case!==$cCase and $case->getSquare()!==$cCase->getSquare()){
- if(!$case->isDone()) {
- $case->restaurer($cCase->getObjectID());
- }
- }
- }
- return $this;
- }
- /**
- * @desc toString
- * @return string
- * @param
- **/
- public function __toString() {
- return "Ligne #".$this->m_iOrd;
- }
- }
- class CSuDoKuColumn extends CObject {
- private $m_oDebug;
- protected $m_iAbsc;
- protected $m_aCases;
- /**
- * @desc Constructeur par défaut
- * @return CSuDoKuColumn
- * @param int $i
- **/
- public function CSuDoKuColumn($i) {
- //$this->m_oDebug=CDebug::getInstance(false,true);
- if(intval($i)*10==$i*10){
- //$this->m_oDebug->addTrace(7,$this->getObjectID(),"CSuDoKuColumn","Constructor","($i)","$this");
- $this->m_iAbsc=$i;
- }
- }
- /**
- * @desc Add a case
- * @return CSuDoKuColumn
- * @param CSuDoKuCase $case
- **/
- public function addCase(CSuDoKuCase $case) {
- if($case instanceof CSuDoKuCase) {
- //$this->m_oDebug->addTrace(7,$this->getObjectID(),"CSuDoKuColumn","addCase","($case)","Colonne($this->m_iAbsc)<=Case: (".$case->getAbsc().",".$case->getOrd().")");
- $this->m_aCases[]=$case;
- return $this;
- }
- else {
- echo "<hr>Fatal error: CSuDoKuColumn::addCase(\$case) shouldn't be empty.";
- return null;
- }
- }
- /**
- * @desc Accesseur
- * @return CSuDoKuCase
- * @param int $i
- **/
- public function getCase($i) {
- if($i>=0 and $i<count($this->m_aCases)) {
- return $this->m_aCases[$i];
- }
- else {
- echo "<hr>Fatal Error: \$i out of range.";
- return null;
- }
- }
- /**
- * @desc Accesseur
- * @return array
- * @param
- **/
- public function getCases() {
- return $this->m_aCases;
- }
- /**
- * @desc Accesseur
- * @return int
- * @param void
- **/
- public function getAbsc() {
- return $this->m_iAbsc;
- }
- /**
- * @desc Accesseur
- * @return bool
- * @param void
- **/
- public function isValid() {
- $bRet=true;
- $tmp=array();
- foreach ($this->m_aCases as $case) {
- if($case->isDone()) $tmp[]=$case;
- }
- foreach ($tmp as $case1) {
- $sym1=$case1->getSymbols();
- foreach ($tmp as $case2) {
- $sym2=$case2->getSymbols();
- if(($sym1[0]==$sym2[0] or !strcasecmp($sym1[0],$sym2[0])) and strcasecmp($case1->__toString(),$case2->__toString())) {
- //$this->m_oDebug->addTrace(4,$this->getObjectID(),"CSuDoKuColumn","isValid","","Violation de contrainte d'unicité de la Colonne ".$this->m_iAbsc.": ".$case1->__toString()."=".$case2->__toString()."=".$sym1[0]);
- $bRet=false;
- }
- }
- }
- return $bRet;
- }
- /**
- * @desc Propage le fait qu'une case a été découverte
- * @return CSuDoKuColumn
- * @param mixed $symbole
- * @param CSuDoKuCase $cCase
- **/
- public function propagate($symbole,CSuDoKuCase $cCase) {
- $bOK=true;
- foreach ($this->m_aCases as $case) {
- if(!$case->isDone() and $case!==$cCase and $case->getSquare()!==$cCase->getSquare()) {
- $case->delSymbols($symbole,true,$cCase->getObjectID());
- if($case->isEmpty()) {
- //$this->m_oDebug->addTrace(4,$this->getObjectID(),"CSuDoKuColumn","propagate","($symbole,$absc,$ord)",$this->__toString().": ".$case->__toString()." est vide");
- $bOK=false;
- }
- }
- }
- //$bOK?//$this->m_oDebug->addTrace(4,$this->getObjectID(),"CSuDoKuColumn","propagate","($symbole,$absc,$ord)",$this->__toString().": propagation réussie.($bOK)")://$this->m_oDebug->addTrace(4,$this->getObjectID(),"CSuDoKuColumn","propagate","($symbole,$absc,$ord)",$this->__toString().": propagation échouée.");
- return $bOK;
- }
- /**
- * @desc déPropage le fait qu'une case a été remis à l'état incertain
- * @return CSuDoKuColumn
- * @param CSuDoKuCase $cCase
- **/
- public function unpropagate(CSuDoKuCase $cCase) {
- ////$this->m_oDebug->addTrace(4,$this->getObjectID(),"CSuDoKuColumn","unpropagate","(".$cCase->__toString().")",$this->__toString().": dépropagation");
- foreach ($this->m_aCases as $case) {
- if($case!==$cCase and $case->getSquare()!==$cCase->getSquare()){
- if(!$case->isDone()) {
- $case->restaurer($cCase->getObjectID());
- }
- }
- }
- return $this;
- }
- /**
- * @desc toString
- * @return string
- * @param void
- **/
- public function __toString() {
- return "Colonne #".$this->m_iAbsc;
- }
- }
- class CSuDoKuSquare extends CObject {
- private $m_oDebug;
- protected $m_iAbsc;
- protected $m_iOrd;
- protected $m_aCases;
- /**
- * @desc Constructeur par défaut
- * @return CSuDoKuSquare
- * @param int $i
- * @param int $j
- **/
- public function CSuDoKuSquare($i,$j) {
- //$this->m_oDebug=CDebug::getInstance(false,true);
- if(intval($i)*10==$i*10 and intval($j)*10==$j*10){
- $this->m_iAbsc=$i;
- $this->m_iOrd=$j;
- $this->m_aCases=array();
- //$this->m_oDebug->addTrace(7,$this->getObjectID(),"CSuDoKuSquare","Constructor","($i,$j)","$this");
- }
- else echo "<hr>Fatal error: CSuDoKuSquare(\$i,\$j,\$sym) shouldn't be empty.";
- }
- /**
- * @desc Add a case
- * @return CSuDoKuSquare
- * @param CSuDoKuCase $case
- * @param int $i
- * @param int $j
- **/
- public function addCase(CSuDoKuCase $case,$i,$j) {
- if($case instanceof CSuDoKuCase) {
- //$this->m_oDebug->addTrace(7,$this->getObjectID(),"CSuDoKuSquare","addCase","($case,$i,$j)","Carré(".$this->m_iAbsc.",".$this->m_iOrd.")<=Case: (".$case->getAbsc().",".$case->getOrd().")");
- if(!is_array($this->m_aCases[$i])) $this->m_aCases[$i]=array();
- $this->m_aCases[$i][$j]=$case;
- return $this;
- }
- else {
- echo "<hr>Fatal error: CSuDoKuSquare::addCase(\$case) shouldn't be empty.";
- return null;
- }
- }
- /**
- * @desc Accesseur
- * @return CSuDoKuCase
- * @param int $i
- * @param int $j
- **/
- public function getCase($i,$j) {
- if($i>=0 and $i<count($this->m_aCases) and $j>=0 and $j<count($this->m_aCases[$i])) {
- return $this->m_aCases[$i][$j];
- }
- else {
- echo "<hr>Fatal Error: \$i or \$j out of range.";
- return null;
- }
- }
- /**
- * @desc Accesseur
- * @return array
- * @param void
- **/
- public function getCases() {
- return $this->m_aCases;
- }
- /**
- * @desc Accesseur
- * @return int
- * @param void
- **/
- public function getAbsc() {
- return $this->m_iAbsc;
- }
- /**
- * @desc Accesseur
- * @return int
- * @param void
- **/
- public function getOrd() {
- return $this->m_iOrd;
- }
- /**
- * @desc Accesseur
- * @return string
- * @param void
- **/
- public function __toString() {
- return "Carre[".$this->getObjectID()."](".$this->m_iAbsc.",".$this->m_iOrd.")";
- }
- /**
- * @desc Accesseur
- * @return bool
- * @param void
- **/
- public function isValid() {
- $bRet=true;
- $tmp=array();
- foreach ($this->m_aCases as $col) {
- foreach ($col as $case) {
- if($case->isDone()) $tmp[]=$case;
- }
- }
- foreach ($tmp as $col1) {
- foreach ($col1 as $case1) {
- $sym1=$case1->getSymbols();
- foreach ($tmp as $col2) {
- foreach ($col2 as $case2) {
- $sym2=$case2->getSymbols();
- if(($sym1[0]==$sym2[0] or !strcasecmp($sym1[0],$sym2[0])) and strcasecmp($case1->__toString(),$case2->__toString())) {
- //$this->m_oDebug->addTrace(4,$this->getObjectID(),"CSuDoKuSquare","isValid","","Violation de contrainte d'unicité du Carré ".$this->__toString().": ".$case1->__toString()."=".$case2->__toString()."=".$sym1[0]);
- $bRet=false;
- }
- }
- }
- }
- }
- return $bRet;
- }
- /**
- * @desc Propage le fait qu'une case a été découverte
- * @return CSuDoKuSquare
- * @param mixed $symbole
- * @param CSuDoKuCase $cCase
- **/
- public function propagate($symbole,CSuDoKuCase $cCase) {
- $bOK=true;
- foreach ($this->m_aCases as $cases) {
- foreach ($cases as $case) {
- if(!$case->isDone() and $case!==$cCase){
- $case->delSymbols($symbole,true,$cCase->getObjectID());
- if($case->isEmpty()) {
- //$this->m_oDebug->addTrace(4,$this->getObjectID(),"CSuDoKuSquare","propagate","($symbole,$cCase)",$this->__toString().": ".$case->__toString()." est vide.");
- $bOK=false;
- }
- }
- }
- }
- //$bOK?//$this->m_oDebug->addTrace(4,$this->getObjectID(),"CSuDoKuSquare","propagate","($symbole,$absc,$ord)",$this->__toString().": propagation réussie.")://$this->m_oDebug->addTrace(4,$this->getObjectID(),"CSuDoKuSquare","propagate","($symbole,$absc,$ord)",$this->__toString().": propagation échouée.");
- return $bOK;
- }
- /**
- * @desc déPropage le fait qu'une case a été découverte
- * @return CSuDoKuSquare
- * @param CSuDoKuCase $cCase
- **/
- public function unpropagate(CSuDoKuCase $cCase) {
- ////$this->m_oDebug->addTrace(4,$this->getObjectID(),"CSuDoKuSquare","unpropagate","(".$cCase->__toString().")",$this->__toString().": dépropagation");
- foreach ($this->m_aCases as $cases) {
- foreach ($cases as $case) {
- if($case!==$cCase){
- if(!$case->isDone()) {!
- $case->restaurer($cCase->getObjectID());
- }
- }
- }
- }
- return $this;
- }
- }
- /**
- * @desc Classe CSuDoKuCase
- *
- */
- class CSuDoKuCase extends CObject {
- protected $m_oDebug;
- protected $m_iAbsc;
- protected $m_iOrd;
- protected $m_aSaveSymbols;
- protected $m_aSymbols;
- protected $m_aOSymbols;
- protected $m_oSquare;
- protected $m_oLine;
- protected $m_oColumn;
- protected $m_iNb;
- protected $m_sType;
- protected $m_bDone;
- protected $m_sTest=null;
- /**
- * @desc Constructeur par défaut
- * @return CSuDoKuCase
- * @param int $i
- * @param int $j
- * @param int $nb
- * @param string $type
- **/
- public function CSuDoKuCase($i,$j,$nb,$type) {
- //$this->m_oDebug=CDebug::getInstance(false,true);
- if(intval($i*10)==$i*10 and intval($j*10)==$j*10 ) {
- //$this->m_oDebug->addTrace(7,$this->getObjectID(),"CSuDoKuCase","Constructor","($i,$j,$nb,$type)","$this");
- $this->m_iAbsc=$i;
- $this->m_iOrd=$j;
- $this->m_iNb=$nb;
- $this->m_bDone=false;
- $this->m_aSaveSymbols=array();
- switch($type) {
- case 'numeric':
- $this->m_sType='numeric';
- $this->m_aSymbols=array();
- for($i=1;$i<=$nb;$i++) {
- $this->m_aSymbols[]=$i;
- $this->m_aOSymbols[]=$i;
- }
- shuffle($this->m_aSymbols);
- $this->sauvegarder(-1);
- break;
- case 'alpha':
- $this->m_sType='alpha';
- $this->m_aSymbols=array();
- for($i=0;$i<$nb;$i++) {
- $this->m_aSymbols[]=chr(65+$i);
- $this->m_aOSymbols[]=chr(65+$i);
- }
- shuffle($this->m_aSymbols);
- $this->sauvegarder(-1);
- break;
- default: echo "<hr>Fatal error: CSuDoKuCase(\$type) should be 'numeric' or 'alpha'.";
- }
- }
- else echo "<hr>Fatal error: CSuDoKuCase(\$i, \$j, \$nb,\$type) shouldn't be empty or \$i and \$j should be integers and \$sym should be a CSuDoKuSymboles";
- }
- /**
- * @desc Accesseur
- * @return CSuDoKuCase
- * @param CSuDoKuSquare $square
- **/
- public function square(CSuDoKuSquare $square) {
- if($square instanceof CSuDoKuSquare ) {
- //$this->m_oDebug->addTrace(7,$this->getObjectID(),"CSuDoKuCase","square","($square)","Association de la boîte (".$square->getAbsc().",".$square->getOrd().") à ".$this->__toString());
- $this->m_oSquare=$square;
- return $this;
- }
- else {
- echo "<hr>\nCSuDoKuCase::square(\$square)::ERROR:: \$square should be an CSuDoKuSquare object";
- return null;
- }
- }
- /**
- * @desc Accesseur
- * @return CSuDoKuCase
- * @param CSuDoKuLine $line
- **/
- public function line(CSuDoKuLine $line) {
- if($line instanceof CSuDoKuLine) {
- //$this->m_oDebug->addTrace(7,$this->getObjectID(),"CSuDoKuCase","line","($line)","Association de la ligne(".$line->getOrd().") à ".$this->__toString());
- $this->m_oLine=$line;
- return $this;
- }
- else {
- echo "<hr>\nCSuDoKuCase::line(\$line)::ERROR:: \$line should be an CSuDoKuLine object";
- return null;
- }
- }
- /**
- * @desc Accesseur
- * @return CSuDoKuCase
- * @param CSuDoKuColumn $column
- **/
- public function column(CSuDoKuColumn $column) {
- if($column instanceof CSuDoKuColumn) {
- //$this->m_oDebug->addTrace(7,$this->getObjectID(),"CSuDoKuCase","column","($column)","Association de la colonne (".$column->getAbsc().") à ".$this->__toString());
- $this->m_oColumn=$column;
- return $this;
- }
- else {
- echo "<hr>\nCSuDoKuCase::column(\$column)::ERROR:: \$column should be an CSuDoKuColumn object";
- return null;
- }
- }
- /**
- * @desc Accesseur
- * @return int
- * @param void
- **/
- public function getRelativeOrd() {
- return $this->m_iOrd-sqrt($this->m_iNb)*$this->m_oSquare->getOrd();
- }
- /**
- * @desc Accesseur
- * @return int
- * @param void
- **/
- public function getRelativeAbsc() {
- return $this->m_iAbsc-sqrt($this->m_iNb)*$this->m_oSquare->getAbsc();
- }
- /**
- * @desc Accesseur
- * @return int
- * @param void
- **/
- public function getOrd() {
- return $this->m_iOrd;
- }
- /**
- * @desc Accesseur
- * @return int
- * @param void
- **/
- public function getAbsc() {
- return $this->m_iAbsc;
- }
- /**
- * @desc Accesseur
- * @return CSuDoKuLine
- * @param void
- **/
- public function getLine() {
- return $this->m_oLine;
- }
- /**
- * @desc Accesseur
- * @return CSuDoKuColumn
- * @param void
- **/
- public function getColumn() {
- return $this->m_oColumn;
- }
- /**
- * @desc Accesseur
- * @return CSuDoKuSquare
- * @param void
- **/
- public function getSquare() {
- return $this->m_oSquare;
- }
- /**
- * @desc Renvoie string
- * @return string
- * @param void
- **/
- public function __toString() {
- return "Case[".$this->getObjectID()."](".$this->m_iAbsc.",".$this->m_iOrd.")";
- }
- /**
- * @desc Sauvegarde les symboles qui ont été modifié par la case dont l'id est $idCase
- * @return bool
- * @param int $idCase
- **/
- public function sauvegarder($idCase) {
- if(!$this->isDone() and !$this->isEmpty()){
- //$this->m_oDebug->addTrace(4,$this->getObjectID(),"CSuDoKuCase","sauvegarder","($idCase)",$this->__toString()."=> sauvegarde n°".$idCase.": (".join(", ",$this->m_aSymbols).")");
- $this->m_aSaveSymbols[$idCase]=$this->m_aSymbols;
- }
- else {
- if($this->isDone()) {
- //$this->m_oDebug->addTrace(4,$this->getObjectID(),"CSuDoKuCase","sauvegarder","($idCase)",$this->__toString()."=> non sauvegarde car découverte");
- }
- else {
- if($this->isEmpty()) {
- //$this->m_oDebug->addTrace(4,$this->getObjectID(),"CSuDoKuCase","sauvegarder","($idCase)",$this->__toString()."=> non sauvegarde car vide");
- }
- }
- }
- }
- /**
- * @desc Restaure les symboles
- * @return bool
- * @param int $idCase
- **/
- public function restaurer($idCase) {
- if(count($this->m_aSaveSymbols)>0) {
- if(is_array($this->m_aSaveSymbols[$idCase])) {
- //$this->m_oDebug->addTrace(4,$this->getObjectID(),"CSuDoKuCase","restaurer","($idCase)",$this->__toString()."=> restauration de la sauvegarde n°".$idCase.": (".join(", ",$this->m_aSaveSymbols[$idCase]).")");
- $this->m_aSymbols=$this->m_aSaveSymbols[$idCase];
- if(count($this->m_aSymbols)>1) $this->m_bDone=false;
- if(count($this->m_aSaveSymbols)>1) unset($this->m_aSaveSymbols[$idCase]);
- }
- else {
- //$this->m_oDebug->addTrace(4,$this->getObjectID(),"CSuDoKuCase","restaurer","($idCase)",$this->__toString()."=> La sauvegarde n°".$idCase." n'existe pas.");
- }
- }
- else {
- //$this->m_oDebug->addTrace(4,$this->getObjectID(),"CSuDoKuCase","restaurer","($idCase)",$this->__toString()."=> pas assez de sauvegarde disponible: ".count($this->m_aSaveSymbols));
- }
- }
- /**
- * @desc Attribue un symbole
- * @return bool
- * @param string $sym
- **/
- public function attribuer($sym){
- if($this->setSymbols($sym,$this->getObjectID())) {
- $this->m_bDone=true;
- //$this->m_oDebug->addTrace(3,$this->getObjectID(),"CSuDoKuCase","attribuer","(".$sym.")",$this->__toString()."=> attribue $sym");
- return $this->propagate();
- }
- else {
- //$this->m_oDebug->addTrace(3,$this->getObjectID(),"CSuDoKuCase","attribuer","(".$sym.")",$this->__toString()."=> setSymbols($sym) a échoué");
- $this->m_bDone=false;
- return false;
- }
- }
- /**
- * @desc DesAttribue un symbole
- * @return CSuDoKuCase
- **/
- public function desattribuer() {
- //$this->m_oDebug->addTrace(3,$this->getObjectID(),"CSuDoKuCase","desattribuer","()",$this->__toString()."=> désattribue ");
- $this->m_bDone=false;
- $this->restaurer($this->getObjectID());
- return $this->unpropagate();
- }
- /**
- * @desc Accesseur
- * @return CSuDoKuCase
- * @param mixed $symboles
- * @package int $idCase
- **/
- public function setSymbols($symboles,$idCase) {
- $this->sauvegarder($idCase);
- $bOK=1;
- if(is_array($symboles)){
- $symboles=array_unique($symboles);
- if(count($this->m_aOSymbols)>=count($symboles) and count($symboles)>0) {
- //$this->m_oDebug->addTrace(4,$this->getObjectID(),"CSuDoKuCase","setSymbols","(".$symboles.")",$this->__toString().": Modification de la liste des symboles.");
- $a_enlever=array_diff($this->m_aSymbols,$symboles);
- $a_ajouter=array_diff($symboles,$this->m_aSymbols);
- if(count($a_enlever)) {
- foreach ($a_enlever as $sym) {
- $bOK=$bOK*$this->delSymbols($sym,false);
- }
- }
- if(count($a_ajouter)) {
- foreach ($a_ajouter as $sym) {
- $bOK=$bOK*$this->addSymbols($sym,false);
- }
- }
- }
- else $bOK=0;
- }
- elseif(!is_array($symboles) and in_array($symboles,$this->m_aOSymbols)) {
- ////$this->m_oDebug->addTrace(4,$this->getObjectID(),"CSuDoKuCase","setSymbols","(".$symboles.")",$this->__toString().": isDone() => true, Symbole=$symboles.");
- $this->m_aSymbols=array(0 => $symboles);
- $bOK=1;
- }
- else {
- //$this->m_oDebug->addTrace(4,$this->getObjectID(),"CSuDoKuCase","setSymbols","(".join(", ",$symboles).")",$this->__toString().": Le tableau est vide ou contient trop de symboles, ou ce symbole n'existe pas.");
- $bOK=0;
- }
- return $bOK;
- }
- /**
- * @desc Accesseur
- * @return CSuDoKu
- * @param mixed $symboles
- * @param bool $bSave
- * @param int $idCase
- **/
- public function addSymbols($symboles,$bSave,$idCase) {
- if($bSave) $this->sauvegarder($idCase);
- $bOK=1;
- if(is_array($symboles)){
- $symboles=array_unique($symboles);
- if(count($symboles)>0) {
- $a_ajouter=array_diff($symboles,$this->m_aSymbols);
- if(count($a_ajouter)>0) {
- foreach ($a_ajouter as $sym) {
- $bOK=$bOK*$this->addSymbols($sym,false);
- }
- }
- }
- else $bOK=0;
- }
- elseif(!is_array($symboles) and in_array($symboles,$this->m_aSymbols)) {
- //$this->m_oDebug->addTrace(7,$this->getObjectID(),"CSuDoKuCase","addSymbols","(".$symboles.")",$this->__toString().": Ce symbole existe déja.");
- $bOK=0;
- }
- elseif(!is_array($symboles) and !in_array($symboles,$this->m_aSymbols) and in_array($symboles,$this->m_aOSymbols)) {
- $this->m_aSymbols[]=$symboles;
- //shuffle($this->m_aSymbols);
- //$this->m_oDebug->addTrace(7,$this->getObjectID(),"CSuDoKuCase","addSymbols","(".$symboles.")",$this->__toString().": Ajout de $symboles:".join(", ",$this->m_aSymbols));
- $bOK=1;
- }
- else {
- //$this->m_oDebug->addTrace(7,$this->getObjectID(),"CSuDoKuCase","addSymbols","(".$symboles.")",$this->__toString().": Ce symbole en dehors de tous les cas.");
- $bOK=0;
- }
- return $bOK;
- }
- /**
- * @desc Accesseur
- * @return CSuDoKu
- * @param mixed $symboles
- * @param bool $bSave
- * @param int $idCase
- **/
- public function delSymbols($symboles,$bSave,$idCase) {
- if($bSave) $this->sauvegarder($idCase);
- $bOK=1;
- if(is_array($symboles)) {
- $symboles=array_unique($symboles);
- if(count($symboles)>0) {
- $a_enlever=array_diff($this->m_aSymbols,$symboles);
- if(count($a_enlever)>0) {
- foreach ($a_enlever as $sym) {
- $bOK=$bOK*$this->delSymbols($sym,false);
- }
- }
- }
- else {
- $bOK=0;
- }
- }
- elseif(!is_array($symboles) and !in_array($symboles,$this->m_aSymbols)) {
- //$this->m_oDebug->addTrace(7,$this->getObjectID(),"CSuDoKuCase","delSymbols","(".$symboles.")",$this->__toString().": Ce symbole n'existe déja plus.");
- $bOK=0;
- }
- elseif(!is_array($symboles) and in_array($symboles,$this->m_aSymbols)) {
- unset($this->m_aSymbols[array_search($symboles,$this->m_aSymbols)]);
- //shuffle($this->m_aSymbols);
- //$this->m_oDebug->addTrace(7,$this->getObjectID(),"CSuDoKuCase","delSymbols","(".$symboles.")",$this->__toString().": Suppression de $symboles:".join(", ",$this->m_aSymbols));
- $bOK=1;
- }
- else {
- //$this->m_oDebug->addTrace(7,$this->getObjectID(),"CSuDoKuCase","delSymbols","(".join(", ",$symboles).")",$this->__toString().": Ce symbole en dehors de tous les cas.");
- $bOK=0;
- }
- return $bOK;
- }
- /**
- * @desc Accesseur
- * @return array
- * @param int $i
- **/
- public function getOriginalSymbols($i=null) {
- if(isset($i) and $i>=0 and $i<count($this->m_aOSymbols)) {
- //$this->m_oDebug->addTrace(7,$this->getObjectID(),"CSuDoKuCase","getOriginalSymbols","($i)",$this->__toString().": Symbole #$i=".$this->m_aOSymbols[$i]);
- return $this->m_aOSymbols[$i];
- }
- else {
- //$this->m_oDebug->addTrace(7,$this->getObjectID(),"CSuDoKuCase","getOriginalSymbols","()",$this->__toString().": Symboles=".join(", ",$this->m_aOSymbols));
- return $this->m_aOSymbols;
- }
- }
- /**
- * @desc Accesseur
- * @return array
- * @param int $i
- **/
- public function getSymbols($i=null) {
- if(isset($i) and $i>=0 and $i<count($this->m_aSymbols)) {
- //$this->m_oDebug->addTrace(7,$this->getObjectID(),"CSuDoKuCase","getSymbols","($i)",$this->__toString().": Symbole #$i=".$this->m_aSymbols[$i]);
- return $this->m_aSymbols[$i];
- }
- else {
- //$this->m_oDebug->addTrace(7,$this->getObjectID(),"CSuDoKuCase","getSymbols","()",$this->__toString().": Symboles=".join(", ",$this->m_aSymbols));
- return $this->m_aSymbols;
- }
- }
- /**
- * @desc Accesseur
- * @return bool
- * @param void
- **/
- public function isDone() {
- if($this->m_bDone) {
- //$this->m_oDebug->addTrace(7,$this->getObjectID(),"CSuDoKuCase","isDone","()",$this->__toString().": true");
- return true;
- }
- else {
- //$this->m_oDebug->addTrace(7,$this->getObjectID(),"CSuDoKuCase","isDone","()",$this->__toString().": false");
- return false;
- }
- }
- /**
- * @desc Accesseur
- * @return bool
- * @param void
- **/
- public function isEmpty() {
- if(count($this->m_aSymbols)<=0) {
- //$this->m_oDebug->addTrace(7,$this->getObjectID(),"CSuDoKuCase","isEmpty","()",$this->__toString().": true");
- return true;
- }
- else {
- //$this->m_oDebug->addTrace(7,$this->getObjectID(),"CSuDoKuCase","isEmpty","()",$this->__toString().": false");
- return false;
- }
- }
- /**
- * @desc Remet à zero.
- * Si $shuffle est à vrai, génére une nouvelle série aléatoire (par défaut)
- * Si $shuffle est à faux, conserve l'ordre des symboles généré précdemment.
- * @return CSuDoKuCase
- * @param bool $shuffle = true
- **/
- public function reSet($shuffle=true) {
- //$this->m_oDebug->addTrace(4,$this->getObjectID(),"CSuDoKuCase","reSet","($shuffle)",$this->__toString().": réinitialisation");
- $this->restaurer(-1);
- unset($this->m_aSaveSymbols);
- if($shuffle) shuffle($this->m_aSymbols);
- $this->sauvegarder(-1);
- return $this;
- }
- /**
- * @desc Propage le fait que la case a été découverte
- * @return bool
- * @param
- **/
- public function propagate() {
- if($this->m_oColumn->propagate($this->m_aSymbols[0],$this)){
- ////$this->m_oDebug->addTrace(4,$this->getObjectID(),"CSuDoKuCase","propagate","()",$this->__toString().": propagation de la colonne réussie");
- if($this->m_oLine->propagate($this->m_aSymbols[0],$this)) {
- ////$this->m_oDebug->addTrace(4,$this->getObjectID(),"CSuDoKuCase","propagate","()",$this->__toString().": propagation de la ligne réussie");
- if($this->m_oSquare->propagate($this->m_aSymbols[0],$this)) {
- ////$this->m_oDebug->addTrace(4,$this->getObjectID(),"CSuDoKuCase","propagate","()",$this->__toString().": propagation de la boîte réussie");
- return true;
- }
- else {
- ////$this->m_oDebug->addTrace(4,$this->getObjectID(),"CSuDoKuCase","propagate","()",$this->__toString().": propagation de la boîte échouée");
- //$this->m_oSquare->unpropagate($this->getAbsc(),$this->getOrd());
- return false;
- }
- }
- else {
- ////$this->m_oDebug->addTrace(4,$this->getObjectID(),"CSuDoKuCase","propagate","()",$this->__toString().": propagation de la ligne échouée");
- //$this->m_oLine->unpropagate($this->getAbsc(),$this->getOrd());
- return false;
- }
- }
- else {
- ////$this->m_oDebug->addTrace(4,$this->getObjectID(),"CSuDoKuCase","propagate","()",$this->__toString().": propagation de la colonne échouée");
- //$this->m_oColumn->unpropagate($this->getAbsc(),$this->getOrd());
- return false;
- }
- }
- /**
- * @desc déPropage le fait que la case a été découverte
- * @return CSudoKuCase
- * @param
- **/
- public function unpropagate() {
- //$this->m_oDebug->addTrace(4,$this->getObjectID(),"CSuDoKuCase","unpropagate","()",$this->__toString().": dépropagation");
- $this->m_oColumn->unpropagate($this);
- $this->m_oLine->unpropagate($this);
- $this->m_oSquare->unpropagate($this);
- return $this;
- }
- /**
- * @desc Renvoie le symbole temporaire du joueur
- * @return string
- * @param
- **/
- public function getTest() {
- return $this->m_sTest;
- }
- /**
- * @desc Permet de sauvegarder le choix temporaire du joueur
- * @return CSudoKuCase
- * @param string $sym
- **/
- public function test($sym) {
- if(in_array($sym,$this->m_aOSymbols)){
- $this->m_sTest=$sym;
- return $this;
- }
- else return null;
- }
- /**
- * @desc Permet d'effacer la sauvegarde du choix temporaire du joueur
- * @return CSudoKuCase
- * @param
- **/
- public function untest() {
- $this->m_sTest=null;
- return $this;
- }
- }
<?php
/**
* @desc Generateur et solveur de grille de Sudoku *
* @author Nifhell
* @package sudoku
* @version 1.0
*/
include_once($_SERVER['DOCUMENT_ROOT']."cobject.php");
/**
* @desc Classe CSudoku
*
*/
class CSuDoKu extends CObject {
private $m_oDebug;
private static $m_oInstance;
protected $m_iNb;
protected $m_sType;
protected $m_aLines;
protected $m_aCols;
protected $m_aCases;
protected $m_aSquare;
protected $m_iLevel;
protected $m_iCache;
protected $m_bTutorial=false;
protected $m_iTime;
protected $m_iIter=-1;
/**
* @desc Constructeur par valeur
* @return CSuDoKu
* @param int $nb
* @param string $type
* @param int $level
* @param bool $tuto
**/
public function CSuDoKu() {
//$this->m_oDebug=CDebug::getInstance(false,true);
$start=microtime(true);
if(func_num_args()>1 and func_num_args()<=4) {
func_get_arg(0)?$nb=func_get_arg(0):$nb=9;
func_get_arg(1)?$type=func_get_arg(1):$type='numeric';
func_get_arg(2)?$level=func_get_arg(2):$level=4;
func_get_arg(3)?$tuto=func_get_arg(3):$tuto=false;
$this->m_bTutorial=$tuto;
$this->CSuDoKuGrille($nb,$type);
$this->CSuDoKuLevel($level);
}
elseif (func_num_args()==1 and $param=func_get_arg(0)) {
$this->XML2CSuDoKu($param);
}
$this->m_iTime=microtime(true)-$start;
//$this->m_oDebug->addTrace(1,$this->getObjectID(),"CSuDoKu","Constructor","($this->m_iNb,$this->m_sType,$this->m_iLevel,$this->m_bTutorial)","Sudoku initialisé: ".$this->m_iTime."s");
}
/**
* @desc Détermine le nombre de cases a cacher
* @return CSuDoKu
* @param int $nb
* @param string $type
**/
private function CSuDoKuGrille($nb,$type) {
if(4<=$nb and $nb<=25
and intval($sqrt=sqrt($nb))*10==$sqrt*10) {
$this->m_iNb=$nb;
$this->m_sType=$type;
//$this->m_oDebug->addTrace(1,$this->getObjectID(),"CSuDoKu","CSuDoKuGrille","($nb,$type)","Racine: $sqrt.");
$this->m_aLines=array();
$this->m_aCols=array();
$this->m_aCases=array();
$this->m_aSquare=array();
for($i=0;$i<$nb;$i++) {
if(!($this->m_aLines[$i] instanceof CSuDoKuLine)){
$this->m_aLines[$i]=new CSuDoKuLine($i);
}
if(!($i%$sqrt)) {
$this->m_aSquare[$i/$sqrt]=array();
}
$this->m_aCases[$i]=array();
for($j=0;$j<$nb;$j++) {
if(!($this->m_aCols[$j] instanceof CSuDoKuColumn)){
$this->m_aCols[$j]=new CSuDoKuColumn($j);
}
$this->m_aCases[$i][$j]=new CSuDoKuCase($i,$j,$nb,$type);
$this->m_aLines[$i]->addCase($this->m_aCases[$i][$j]);
$this->m_aCols[$j]->addCase($this->m_aCases[$i][$j]);
if(!($j%$sqrt) and !($i%$sqrt)) {
$this->m_aSquare[$i/$sqrt][$j/$sqrt]=new CSuDoKuSquare($i/$sqrt,$j/$sqrt);
}
$this->m_aSquare[intval($i/$sqrt)][intval($j/$sqrt)]->addCase($this->m_aCases[$i][$j],$i-($sqrt*intval($i/$sqrt)),$j-($sqrt*intval($j/$sqrt)));
$this->m_aCases[$i][$j]->square($this->m_aSquare[intval($i/$sqrt)][intval($j/$sqrt)]);
$this->m_aCases[$i][$j]->line($this->m_aLines[$i]);
$this->m_aCases[$i][$j]->column($this->m_aCols[$j]);
}
}
}
return $this;
}
/**
* @desc Détermine le nombre de cases a cacher
* @return CSuDoKu
* @param int $level
**/
public function CSuDoKuLevel($level) {
switch ($level){
case 1:
$this->m_iLevel=1;
$base=mt_rand(30,35);
break;
case 2:
$this->m_iLevel=2;
$base=mt_rand(36,41);
break;
case 3:
$this->m_iLevel=3;
$base=mt_rand(42,47);
break;
case 4:
$this->m_iLevel=4;
$base=mt_rand(48,53);
break;
case 5:
$this->m_iLevel=5;
$base=mt_rand(54,59);
break;
case 6:
$this->m_iLevel=6;
$base=mt_rand(60,65);
break;
case 7:
$this->m_iLevel=7;
$base=mt_rand(66,71);
break;
default:
$this->m_iLevel=4;
$base=mt_rand(48,53);
}
$this->m_iCache=intval($base/100*pow($this->m_iNb,2));
//$this->m_oDebug->addTrace(1,$this->getObjectID(),"CSuDoKu","CSuDoKuLevel","($level)","Niveau: $this->m_iLevel, Caches: $this->m_iCache");
return $this;
}
/**
* @desc XML => CSuDoKu
* @return CSuDoKu
* @param string $xml_source
**/
private function XML2CSuDoKu($xml_source) {
if(isset($xml_source)){
if(!is_file($xml_source)){
$xml=simplexml_load_string($xml_source);
$this->CSuDoKu((int)$xml['nbr'],(string)$xml['type'],(int)$xml['level'],($xml['tuto']=='true'?true:false));
foreach ($xml->cell as $cell) {
$case=$this->m_aCases[(int)$cell['x']][(int)$cell['y']];
if((string)$cell) $case->attribuer((string)$cell);
if((string)$cell['test']) $case->test((string)$cell['test']);
}
////$this->m_oDebug->addTrace(1,$this->getObjectID(),"CSuDoKu","XML2SuDoKu","($path)","XML => Chargement OK");
return $this;
}
elseif(is_file($xml_source)) {
$xml=simplexml_load_file($xml_source);
$this->CSuDoKu((int)$xml['nbr'],(string)$xml['type'],(int)$xml['level'],($xml['tuto']=='true'?true:false));
foreach ($xml->cell as $cell) {
$case=$this->m_aCases[(int)$cell['x']][(int)$cell['y']];
if((string)$cell) $case->attribuer((string)$cell);
if((string)$cell['test']) $case->test((string)$cell['test']);
}
////$this->m_oDebug->addTrace(1,$this->getObjectID(),"CSuDoKu","XML2SuDoKu","($path)","XML => Chargement OK");
return $this;
}
}
else {
//$this->m_oDebug->addTrace(1,$this->getObjectID(),"CSuDoKu","XML2SuDoKu","($path)","XML => Chargement ECHEC (Le fichier n'existe pas)");
return null;
}
}
/**
* @desc Cache les cases de la grille de SuDoKu en cours
* @return bool
* @param void
**/
private function cache() {
for($i=0;$i<$this->m_iCache;$i++) {
do {
$x=mt_rand(0,$this->m_iNb-1);
$y=mt_rand(0,$this->m_iNb-1);
$case=$this->m_aCases[$x][$y];
}while(!$case->isDone());
$case->reSet();
//$this->m_oDebug->addTrace(2,$this->getObjectID(),"CSuDoKu","cache","($i)",$case->__toString()." cachée");
}
for($x=0;$x<$this->m_iNb;$x++) {
for($y=0;$y<$this->m_iNb;$y++) {
$case=$this->m_aCases[$x][$y];
if($case->isDone()) {
$case->attribuer($case->getSymbols(0));
}
}
}
}
/**
* @desc Résoud la grille de SuDoKu en cours
* @return bool
* @param int $i
**/
private function resoudre($i) {
$tab="";
$this->m_iIter++;
//$this->m_oDebug->addTrace(2,$this->getObjectID(),"CSuDoKu","resoudre","($i)",$this->toStrTable());
if(is_array($coord=$this->best2solve())) {
$case=$this->m_aCases[$coord['x']][$coord['y']];
//$this->m_oDebug->addTrace(2,$this->getObjectID(),"CSuDoKu","resoudre","($i)",$tab.$case->__toString()." choisie.");
foreach($case->getSymbols() as $s) {
//$this->m_oDebug->addTrace(2,$this->getObjectID(),"CSuDoKu","resoudre","($i)",$tab."Symboles possibles de la ".$case->__toString().": ".join(", ",$case->getSymbols()));
//$this->m_oDebug->addTrace(2,$this->getObjectID(),"CSuDoKu","resoudre","($i)",$tab."\t Test du symbole $s: ");
if($case->attribuer($s)) {
//$this->m_oDebug->addTrace(2,$this->getObjectID(),"CSuDoKu","resoudre","($i)",$tab."\t $s valider provisoirement.");
if($this->resoudre($i+1)){
//$this->m_oDebug->addTrace(2,$this->getObjectID(),"CSuDoKu","resoudre","($i)",$tab."\t $s enterriner.");
return true;
}
else {
//$this->m_oDebug->addTrace(2,$this->getObjectID(),"CSuDoKu","resoudre","($i)",$tab."\t $s ne convient pas au case d'ordre inférieur => on réinitialise la case symbole suivant.");
$case->desattribuer();
}
}
else {
//$this->m_oDebug->addTrace(2,$this->getObjectID(),"CSuDoKu","resoudre","($i)",$tab."\t $s ne convient au case de la même ligne, colonne ou boite => symbole suivant.");
$case->desattribuer();
}
}
return false;
}
else return true;
}
/**
* @desc Renvoie les coordonnées de la case qui a le moins de possibilité
* @return array
* @param
**/
public function best2solve() {
$min=$this->m_iNb+1;
$min_x=$min_y=-1;
for($x=0;$x<$this->m_iNb;$x++) {
for($y=0;$y<$this->m_iNb;$y++) {
if(!$this->m_aCases[$x][$y]->isDone()){
$tmp=count($this->m_aCases[$x][$y]->getSymbols());
if($tmp<$min) {
$min=$tmp;
$min_x=$x;
$min_y=$y;
}
}
}
}
if($min>0 and $min!=$this->m_iNb+1) {
//$this->m_oDebug->addTrace(4,$this->getObjectID(),"CSuDoKu","best2solve","()","Case best2solve: ".$this->m_aCases[$min_x][$min_y]->__toString()." minimum => $min.");
return array('x' => $min_x, 'y' => $min_y, 0 => $min_x, 1 => $min_y);
}
else {
//$this->m_oDebug->addTrace(4,$this->getObjectID(),"CSuDoKu","best2solve","()","Case best2solve: ".($this->m_aCases[$min_x][$min_y]?$this->m_aCases[$min_x][$min_y]->__toString():"")." | minimum => $min");
return null;
}
}
/**
* @desc Génere une grille
* @return CSuDoKu
* @param
**/
public function genererGrille() {
$start=microtime(true);
$this->reSet();
$bOK=$this->resoudre(0);
$bOK=$bOK*$this->isValid();
$this->cache();
$bOK=$bOK*$this->isValid();
$this->m_iTime=microtime(true)-$start;
//$this->m_oDebug->addTrace(1,$this->getObjectID(),"CSuDoKu","genererGrille","()","Grille initialisé (".$this->m_iTime."s): ".($bOK?"OK":"ECHEC"));
return $bOK;
}
/**
* @desc Résoud une grille non résolu
* @return CSuDoKu
* @param
**/
public function resoudreGrille() {
$start=microtime(true);
$bOK=$this->resoudre(0);
$bOK=$bOK*$this->isValid();
$this->m_iTime=microtime(true)-$start;
//$this->m_oDebug->addTrace(1,$this->getObjectID(),"CSuDoKu","resoudreGrille","()","Grille résolue (".$this->m_iTime."s): ".($bOK?"OK":"ECHEC"));
return $bOK;
}
/**
* @desc Renvoie le nombre d'itération que l'algo de résolution a effectuer
* @return int
* @param
**/
public function getIter() {
return $this->m_iIter-pow($this->m_iNb,2);
}
/**
* @desc Renvoie le nombre de case par ligne
* @return int
* @param
**/
public function getNbr() {
return $this->m_iNb;
}
/**
* @desc Renvoie le nombre de case par ligne
* @return int
* @param
**/
public function getLevel() {
return $this->m_iLevel;
}
/**
* @desc Résoud une grille non résolu
* @return CSuDoKu
* @param string $mode
**/
public function getTime($mode) {
switch($mode){
case 's':
return round($this->m_iTime,2);
break;
case 'cs':
return round($this->m_iTime*10,2);
break;
case 'ms':
return round($this->m_iTime*100,2);
break;
case '_s':
return round($this->m_iTime*1000,2);
break;
default:
return round($this->m_iTime,2);
}
}
/**
* @desc Vide la grille.
* Si $shuffle est à vrai, alors le prochain appel de résoudre(), générera une nouvelle grille (par défaut)
* Si $shuffle est à faux, alors la grille est simplement vidé, mais le prochain appel de resoudre() générera la même grille que précédemment. Pratique, si vous souhiatez avoir la même grille mais avec des niveaux de difficulté différents.
* @return CSuDoKu
* @param bool $shuffle = true
**/
public function reSet($shuffle=true) {
//$this->m_oDebug->addTrace(4,$this->getObjectID(),"CSuDoKu","reSet","()","initialisation");
$this->m_iIter=-1;
for($i=0;$i<count($this->m_aCases);$i++){
for($j=0;$j<count($this->m_aCases[$i]);$j++){
$this->m_aCases[$i][$j]->reSet($shuffle);
}
}
return $this;
}
/**
* @desc (Static) Renvoie l'instance en cours de la classe CSuDoKu
* @return CSuDoKu
* @param int $nb
* @param string $type
* @param int $level
* @param bool $tuto
**/
public static function getInstance($nb,$type, $level, $tuto) {
if (empty(self::$m_oInstance)) {
self::$m_oInstance = new CSuDoKu($nb,$type, $level, $tuto);
}
return self::$m_oInstance;
}
/**
* @desc CSuDoKu => SimpleXMLElement
* @return SimpleXMLElement
* @param string $path
**/
public function toXML($path=false) {
$xml_string="<?xml version=\"1.0\" standalone=\"yes\"?>\n";
$xml_string.="<sudoku type=\"".$this->m_sType."\" nbr=\"".$this->m_iNb."\" level=\"".$this->m_iLevel."\" tuto=\"".($this->m_bTutorial?'true':'false')."\">\n";
for($i=0;$i<$this->m_iNb;$i++){
for($j=0;$j<$this->m_iNb;$j++){
if($this->getCase($i,$j)->getTest()) $test=$this->getCase($i,$j)->getTest();
else $test="";
$xml_string.="<cell x=\"".$i."\" y=\"".$j."\" test=\"".$test."\">";
if($this->m_aCases[$i][$j]->isDone()) $xml_string.=$this->m_aCases[$i][$j]->getSymbols(0);
$xml_string.="</cell>\n";
}
}
$xml_string.="</sudoku>";
//$this->m_oDebug->addTrace(1,$this->getObjectID(),"CSuDoKu","toXML","($path)","Chargement de la grille: ".$xml_string);
$xml=simplexml_load_string($xml_string);
if((!isset($path) and $path!=false) or !$xml->asXML($path)) {
//$this->m_oDebug->addTrace(1,$this->getObjectID(),"CSuDoKu","toXML","($path)","XML => Enregistrement du fichier XML ECHEC");
}
return $xml_string;
}
/**
* @desc Transforme le SuDoKu en Table HTML
* @return string
* @param
**/
public function toHTMLTable() {
$table="<table>\n\t";
for($i=1;$i<=$this->m_iNb;$i++){
$table.="<tr>";
for($j=1;$j<=$this->m_iNb;$j++){
$absc=$i-1;
$ord=$j-1;
$symbols=$this->getCase($absc,$ord)->getSymbols();
$table.="<td>";
if($this->getCase($absc,$ord)->isDone()){
$table.=$symbols[0];
}
else {
if($this->m_bTutorial) {
$table.="<select name=\"case_".$i."_".$j."\" size=1>";
$table.="<option value=\"null\">";
natcasesort($symbols);
foreach ($symbols as $sym) {
$b="";
if($this->getCase($absc,$ord)->getTest()) {
if($sym==$this->getCase($absc,$ord)->getTest()) $b="selected";
}
$table.="<option value=\"".$sym."\" ".$b." >".$sym."";
}
}
else {
if($this->getCase($absc,$ord)->getTest()) $default=$this->getCase($absc,$ord)->getTest();
else $default="";
$table.="<input type=\"text\" name=\"case_".$i."_".$j."\" size=\"1\" maxlength=\"1\" onchange=\"check_sudoku_input(this)\" value=\"".$default."\">";
}
}
$table.="</td>";
}
$table.="</tr>\n";
}
$table.="</table>\n";
$table.="<script type=\"Javascript\">";
$table.="function check_sudoku_input(nCase) {
var Symbols=/^\s|".join("|",$this->getCase(0,0)->getOriginalSymbols())."$/;
var bOk=false;
if(nCase.value && !Symbols.test(nCase.value)) {
alert('Arrrg! Vous devez saisir un caractère parmi ceux-ci: ".join(", ",$this->getCase(0,0)->getOriginalSymbols())."');
nCase.value='';
nCase.focus();
}
return bOk;
}
</script>\n";
$this->setHTML($table);
return $table;
}
/**
* @desc Transforme le SuDoKu en Table
* @return string
* @param
**/
public function toStrTable() {
$str="\n";
for($i=0;$i<$this->m_iNb;$i++){
if (!($i%sqrt($this->m_iNb))){
for($j=1;$j<=$this->m_iNb;$j++){
$str.="\t-";
}
$str.="\n";
}
for($j=0;$j<$this->m_iNb;$j++){
if(!($j%sqrt($this->m_iNb))) {
$str.="\t|";
}
$symbols=$this->getCase($i,$j)->getSymbols();
if($this->getCase($i,$j)->isDone()){
$str.="\t".$symbols[0];
}
else {
$str.="\t ";
}
}
$str.="\n";
}
return $str;
}
/**
* @desc Transforme le SuDoKu en tableau HTML
* @return string
* @param void
**/
public function __toString() {
return $this->toHTMLTable();
}
/**
* @desc Accesseur
* @return CSuDoKuCase
* @param int $i
* @param int $j
**/
public function getCase($i,$j) {
if($i<$this->m_iNb and $j<$this->m_iNb){
return $this->m_aCases[$i][$j];
}
else {
echo "<hr>Fatal error: CSudoku:getCase($i,$j):: out of range";
return null;
}
}
/**
* @desc Vérifie si le mod tutoriel est activé
* @return bool
* @param
**/
public function isEasy() {
return $this->m_bTutorial;
}
/**
* @desc Vérifie les contraintes d'unicité
* @return bool
* @param
**/
public function isValid() {
$bRet=array();
for($x=0;$x<$this->m_iNb;$x++) {
for($y=0;$y<$this->m_iNb;$y++) {
if($this->m_aCases[$x][$y]->isEmpty()){
$bRet[]=false;
break;
}
}
}
foreach ($this->m_aLines as $obj) {
$bRet[]=$obj->isValid();
}
foreach ($this->m_aCols as $obj) {
$bRet[]=$obj->isValid();
}
foreach ($this->m_aSquare as $tmp) {
foreach ($tmp as $obj) {
$bRet[]=$obj->isValid();
}
}
if(in_array(false,$bRet)) {
//$this->m_oDebug->addTrace(2,$this->getObjectID(),"CSuDoKu","isValid","","Cette grille est fausse.");
return false;
}
else {
//$this->m_oDebug->addTrace(2,$this->getObjectID(),"CSuDoKu","isValid","","Cette grille est valide.");
return true;
}
}
}
class CSuDoKuLine extends CObject {
private $m_oDebug;
protected $m_iOrd;
protected $m_aCases;
/**
* @desc Constructeur par défaut
* @return CSuDoKuLine
* @param int $i
**/
public function CSuDoKuLine($i) {
//$this->m_oDebug=CDebug::getInstance(false,true);
if(intval($i)*10==$i*10){
//$this->m_oDebug->addTrace(7,$this->getObjectID(),"CSuDoKuLine","Constructor","($i)","$this");
$this->m_iOrd=$i;
}
}
/**
* @desc Add a case
* @return CSuDoKuLine
* @param CSuDoKuCase $case
**/
public function addCase(CSuDoKuCase $case) {
if($case instanceof CSuDoKuCase) {
//$this->m_oDebug->addTrace(7,$this->getObjectID(),"CSuDoKuLine","addCase","($case)","Ligne($this->m_iOrd)<=Case: (".$case->getAbsc().",".$case->getOrd().")");
$this->m_aCases[]=$case;
return $this;
}
else {
echo "<hr>Fatal error: CSuDoKuLine::addCase(\$case) shouldn't be empty.";
return null;
}
}
/**
* @desc Accesseur
* @return array
* @param
**/
public function getCases() {
return $this->m_aCases;
}
/**
* @desc Accesseur
* @return CSuDoKuCase
* @param int $i
**/
public function getCase($i) {
if($i>=0 and $i<count($this->m_aCases)) {
return $this->m_aCases[$i];
}
else {
echo "<hr>Fatal Error: \$i out of range.";
return null;
}
}
/**
* @desc Accesseur
* @return int
* @param
**/
public function getOrd() {
return $this->m_iOrd;
}
/**
* @desc Vérifie les contraintes d'unicité
* @return bool
* @param
**/
public function isValid() {
$bRet=true;
$tmp=array();
foreach ($this->m_aCases as $case) {
if($case->isDone()) $tmp[]=$case;
}
foreach ($tmp as $case1) {
$sym1=$case1->getSymbols();
foreach ($tmp as $case2) {
$sym2=$case2->getSymbols();
if(($sym1[0]==$sym2[0] or !strcasecmp($sym1[0],$sym2[0])) and strcasecmp($case1->__toString(),$case2->__toString())) {
//$this->m_oDebug->addTrace(4,$this->getObjectID(),"CSudoKuLine","isValid","","Violation de contrainte d'unicité de la ligne ".$this->m_iOrd.": ".$case1->__toString()."=".$case2->__toString()."=".$sym1[0]);
$bRet=false;
}
}
}
return $bRet;
}
/**
* @desc Propage le fait qu'une case a été découverte
* @return CSuDoKuLine
* @param mixed $symbole
* @param CSuDoKuCase $cCase
**/
public function propagate($symbole,CSuDoKuCase $cCase) {
$bOK=true;
foreach ($this->m_aCases as $case) {
if(!$case->isDone() and $case!==$cCase and $case->getSquare()!==$cCase->getSquare()){
$case->delSymbols($symbole,true,$cCase->getObjectID());
if($case->isEmpty()) {
//$this->m_oDebug->addTrace(4,$this->getObjectID(),"CSuDoKuLine","propagate","($symbole,$cCase)",$this->__toString().": ".$case->__toString()." est vide.");
$bOK=false;
}
}
}
//$bOK?//$this->m_oDebug->addTrace(4,$this->getObjectID(),"CSuDoKuLine","propagate","($symbole,$absc,$ord)",$this->__toString().": propagation réussie.")://$this->m_oDebug->addTrace(4,$this->getObjectID(),"CSuDoKuLine","propagate","($symbole,$absc,$ord)",$this->__toString().": propagation échouée.");
return $bOK;
}
/**
* @desc déPropage le fait qu'une case n'est plus découverte
* @return CSuDoKuLine
* @param CSuDoKuCase $cCase
**/
public function unpropagate(CSuDoKuCase $cCase) {
////$this->m_oDebug->addTrace(4,$this->getObjectID(),"CSuDoKuLine","unpropagate","(".$cCase->__toString().")",$this->__toString().": dépropagation");
foreach ($this->m_aCases as $case) {
if($case!==$cCase and $case->getSquare()!==$cCase->getSquare()){
if(!$case->isDone()) {
$case->restaurer($cCase->getObjectID());
}
}
}
return $this;
}
/**
* @desc toString
* @return string
* @param
**/
public function __toString() {
return "Ligne #".$this->m_iOrd;
}
}
class CSuDoKuColumn extends CObject {
private $m_oDebug;
protected $m_iAbsc;
protected $m_aCases;
/**
* @desc Constructeur par défaut
* @return CSuDoKuColumn
* @param int $i
**/
public function CSuDoKuColumn($i) {
//$this->m_oDebug=CDebug::getInstance(false,true);
if(intval($i)*10==$i*10){
//$this->m_oDebug->addTrace(7,$this->getObjectID(),"CSuDoKuColumn","Constructor","($i)","$this");
$this->m_iAbsc=$i;
}
}
/**
* @desc Add a case
* @return CSuDoKuColumn
* @param CSuDoKuCase $case
**/
public function addCase(CSuDoKuCase $case) {
if($case instanceof CSuDoKuCase) {
//$this->m_oDebug->addTrace(7,$this->getObjectID(),"CSuDoKuColumn","addCase","($case)","Colonne($this->m_iAbsc)<=Case: (".$case->getAbsc().",".$case->getOrd().")");
$this->m_aCases[]=$case;
return $this;
}
else {
echo "<hr>Fatal error: CSuDoKuColumn::addCase(\$case) shouldn't be empty.";
return null;
}
}
/**
* @desc Accesseur
* @return CSuDoKuCase
* @param int $i
**/
public function getCase($i) {
if($i>=0 and $i<count($this->m_aCases)) {
return $this->m_aCases[$i];
}
else {
echo "<hr>Fatal Error: \$i out of range.";
return null;
}
}
/**
* @desc Accesseur
* @return array
* @param
**/
public function getCases() {
return $this->m_aCases;
}
/**
* @desc Accesseur
* @return int
* @param void
**/
public function getAbsc() {
return $this->m_iAbsc;
}
/**
* @desc Accesseur
* @return bool
* @param void
**/
public function isValid() {
$bRet=true;
$tmp=array();
foreach ($this->m_aCases as $case) {
if($case->isDone()) $tmp[]=$case;
}
foreach ($tmp as $case1) {
$sym1=$case1->getSymbols();
foreach ($tmp as $case2) {
$sym2=$case2->getSymbols();
if(($sym1[0]==$sym2[0] or !strcasecmp($sym1[0],$sym2[0])) and strcasecmp($case1->__toString(),$case2->__toString())) {
//$this->m_oDebug->addTrace(4,$this->getObjectID(),"CSuDoKuColumn","isValid","","Violation de contrainte d'unicité de la Colonne ".$this->m_iAbsc.": ".$case1->__toString()."=".$case2->__toString()."=".$sym1[0]);
$bRet=false;
}
}
}
return $bRet;
}
/**
* @desc Propage le fait qu'une case a été découverte
* @return CSuDoKuColumn
* @param mixed $symbole
* @param CSuDoKuCase $cCase
**/
public function propagate($symbole,CSuDoKuCase $cCase) {
$bOK=true;
foreach ($this->m_aCases as $case) {
if(!$case->isDone() and $case!==$cCase and $case->getSquare()!==$cCase->getSquare()) {
$case->delSymbols($symbole,true,$cCase->getObjectID());
if($case->isEmpty()) {
//$this->m_oDebug->addTrace(4,$this->getObjectID(),"CSuDoKuColumn","propagate","($symbole,$absc,$ord)",$this->__toString().": ".$case->__toString()." est vide");
$bOK=false;
}
}
}
//$bOK?//$this->m_oDebug->addTrace(4,$this->getObjectID(),"CSuDoKuColumn","propagate","($symbole,$absc,$ord)",$this->__toString().": propagation réussie.($bOK)")://$this->m_oDebug->addTrace(4,$this->getObjectID(),"CSuDoKuColumn","propagate","($symbole,$absc,$ord)",$this->__toString().": propagation échouée.");
return $bOK;
}
/**
* @desc déPropage le fait qu'une case a été remis à l'état incertain
* @return CSuDoKuColumn
* @param CSuDoKuCase $cCase
**/
public function unpropagate(CSuDoKuCase $cCase) {
////$this->m_oDebug->addTrace(4,$this->getObjectID(),"CSuDoKuColumn","unpropagate","(".$cCase->__toString().")",$this->__toString().": dépropagation");
foreach ($this->m_aCases as $case) {
if($case!==$cCase and $case->getSquare()!==$cCase->getSquare()){
if(!$case->isDone()) {
$case->restaurer($cCase->getObjectID());
}
}
}
return $this;
}
/**
* @desc toString
* @return string
* @param void
**/
public function __toString() {
return "Colonne #".$this->m_iAbsc;
}
}
class CSuDoKuSquare extends CObject {
private $m_oDebug;
protected $m_iAbsc;
protected $m_iOrd;
protected $m_aCases;
/**
* @desc Constructeur par défaut
* @return CSuDoKuSquare
* @param int $i
* @param int $j
**/
public function CSuDoKuSquare($i,$j) {
//$this->m_oDebug=CDebug::getInstance(false,true);
if(intval($i)*10==$i*10 and intval($j)*10==$j*10){
$this->m_iAbsc=$i;
$this->m_iOrd=$j;
$this->m_aCases=array();
//$this->m_oDebug->addTrace(7,$this->getObjectID(),"CSuDoKuSquare","Constructor","($i,$j)","$this");
}
else echo "<hr>Fatal error: CSuDoKuSquare(\$i,\$j,\$sym) shouldn't be empty.";
}
/**
* @desc Add a case
* @return CSuDoKuSquare
* @param CSuDoKuCase $case
* @param int $i
* @param int $j
**/
public function addCase(CSuDoKuCase $case,$i,$j) {
if($case instanceof CSuDoKuCase) {
//$this->m_oDebug->addTrace(7,$this->getObjectID(),"CSuDoKuSquare","addCase","($case,$i,$j)","Carré(".$this->m_iAbsc.",".$this->m_iOrd.")<=Case: (".$case->getAbsc().",".$case->getOrd().")");
if(!is_array($this->m_aCases[$i])) $this->m_aCases[$i]=array();
$this->m_aCases[$i][$j]=$case;
return $this;
}
else {
echo "<hr>Fatal error: CSuDoKuSquare::addCase(\$case) shouldn't be empty.";
return null;
}
}
/**
* @desc Accesseur
* @return CSuDoKuCase
* @param int $i
* @param int $j
**/
public function getCase($i,$j) {
if($i>=0 and $i<count($this->m_aCases) and $j>=0 and $j<count($this->m_aCases[$i])) {
return $this->m_aCases[$i][$j];
}
else {
echo "<hr>Fatal Error: \$i or \$j out of range.";
return null;
}
}
/**
* @desc Accesseur
* @return array
* @param void
**/
public function getCases() {
return $this->m_aCases;
}
/**
* @desc Accesseur
* @return int
* @param void
**/
public function getAbsc() {
return $this->m_iAbsc;
}
/**
* @desc Accesseur
* @return int
* @param void
**/
public function getOrd() {
return $this->m_iOrd;
}
/**
* @desc Accesseur
* @return string
* @param void
**/
public function __toString() {
return "Carre[".$this->getObjectID()."](".$this->m_iAbsc.",".$this->m_iOrd.")";
}
/**
* @desc Accesseur
* @return bool
* @param void
**/
public function isValid() {
$bRet=true;
$tmp=array();
foreach ($this->m_aCases as $col) {
foreach ($col as $case) {
if($case->isDone()) $tmp[]=$case;
}
}
foreach ($tmp as $col1) {
foreach ($col1 as $case1) {
$sym1=$case1->getSymbols();
foreach ($tmp as $col2) {
foreach ($col2 as $case2) {
$sym2=$case2->getSymbols();
if(($sym1[0]==$sym2[0] or !strcasecmp($sym1[0],$sym2[0])) and strcasecmp($case1->__toString(),$case2->__toString())) {
//$this->m_oDebug->addTrace(4,$this->getObjectID(),"CSuDoKuSquare","isValid","","Violation de contrainte d'unicité du Carré ".$this->__toString().": ".$case1->__toString()."=".$case2->__toString()."=".$sym1[0]);
$bRet=false;
}
}
}
}
}
return $bRet;
}
/**
* @desc Propage le fait qu'une case a été découverte
* @return CSuDoKuSquare
* @param mixed $symbole
* @param CSuDoKuCase $cCase
**/
public function propagate($symbole,CSuDoKuCase $cCase) {
$bOK=true;
foreach ($this->m_aCases as $cases) {
foreach ($cases as $case) {
if(!$case->isDone() and $case!==$cCase){
$case->delSymbols($symbole,true,$cCase->getObjectID());
if($case->isEmpty()) {
//$this->m_oDebug->addTrace(4,$this->getObjectID(),"CSuDoKuSquare","propagate","($symbole,$cCase)",$this->__toString().": ".$case->__toString()." est vide.");
$bOK=false;
}
}
}
}
//$bOK?//$this->m_oDebug->addTrace(4,$this->getObjectID(),"CSuDoKuSquare","propagate","($symbole,$absc,$ord)",$this->__toString().": propagation réussie.")://$this->m_oDebug->addTrace(4,$this->getObjectID(),"CSuDoKuSquare","propagate","($symbole,$absc,$ord)",$this->__toString().": propagation échouée.");
return $bOK;
}
/**
* @desc déPropage le fait qu'une case a été découverte
* @return CSuDoKuSquare
* @param CSuDoKuCase $cCase
**/
public function unpropagate(CSuDoKuCase $cCase) {
////$this->m_oDebug->addTrace(4,$this->getObjectID(),"CSuDoKuSquare","unpropagate","(".$cCase->__toString().")",$this->__toString().": dépropagation");
foreach ($this->m_aCases as $cases) {
foreach ($cases as $case) {
if($case!==$cCase){
if(!$case->isDone()) {!
$case->restaurer($cCase->getObjectID());
}
}
}
}
return $this;
}
}
/**
* @desc Classe CSuDoKuCase
*
*/
class CSuDoKuCase extends CObject {
protected $m_oDebug;
protected $m_iAbsc;
protected $m_iOrd;
protected $m_aSaveSymbols;
protected $m_aSymbols;
protected $m_aOSymbols;
protected $m_oSquare;
protected $m_oLine;
protected $m_oColumn;
protected $m_iNb;
protected $m_sType;
protected $m_bDone;
protected $m_sTest=null;
/**
* @desc Constructeur par défaut
* @return CSuDoKuCase
* @param int $i
* @param int $j
* @param int $nb
* @param string $type
**/
public function CSuDoKuCase($i,$j,$nb,$type) {
//$this->m_oDebug=CDebug::getInstance(false,true);
if(intval($i*10)==$i*10 and intval($j*10)==$j*10 ) {
//$this->m_oDebug->addTrace(7,$this->getObjectID(),"CSuDoKuCase","Constructor","($i,$j,$nb,$type)","$this");
$this->m_iAbsc=$i;
$this->m_iOrd=$j;
$this->m_iNb=$nb;
$this->m_bDone=false;
$this->m_aSaveSymbols=array();
switch($type) {
case 'numeric':
$this->m_sType='numeric';
$this->m_aSymbols=array();
for($i=1;$i<=$nb;$i++) {
$this->m_aSymbols[]=$i;
$this->m_aOSymbols[]=$i;
}
shuffle($this->m_aSymbols);
$this->sauvegarder(-1);
break;
case 'alpha':
$this->m_sType='alpha';
$this->m_aSymbols=array();
for($i=0;$i<$nb;$i++) {
$this->m_aSymbols[]=chr(65+$i);
$this->m_aOSymbols[]=chr(65+$i);
}
shuffle($this->m_aSymbols);
$this->sauvegarder(-1);
break;
default: echo "<hr>Fatal error: CSuDoKuCase(\$type) should be 'numeric' or 'alpha'.";
}
}
else echo "<hr>Fatal error: CSuDoKuCase(\$i, \$j, \$nb,\$type) shouldn't be empty or \$i and \$j should be integers and \$sym should be a CSuDoKuSymboles";
}
/**
* @desc Accesseur
* @return CSuDoKuCase
* @param CSuDoKuSquare $square
**/
public function square(CSuDoKuSquare $square) {
if($square instanceof CSuDoKuSquare ) {
//$this->m_oDebug->addTrace(7,$this->getObjectID(),"CSuDoKuCase","square","($square)","Association de la boîte (".$square->getAbsc().",".$square->getOrd().") à ".$this->__toString());
$this->m_oSquare=$square;
return $this;
}
else {
echo "<hr>\nCSuDoKuCase::square(\$square)::ERROR:: \$square should be an CSuDoKuSquare object";
return null;
}
}
/**
* @desc Accesseur
* @return CSuDoKuCase
* @param CSuDoKuLine $line
**/
public function line(CSuDoKuLine $line) {
if($line instanceof CSuDoKuLine) {
//$this->m_oDebug->addTrace(7,$this->getObjectID(),"CSuDoKuCase","line","($line)","Association de la ligne(".$line->getOrd().") à ".$this->__toString());
$this->m_oLine=$line;
return $this;
}
else {
echo "<hr>\nCSuDoKuCase::line(\$line)::ERROR:: \$line should be an CSuDoKuLine object";
return null;
}
}
/**
* @desc Accesseur
* @return CSuDoKuCase
* @param CSuDoKuColumn $column
**/
public function column(CSuDoKuColumn $column) {
if($column instanceof CSuDoKuColumn) {
//$this->m_oDebug->addTrace(7,$this->getObjectID(),"CSuDoKuCase","column","($column)","Association de la colonne (".$column->getAbsc().") à ".$this->__toString());
$this->m_oColumn=$column;
return $this;
}
else {
echo "<hr>\nCSuDoKuCase::column(\$column)::ERROR:: \$column should be an CSuDoKuColumn object";
return null;
}
}
/**
* @desc Accesseur
* @return int
* @param void
**/
public function getRelativeOrd() {
return $this->m_iOrd-sqrt($this->m_iNb)*$this->m_oSquare->getOrd();
}
/**
* @desc Accesseur
* @return int
* @param void
**/
public function getRelativeAbsc() {
return $this->m_iAbsc-sqrt($this->m_iNb)*$this->m_oSquare->getAbsc();
}
/**
* @desc Accesseur
* @return int
* @param void
**/
public function getOrd() {
return $this->m_iOrd;
}
/**
* @desc Accesseur
* @return int
* @param void
**/
public function getAbsc() {
return $this->m_iAbsc;
}
/**
* @desc Accesseur
* @return CSuDoKuLine
* @param void
**/
public function getLine() {
return $this->m_oLine;
}
/**
* @desc Accesseur
* @return CSuDoKuColumn
* @param void
**/
public function getColumn() {
return $this->m_oColumn;
}
/**
* @desc Accesseur
* @return CSuDoKuSquare
* @param void
**/
public function getSquare() {
return $this->m_oSquare;
}
/**
* @desc Renvoie string
* @return string
* @param void
**/
public function __toString() {
return "Case[".$this->getObjectID()."](".$this->m_iAbsc.",".$this->m_iOrd.")";
}
/**
* @desc Sauvegarde les symboles qui ont été modifié par la case dont l'id est $idCase
* @return bool
* @param int $idCase
**/
public function sauvegarder($idCase) {
if(!$this->isDone() and !$this->isEmpty()){
//$this->m_oDebug->addTrace(4,$this->getObjectID(),"CSuDoKuCase","sauvegarder","($idCase)",$this->__toString()."=> sauvegarde n°".$idCase.": (".join(", ",$this->m_aSymbols).")");
$this->m_aSaveSymbols[$idCase]=$this->m_aSymbols;
}
else {
if($this->isDone()) {
//$this->m_oDebug->addTrace(4,$this->getObjectID(),"CSuDoKuCase","sauvegarder","($idCase)",$this->__toString()."=> non sauvegarde car découverte");
}
else {
if($this->isEmpty()) {
//$this->m_oDebug->addTrace(4,$this->getObjectID(),"CSuDoKuCase","sauvegarder","($idCase)",$this->__toString()."=> non sauvegarde car vide");
}
}
}
}
/**
* @desc Restaure les symboles
* @return bool
* @param int $idCase
**/
public function restaurer($idCase) {
if(count($this->m_aSaveSymbols)>0) {
if(is_array($this->m_aSaveSymbols[$idCase])) {
//$this->m_oDebug->addTrace(4,$this->getObjectID(),"CSuDoKuCase","restaurer","($idCase)",$this->__toString()."=> restauration de la sauvegarde n°".$idCase.": (".join(", ",$this->m_aSaveSymbols[$idCase]).")");
$this->m_aSymbols=$this->m_aSaveSymbols[$idCase];
if(count($this->m_aSymbols)>1) $this->m_bDone=false;
if(count($this->m_aSaveSymbols)>1) unset($this->m_aSaveSymbols[$idCase]);
}
else {
//$this->m_oDebug->addTrace(4,$this->getObjectID(),"CSuDoKuCase","restaurer","($idCase)",$this->__toString()."=> La sauvegarde n°".$idCase." n'existe pas.");
}
}
else {
//$this->m_oDebug->addTrace(4,$this->getObjectID(),"CSuDoKuCase","restaurer","($idCase)",$this->__toString()."=> pas assez de sauvegarde disponible: ".count($this->m_aSaveSymbols));
}
}
/**
* @desc Attribue un symbole
* @return bool
* @param string $sym
**/
public function attribuer($sym){
if($this->setSymbols($sym,$this->getObjectID())) {
$this->m_bDone=true;
//$this->m_oDebug->addTrace(3,$this->getObjectID(),"CSuDoKuCase","attribuer","(".$sym.")",$this->__toString()."=> attribue $sym");
return $this->propagate();
}
else {
//$this->m_oDebug->addTrace(3,$this->getObjectID(),"CSuDoKuCase","attribuer","(".$sym.")",$this->__toString()."=> setSymbols($sym) a échoué");
$this->m_bDone=false;
return false;
}
}
/**
* @desc DesAttribue un symbole
* @return CSuDoKuCase
**/
public function desattribuer() {
//$this->m_oDebug->addTrace(3,$this->getObjectID(),"CSuDoKuCase","desattribuer","()",$this->__toString()."=> désattribue ");
$this->m_bDone=false;
$this->restaurer($this->getObjectID());
return $this->unpropagate();
}
/**
* @desc Accesseur
* @return CSuDoKuCase
* @param mixed $symboles
* @package int $idCase
**/
public function setSymbols($symboles,$idCase) {
$this->sauvegarder($idCase);
$bOK=1;
if(is_array($symboles)){
$symboles=array_unique($symboles);
if(count($this->m_aOSymbols)>=count($symboles) and count($symboles)>0) {
//$this->m_oDebug->addTrace(4,$this->getObjectID(),"CSuDoKuCase","setSymbols","(".$symboles.")",$this->__toString().": Modification de la liste des symboles.");
$a_enlever=array_diff($this->m_aSymbols,$symboles);
$a_ajouter=array_diff($symboles,$this->m_aSymbols);
if(count($a_enlever)) {
foreach ($a_enlever as $sym) {
$bOK=$bOK*$this->delSymbols($sym,false);
}
}
if(count($a_ajouter)) {
foreach ($a_ajouter as $sym) {
$bOK=$bOK*$this->addSymbols($sym,false);
}
}
}
else $bOK=0;
}
elseif(!is_array($symboles) and in_array($symboles,$this->m_aOSymbols)) {
////$this->m_oDebug->addTrace(4,$this->getObjectID(),"CSuDoKuCase","setSymbols","(".$symboles.")",$this->__toString().": isDone() => true, Symbole=$symboles.");
$this->m_aSymbols=array(0 => $symboles);
$bOK=1;
}
else {
//$this->m_oDebug->addTrace(4,$this->getObjectID(),"CSuDoKuCase","setSymbols","(".join(", ",$symboles).")",$this->__toString().": Le tableau est vide ou contient trop de symboles, ou ce symbole n'existe pas.");
$bOK=0;
}
return $bOK;
}
/**
* @desc Accesseur
* @return CSuDoKu
* @param mixed $symboles
* @param bool $bSave
* @param int $idCase
**/
public function addSymbols($symboles,$bSave,$idCase) {
if($bSave) $this->sauvegarder($idCase);
$bOK=1;
if(is_array($symboles)){
$symboles=array_unique($symboles);
if(count($symboles)>0) {
$a_ajouter=array_diff($symboles,$this->m_aSymbols);
if(count($a_ajouter)>0) {
foreach ($a_ajouter as $sym) {
$bOK=$bOK*$this->addSymbols($sym,false);
}
}
}
else $bOK=0;
}
elseif(!is_array($symboles) and in_array($symboles,$this->m_aSymbols)) {
//$this->m_oDebug->addTrace(7,$this->getObjectID(),"CSuDoKuCase","addSymbols","(".$symboles.")",$this->__toString().": Ce symbole existe déja.");
$bOK=0;
}
elseif(!is_array($symboles) and !in_array($symboles,$this->m_aSymbols) and in_array($symboles,$this->m_aOSymbols)) {
$this->m_aSymbols[]=$symboles;
//shuffle($this->m_aSymbols);
//$this->m_oDebug->addTrace(7,$this->getObjectID(),"CSuDoKuCase","addSymbols","(".$symboles.")",$this->__toString().": Ajout de $symboles:".join(", ",$this->m_aSymbols));
$bOK=1;
}
else {
//$this->m_oDebug->addTrace(7,$this->getObjectID(),"CSuDoKuCase","addSymbols","(".$symboles.")",$this->__toString().": Ce symbole en dehors de tous les cas.");
$bOK=0;
}
return $bOK;
}
/**
* @desc Accesseur
* @return CSuDoKu
* @param mixed $symboles
* @param bool $bSave
* @param int $idCase
**/
public function delSymbols($symboles,$bSave,$idCase) {
if($bSave) $this->sauvegarder($idCase);
$bOK=1;
if(is_array($symboles)) {
$symboles=array_unique($symboles);
if(count($symboles)>0) {
$a_enlever=array_diff($this->m_aSymbols,$symboles);
if(count($a_enlever)>0) {
foreach ($a_enlever as $sym) {
$bOK=$bOK*$this->delSymbols($sym,false);
}
}
}
else {
$bOK=0;
}
}
elseif(!is_array($symboles) and !in_array($symboles,$this->m_aSymbols)) {
//$this->m_oDebug->addTrace(7,$this->getObjectID(),"CSuDoKuCase","delSymbols","(".$symboles.")",$this->__toString().": Ce symbole n'existe déja plus.");
$bOK=0;
}
elseif(!is_array($symboles) and in_array($symboles,$this->m_aSymbols)) {
unset($this->m_aSymbols[array_search($symboles,$this->m_aSymbols)]);
//shuffle($this->m_aSymbols);
//$this->m_oDebug->addTrace(7,$this->getObjectID(),"CSuDoKuCase","delSymbols","(".$symboles.")",$this->__toString().": Suppression de $symboles:".join(", ",$this->m_aSymbols));
$bOK=1;
}
else {
//$this->m_oDebug->addTrace(7,$this->getObjectID(),"CSuDoKuCase","delSymbols","(".join(", ",$symboles).")",$this->__toString().": Ce symbole en dehors de tous les cas.");
$bOK=0;
}
return $bOK;
}
/**
* @desc Accesseur
* @return array
* @param int $i
**/
public function getOriginalSymbols($i=null) {
if(isset($i) and $i>=0 and $i<count($this->m_aOSymbols)) {
//$this->m_oDebug->addTrace(7,$this->getObjectID(),"CSuDoKuCase","getOriginalSymbols","($i)",$this->__toString().": Symbole #$i=".$this->m_aOSymbols[$i]);
return $this->m_aOSymbols[$i];
}
else {
//$this->m_oDebug->addTrace(7,$this->getObjectID(),"CSuDoKuCase","getOriginalSymbols","()",$this->__toString().": Symboles=".join(", ",$this->m_aOSymbols));
return $this->m_aOSymbols;
}
}
/**
* @desc Accesseur
* @return array
* @param int $i
**/
public function getSymbols($i=null) {
if(isset($i) and $i>=0 and $i<count($this->m_aSymbols)) {
//$this->m_oDebug->addTrace(7,$this->getObjectID(),"CSuDoKuCase","getSymbols","($i)",$this->__toString().": Symbole #$i=".$this->m_aSymbols[$i]);
return $this->m_aSymbols[$i];
}
else {
//$this->m_oDebug->addTrace(7,$this->getObjectID(),"CSuDoKuCase","getSymbols","()",$this->__toString().": Symboles=".join(", ",$this->m_aSymbols));
return $this->m_aSymbols;
}
}
/**
* @desc Accesseur
* @return bool
* @param void
**/
public function isDone() {
if($this->m_bDone) {
//$this->m_oDebug->addTrace(7,$this->getObjectID(),"CSuDoKuCase","isDone","()",$this->__toString().": true");
return true;
}
else {
//$this->m_oDebug->addTrace(7,$this->getObjectID(),"CSuDoKuCase","isDone","()",$this->__toString().": false");
return false;
}
}
/**
* @desc Accesseur
* @return bool
* @param void
**/
public function isEmpty() {
if(count($this->m_aSymbols)<=0) {
//$this->m_oDebug->addTrace(7,$this->getObjectID(),"CSuDoKuCase","isEmpty","()",$this->__toString().": true");
return true;
}
else {
//$this->m_oDebug->addTrace(7,$this->getObjectID(),"CSuDoKuCase","isEmpty","()",$this->__toString().": false");
return false;
}
}
/**
* @desc Remet à zero.
* Si $shuffle est à vrai, génére une nouvelle série aléatoire (par défaut)
* Si $shuffle est à faux, conserve l'ordre des symboles généré précdemment.
* @return CSuDoKuCase
* @param bool $shuffle = true
**/
public function reSet($shuffle=true) {
//$this->m_oDebug->addTrace(4,$this->getObjectID(),"CSuDoKuCase","reSet","($shuffle)",$this->__toString().": réinitialisation");
$this->restaurer(-1);
unset($this->m_aSaveSymbols);
if($shuffle) shuffle($this->m_aSymbols);
$this->sauvegarder(-1);
return $this;
}
/**
* @desc Propage le fait que la case a été découverte
* @return bool
* @param
**/
public function propagate() {
if($this->m_oColumn->propagate($this->m_aSymbols[0],$this)){
////$this->m_oDebug->addTrace(4,$this->getObjectID(),"CSuDoKuCase","propagate","()",$this->__toString().": propagation de la colonne réussie");
if($this->m_oLine->propagate($this->m_aSymbols[0],$this)) {
////$this->m_oDebug->addTrace(4,$this->getObjectID(),"CSuDoKuCase","propagate","()",$this->__toString().": propagation de la ligne réussie");
if($this->m_oSquare->propagate($this->m_aSymbols[0],$this)) {
////$this->m_oDebug->addTrace(4,$this->getObjectID(),"CSuDoKuCase","propagate","()",$this->__toString().": propagation de la boîte réussie");
return true;
}
else {
////$this->m_oDebug->addTrace(4,$this->getObjectID(),"CSuDoKuCase","propagate","()",$this->__toString().": propagation de la boîte échouée");
//$this->m_oSquare->unpropagate($this->getAbsc(),$this->getOrd());
return false;
}
}
else {
////$this->m_oDebug->addTrace(4,$this->getObjectID(),"CSuDoKuCase","propagate","()",$this->__toString().": propagation de la ligne échouée");
//$this->m_oLine->unpropagate($this->getAbsc(),$this->getOrd());
return false;
}
}
else {
////$this->m_oDebug->addTrace(4,$this->getObjectID(),"CSuDoKuCase","propagate","()",$this->__toString().": propagation de la colonne échouée");
//$this->m_oColumn->unpropagate($this->getAbsc(),$this->getOrd());
return false;
}
}
/**
* @desc déPropage le fait que la case a été découverte
* @return CSudoKuCase
* @param
**/
public function unpropagate() {
//$this->m_oDebug->addTrace(4,$this->getObjectID(),"CSuDoKuCase","unpropagate","()",$this->__toString().": dépropagation");
$this->m_oColumn->unpropagate($this);
$this->m_oLine->unpropagate($this);
$this->m_oSquare->unpropagate($this);
return $this;
}
/**
* @desc Renvoie le symbole temporaire du joueur
* @return string
* @param
**/
public function getTest() {
return $this->m_sTest;
}
/**
* @desc Permet de sauvegarder le choix temporaire du joueur
* @return CSudoKuCase
* @param string $sym
**/
public function test($sym) {
if(in_array($sym,$this->m_aOSymbols)){
$this->m_sTest=$sym;
return $this;
}
else return null;
}
/**
* @desc Permet d'effacer la sauvegarde du choix temporaire du joueur
* @return CSudoKuCase
* @param
**/
public function untest() {
$this->m_sTest=null;
return $this;
}
}
Conclusion
Si vous souhaitez le voir en fonctionnement rendez vous sur http://nifhell.free.fr. Le seul bug connu à ce jour, est que les Sudoku générés ne sont pas forcément à solution unique.
Fichier Zip
Pour les "Membres Club", vous pouvez télécharger directement un fichier contenu dans le zip sans télécharger le zip en entier !
Télécharger le zip
Historique
- 19 avril 2006 22:30:54 :
- Rajout de la liste des fonctionnalites disponibles.
- 20 avril 2006 19:33:17 :
- Rajout du ZIP
- 20 avril 2006 19:38:06 :
- Mise à jour du ZIP ;p
- 23 avril 2006 10:30:13 :
- Correction Titre + Catégorie
- 29 août 2006 13:24:22 :
- Correction de la fonction magique "__toString()" qui faisait référence à une fonction inconnue
Sources du même auteur
Sources de la même categorie
Sources en rapport avec celle ci
Commentaires et avis
Discussions en rapport avec ce code source dans le forum
differnec entre php 4 et php5 [ par hardelgylls ]
Bonjourpetite question :j'ai passer un oral et l'examinateur m'a demandé quel était la différence entre php4 et php5. et la gros blanc, est ce que qqu
Doc PHP5 sniff sniff [ par slhuilli ]
Bonjour, Bonsoir,Je suis a la recherche d'un PDF qui recenserait les mots-clefs + explications (bref un bouquin complet) sur PHP 5 qui parait-il est
Algorithme de tri ... [ par LocalStone ]
Salut à tous ! Il y a peut-être 1 mois et demi, j'ai lu un article - ou plutôt un tutorial - sur comment mettre en place un algorithme de tri automati
Class POO retourné le nom de l'objet [ par MeTh ]
Bonjour,Comment retourné le nom de l'objet déclaré?exemple :$monobjet = new GridR();comment recuperé $monobjet dans ma class?Merci
Pb passage PHP4 -> PHP5 [ par Galmiza ]
Salut,J'ai acheté un bouquin pour débuter le PHP.J'ai suivi a la lettre les instructions du livre:-installer EasyPHP 1.7-installer PHP 5.0..-lancer Ea
Cohabitation PHP4 PHP5 sur même serveur ! [ par Zacland ]
Ce n'est pas une question, mais je me doute que certaines personnes veulent essayer de faire cohabiter 2 versions de PHP sur un même serveur Apache...
Un caractére se trouve t'il dans ma chaîne... [ par juki_webmaster ]
Bonsoir,Je travaille depuis 14h cette apres-midi sur une fonction alternative d'une fonction connu et disponible uniquement sur php5, je fait cette fo
PHP5 en PHP3 [ par el shaddai ]
J'ai développé une partie de site en PHP5. MAlheureusement , chargé chez FREE, ils n'utilisent que PHP3. Y a t-il une manip simple pour qur du PHP5 pa
PHP5 et MySQL 4.1.7 [ par TMT ]
J'ai installé PHP5 et MySQL sur mon Windows XP avec IIS. J'ai bien activé le module php_mysql dans le fichier php.ini Là mon problème est qu-à chaque
php4 vers php5 [ par aurelielaugraud ]
Bonjour, Je suis passée de php4 à php5 pour utiliser la librairie graphique GD. Seulement, un programme que j'avais précédemment faire refuse de fonct
|
Téléchargements
Logiciels à télécharger sur le même thème :
Comparez les prix Nouvelle version
|