SEclone basic classes for tagging

CHAIN  table of identified chains



The “class” TCHAIN plays a key role in the process.

Basically, it stores during a cycle necessary parameters to do eliminations if finally the chain is valid in the process.


The design is made to resist to future steps (I hope so).


Each candidate to eliminate is a CHAIN_POINT


class CHAIN_POINT  // storing single candidate in ch mode

{publicchar ch,i8;

inline void Set(USHORT i8e,USHORT che) {ch=(char)che;i8=(char)i8e;}

}; //just to avoid warnings at compilation time


Only chains having the lowest seen rating are stored.

An elementary CHAIN has  the following description and functions

Note that room has been kept for up to 30 elimination.

This is enough to avoid looking for double count and to have an efficient process.

We accept to loose some eliminations in the process.

Out of the table of eliminations, the CHAIN  contains a milestone to locate the source in test mode.



class CHAIN   //defining a chain and elimination in one buffer


CHAIN_POINT cp[30]; // buffer eliminations (limited to 30)

USHORT ncp,         //number of candidates to clean

       urem;        // milestone of the explanation


inline void Set(){urem=jdk.couprem; ncp=0;}


inline void Add(USHORT ig,USHORT ch)     {if(ncp<30) cp[ncp++].Set(ig,ch);}


int Clean() // clear candidates

     {if(o$.ot){E$.E("clean for UREM=");E$.Enl(urem);}

         int ir=0;

      for(int i=0;i<ncp;i++)    ir+= T81t[cp[i].i8].Change(cp[i].ch);

      return ir;}


void PrintElims()

     {E$.E("chain elims ncp=");E$.E(ncp);E$.Esp();

      for(int i=0;i<ncp;i++)








The table   TCHAIN  is basically a storing capacity of 20 CHAIN and the management of the rating.

It uses the scaling table steps giving the adjustment to the basic rating.


Each time the Chaine() function finds a lower rating, storing index “ichain” is reset to 0.


rating is the current rating for the table.

maxlength  is an important data. It is used to limit the search of a path.

           This filter is working in tag mode, equivalent to about length/2 in SE process

           It must be set to the appropriate value when we are looking for a single path

           The limit is

                      given by SetMaxLength()  at the start of a step

                      Adjusted is necessary when rating is changed in Chaine()

base  is the rating base of the current step


After a chain has been successfully entered, the calling sequence must Add() eliminations.

PrintEliminations() is just for tests.


Next important routines are :

IsOK() asking whether the process can be stopped

Clean() to do eliminations for all stored chains

             At least one elimination must be effective to avoid a looping process.

             This should be true if the code is ok.



USHORT  steps[] = {4, 6, 8, 12, 16, 24, 32, 48, 64, 96, 128,

            192, 256, 384, 512, 768, 1024, 1536, 2048, 3072, 4096, 6144, 8192};





class TCHAIN // storing up to 20 chains having the same "lowest"rating


 USHORT rating,             // current rating

           maxlength;          // filter for the search of a path (tags)

 CHAIN chainw,chains[20]; // enough to store several small loops

 USHORT ichain,base;


 void Init() {rating=200;ichain=0;maxlength=10;}


 void SetMaxLength( int bw)  //


          if(bw>=70  || bw<rating) maxlength=12; // same as no limit

        if(bw==rating ) maxlength=4; // equivalent to loop length 6

              int ii=rating - bw; maxlength=steps[ii]/2+1;}


 int Chaine(USHORT lengthe,USHORT tag=0)

        { if(lengthe<2) return 0; // should not happen

                USHORT wrating=300,length=lengthe-2;

          for(int i=0;i<22;i++)

                if(length<= steps[i]) {wrating=base+i; break;}


           {E$.E("tchain entree length=");E$.E(lengthe);E$.E(" base=");E$.E(base);

                  E$.E(" wrating=");E$.Enl(wrating);}

          if(wrating>rating) return 0;

              if(wrating<rating)    {ichain=0;  rating=wrating;}

              if(ichain>19) return 0; //tell back it's not taken


                if(base<=75) maxlength=steps[ichain]/2+1;

          return 1;}


inline void AddLast(USHORT ig,USHORT ch)

         {if(ichain) // should not happen



void Add_Print(ZINFL z,USHORT ch)

       {if(!ichain) return; // should never happen

            for (int i=0;i<81;i++) if (z.On(i))chains[ichain-1].Add(i,ch);



inline int IsOK(USHORT x){ return ((rating <= x ) || (rating <= o$.ermax));}


int Clean()  // clear all pending candidates

      {int ir=0; for(int i=0;i<ichain;i++) ir+=chains[i].Clean();

        return ir;}


 void Status()

     {E$.E("tchain ichain=");E$.E(ichain);E$.E(" rating=");E$.Enl(rating);



 void PrintElims() {chains[ichain-1].PrintElims();}


 }tchain ;



IPT  direct index for candidates and managing groups



The “class” IPT was designed in my solver mainly for “groups” management.

I keep it in SE clone for 2 main reasons:


It provides a direct index “candidate”  -> “ table of candidate “to speed up the process.

We need a “group” equivalence for future steps (NISHIO for example)

The main index ic;ig has room for 81 cells and 54 row/box or column/box groups.

     The “9*” is for the digits.

Some functions as QuasiJumeaux() are kept for future steps


class IPT


USHORT ic[9*81],  // chiffres 81 cases

       ig[9*54],  // 2*3*9 + tronqués 2 par boite


UCHAR  bolc[18][3];// indice boite sur vecteur 54

IPT(){for(int i=0;i<9;i++)for(int j=0;j<3;j++)

            { bolc[i][j]=(UCHAR)( 3*(3*(i/3)+j)+(i%3));

           bolc[i+9][j]=(UCHAR)(27 +(3*(3*(i%3)+j) + (i/3))); }  }


void Initp() {for (int i=0;i<9*81;i++)ic[i]=0;icm=igm=0 ;

              for (int i=0;i<9*54;i++)ig[i]=0;}

void Init(){Initp();      GenPcand();}

void setc(UCHAR c,UCHAR p,USHORT ip) {ic[81*c+p]= ip;}

void GenPcand();

void GenPgroupes();

inline USHORT GetPoint(USHORT i8,USHORT ch){return ic[81*ch+i8];}


void GLI(USHORT cch,int j,ZINFL &zch,USHORT * igch);

void GenLiensIsoles();

void GenLiensIsolesG();

void QuasiJumeaux();

void QuasiJumeauxCh(USHORT cch);




void IPT::GenPcand()

{for (UCHAR i=0;i<81;i++)

{if(T81t[i].v.ncand<2) continue; CB9CH chs=T81t[i].v.cand; //if(!chs.f) continue;

 for(UCHAR j=0;j<9;j++) if(chs.On(j))

  {zpln.zp[0].Charge(i,j);icm=zpln.Charge0();iptl.setc(j,i,icm);  }







void IPT::GenPgroupes()

{for (USHORT cch=0;cch<9;cch++)    // on applique grilles chiffres aux groupes

  { ZINFL * zz=&zgs.z[81];     for(int j=0;j<54;j++)

   {ZINFL zw=zz[j] & jdk.c[cch];    if(zw.NonNul())

      { int ix=zgs.Charge(zw);

        if(ix<81) ig[cch*54+j]=ic[cch*81+ix];

         else ig[cch*54+j]= zpln.Chargexx(ix,cch); // un vrai groupe

      }  //end non nul

    }     // end j

 } //end cch






//-----   uniquement sur points  si tout=FALSE

void IPT::GenLiensIsoles( )

{for(int ie=0;ie<27;ie++)   // on balaye tous éléments positions

 {int i;

  for(i=0;i<9;i++)  //les points

   {int i81= divf.el81[ie][i];  P81 *p=&T81t[i81];


    for(USHORT k=0;k<9;k++)

    {int j=k*81+i81; if(ic[j])

     {ZINFL z1= zgs.z[zpln.zp[ic[j]].ig],z2=jdk.elza81[ie] & jdk.c[k];

      z2=z2^z1; USHORT igc=zgs.Charge(z2),ipp=zpln.Chargexx((int)igc,k);


     }  } //end if k


 }//end i ie  proc

//-----   uniquement sur points  si tout=FALSE

void IPT::GLI(USHORT cch,int j,ZINFL &zch,USHORT * igch)

{USHORT iw= igch[j]; if(iw)

  {ZINFL zcr= zgs.z[zpln.zp[iw].ig] ^ zch;


   {USHORT iw2=zpln.Charge(cch,zcr);zl.Charge(iw,iw2); }} }


void IPT::GenLiensIsolesG( )

{for(int ie=0;ie<27;ie++)   // on balaye tous éléments positions

 {int i;   for (USHORT cch=0;cch<9;cch++)

    {USHORT * igch=&ig[cch*54];  ZINFL zch= jdk.elza81[ie] & jdk.c[cch];


      {int ib=ie-18;;   if(ie<18)  GLI(cch,3*ie+i,zch,igch);

       else  { GLI(cch,bolc[ib][i],zch,igch); GLI(cch,bolc[ib+9][i],zch,igch); }

      }} // end i cch

 }}//end  ie  proc






void IPT::QuasiJumeaux()

{ for (USHORT cch=0;cch<9;cch++)QuasiJumeauxCh( cch);  }

void IPT::QuasiJumeauxCh(USHORT cch)

{USHORT * igch=&ig[cch*54];

  for (int i=0;i<18;i++)      // ligne colonne  2 groupes un isolé maxi

     {  int ng=0,nc=0,p[3],ij=3*i,ijl=ij+3;

       for(int  j=ij;j<ijl;j++)

          { int iw= igch[j];  if(iw) { p[ng++]=iw ;  if(iw<=icm) nc++ ;  }  }

            if( (ng==2) && (nc<2)) zl.Charge(p[0],p[1]);

        if(ng>2 && niveau) // alors on charge "isoles" étendu à niveau 1 pour effet lmem

          for (int j=0;j<3;j++) if(p[j]>=icm) // sauf point deja fait


         } // end ligne colonne

   for (int ib=0;ib<9;ib++)         //______________ boite

  {   int i,nbgl=0,pgsl[3],nbgc=0 ,pgsc[3],

           nbnjl=0,pgnjsl[3],nbnjc=0,pgnjsc[3]; // groupes et jumeaux

       // on veut  deux groupes  lignes ,   colonnes , ligne/colonne

     for( i=0;i<3;i++)  // on cherche  ligne  colonne

       {int iw= igch[bolc[ib][i]]; if(iw>icm)  pgnjsl[nbnjl++]=iw ;

         if(iw) pgsl[nbgl++]=iw ;    //ligne

         iw= igch[bolc[ib+9][i]]; if(iw>icm) pgnjsc[nbnjc++]=iw ;

         if(iw)pgsc[nbgc++]=iw ; }    //colonne



     if((nbnjl-1) ||(nbnjc-1))  continue;   //  maintenant lignecolonne : commun?

     ZINFL z1=zgs.z[zpln.zp[pgnjsl[0]].ig], z2=zgs.z[zpln.zp[pgnjsc[0]].ig],


     if(!(z4==z5)) continue;    //toute la boite

     if(!z3.NonNul()) zl.Charge(pgnjsl[0],pgnjsc[0]);




 }  // end for  boite boite