private void EmptyRectangle_SolResult(int no, int bx, UCellLink PLK, UCell PElm) { int noB = (1 << no); SolCode = 2; Result = $"EmptyRectangl #{(no+1)} in b{(bx+1)}"; PElm.CancelB = noB; //Cancellation Digit Setting if (!SolInfoB) { return; } ResultLong = "EmptyRectangl"; PLK.UCe1.SetNoBBgColor(noB, AttCr, SolBkCr2); //Mark Strong Links PLK.UCe2.SetNoBBgColor(noB, AttCr, SolBkCr2); //Mark Strong Links string st = ""; foreach (var Q in pBDL.IEGetCellInHouse(bx + 18, noB)) { Q.SetNoBBgColor(noB, AttCr, SolBkCr); //Empty Rectangle st += " " + Q.rc.ToRCString(); } string msg = $"\r digit: #{(no+1)}\r ER: B{(bx+1)}({st.ToString_SameHouseComp()})"; msg += $"\r S-Link: {PLK.rc1.ToRCString()}-{PLK.rc2.ToRCString()}"; msg += $"\rEliminatedCell: {PElm.rc.ToRCString()}"; ResultLong = "EmptyRectangl" + msg; }
public bool Check_CellCellSequence(UCellLink LKpre, UCellLink LKnxt) { int noP = LKpre.no, noN = LKnxt.no; UCell UCX = LKpre.UCe2; switch (LKpre.type) { case 1: switch (LKnxt.type) { case 1: return(noP != noN); //S->S case 2: return(noP == noN); //S->W } break; case 2: switch (LKnxt.type) { case 1: return(noP == noN); //W->S case 2: return((noP != noN) && (UCX.FreeBC == 2)); //W->W } break; } return(false); }
public GroupedLink(UCellLink LK) : this() { UCelLK = LK; UGCellsA = new UGrCells(LK.tfx, LK.no, LK.UCe1); UGCellsB = new UGrCells(LK.tfx, LK.no, LK.UCe2); this.type = LK.type; this.tfx = LK.tfx; FreeB = UGCellsA.Aggregate(0, (Q, P) => Q | P.FreeB); FreeB = UGCellsB.Aggregate(FreeB, (Q, P) => Q | P.FreeB); }
private bool _NL_Search(UCellLink LK0, UCellLink LKpre, Stack <UCellLink> SolStack, Bit81 UsedCells, int szCtrl) { if (szCtrl <= 0) { return(false); } foreach (var LKnxt in CeLKMan.IEGet_CeCeSeq(LKpre)) //links that satisfy concatenation conditions { int rc2Nxt = LKnxt.rc2; if (UsedCells.IsHit(rc2Nxt)) { continue; //UsedCells does not include Origin Cell } { //===== Chain Search ===== SolStack.Push(LKnxt); //___Debug_Print_NLChain(SolStack); if (rc2Nxt == LK0.rc1 && szCtrl == 1) { if (SolStack.Count > 2) //Loop was formed (the next cell matches the Origin Cell) { int SolType = _NL_CheckSolution(LK0, LKnxt, SolStack, UsedCells); //Solved? if (SolType > 0) { if (SolInfoB) { _NL_SolResult(LK0, LKnxt, SolStack, SolType); } if (__SimpleAnalizerB__) { return(true); } if (!pAnMan.SnapSaveGP(false)) { return(true); } } } } else { Bit81 UsedCellsNxt = UsedCells | (new Bit81(rc2Nxt)); //Create a new bit representation of used cell _NL_Search(LK0, LKnxt, SolStack, UsedCellsNxt, szCtrl - 1); //Next step Search(recursive call if (SolCode > 0) { return(true); } } SolStack.Pop(); //Failure(Cancel link extension processing) } //----------------------------- } return(false); }
public void SetLinkList(int tfx, int type, int no, UCell UC1, UCell UC2, bool SFlag = false) { var LK = new UCellLink(tfx, type, no, UC1, UC2, SFlag); int rc1 = UC1.rc; if (CeLK81[rc1] == null) { CeLK81[rc1] = new List <UCellLink>(); } if (!CeLK81[rc1].Contains(LK)) { CeLK81[rc1].Add(LK); } }
public bool Check_SuperLinkSequence(GroupedLink GLKpre, GroupedLink GLKnxt) { if (GLKpre == null) { WriteLine("null"); } int typP = GLKpre.type; if (GLKpre is ALSLink) { typP = S; } int noP = GLKpre.no2; int typN = GLKnxt.type; int noN = GLKnxt.no; UCellLink LKpre = GLKpre.UCelLK; UCellLink LKnxt = GLKnxt.UCelLK; int FreeBC = 0; if (LKpre != null) { FreeBC = pBDL[LKpre.rc2].FreeBC; if (LKnxt != null) //singleLink -> singleLink { return(_Check_SWSequenceSub(typP, noP, LKnxt.type, noN, FreeBC)); } else //singleLink -> multiLink { UGrCells UGrCs = GLKnxt.UGCellsA; if (UGrCs.Count == 1) //singleCell -> singleCell { return(_Check_SWSequenceSub(typP, noP, typN, noN, FreeBC)); } } } else if (GLKpre.UGCellsB.Count == 1 && LKnxt != null) // multiLink -> singleLink { FreeBC = GLKpre.UGCellsB.FreeB.BitCount(); return(_Check_SWSequenceSub(typP, noP, typN, noN, FreeBC)); } FreeBC = GLKpre.UGCellsB.FreeB.BitCount(); return(_Check_SWSequenceSub(typP, noP, typN, noN, FreeBC)); }
private void _NL_SolResult(UCellLink LK0, UCellLink LKnxt, Stack <UCellLink> SolStack, int SolType) { string st = ""; List <UCellLink> SolLst = SolStack.ToList(); SolLst.Reverse(); SolLst.Add(LK0); foreach (var LK in SolLst) { int noB = (1 << LK.no); UCell P1 = pBDL[LK.rc1], P2 = pBDL[LK.rc2]; P2.SetCellBgColor(SolBkCr); if (LK.type == S) { P1.SetNoBColor(noB, AttCr); P2.SetNoBColor(noB, AttCr3); } else { P2.SetNoBColor(noB, AttCr); P1.SetNoBColor(noB, AttCr3); } } if (SolType == 1) { st = "Nice Loop(Continuous)"; //continuous } else //discontinuous { st = $"Nice Loop(Discontinuous) r{(LK0.rc1/9+1)}c{(LK0.rc1%9+1)}"; int dcTyp = LK0.type * 10 + LKnxt.type; switch (dcTyp) { case 11: st += $" is {(LK0.no+1)}"; break; //S->S case 12: st += $" is not {(LKnxt.no+1)}"; break; //S->W case 21: st += $" is not {(LK0.no+1)}"; break; //W->S case 22: st += $" is not {(LK0.no+1)}"; break; //W->W } } Result = st; ResultLong = st + "\r" + _ToRCSequenceString(SolStack); }
public IEnumerable <UCellLink> IEGet_CeCeSeq(UCellLink LKpre) { var P = CeLK81[LKpre.rc2]; if (P == null) { yield break; } foreach (var LKnxt in P) { if (Check_CellCellSequence(LKpre, LKnxt)) { yield return(LKnxt); } } yield break; }
public override bool Equals(object obj) { UCellLink Q = obj as UCellLink; if (Q == null) { return(true); } if (this.type != Q.type || this.no != Q.no) { return(false); } if (this.rc1 != Q.rc1 || this.rc2 != Q.rc2) { return(false); } return(true); }
public GroupedLink(UCell UC, int no1, int no2, int type, bool rootF = false) : this() { this.rootF = rootF; int F = (1 << no1) | (1 << no2); // if( no1==no2 || (UC.FreeB&(1<<no1))==0 || (UC.FreeB&(1<<no2))==0 ){ if ((UC.FreeB & (1 << no1)) == 0 || (UC.FreeB & (1 << no2)) == 0) { UGCellsA = UGCellsB = null; return; } UGCellsA = new UGrCells(-1, no1, UC); UGCellsB = new UGrCells(-1, no2, UC); UCelLK = null; this.type = (UC.FreeBC == 2)? type: 2; //2:WeakLink FreeB = UGCellsA.Aggregate(0, (Q, P) => Q | P.FreeB); FreeB = UGCellsB.Aggregate(FreeB, (Q, P) => Q | P.FreeB); }
public int CompareTo(object obj) { UCellLink Q = obj as UCellLink; if (this.type != Q.type) { return(this.type - Q.type); } if (this.no != Q.no) { return(this.no - Q.no); } if (this.rc1 != Q.rc1) { return(this.rc1 - Q.rc1); } if (this.rc2 != Q.rc2) { return(this.rc2 - Q.rc2); } return(this.ID - Q.ID); }
private string _ToRCSequenceString(Stack <UCellLink> SolStack) { if (SolStack.Count == 0) { return("[rc]:-"); } List <UCellLink> SolLst = SolStack.ToList(); SolLst.Reverse(); UCellLink LK0 = SolLst[0]; UCell P0 = pBDL[LK0.rc1]; string po = $"[rc]:[{(P0.rc/9*10+(P0.rc%9)+11)}]"; foreach (var LK in SolLst) { UCell P1 = pBDL[LK.rc2]; string mk = (LK.type == 1)? "=": "-"; po += mk + (LK.no + 1) + mk + $"[{(P1.rc/9*10+(P1.rc%9)+11)}]"; } return(po); }
//Skyscraper is an algorithm consisting of two StrongLinks. //http://csdenpe.web.fc2.com/page40.html public bool Skyscraper() { Prepare(); CeLKMan.PrepareCellLink(1); //Generate StrongLink for (int no = 0; no < 9; no++) { int noB = (1 << no); var SSLst = CeLKMan.IEGetNoType(no, 1).ToList(); //select only StrongLink of #no if (SSLst.Count <= 2) { continue; } var prm = new Permutation(SSLst.Count, 2); int nxtX = 99; while (prm.Successor(nxtX)) { UCellLink UCLa = SSLst[prm.Index[0]], UCLb = SSLst[prm.Index[1]]; nxtX = 1; if (UCLa.ID > UCLb.ID) { nxtX = 0; continue; } //next permutation data skip_generation(nxtX=0) if ((UCLa.B81 | UCLb.B81).Count != 4) { continue; //All cells are different? } Bit81 ConA1 = ConnectedCells[UCLa.rc1]; //ConA1:cell group related to cell rc1 if (!ConA1.IsHit(UCLb.rc1) || ConA1.IsHit(UCLb.rc2)) { continue; } Bit81 ConA2 = ConnectedCells[UCLa.rc2]; //ConA2:cell group related to cell rc1 if (ConA2.IsHit(UCLb.rc1) || ConA2.IsHit(UCLb.rc2)) { continue; } //Only UCLa.rc1 and UCLb.rc1 belong to the same house. Bit81 ELM = ConA2 & ConnectedCells[UCLb.rc2]; ELM -= (ConA1 | ConnectedCells[UCLb.rc1]); //ELM:eliminatable cells bool SSfound = false; foreach (UCell P in ELM.IEGetUCeNoB(pBDL, noB)) { P.CancelB = P.FreeB & noB; SSfound = true; } if (!SSfound) { continue; //Skyscraper found } #region Result SolCode = 2; if (SolInfoB) { pBDL[UCLa.rc1].SetNoBBgColor(noB, AttCr, SolBkCr); pBDL[UCLa.rc2].SetNoBBgColor(noB, AttCr, SolBkCr); pBDL[UCLb.rc1].SetNoBBgColor(noB, AttCr, SolBkCr); pBDL[UCLb.rc2].SetNoBBgColor(noB, AttCr, SolBkCr); string msg = "\r", msg2 = ""; msg += $" on {(no+1)} in {UCLa.rc1.ToRCNCLString()} {UCLb.rc1.ToRCNCLString()}"; msg += $"\r connected by {UCLa.rc2.ToRCNCLString()} {UCLb.rc2.ToRCNCLString()}"; msg += "\r eliminated "; foreach (UCell P in ELM.IEGetUCeNoB(pBDL, noB)) { msg2 += " " + P.rc.ToRCString(); } msg2 += " " + msg2.ToString_SameHouseComp(); ResultLong = "Skyscraper" + msg + msg2; Result = $"Skyscraper #{(no+1)} in {msg2}"; } else { Result = $"Skyscraper #{(no+1)}"; } #endregion Result if (__SimpleAnalizerB__) { return(true); } if (!pAnMan.SnapSaveGP(true)) { return(true); } } } return(false); }
public UCellLink Reverse() { UCellLink ULK = new UCellLink(tfx, type, no, UCe2, UCe1, SFlag); return(ULK); }
//XYwing is an algorithm that consists of two WeakLinks with common cells. //http://csdenpe.web.fc2.com/page42.html public bool XYwing( ) { Prepare(); CeLKMan.PrepareCellLink(2); //Generate WeakLinks if (BVCellLst == null) { BVCellLst = pBDL.FindAll(p => (p.FreeBC == 2)); //Generate BVs(BV:bivalue). } if (BVCellLst.Count < 3) { return(false); } bool XYwing = false; foreach (var P0 in BVCellLst) //Choose one BV_Cell(=>PS) { List <UCellLink> BVLKLst = CeLKMan.IEGetRcNoBTypB(P0.rc, 0x1FF, 2).Where(R => R.BVFlag).ToList(); //Extract WeakLinks starting from P0 //foreach( var P in BVLKLst ) WriteLine(P); if (BVLKLst.Count < 2) { continue; } var cmb = new Combination(BVLKLst.Count, 2); int nxt = 1; while (cmb.Successor(nxt)) //Combine two WLinks from BVLKLst { UCellLink LKA = BVLKLst[cmb.Index[0]], LKB = BVLKLst[cmb.Index[1]]; //( UCell Q = LKA.UCe2, R = LKB.UCe2; if (Q.rc == R.rc || LKA.no == LKB.no) { continue; //Two WLinks have different end and different digits } Bit81 Q81 = ConnectedCells[LKA.rc2] & ConnectedCells[LKB.rc2]; if (Q81.Count <= 0) { continue; //Two WLinks have cells connected indirectly } int noB = Q.FreeB.DifSet(1 << LKA.no) & R.FreeB.DifSet(1 << LKB.no); if (noB == 0) { continue; //Two WLinks have common digit(=>no). } int no = noB.BitToNum(); string msg2 = ""; foreach (var A in Q81.IEGetUCeNoB(pBDL, noB)) { if (A == P0 || A == Q || A == R) { continue; } A.CancelB = noB; XYwing = true; //cell(A)/digit(no) can be excluded if (SolInfoB) { msg2 += $" {A.rc.ToRCNCLString()}(#{no+1})"; } } if (XYwing) { SolCode = 2; P0.SetNoBColor(P0.FreeB, AttCr); P0.SetCellBgColor(SolBkCr); Q.SetCellBgColor(SolBkCr); R.SetCellBgColor(SolBkCr); string msg0 = $" Pivot: {_XYwingResSub(P0)}"; string msg1 = $" Pin: {_XYwingResSub(R)} ,{_XYwingResSub(Q)}"; Result = "XY Wing" + msg0; if (SolInfoB) { ResultLong = $"XY Wing\r {msg0}\r {msg1}\r Eliminated:{msg2}"; } if (__SimpleAnalizerB__) { return(true); } if (!pAnMan.SnapSaveGP()) { return(true); } XYwing = false; } } } return(false); }
private int _NL_CheckSolution(UCellLink LK0, UCellLink LKnxt, Stack <UCellLink> SolStack, Bit81 UsedCells) { bool SolFound = false; int SolType = CeLKMan.Check_CellCellSequence(LKnxt, LK0)? 1: 2; //1:Continuous 2:DisContinuous if (SolType == 1) //===== continuous ===== //=== Change WeakLink to StrongLink { List <UCellLink> SolLst = SolStack.ToList(); Bit81 UsedCellsT = UsedCells | (new Bit81(LK0.rc1)); foreach (var L in SolLst) { int noB = 1 << L.no; foreach (var P in pBDL.IEGetCellInHouse(L.tfx, noB)) { if (UsedCellsT.IsHit(P.rc)) { continue; } P.CancelB |= noB; SolFound = true; } } //=== S-S (There are no other numbers) SolLst.Reverse(); SolLst.Add(LK0); var LKpre = SolLst[0]; foreach (var LK in SolLst.Skip(1)) { if (LKpre.type == 1 && LK.type == 1) //S-S { UCell P = pBDL[LK.rc1]; int noB = P.FreeB.DifSet((1 << LKpre.no) | (1 << LK.no)); if (noB > 0) { P.CancelB = noB; SolFound = true; } } LKpre = LK; } if (SolFound) { SolCode = 2; } } else if (SolType == 2) //===== discontinuous ===== { UCell P = pBDL[LK0.UCe1.rc]; //(for MultiAns code) int dcTyp = LK0.type * 10 + LKnxt.type; switch (dcTyp) { case 11: P.FixedNo = LK0.no + 1; //Cell number determination P.CancelB = P.FreeB.DifSet(1 << (LK0.no)); SolCode = 1; SolFound = true; //(1:Fixed) break; case 12: P.CancelB = 1 << LKnxt.no; SolCode = 2; SolFound = true; break;//(2:Exclude from candidates) case 21: P.CancelB = 1 << LK0.no; SolCode = 2; SolFound = true; break; case 22: if (LK0.no == LKnxt.no) { P.CancelB = 1 << LK0.no; SolFound = true; SolCode = 2; } break; } } if (SolFound) { return(SolType); } return(-1); }