Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- using System.Threading.Tasks;
- namespace mestint2020_03_04
- {
- class HuszárCsere : AbsztraktÁllapot
- {
- int[,] tábla = new int[3, 3];
- public HuszárCsere()
- {
- tábla[0, 0] = 1; // fehér huszár
- tábla[0, 1] = 0; // üres hely
- tábla[0, 2] = 1; // fehér huszár
- tábla[1, 0] = 0;
- tábla[1, 1] = 0; // üres hely
- tábla[1, 2] = 0;
- tábla[2, 0] = -1; // fekete huszár
- tábla[2, 1] = 0; // üres hely
- tábla[2, 2] = -1; // fekete huszár
- }
- public override bool CélÁllapotE()
- {
- return (tábla[0, 0] == -1) &&
- (tábla[0, 2] == -1) &&
- (tábla[2, 0] == 1) &&
- (tábla[2, 2] == 1);
- }
- public override int OperátorokSzáma()
- {
- return 1;
- }
- public override bool SzuperOperátor(int i)
- {
- switch (i)
- {
- case 0: return forgatJobbra();
- default: return false;
- }
- }
- public bool forgatJobbra()
- {
- if (!preForgatJobbra()) return false;
- // állapot átmenet
- // 1->5->6->2->8->4->3->7->1
- // (0,0) -> (1,2) -> (2,0) ->
- // (0,1) -> (2,2) -> (1,0) ->
- // (0,2) -> (2,1) -> (0,0)
- int akt;
- int újAkt;
- akt = tábla[0, 0];
- int[] x = {1, 2, 0, 2, 1, 0, 2, 0 };
- int[] y = {2, 0, 1, 2, 0, 2, 1, 0 };
- for (int i = 0; i < x.Length; i++)
- {
- újAkt = tábla[x[i], y[i]];
- tábla[x[i], y[i]] = akt;
- akt = újAkt;
- }
- return ÁllapotE();
- }
- private bool preForgatJobbra()
- {
- return true;
- }
- public override bool ÁllapotE()
- {
- return true;
- }
- public override object Clone()
- {
- HuszárCsere myClone = new HuszárCsere();
- myClone.tábla = (int[,])this.tábla.Clone();
- return myClone;
- }
- public override bool Equals(object a)
- {
- HuszárCsere másik = (HuszárCsere)a;
- return this.tábla.Equals(másik.tábla);
- }
- public override string ToString()
- {
- StringBuilder sb = new StringBuilder();
- for (int i = 0; i < 3; i++)
- {
- for (int j = 0; j < 3; j++)
- {
- sb.Append(tábla[i, j]);
- sb.Append(" ");
- }
- sb.Append("\n");
- }
- return sb.ToString();
- }
- }
- class Lucky7Allapot : AbsztraktÁllapot
- {
- int[,] tabla = new int[3, 3];
- int x, y;
- public override bool CélÁllapotE()
- {
- return tabla[0, 0] == 1 &&
- tabla[0, 1] == -1 &&
- tabla[0, 2] == 7 &&
- tabla[1, 0] == 2 &&
- tabla[1, 1] == 0 &&
- tabla[1, 2] == 6 &&
- tabla[2, 0] == 3 &&
- tabla[2, 1] == 4 &&
- tabla[2, 2] == 5;
- }
- public Lucky7Allapot()
- {
- tabla[0, 0] = 2;
- tabla[0, 1] = 3;
- tabla[0, 2] = 1;
- tabla[1, 0] = 4;
- tabla[1, 1] = 0; // közepe
- tabla[1, 2] = 7;
- tabla[2, 0] = 6;
- tabla[2, 1] = -1; // ez az üres, az x, y-ba kell írni ennek a helyét
- tabla[2, 2] = 5;
- this.x = 2; // üres helye
- this.y = 1; // üres helye
- }
- public override int OperátorokSzáma()
- {
- return 6; // az üres 4 felé mozoghat: fel, le, jobb, bal
- }
- public override bool SzuperOperátor(int i)
- {
- switch (i)
- {
- case 0: return mozgatÜres(-1, 0); // fel 1
- case 1: return mozgatÜres(-2, 0); //fel 3
- case 2: return mozgatÜres(0, -1); //jobb 1
- case 3: return mozgatÜres(0, 1); //bal
- case 4: return mozgatÜres(1, 0);
- case 5: return mozgatÜres(2, 0);
- }
- return false;
- }
- /// <summary>
- /// mozhatja az üreset a táblán
- /// </summary>
- /// <param name="relativeX"> ennyivel mozdítom el x irányba</param>
- /// <param name="relativeY">ennyivel mozdítom el y irányba</param>
- /// <returns></returns>
- public bool mozgatÜres(int relativeX, int relativeY)
- {
- if (!preMozgatUres(relativeX, relativeY))
- {
- return false;
- }
- //mozgat
- int ujX = this.x + relativeX;
- int ujY = this.y + relativeY;
- this.tabla[this.x, this.y] = this.tabla[ujX, ujY];
- this.tabla[ujX, ujY] = -1;
- //üres helyének a mozgatása
- this.x = ujX;
- this.y = ujY;
- return ÁllapotE();
- }
- private bool preMozgatUres(int relativeX, int relativeY)
- {
- /*
- * akkor szabad mozgatni ha nem lépünk le a tábláról
- * nem ütközünk falba
- */
- bool b1 = nemLepunkLe(relativeX, relativeY);
- bool b2 = nemUtkozunkFalba(relativeX, relativeY);
- bool b3 = nemKozepreLepunk(relativeX, relativeY);
- return b1 && b2 && b3;
- }
- private bool nemKozepreLepunk(int relativeX, int relativeY)
- {
- int ujX = this.x + relativeX;
- int ujY = this.y + relativeY;
- if (ujX == 1 && ujY == 1)
- {
- return false;
- }
- return true;
- }
- private bool nemUtkozunkFalba(int relativeX, int relativeY)
- {
- //tabla[1, 0] = 4;
- //tabla[1, 2] = 7;
- if (this.x == 1 &&
- this.y == 0 &&
- relativeY != 0)
- {
- return false;
- }
- if (this.x == 1 && this.y == 2 && relativeY != 0)
- {
- return false;
- }
- return true;
- }
- private bool nemLepunkLe(int relativeX, int relativeY)
- {
- int ujX = this.x + relativeX;
- int ujY = this.y + relativeY;
- return ujX < 3 && ujX >= 0 && ujY >= 0 && ujY < 3;
- }
- public override bool ÁllapotE()
- {
- return true;
- }
- public override string ToString()
- {
- StringBuilder sb = new StringBuilder();
- for (int i = 0; i < 3; i++)
- {
- for (int j = 0; j < 3; j++)
- {
- sb.Append(tabla[i, j]);
- sb.Append(" ");
- }
- sb.Append("\n");
- }
- return sb.ToString();
- }
- public override object Clone()
- {
- Lucky7Allapot myClone = new Lucky7Allapot();
- myClone.x = this.x;
- myClone.y = this.y;
- for (int i = 0; i < 3; i++)
- {
- for (int j = 0; j < 3; j++)
- {
- myClone.tabla[i, j] = this.tabla[i, j];
- }
- }
- return myClone;
- }
- public override bool Equals(object a)
- {
- Lucky7Allapot masik = (Lucky7Allapot)a;
- bool tablakEgyenlok = true;
- for (int i = 0; i < 3; i++)
- {
- for (int j = 0; j < 3; j++)
- {
- if (this.tabla[i, j] != masik.tabla[i, j])
- {
- tablakEgyenlok = false;
- }
- }
- }
- return this.x == masik.x && this.y == masik.y && tablakEgyenlok;
- }
- }
- abstract class AbsztraktÁllapot : ICloneable
- {
- // Megvizsgálja, hogy a belső állapot állapot-e.
- // Ha igen, akkor igazat ad vissza, egyébként hamisat.
- public abstract bool ÁllapotE();
- // Megvizsgálja, hogy a belső állapot célállapot-e.
- // Ha igen, akkor igazat ad vissza, egyébként hamisat.
- public abstract bool CélÁllapotE();
- // Visszaadja az alapoperátorok számát.
- public abstract int OperátorokSzáma();
- // A szuper operátoron keresztül lehet elérni az összes operátort.
- // Igazat ad vissza, ha az i.dik alap operátor alkalmazható a belső állapotra.
- // for ciklusból kell hívni 0-tól kezdve az alap operátorok számig. Pl. így:
- // for (int i = 0; i < állapot.OperátorokSzáma(); i++)
- // {
- // AbsztraktÁllapot klón=(AbsztraktÁllapot)állapot.Clone();
- // if (klón.SzuperOperátor(i))
- // {
- // Console.WriteLine("Az {0} állapotra az {1}.dik " +
- // "operátor alkalmazható", állapot, i);
- // }
- // }
- public abstract bool SzuperOperátor(int i);
- // Klónoz. Azért van rá szükség, mert némelyik operátor hatását vissza kell vonnunk.
- // A legegyszerűbb, hogy az állapotot leklónozom. Arra hívom az operátort.
- // Ha gond van, akkor visszatérek az eredeti állapothoz.
- // Ha nincs gond, akkor a klón lesz az állapot, amiből folytatom a keresést.
- // Ez sekély klónozást alkalmaz. Ha elég a sekély klónozás, akkor nem kell felülírni a gyermek osztályban.
- // Ha mély klónozás kell, akkor mindenképp felülírandó.
- public virtual object Clone() { return MemberwiseClone(); }
- // Csak akkor kell felülírni, ha emlékezetes backtracket akarunk használni, vagy mélységi keresést.
- // Egyébként maradhat ez az alap implementáció.
- // Programozás technikailag ez egy kampó metódus, amit az OCP megszegése nélkül írhatok felül.
- public override bool Equals(Object a) { return false; }
- // Ha két példány egyenlő, akkor a hasítókódjuk is egyenlő.
- // Ezért, ha valaki felülírja az Equals metódust, ezt is illik felülírni.
- public override int GetHashCode() { return base.GetHashCode(); }
- }
- abstract class VakÁllapot : AbsztraktÁllapot
- {
- // Itt kell megadni azokat a mezőket, amelyek tartalmazzák a belső állapotot.
- // Az operátorok belső állapot átmenetet hajtanak végre.
- // Először az alapoperátorokat kell megírni.
- // Minden operátornak van előfeltétele.
- // Minden operátor utófeltétele megegyezik az ÁllapotE predikátummal.
- // Az operátor igazat ad vissza, ha alkalmazható, hamisat, ha nem alkalmazható.
- // Egy operátor alkalmazható, ha a belső állapotra igaz
- // az előfeltétele és az állapotátmenet után igaz az utófeltétele.
- // Ez az első alapoperátor.
- private bool op1()
- {
- // Ha az előfeltétel hamis, akkor az operátor nem alkalmazható.
- if (!preOp1()) return false;
- // állapot átmenet
- //
- // TODO: Itt kell kiegészíteni a kódot!
- //
- // Utófeltétel vizsgálata, ha igaz, akkor alkalmazható az operátor.
- if (ÁllapotE()) return true;
- // Egyébként vissza kell vonni a belső állapot átmenetet,
- //
- // TODO: Itt kell kiegészíteni a kódot!
- //
- // és vissza kell adni, hogy nem alkalmazható az operátor.
- return false;
- }
- // Az első alapoperátor előfeltétele. Az előfeltétel neve általában ez: pre+operátor neve.
- // Ez segíti a kód megértését, de nyugodtan eltérhetünk ettől.
- private bool preOp1()
- {
- // Ha igaz az előfeltétel, akkor igazat ad vissza.
- return true;
- }
- // Egy másik operátor.
- private bool op2()
- {
- if (!preOp2()) return false;
- // Állapot átmenet:
- // TODO: Itt kell kiegészíteni a kódot!
- if (ÁllapotE()) return true;
- // Egyébként vissza kell vonni a belső állapot átmenetet:
- // TODO: Itt kell kiegészíteni a kódot!
- return false;
- }
- private bool preOp2()
- {
- // Ha igaz az előfeltétel, akkor igazat ad vissza.
- return true;
- }
- // Nézzük, mi a helyzet, ha az operátornak van paramétere.
- // Ilyenkor egy operátor több alapoperátornak felel meg.
- private bool op3(int i)
- {
- // Az előfeltételt ugyanazokkal a pereméterekkel kell hívni, mint magát az operátort.
- if (!preOp3(i)) return false;
- // Állapot átmenet:
- // TODO: Itt kell kiegészíteni a kódot!
- if (ÁllapotE()) return true;
- // egyébként vissza kell vonni a belső állapot átmenetet
- // TODO: Itt kell kiegészíteni a kódot!
- return false;
- }
- // Az előfeltétel paraméterlistája megegyezik az operátor paraméterlistájával.
- private bool preOp3(int i)
- {
- // Ha igaz az előfeltétel, akkor igazat ad vissza. Az előfeltétel függ a paraméterektől.
- return true;
- }
- // Ez a szuper operátor. Ezen keresztül lehet hívni az alapoperátorokat.
- // Az i paraméterrel mondjuk meg, hanyadik operátort akarjuk hívni.
- // Általában egy for ciklusból hívjuk, ami 0-tól az OperátorokSzáma()-ig fut.
- public override bool SzuperOperátor(int i)
- {
- switch (i)
- {
- // Itt kell felsorolnom az összes alapoperátort.
- // Ha egy új operátort veszek fel, akkor ide is fel kell venni.
- case 0: return op1();
- case 1: return op2();
- // A paraméteres operátorok több alap operátornak megfelelnek, ezért itt több sor is tartozik hozzájuk.
- // Hogy hány sor, az feladat függő.
- case 3: return op3(0);
- case 4: return op3(1);
- case 5: return op3(2);
- default: return false;
- }
- }
- // Visszaadja az alap operátorok számát.
- public override int OperátorokSzáma()
- {
- // Az utolsó case számát kell itt visszaadni.
- // Ha bővítjük az operátorok számát, ezt a számot is növelni kell.
- return 5;
- }
- }
- class ÉhesHuszárÁllapot : AbsztraktÁllapot
- {
- // Alapértelmezetten egy 3*3-as sakktáblán fut.
- static int N = 3;
- // A belső állapotot leíró mezők.
- int x, y;
- // Beállítja a kezdő állapotra a belső állapotot.
- public ÉhesHuszárÁllapot()
- {
- x = 2; // A bal felső sarokból indulunk, ami a margó
- y = 2; // miatt a (2,2) koordinátán van.
- }
- // Beállítja a kezdő állapotra a belső állapotot.
- // Itt lehet megadni a tábla méretét is.
- public ÉhesHuszárÁllapot(int n)
- {
- x = 2;
- y = 2;
- N = n;
- }
- public override bool CélÁllapotE()
- {
- // A jobb alsó sarok a margó miatt a (N+1,N+1) helyen van.
- return x == N + 1 && y == N + 1;
- }
- public override bool ÁllapotE()
- {
- // a ló nem a margon van
- return x >= 2 && y >= 2 && x <= N + 1 && y <= N + 1;
- }
- private bool preLóLépés(int x, int y)
- {
- // jó lólépés-e, ha nem akkor return false
- if (!(x * y == 2 || x * y == -2)) return false;
- return true;
- }
- /* Ez az operátorom, igaz ad vissza, ha alakalmazható,
- * egyébként hamisat.
- * Paraméterek:
- * x: x irányú elmozdulás
- * y: y irányú elmozdulás
- * Az előfeltétel ellenőrzi, hogy az elmozdulás lólépés-e.
- * Az utófeltétel ellenőrzi, hogy a táblán maradtunk-e.
- * Példa:
- * lóLépés(1,-2) jelentése felfelé 2-öt jobbra 1-et.
- */
- private bool lóLépés(int x, int y)
- {
- if (!preLóLépés(x, y)) return false;
- // Ha az előfeltétel igaz, akkor megcsinálom az
- // állapot átmenetet.
- this.x += x;
- this.y += y;
- // Az utófeltétel mindig megegyezik az ÁllapotE-vel.
- if (ÁllapotE()) return true;
- // Ha az utófeltétel nem igaz, akkor vissza kell csinálni.
- this.x -= x;
- this.y -= y;
- return false;
- }
- public override bool SzuperOperátor(int i)
- {
- switch (i)
- { // itt sorolom fel a lehetséges 8 lólépést
- case 0: return lóLépés(1, 2);
- case 1: return lóLépés(1, -2);
- case 2: return lóLépés(-1, 2);
- case 3: return lóLépés(-1, -2);
- case 4: return lóLépés(2, 1);
- case 5: return lóLépés(2, -1);
- case 6: return lóLépés(-2, 1);
- case 7: return lóLépés(-2, -1);
- default: return false;
- }
- }
- public override int OperátorokSzáma() { return 8; }
- // A kiíratásnál kivonom x-ből és y-ból a margó szélességét.
- public override string ToString() { return (x - 2) + " : " + (y - 2); }
- public override bool Equals(Object a)
- {
- ÉhesHuszárÁllapot aa = (ÉhesHuszárÁllapot)a;
- return aa.x == x && aa.y == y;
- }
- // Ha két példány egyenlő, akkor a hasítókódjuk is egyenlő.
- public override int GetHashCode()
- {
- return x.GetHashCode() + y.GetHashCode();
- }
- }
- class SzerzetesekÉsKannibálokÁllapot : AbsztraktÁllapot
- {
- int sz; // ennyi szerzetes van összesen
- int k; // ennyi kannibál van összesen
- int szb; // szerzetesek száma a bal oldalon
- int kb; // kannibálok száma a bal oldalon
- char cs; // Hol a csónak? Értéke vagy 'B' vagy 'J'.
- int szj; // szerzetesek száma a jobb oldalon
- int kj; // kannibálok száma a jobb oldalon
- public SzerzetesekÉsKannibálokÁllapot(int sz, int k) // beállítja a kezdő állapotot
- {
- this.sz = sz;
- this.k = k;
- szb = sz;
- kb = k;
- cs = 'B';
- szj = 0;
- kj = 0;
- }
- public override bool ÁllapotE()
- { // igaz, ha a szerzetesek biztonságban vannak
- return ((szb >= kb) || (szb == 0)) &&
- ((szj >= kj) || (szj == 0));
- }
- public override bool CélÁllapotE()
- {
- // igaz, ha mindenki átért a jobb oldalra
- return szj == sz && kj == k;
- }
- private bool preOp(int sz, int k)
- {
- // A csónak 2 személyes, legalább egy ember kell az evezéshez.
- // Ezt végül is felesleges vizsgálni, mert a szuper operátor csak ennek megfelelően hívja.
- if (sz + k > 2 || sz + k < 0 || sz < 0 || k < 0) return false;
- // Csak akkor lehet átvinni sz szerzetest és
- // k kannibált, ha a csónak oldalán van is legalább ennyi.
- if (cs == 'B')
- return szb >= sz && kb >= k;
- else
- return szj >= sz && kj >= k;
- }
- // Átvisz a másik oldalra sz darab szerzetes és k darab kannibált.
- private bool op(int sz, int k)
- {
- if (!preOp(sz, k)) return false;
- SzerzetesekÉsKannibálokÁllapot mentes = (SzerzetesekÉsKannibálokÁllapot)Clone();
- if (cs == 'B')
- {
- szb -= sz;
- kb -= k;
- cs = 'J';
- szj += sz;
- kj += k;
- }
- else
- {
- szb += sz;
- kb += k;
- cs = 'B';
- szj -= sz;
- kj -= k;
- }
- if (ÁllapotE()) return true;
- szb = mentes.szb;
- kb = mentes.kb;
- cs = mentes.cs;
- szj = mentes.szj;
- kj = mentes.kj;
- return false;
- }
- public override int OperátorokSzáma() { return 5; }
- public override bool SzuperOperátor(int i)
- {
- switch (i)
- {
- case 0: return op(0, 1);
- case 1: return op(0, 2);
- case 2: return op(1, 1);
- case 3: return op(1, 0);
- case 4: return op(2, 0);
- default: return false;
- }
- }
- public override string ToString()
- {
- return szb + "," + kb + "," + cs + "," + szj + "," + kj;
- }
- public override bool Equals(Object a)
- {
- SzerzetesekÉsKannibálokÁllapot aa = (SzerzetesekÉsKannibálokÁllapot)a;
- // szj és kj számítható, ezért nem kell vizsgálni
- return aa.szb == szb && aa.kb == kb && aa.cs == cs;
- }
- // Ha két példány egyenlő, akkor a hasítókódjuk is egyenlő.
- public override int GetHashCode()
- {
- return szb.GetHashCode() + kb.GetHashCode() + cs.GetHashCode();
- }
- }
- class Csúcs
- {
- // A csúcs tartalmaz egy állapotot, a mélységét és a szülőjét
- AbsztraktÁllapot állapot;
- int mélység;
- Csúcs szülő; // A szülőkön felfelé haladva a start csúcsig jutok.
- // Konstruktor:
- // A belső állapotot beállítja a start csúcsra.
- // A hívó felelőssége, hogy a kezdő állapottal hívja meg.
- // A start csúcs mélysége 0, szülője nincs.
- public Csúcs(AbsztraktÁllapot kezdőÁllapot)
- {
- állapot = kezdőÁllapot;
- mélység = 0;
- szülő = null;
- }
- // Egy új gyermek csúcsot készít.
- // Erre még meg kell hívni egy alkalmazható operátor is, csak azután lesz kész.
- public Csúcs(Csúcs szülő)
- {
- állapot = (AbsztraktÁllapot)szülő.állapot.Clone();
- mélység = szülő.mélység + 1;
- this.szülő = szülő;
- }
- public Csúcs GetSzülő() { return szülő; }
- public int GetMélység() { return mélység; }
- public bool TerminálisCsúcsE() { return állapot.CélÁllapotE(); }
- public int OperátorokSzáma() { return állapot.OperátorokSzáma(); }
- public bool SzuperOperátor(int i) { return állapot.SzuperOperátor(i); }
- public override bool Equals(Object obj)
- {
- Csúcs cs = (Csúcs)obj;
- return állapot.Equals(cs.állapot);
- }
- public override int GetHashCode() { return állapot.GetHashCode(); }
- public override String ToString() { return állapot.ToString(); }
- // Alkalmazza az összes alkalmazható operátort.
- // Visszaadja az így előálló új csúcsokat.
- public List<Csúcs> Kiterjesztes()
- {
- List<Csúcs> újCsúcsok = new List<Csúcs>();
- for (int i = 0; i < OperátorokSzáma(); i++)
- {
- // Új gyermek csúcsot készítek.
- Csúcs újCsúcs = new Csúcs(this);
- // Kiprobálom az i.dik alapoperátort. Alkalmazható?
- if (újCsúcs.SzuperOperátor(i))
- {
- // Ha igen, hozzáadom az újakhoz.
- újCsúcsok.Add(újCsúcs);
- }
- }
- return újCsúcsok;
- }
- }
- abstract class GráfKereső
- {
- private Csúcs startCsúcs; // A start csúcs csúcs.
- // Minden gráfkereső a start csúcsból kezd el keresni.
- public GráfKereső(Csúcs startCsúcs)
- {
- this.startCsúcs = startCsúcs;
- }
- // Jobb, ha a start csúcs privát, de a gyermek osztályok lekérhetik.
- protected Csúcs GetStartCsúcs() { return startCsúcs; }
- /// Ha van megoldás, azaz van olyan út az állapottér gráfban,
- /// ami a start csúcsból egy terminális csúcsba vezet,
- /// akkor visszaad egy megoldást, egyébként null.
- /// A megoldást egy terminális csúcsként adja vissza.
- /// Ezen csúcs szülő referenciáin felfelé haladva adódik a megoldás fordított sorrendben.
- public abstract Csúcs Keresés();
- /// <summary>
- /// Kiíratja a megoldást egy terminális csúcs alapján.
- /// Feltételezi, hogy a terminális csúcs szülő referenciáján felfelé haladva eljutunk a start csúcshoz.
- /// A csúcsok sorrendjét megfordítja, hogy helyesen tudja kiírni a megoldást.
- /// Ha a csúcs null, akkor kiírja, hogy nincs megoldás.
- /// </summary>
- /// <param name="egyTerminálisCsúcs">
- /// A megoldást képviselő terminális csúcs vagy null.
- /// </param>
- public void megoldásKiírása(Csúcs egyTerminálisCsúcs)
- {
- if (egyTerminálisCsúcs == null)
- {
- Console.WriteLine("Nincs megoldás");
- return;
- }
- // Meg kell fordítani a csúcsok sorrendjét.
- Stack<Csúcs> megoldás = new Stack<Csúcs>();
- Csúcs aktCsúcs = egyTerminálisCsúcs;
- while (aktCsúcs != null)
- {
- megoldás.Push(aktCsúcs);
- aktCsúcs = aktCsúcs.GetSzülő();
- }
- // Megfordítottuk, lehet kiírni.
- foreach (Csúcs akt in megoldás) Console.WriteLine(akt);
- }
- }
- class BackTrack : GráfKereső
- {
- int korlát; // Ha nem nulla, akkor mélységi korlátos kereső.
- bool emlékezetes; // Ha igaz, emlékezetes kereső.
- public BackTrack(Csúcs startCsúcs, int korlát, bool emlékezetes) : base(startCsúcs)
- {
- this.korlát = korlát;
- this.emlékezetes = emlékezetes;
- }
- // nincs mélységi korlát, se emlékezet
- public BackTrack(Csúcs startCsúcs) : this(startCsúcs, 0, false) { }
- // mélységi korlátos kereső
- public BackTrack(Csúcs startCsúcs, int korlát) : this(startCsúcs, korlát, false) { }
- // emlékezetes kereső
- public BackTrack(Csúcs startCsúcs, bool emlékezetes) : this(startCsúcs, 0, emlékezetes) { }
- // A keresés a start csúcsból indul.
- // Egy terminális csúcsot ad vissza. A start csúcsból el lehet jutni ebbe a terminális csúcsba.
- // Ha nincs ilyen, akkor null értéket ad vissza.
- public override Csúcs Keresés() { return Keresés(GetStartCsúcs()); }
- // A kereső algoritmus rekurzív megvalósítása.
- // Mivel rekurzív, ezért a visszalépésnek a "return null" felel meg.
- private Csúcs Keresés(Csúcs aktCsúcs)
- {
- int mélység = aktCsúcs.GetMélység();
- // mélységi korlát vizsgálata
- if (korlát > 0 && mélység >= korlát) return null;
- // emlékezet használata kör kiszűréséhez
- Csúcs aktSzülő = null;
- if (emlékezetes) aktSzülő = aktCsúcs.GetSzülő();
- while (aktSzülő != null)
- {
- // Ellenőrzöm, hogy jártam-e ebben az állapotban. Ha igen, akkor visszalépés.
- if (aktCsúcs.Equals(aktSzülő)) return null;
- // Visszafelé haladás a szülői láncon.
- aktSzülő = aktSzülő.GetSzülő();
- }
- if (aktCsúcs.TerminálisCsúcsE())
- {
- // Megvan a megoldás, vissza kell adni a terminális csúcsot.
- return aktCsúcs;
- }
- // Itt hívogatom az alapoperátorokat a szuper operátoron
- // keresztül. Ha valamelyik alkalmazható, akkor új csúcsot
- // készítek, és meghívom önmagamat rekurzívan.
- for (int i = 0; i < aktCsúcs.OperátorokSzáma(); i++)
- {
- // Elkészítem az új gyermek csúcsot.
- // Ez csak akkor lesz kész, ha alkalmazok rá egy alkalmazható operátort is.
- Csúcs újCsúcs = new Csúcs(aktCsúcs);
- // Kipróbálom az i.dik alapoperátort. Alkalmazható?
- if (újCsúcs.SzuperOperátor(i))
- {
- // Ha igen, rekurzívan meghívni önmagam az új csúcsra.
- // Ha nem null értéket ad vissza, akkor megvan a megoldás.
- // Ha null értéket, akkor ki kell próbálni a következő alapoperátort.
- //Console.WriteLine(újCsúcs.GetMélység());
- Csúcs terminális = Keresés(újCsúcs);
- if (terminális != null)
- {
- // Visszaadom a megoldást képviselő terminális csúcsot.
- return terminális;
- }
- // Az else ágon kellene visszavonni az operátort.
- // Erre akkor van szükség, ha az új gyermeket létrehozásában nem lenne klónozást.
- // Mivel klónoztam, ezért ez a rész üres.
- }
- }
- // Ha kipróbáltam az összes operátort és egyik se vezetett megoldásra, akkor visszalépés.
- // A visszalépés hatására eggyel feljebb a következő alapoperátor kerül sorra.
- return null;
- }
- }
- class MélységiKeresés : GráfKereső
- {
- // Mélységi keresésnél érdemes a nyílt csúcsokat veremben tárolni,
- // mert így mindig a legnagyobb mélységű csúcs lesz a verem tetején.
- // Így nem kell külön keresni a legnagyobb mélységű nyílt csúcsot, amit ki kell terjeszteni.
- Stack<Csúcs> Nyilt; // Nílt csúcsok halmaza.
- List<Csúcs> Zárt; // Zárt csúcsok halmaza.
- bool körFigyelés; // Ha hamis, végtelen ciklusba eshet.
- public MélységiKeresés(Csúcs startCsúcs, bool körFigyelés) :
- base(startCsúcs)
- {
- Nyilt = new Stack<Csúcs>();
- Nyilt.Push(startCsúcs); // kezdetben csak a start csúcs nyílt
- Zárt = new List<Csúcs>(); // kezdetben a zárt csúcsok halmaza üres
- this.körFigyelés = körFigyelés;
- }
- // A körfigyelés alapértelmezett értéke igaz.
- public MélységiKeresés(Csúcs startCsúcs) : this(startCsúcs, true) { }
- // A megoldás keresés itt indul.
- public override Csúcs Keresés()
- {
- // Ha nem kell körfigyelés, akkor sokkal gyorsabb az algoritmus.
- if (körFigyelés) return TerminálisCsúcsKeresés();
- return TerminálisCsúcsKeresésGyorsan();
- }
- private Csúcs TerminálisCsúcsKeresés()
- {
- // Amíg a nyílt csúcsok halmaza nem nem üres.
- while (Nyilt.Count != 0)
- {
- // Ez a legnagyobb mélységű nyílt csúcs.
- Csúcs C = Nyilt.Pop();
- // Ezt kiterjesztem.
- List<Csúcs> újCsucsok = C.Kiterjesztes();
- foreach (Csúcs D in újCsucsok)
- {
- // Ha megtaláltam a terminális csúcsot, akkor kész vagyok.
- if (D.TerminálisCsúcsE()) return D;
- // Csak azokat az új csúcsokat veszem fel a nyíltak közé,
- // amik nem szerepeltek még sem a zárt, sem a nyílt csúcsok halmazában.
- // A Contains a Csúcs osztályban megírt Equals metódust hívja.
- if (!Zárt.Contains(D) && !Nyilt.Contains(D)) Nyilt.Push(D);
- }
- // A kiterjesztett csúcsot átminősítem zárttá.
- Zárt.Add(C);
- }
- return null;
- }
- // Ezt csak akkor szabad használni, ha biztos, hogy az állapottér gráfban nincs kör!
- // Különben valószínűleg végtelen ciklust okoz.
- private Csúcs TerminálisCsúcsKeresésGyorsan()
- {
- while (Nyilt.Count != 0)
- {
- Csúcs C = Nyilt.Pop();
- List<Csúcs> ujCsucsok = C.Kiterjesztes();
- foreach (Csúcs D in ujCsucsok)
- {
- if (D.TerminálisCsúcsE()) return D;
- // Ha nincs kör, akkor felesleges megnézni, hogy D volt-e már nyíltak vagy a zártak közt.
- Nyilt.Push(D);
- }
- // Ha nincs kör, akkor felesleges C-t zárttá minősíteni.
- }
- return null;
- }
- }
- class Program
- {
- static void Main(string[] args)
- {
- Csúcs startCsúcs;
- GráfKereső kereső;
- Console.WriteLine("Luck7 megoldása.");
- AbsztraktÁllapot k = new HuszárCsere();
- startCsúcs = new Csúcs(k);
- //Console.WriteLine(k);
- //bool b = k.SzuperOperátor(0);
- //Console.WriteLine(b);
- //Console.WriteLine(k);
- //b = k.SzuperOperátor(0);
- //Console.WriteLine(b);
- //Console.WriteLine(k);
- Console.WriteLine("A kereső egy 10 mélységi korlátos és emlékezetes backtrack.");
- kereső = new BackTrack(startCsúcs, 10, true);
- kereső.megoldásKiírása(kereső.Keresés());
- //Console.WriteLine("A kereső egy mélységi keresés körfigyeléssel.");
- //kereső = new MélységiKeresés(startCsúcs, true);
- //kereső.megoldásKiírása(kereső.Keresés());
- //Console.WriteLine("A 3 szerzetes 3 kanibál problémát oldjuk meg.");
- //startCsúcs = new Csúcs(new SzerzetesekÉsKannibálokÁllapot(3, 3));
- //Console.WriteLine("A kereső egy 15 mélységi korlátos és emlékezetes backtrack.");
- //kereső = new BackTrack(startCsúcs, 15, true);
- //kereső.megoldásKiírása(kereső.Keresés());
- //Console.WriteLine("A kereső egy mélységi keresés körfigyeléssel.");
- //kereső = new MélységiKeresés(startCsúcs, true);
- //kereső.megoldásKiírása(kereső.Keresés());
- Console.ReadLine();
- }
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement