Advertisement
Guest User

mestint huszarcsere jo

a guest
Apr 8th, 2020
277
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 35.21 KB | None | 0 0
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Threading.Tasks;
  6.  
  7. namespace mestint2020_03_04
  8. {
  9.     class HuszárCsere : AbsztraktÁllapot
  10.     {
  11.         int[,] tábla = new int[3, 3];
  12.  
  13.         public HuszárCsere()
  14.         {
  15.             tábla[0, 0] = 1; // fehér huszár
  16.             tábla[0, 1] = 0; // üres hely
  17.             tábla[0, 2] = 1; // fehér huszár
  18.             tábla[1, 0] = 0;
  19.             tábla[1, 1] = 0; // üres hely
  20.             tábla[1, 2] = 0;
  21.             tábla[2, 0] = -1; // fekete huszár
  22.             tábla[2, 1] = 0; // üres hely
  23.             tábla[2, 2] = -1; // fekete huszár
  24.         }
  25.  
  26.         public override bool CélÁllapotE()
  27.         {
  28.             return (tábla[0, 0] == -1) &&
  29.                    (tábla[0, 2] == -1) &&
  30.                    (tábla[2, 0] == 1) &&
  31.                    (tábla[2, 2] == 1);
  32.         }
  33.  
  34.         public override int OperátorokSzáma()
  35.         {
  36.             return 1;
  37.         }
  38.  
  39.         public override bool SzuperOperátor(int i)
  40.         {
  41.             switch (i)
  42.             {
  43.                 case 0: return forgatJobbra();
  44.                 default: return false;
  45.             }
  46.         }
  47.         public bool forgatJobbra()
  48.         {
  49.             if (!preForgatJobbra()) return false;
  50.             // állapot átmenet
  51.             // 1->5->6->2->8->4->3->7->1
  52.             // (0,0) -> (1,2) -> (2,0) ->
  53.             // (0,1) -> (2,2) -> (1,0) ->
  54.             // (0,2) -> (2,1) -> (0,0)
  55.             int akt;
  56.             int újAkt;
  57.             akt = tábla[0, 0];
  58.             int[] x = {1, 2, 0, 2, 1, 0, 2, 0 };
  59.             int[] y = {2, 0, 1, 2, 0, 2, 1, 0 };
  60.             for (int i = 0; i < x.Length; i++)
  61.             {
  62.                 újAkt = tábla[x[i], y[i]];
  63.                 tábla[x[i], y[i]] = akt;
  64.                 akt = újAkt;
  65.             }
  66.             return ÁllapotE();
  67.         }
  68.         private bool preForgatJobbra()
  69.         {
  70.             return true;
  71.         }
  72.         public override bool ÁllapotE()
  73.         {
  74.             return true;
  75.         }
  76.         public override object Clone()
  77.         {
  78.             HuszárCsere myClone = new HuszárCsere();
  79.             myClone.tábla = (int[,])this.tábla.Clone();
  80.             return myClone;
  81.         }
  82.         public override bool Equals(object a)
  83.         {
  84.             HuszárCsere másik = (HuszárCsere)a;
  85.             return this.tábla.Equals(másik.tábla);
  86.         }
  87.         public override string ToString()
  88.         {
  89.             StringBuilder sb = new StringBuilder();
  90.             for (int i = 0; i < 3; i++)
  91.             {
  92.                 for (int j = 0; j < 3; j++)
  93.                 {
  94.                     sb.Append(tábla[i, j]);
  95.                     sb.Append(" ");
  96.                 }
  97.                 sb.Append("\n");
  98.             }
  99.             return sb.ToString();
  100.         }
  101.     }
  102.     class Lucky7Allapot : AbsztraktÁllapot
  103.     {
  104.         int[,] tabla = new int[3, 3];
  105.         int x, y;
  106.         public override bool CélÁllapotE()
  107.         {
  108.             return tabla[0, 0] == 1 &&
  109.             tabla[0, 1] == -1 &&
  110.             tabla[0, 2] == 7 &&
  111.             tabla[1, 0] == 2 &&
  112.             tabla[1, 1] == 0 &&
  113.             tabla[1, 2] == 6 &&
  114.             tabla[2, 0] == 3 &&
  115.             tabla[2, 1] == 4 &&
  116.             tabla[2, 2] == 5;
  117.         }
  118.         public Lucky7Allapot()
  119.         {
  120.             tabla[0, 0] = 2;
  121.             tabla[0, 1] = 3;
  122.             tabla[0, 2] = 1;
  123.  
  124.             tabla[1, 0] = 4;
  125.             tabla[1, 1] = 0;  // közepe
  126.             tabla[1, 2] = 7;
  127.  
  128.             tabla[2, 0] = 6;
  129.             tabla[2, 1] = -1; // ez az üres, az x, y-ba kell írni ennek a helyét
  130.             tabla[2, 2] = 5;
  131.  
  132.             this.x = 2; // üres helye
  133.             this.y = 1; // üres helye
  134.         }
  135.         public override int OperátorokSzáma()
  136.         {
  137.             return 6; // az üres 4 felé mozoghat: fel, le, jobb, bal
  138.         }
  139.  
  140.         public override bool SzuperOperátor(int i)
  141.         {
  142.             switch (i)
  143.             {
  144.                 case 0: return mozgatÜres(-1, 0); // fel 1
  145.                 case 1: return mozgatÜres(-2, 0); //fel 3
  146.                 case 2: return mozgatÜres(0, -1); //jobb 1
  147.                 case 3: return mozgatÜres(0, 1);  //bal
  148.                 case 4: return mozgatÜres(1, 0);
  149.                 case 5: return mozgatÜres(2, 0);
  150.             }
  151.             return false;
  152.         }
  153.         /// <summary>
  154.         /// mozhatja az üreset a táblán
  155.         /// </summary>
  156.         /// <param name="relativeX"> ennyivel mozdítom el x irányba</param>
  157.         /// <param name="relativeY">ennyivel mozdítom el y irányba</param>
  158.         /// <returns></returns>
  159.         public bool mozgatÜres(int relativeX, int relativeY)
  160.         {
  161.             if (!preMozgatUres(relativeX, relativeY))
  162.             {
  163.                 return false;
  164.             }
  165.  
  166.             //mozgat
  167.             int ujX = this.x + relativeX;
  168.             int ujY = this.y + relativeY;
  169.  
  170.             this.tabla[this.x, this.y] = this.tabla[ujX, ujY];
  171.             this.tabla[ujX, ujY] = -1;
  172.  
  173.             //üres helyének a mozgatása
  174.  
  175.             this.x = ujX;
  176.             this.y = ujY;
  177.  
  178.             return ÁllapotE();
  179.         }
  180.  
  181.         private bool preMozgatUres(int relativeX, int relativeY)
  182.         {
  183.             /*
  184.              * akkor szabad mozgatni ha nem lépünk le a tábláról
  185.              * nem ütközünk falba
  186.              */
  187.             bool b1 = nemLepunkLe(relativeX, relativeY);
  188.             bool b2 = nemUtkozunkFalba(relativeX, relativeY);
  189.             bool b3 = nemKozepreLepunk(relativeX, relativeY);
  190.  
  191.             return b1 && b2 && b3;
  192.         }
  193.  
  194.         private bool nemKozepreLepunk(int relativeX, int relativeY)
  195.         {
  196.             int ujX = this.x + relativeX;
  197.             int ujY = this.y + relativeY;
  198.  
  199.             if (ujX == 1 && ujY == 1)
  200.             {
  201.                 return false;
  202.             }
  203.             return true;
  204.         }
  205.  
  206.         private bool nemUtkozunkFalba(int relativeX, int relativeY)
  207.         {
  208.             //tabla[1, 0] = 4;
  209.             //tabla[1, 2] = 7;
  210.  
  211.             if (this.x == 1 &&
  212.                 this.y == 0 &&
  213.                 relativeY != 0)
  214.             {
  215.                 return false;
  216.             }
  217.  
  218.             if (this.x == 1 && this.y == 2 && relativeY != 0)
  219.             {
  220.                 return false;
  221.             }
  222.  
  223.             return true;
  224.  
  225.         }
  226.  
  227.         private bool nemLepunkLe(int relativeX, int relativeY)
  228.         {
  229.             int ujX = this.x + relativeX;
  230.             int ujY = this.y + relativeY;
  231.  
  232.             return ujX < 3 && ujX >= 0 && ujY >= 0 && ujY < 3;
  233.         }
  234.  
  235.         public override bool ÁllapotE()
  236.         {
  237.             return true;
  238.         }
  239.  
  240.  
  241.  
  242.         public override string ToString()
  243.         {
  244.             StringBuilder sb = new StringBuilder();
  245.             for (int i = 0; i < 3; i++)
  246.             {
  247.                 for (int j = 0; j < 3; j++)
  248.                 {
  249.                     sb.Append(tabla[i, j]);
  250.                     sb.Append(" ");
  251.                 }
  252.                 sb.Append("\n");
  253.             }
  254.             return sb.ToString();
  255.         }
  256.  
  257.         public override object Clone()
  258.         {
  259.             Lucky7Allapot myClone = new Lucky7Allapot();
  260.             myClone.x = this.x;
  261.             myClone.y = this.y;
  262.  
  263.             for (int i = 0; i < 3; i++)
  264.             {
  265.                 for (int j = 0; j < 3; j++)
  266.                 {
  267.                     myClone.tabla[i, j] = this.tabla[i, j];
  268.                 }
  269.             }
  270.  
  271.             return myClone;
  272.         }
  273.  
  274.         public override bool Equals(object a)
  275.         {
  276.             Lucky7Allapot masik = (Lucky7Allapot)a;
  277.  
  278.             bool tablakEgyenlok = true;
  279.  
  280.             for (int i = 0; i < 3; i++)
  281.             {
  282.                 for (int j = 0; j < 3; j++)
  283.                 {
  284.                     if (this.tabla[i, j] != masik.tabla[i, j])
  285.                     {
  286.                         tablakEgyenlok = false;
  287.                     }
  288.                 }
  289.             }
  290.  
  291.             return this.x == masik.x && this.y == masik.y && tablakEgyenlok;
  292.         }
  293.  
  294.     }
  295.     abstract class AbsztraktÁllapot : ICloneable
  296.     {
  297.         // Megvizsgálja, hogy a belső állapot állapot-e.
  298.         // Ha igen, akkor igazat ad vissza, egyébként hamisat.
  299.         public abstract bool ÁllapotE();
  300.         // Megvizsgálja, hogy a belső állapot célállapot-e.
  301.         // Ha igen, akkor igazat ad vissza, egyébként hamisat.
  302.         public abstract bool CélÁllapotE();
  303.         // Visszaadja az alapoperátorok számát.
  304.         public abstract int OperátorokSzáma();
  305.         // A szuper operátoron keresztül lehet elérni az összes operátort.
  306.         // Igazat ad vissza, ha az i.dik alap operátor alkalmazható a belső állapotra.
  307.         // for ciklusból kell hívni 0-tól kezdve az alap operátorok számig. Pl. így:
  308.         // for (int i = 0; i < állapot.OperátorokSzáma(); i++)
  309.         // {
  310.         // AbsztraktÁllapot klón=(AbsztraktÁllapot)állapot.Clone();
  311.         // if (klón.SzuperOperátor(i))
  312.         // {
  313.         // Console.WriteLine("Az {0} állapotra az {1}.dik " +
  314.         // "operátor alkalmazható", állapot, i);
  315.         // }
  316.         // }
  317.         public abstract bool SzuperOperátor(int i);
  318.         // Klónoz. Azért van rá szükség, mert némelyik operátor hatását vissza kell vonnunk.
  319.         // A legegyszerűbb, hogy az állapotot leklónozom. Arra hívom az operátort.
  320.         // Ha gond van, akkor visszatérek az eredeti állapothoz.
  321.         // Ha nincs gond, akkor a klón lesz az állapot, amiből folytatom a keresést.
  322.         // 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.
  323.         // Ha mély klónozás kell, akkor mindenképp felülírandó.
  324.         public virtual object Clone() { return MemberwiseClone(); }
  325.         // Csak akkor kell felülírni, ha emlékezetes backtracket akarunk használni, vagy mélységi keresést.
  326.         // Egyébként maradhat ez az alap implementáció.
  327.         // Programozás technikailag ez egy kampó metódus, amit az OCP megszegése nélkül írhatok felül.
  328.         public override bool Equals(Object a) { return false; }
  329.         // Ha két példány egyenlő, akkor a hasítókódjuk is egyenlő.
  330.         // Ezért, ha valaki felülírja az Equals metódust, ezt is illik felülírni.
  331.         public override int GetHashCode() { return base.GetHashCode(); }
  332.     }
  333.     abstract class VakÁllapot : AbsztraktÁllapot
  334.     {
  335.         // Itt kell megadni azokat a mezőket, amelyek tartalmazzák a belső állapotot.
  336.         // Az operátorok belső állapot átmenetet hajtanak végre.
  337.         // Először az alapoperátorokat kell megírni.
  338.         // Minden operátornak van előfeltétele.
  339.         // Minden operátor utófeltétele megegyezik az ÁllapotE predikátummal.
  340.         // Az operátor igazat ad vissza, ha alkalmazható, hamisat, ha nem alkalmazható.
  341.         // Egy operátor alkalmazható, ha a belső állapotra igaz
  342.         // az előfeltétele és az állapotátmenet után igaz az utófeltétele.
  343.         // Ez az első alapoperátor.
  344.         private bool op1()
  345.         {
  346.             // Ha az előfeltétel hamis, akkor az operátor nem alkalmazható.
  347.             if (!preOp1()) return false;
  348.             // állapot átmenet
  349.             //
  350.             // TODO: Itt kell kiegészíteni a kódot!
  351.             //
  352.             // Utófeltétel vizsgálata, ha igaz, akkor alkalmazható az operátor.
  353.             if (ÁllapotE()) return true;
  354.             // Egyébként vissza kell vonni a belső állapot átmenetet,
  355.             //
  356.             // TODO: Itt kell kiegészíteni a kódot!
  357.             //
  358.             // és vissza kell adni, hogy nem alkalmazható az operátor.
  359.             return false;
  360.         }
  361.         // Az első alapoperátor előfeltétele. Az előfeltétel neve általában ez: pre+operátor neve.
  362.         // Ez segíti a kód megértését, de nyugodtan eltérhetünk ettől.
  363.         private bool preOp1()
  364.         {
  365.             // Ha igaz az előfeltétel, akkor igazat ad vissza.
  366.             return true;
  367.         }
  368.         // Egy másik operátor.
  369.         private bool op2()
  370.         {
  371.             if (!preOp2()) return false;
  372.             // Állapot átmenet:
  373.             // TODO: Itt kell kiegészíteni a kódot!
  374.             if (ÁllapotE()) return true;
  375.             // Egyébként vissza kell vonni a belső állapot átmenetet:
  376.             // TODO: Itt kell kiegészíteni a kódot!
  377.             return false;
  378.         }
  379.         private bool preOp2()
  380.         {
  381.             // Ha igaz az előfeltétel, akkor igazat ad vissza.
  382.             return true;
  383.         }
  384.         // Nézzük, mi a helyzet, ha az operátornak van paramétere.
  385.         // Ilyenkor egy operátor több alapoperátornak felel meg.
  386.         private bool op3(int i)
  387.         {
  388.             // Az előfeltételt ugyanazokkal a pereméterekkel kell hívni, mint magát az operátort.
  389.             if (!preOp3(i)) return false;
  390.             // Állapot átmenet:
  391.             // TODO: Itt kell kiegészíteni a kódot!
  392.             if (ÁllapotE()) return true;
  393.             // egyébként vissza kell vonni a belső állapot átmenetet
  394.             // TODO: Itt kell kiegészíteni a kódot!
  395.             return false;
  396.         }
  397.         // Az előfeltétel paraméterlistája megegyezik az operátor paraméterlistájával.
  398.         private bool preOp3(int i)
  399.         {
  400.             // Ha igaz az előfeltétel, akkor igazat ad vissza. Az előfeltétel függ a paraméterektől.
  401.             return true;
  402.         }
  403.         // Ez a szuper operátor. Ezen keresztül lehet hívni az alapoperátorokat.
  404.         // Az i paraméterrel mondjuk meg, hanyadik operátort akarjuk hívni.
  405.         // Általában egy for ciklusból hívjuk, ami 0-tól az OperátorokSzáma()-ig fut.
  406.         public override bool SzuperOperátor(int i)
  407.         {
  408.             switch (i)
  409.             {
  410.                 // Itt kell felsorolnom az összes alapoperátort.
  411.                 // Ha egy új operátort veszek fel, akkor ide is fel kell venni.
  412.                 case 0: return op1();
  413.                 case 1: return op2();
  414.                 // A paraméteres operátorok több alap operátornak megfelelnek, ezért itt több sor is tartozik hozzájuk.
  415.                 // Hogy hány sor, az feladat függő.
  416.                 case 3: return op3(0);
  417.                 case 4: return op3(1);
  418.                 case 5: return op3(2);
  419.                 default: return false;
  420.             }
  421.         }
  422.         // Visszaadja az alap operátorok számát.
  423.         public override int OperátorokSzáma()
  424.         {
  425.             // Az utolsó case számát kell itt visszaadni.
  426.             // Ha bővítjük az operátorok számát, ezt a számot is növelni kell.
  427.             return 5;
  428.         }
  429.     }
  430.     class ÉhesHuszárÁllapot : AbsztraktÁllapot
  431.     {
  432.         // Alapértelmezetten egy 3*3-as sakktáblán fut.
  433.         static int N = 3;
  434.         // A belső állapotot leíró mezők.
  435.         int x, y;
  436.         // Beállítja a kezdő állapotra a belső állapotot.
  437.         public ÉhesHuszárÁllapot()
  438.         {
  439.             x = 2; // A bal felső sarokból indulunk, ami a margó
  440.             y = 2; // miatt a (2,2) koordinátán van.
  441.         }
  442.         // Beállítja a kezdő állapotra a belső állapotot.
  443.         // Itt lehet megadni a tábla méretét is.
  444.         public ÉhesHuszárÁllapot(int n)
  445.         {
  446.             x = 2;
  447.             y = 2;
  448.             N = n;
  449.         }
  450.         public override bool CélÁllapotE()
  451.         {
  452.             // A jobb alsó sarok a margó miatt a (N+1,N+1) helyen van.
  453.             return x == N + 1 && y == N + 1;
  454.         }
  455.         public override bool ÁllapotE()
  456.         {
  457.             // a ló nem a margon van
  458.             return x >= 2 && y >= 2 && x <= N + 1 && y <= N + 1;
  459.         }
  460.         private bool preLóLépés(int x, int y)
  461.         {
  462.             // jó lólépés-e, ha nem akkor return false
  463.             if (!(x * y == 2 || x * y == -2)) return false;
  464.             return true;
  465.         }
  466.         /* Ez az operátorom, igaz ad vissza, ha alakalmazható,
  467.         * egyébként hamisat.
  468.         * Paraméterek:
  469.         * x: x irányú elmozdulás
  470.         * y: y irányú elmozdulás
  471.         * Az előfeltétel ellenőrzi, hogy az elmozdulás lólépés-e.
  472.         * Az utófeltétel ellenőrzi, hogy a táblán maradtunk-e.
  473.         * Példa:
  474.         * lóLépés(1,-2) jelentése felfelé 2-öt jobbra 1-et.
  475.         */
  476.         private bool lóLépés(int x, int y)
  477.         {
  478.             if (!preLóLépés(x, y)) return false;
  479.             // Ha az előfeltétel igaz, akkor megcsinálom az
  480.             // állapot átmenetet.
  481.             this.x += x;
  482.             this.y += y;
  483.             // Az utófeltétel mindig megegyezik az ÁllapotE-vel.
  484.             if (ÁllapotE()) return true;
  485.             // Ha az utófeltétel nem igaz, akkor vissza kell csinálni.
  486.             this.x -= x;
  487.             this.y -= y;
  488.             return false;
  489.         }
  490.         public override bool SzuperOperátor(int i)
  491.         {
  492.             switch (i)
  493.             { // itt sorolom fel a lehetséges 8 lólépést
  494.                 case 0: return lóLépés(1, 2);
  495.                 case 1: return lóLépés(1, -2);
  496.                 case 2: return lóLépés(-1, 2);
  497.                 case 3: return lóLépés(-1, -2);
  498.                 case 4: return lóLépés(2, 1);
  499.                 case 5: return lóLépés(2, -1);
  500.                 case 6: return lóLépés(-2, 1);
  501.                 case 7: return lóLépés(-2, -1);
  502.                 default: return false;
  503.             }
  504.         }
  505.         public override int OperátorokSzáma() { return 8; }
  506.         // A kiíratásnál kivonom x-ből és y-ból a margó szélességét.
  507.         public override string ToString() { return (x - 2) + " : " + (y - 2); }
  508.         public override bool Equals(Object a)
  509.         {
  510.             ÉhesHuszárÁllapot aa = (ÉhesHuszárÁllapot)a;
  511.             return aa.x == x && aa.y == y;
  512.         }
  513.         // Ha két példány egyenlő, akkor a hasítókódjuk is egyenlő.
  514.         public override int GetHashCode()
  515.         {
  516.             return x.GetHashCode() + y.GetHashCode();
  517.         }
  518.     }
  519.     class SzerzetesekÉsKannibálokÁllapot : AbsztraktÁllapot
  520.     {
  521.         int sz; // ennyi szerzetes van összesen
  522.         int k; // ennyi kannibál van összesen
  523.         int szb; // szerzetesek száma a bal oldalon
  524.         int kb; // kannibálok száma a bal oldalon
  525.         char cs; // Hol a csónak? Értéke vagy 'B' vagy 'J'.
  526.         int szj; // szerzetesek száma a jobb oldalon
  527.         int kj; // kannibálok száma a jobb oldalon
  528.         public SzerzetesekÉsKannibálokÁllapot(int sz, int k) // beállítja a kezdő állapotot
  529.         {
  530.             this.sz = sz;
  531.             this.k = k;
  532.             szb = sz;
  533.             kb = k;
  534.             cs = 'B';
  535.             szj = 0;
  536.             kj = 0;
  537.         }
  538.         public override bool ÁllapotE()
  539.         { // igaz, ha a szerzetesek biztonságban vannak
  540.             return ((szb >= kb) || (szb == 0)) &&
  541.             ((szj >= kj) || (szj == 0));
  542.         }
  543.         public override bool CélÁllapotE()
  544.         {
  545.             // igaz, ha mindenki átért a jobb oldalra
  546.             return szj == sz && kj == k;
  547.         }
  548.         private bool preOp(int sz, int k)
  549.         {
  550.             // A csónak 2 személyes, legalább egy ember kell az evezéshez.
  551.             // Ezt végül is felesleges vizsgálni, mert a szuper operátor csak ennek megfelelően hívja.
  552.             if (sz + k > 2 || sz + k < 0 || sz < 0 || k < 0) return false;
  553.             // Csak akkor lehet átvinni sz szerzetest és
  554.             // k kannibált, ha a csónak oldalán van is legalább ennyi.
  555.             if (cs == 'B')
  556.                 return szb >= sz && kb >= k;
  557.             else
  558.                 return szj >= sz && kj >= k;
  559.         }
  560.         // Átvisz a másik oldalra sz darab szerzetes és k darab kannibált.
  561.         private bool op(int sz, int k)
  562.         {
  563.             if (!preOp(sz, k)) return false;
  564.             SzerzetesekÉsKannibálokÁllapot mentes = (SzerzetesekÉsKannibálokÁllapot)Clone();
  565.             if (cs == 'B')
  566.             {
  567.                 szb -= sz;
  568.                 kb -= k;
  569.                 cs = 'J';
  570.                 szj += sz;
  571.                 kj += k;
  572.             }
  573.             else
  574.             {
  575.                 szb += sz;
  576.                 kb += k;
  577.                 cs = 'B';
  578.                 szj -= sz;
  579.                 kj -= k;
  580.             }
  581.             if (ÁllapotE()) return true;
  582.             szb = mentes.szb;
  583.             kb = mentes.kb;
  584.             cs = mentes.cs;
  585.             szj = mentes.szj;
  586.             kj = mentes.kj;
  587.             return false;
  588.         }
  589.         public override int OperátorokSzáma() { return 5; }
  590.         public override bool SzuperOperátor(int i)
  591.         {
  592.             switch (i)
  593.             {
  594.                 case 0: return op(0, 1);
  595.                 case 1: return op(0, 2);
  596.                 case 2: return op(1, 1);
  597.                 case 3: return op(1, 0);
  598.                 case 4: return op(2, 0);
  599.                 default: return false;
  600.             }
  601.         }
  602.         public override string ToString()
  603.         {
  604.             return szb + "," + kb + "," + cs + "," + szj + "," + kj;
  605.         }
  606.         public override bool Equals(Object a)
  607.         {
  608.             SzerzetesekÉsKannibálokÁllapot aa = (SzerzetesekÉsKannibálokÁllapot)a;
  609.             // szj és kj számítható, ezért nem kell vizsgálni
  610.             return aa.szb == szb && aa.kb == kb && aa.cs == cs;
  611.         }
  612.         // Ha két példány egyenlő, akkor a hasítókódjuk is egyenlő.
  613.         public override int GetHashCode()
  614.         {
  615.             return szb.GetHashCode() + kb.GetHashCode() + cs.GetHashCode();
  616.         }
  617.     }
  618.     class Csúcs
  619.     {
  620.         // A csúcs tartalmaz egy állapotot, a mélységét és a szülőjét
  621.         AbsztraktÁllapot állapot;
  622.         int mélység;
  623.         Csúcs szülő; // A szülőkön felfelé haladva a start csúcsig jutok.
  624.                      // Konstruktor:
  625.                      // A belső állapotot beállítja a start csúcsra.
  626.                      // A hívó felelőssége, hogy a kezdő állapottal hívja meg.
  627.                      // A start csúcs mélysége 0, szülője nincs.
  628.         public Csúcs(AbsztraktÁllapot kezdőÁllapot)
  629.         {
  630.             állapot = kezdőÁllapot;
  631.             mélység = 0;
  632.             szülő = null;
  633.         }
  634.         // Egy új gyermek csúcsot készít.
  635.         // Erre még meg kell hívni egy alkalmazható operátor is, csak azután lesz kész.
  636.         public Csúcs(Csúcs szülő)
  637.         {
  638.             állapot = (AbsztraktÁllapot)szülő.állapot.Clone();
  639.             mélység = szülő.mélység + 1;
  640.             this.szülő = szülő;
  641.         }
  642.         public Csúcs GetSzülő() { return szülő; }
  643.         public int GetMélység() { return mélység; }
  644.         public bool TerminálisCsúcsE() { return állapot.CélÁllapotE(); }
  645.         public int OperátorokSzáma() { return állapot.OperátorokSzáma(); }
  646.         public bool SzuperOperátor(int i) { return állapot.SzuperOperátor(i); }
  647.         public override bool Equals(Object obj)
  648.         {
  649.             Csúcs cs = (Csúcs)obj;
  650.             return állapot.Equals(cs.állapot);
  651.         }
  652.         public override int GetHashCode() { return állapot.GetHashCode(); }
  653.         public override String ToString() { return állapot.ToString(); }
  654.         // Alkalmazza az összes alkalmazható operátort.
  655.         // Visszaadja az így előálló új csúcsokat.
  656.         public List<Csúcs> Kiterjesztes()
  657.         {
  658.             List<Csúcs> újCsúcsok = new List<Csúcs>();
  659.             for (int i = 0; i < OperátorokSzáma(); i++)
  660.             {
  661.                 // Új gyermek csúcsot készítek.
  662.                 Csúcs újCsúcs = new Csúcs(this);
  663.                 // Kiprobálom az i.dik alapoperátort. Alkalmazható?
  664.                 if (újCsúcs.SzuperOperátor(i))
  665.                 {
  666.                     // Ha igen, hozzáadom az újakhoz.
  667.                     újCsúcsok.Add(újCsúcs);
  668.                 }
  669.             }
  670.             return újCsúcsok;
  671.         }
  672.     }
  673.     abstract class GráfKereső
  674.     {
  675.         private Csúcs startCsúcs; // A start csúcs csúcs.
  676.                                   // Minden gráfkereső a start csúcsból kezd el keresni.
  677.         public GráfKereső(Csúcs startCsúcs)
  678.         {
  679.             this.startCsúcs = startCsúcs;
  680.         }
  681.         // Jobb, ha a start csúcs privát, de a gyermek osztályok lekérhetik.
  682.         protected Csúcs GetStartCsúcs() { return startCsúcs; }
  683.         /// Ha van megoldás, azaz van olyan út az állapottér gráfban,
  684.         /// ami a start csúcsból egy terminális csúcsba vezet,
  685.         /// akkor visszaad egy megoldást, egyébként null.
  686.         /// A megoldást egy terminális csúcsként adja vissza.
  687.         /// Ezen csúcs szülő referenciáin felfelé haladva adódik a megoldás fordított sorrendben.
  688.         public abstract Csúcs Keresés();
  689.         /// <summary>
  690.         /// Kiíratja a megoldást egy terminális csúcs alapján.
  691.         /// Feltételezi, hogy a terminális csúcs szülő referenciáján felfelé haladva eljutunk a start csúcshoz.
  692.         /// A csúcsok sorrendjét megfordítja, hogy helyesen tudja kiírni a megoldást.
  693.         /// Ha a csúcs null, akkor kiírja, hogy nincs megoldás.
  694.         /// </summary>
  695.         /// <param name="egyTerminálisCsúcs">
  696.         /// A megoldást képviselő terminális csúcs vagy null.
  697.         /// </param>
  698.         public void megoldásKiírása(Csúcs egyTerminálisCsúcs)
  699.         {
  700.             if (egyTerminálisCsúcs == null)
  701.             {
  702.                 Console.WriteLine("Nincs megoldás");
  703.                 return;
  704.             }
  705.             // Meg kell fordítani a csúcsok sorrendjét.
  706.             Stack<Csúcs> megoldás = new Stack<Csúcs>();
  707.             Csúcs aktCsúcs = egyTerminálisCsúcs;
  708.             while (aktCsúcs != null)
  709.             {
  710.                 megoldás.Push(aktCsúcs);
  711.                 aktCsúcs = aktCsúcs.GetSzülő();
  712.             }
  713.             // Megfordítottuk, lehet kiírni.
  714.             foreach (Csúcs akt in megoldás) Console.WriteLine(akt);
  715.         }
  716.     }
  717.     class BackTrack : GráfKereső
  718.     {
  719.         int korlát; // Ha nem nulla, akkor mélységi korlátos kereső.
  720.         bool emlékezetes; // Ha igaz, emlékezetes kereső.
  721.         public BackTrack(Csúcs startCsúcs, int korlát, bool emlékezetes) : base(startCsúcs)
  722.         {
  723.             this.korlát = korlát;
  724.             this.emlékezetes = emlékezetes;
  725.         }
  726.         // nincs mélységi korlát, se emlékezet
  727.         public BackTrack(Csúcs startCsúcs) : this(startCsúcs, 0, false) { }
  728.         // mélységi korlátos kereső
  729.         public BackTrack(Csúcs startCsúcs, int korlát) : this(startCsúcs, korlát, false) { }
  730.         // emlékezetes kereső
  731.         public BackTrack(Csúcs startCsúcs, bool emlékezetes) : this(startCsúcs, 0, emlékezetes) { }
  732.         // A keresés a start csúcsból indul.
  733.         // Egy terminális csúcsot ad vissza. A start csúcsból el lehet jutni ebbe a terminális csúcsba.
  734.         // Ha nincs ilyen, akkor null értéket ad vissza.
  735.         public override Csúcs Keresés() { return Keresés(GetStartCsúcs()); }
  736.         // A kereső algoritmus rekurzív megvalósítása.
  737.         // Mivel rekurzív, ezért a visszalépésnek a "return null" felel meg.
  738.         private Csúcs Keresés(Csúcs aktCsúcs)
  739.         {
  740.             int mélység = aktCsúcs.GetMélység();
  741.             // mélységi korlát vizsgálata
  742.             if (korlát > 0 && mélység >= korlát) return null;
  743.             // emlékezet használata kör kiszűréséhez
  744.             Csúcs aktSzülő = null;
  745.             if (emlékezetes) aktSzülő = aktCsúcs.GetSzülő();
  746.             while (aktSzülő != null)
  747.             {
  748.                 // Ellenőrzöm, hogy jártam-e ebben az állapotban. Ha igen, akkor visszalépés.
  749.                 if (aktCsúcs.Equals(aktSzülő)) return null;
  750.                 // Visszafelé haladás a szülői láncon.
  751.                 aktSzülő = aktSzülő.GetSzülő();
  752.             }
  753.             if (aktCsúcs.TerminálisCsúcsE())
  754.             {
  755.                 // Megvan a megoldás, vissza kell adni a terminális csúcsot.
  756.                 return aktCsúcs;
  757.             }
  758.             // Itt hívogatom az alapoperátorokat a szuper operátoron
  759.             // keresztül. Ha valamelyik alkalmazható, akkor új csúcsot
  760.             // készítek, és meghívom önmagamat rekurzívan.
  761.             for (int i = 0; i < aktCsúcs.OperátorokSzáma(); i++)
  762.             {
  763.                 // Elkészítem az új gyermek csúcsot.
  764.                 // Ez csak akkor lesz kész, ha alkalmazok rá egy alkalmazható operátort is.
  765.                 Csúcs újCsúcs = new Csúcs(aktCsúcs);
  766.                 // Kipróbálom az i.dik alapoperátort. Alkalmazható?
  767.                 if (újCsúcs.SzuperOperátor(i))
  768.                 {
  769.                     // Ha igen, rekurzívan meghívni önmagam az új csúcsra.
  770.                     // Ha nem null értéket ad vissza, akkor megvan a megoldás.
  771.                     // Ha null értéket, akkor ki kell próbálni a következő alapoperátort.
  772.                     //Console.WriteLine(újCsúcs.GetMélység());
  773.                     Csúcs terminális = Keresés(újCsúcs);
  774.                     if (terminális != null)
  775.                     {
  776.                         // Visszaadom a megoldást képviselő terminális csúcsot.
  777.                         return terminális;
  778.                     }
  779.                     // Az else ágon kellene visszavonni az operátort.
  780.                     // Erre akkor van szükség, ha az új gyermeket létrehozásában nem lenne klónozást.
  781.                     // Mivel klónoztam, ezért ez a rész üres.
  782.                 }
  783.             }
  784.             // Ha kipróbáltam az összes operátort és egyik se vezetett megoldásra, akkor visszalépés.
  785.             // A visszalépés hatására eggyel feljebb a következő alapoperátor kerül sorra.
  786.             return null;
  787.         }
  788.     }
  789.     class MélységiKeresés : GráfKereső
  790.     {
  791.         // Mélységi keresésnél érdemes a nyílt csúcsokat veremben tárolni,
  792.         // mert így mindig a legnagyobb mélységű csúcs lesz a verem tetején.
  793.         // Így nem kell külön keresni a legnagyobb mélységű nyílt csúcsot, amit ki kell terjeszteni.
  794.         Stack<Csúcs> Nyilt; // Nílt csúcsok halmaza.
  795.         List<Csúcs> Zárt; // Zárt csúcsok halmaza.
  796.         bool körFigyelés; // Ha hamis, végtelen ciklusba eshet.
  797.         public MélységiKeresés(Csúcs startCsúcs, bool körFigyelés) :
  798.         base(startCsúcs)
  799.         {
  800.             Nyilt = new Stack<Csúcs>();
  801.             Nyilt.Push(startCsúcs); // kezdetben csak a start csúcs nyílt
  802.             Zárt = new List<Csúcs>(); // kezdetben a zárt csúcsok halmaza üres
  803.             this.körFigyelés = körFigyelés;
  804.         }
  805.         // A körfigyelés alapértelmezett értéke igaz.
  806.         public MélységiKeresés(Csúcs startCsúcs) : this(startCsúcs, true) { }
  807.         // A megoldás keresés itt indul.
  808.         public override Csúcs Keresés()
  809.         {
  810.             // Ha nem kell körfigyelés, akkor sokkal gyorsabb az algoritmus.
  811.             if (körFigyelés) return TerminálisCsúcsKeresés();
  812.             return TerminálisCsúcsKeresésGyorsan();
  813.         }
  814.         private Csúcs TerminálisCsúcsKeresés()
  815.         {
  816.             // Amíg a nyílt csúcsok halmaza nem nem üres.
  817.             while (Nyilt.Count != 0)
  818.             {
  819.                 // Ez a legnagyobb mélységű nyílt csúcs.
  820.                 Csúcs C = Nyilt.Pop();
  821.                 // Ezt kiterjesztem.
  822.                 List<Csúcs> újCsucsok = C.Kiterjesztes();
  823.                 foreach (Csúcs D in újCsucsok)
  824.                 {
  825.                     // Ha megtaláltam a terminális csúcsot, akkor kész vagyok.
  826.                     if (D.TerminálisCsúcsE()) return D;
  827.                     // Csak azokat az új csúcsokat veszem fel a nyíltak közé,
  828.                     // amik nem szerepeltek még sem a zárt, sem a nyílt csúcsok halmazában.
  829.                     // A Contains a Csúcs osztályban megírt Equals metódust hívja.
  830.                     if (!Zárt.Contains(D) && !Nyilt.Contains(D)) Nyilt.Push(D);
  831.                 }
  832.                 // A kiterjesztett csúcsot átminősítem zárttá.
  833.                 Zárt.Add(C);
  834.             }
  835.             return null;
  836.         }
  837.         // Ezt csak akkor szabad használni, ha biztos, hogy az állapottér gráfban nincs kör!
  838.         // Különben valószínűleg végtelen ciklust okoz.
  839.         private Csúcs TerminálisCsúcsKeresésGyorsan()
  840.         {
  841.             while (Nyilt.Count != 0)
  842.             {
  843.                 Csúcs C = Nyilt.Pop();
  844.                 List<Csúcs> ujCsucsok = C.Kiterjesztes();
  845.                 foreach (Csúcs D in ujCsucsok)
  846.                 {
  847.                     if (D.TerminálisCsúcsE()) return D;
  848.                     // Ha nincs kör, akkor felesleges megnézni, hogy D volt-e már nyíltak vagy a zártak közt.
  849.                     Nyilt.Push(D);
  850.                 }
  851.                 // Ha nincs kör, akkor felesleges C-t zárttá minősíteni.
  852.             }
  853.             return null;
  854.         }
  855.     }
  856.     class Program
  857.     {
  858.         static void Main(string[] args)
  859.         {
  860.             Csúcs startCsúcs;
  861.             GráfKereső kereső;
  862.             Console.WriteLine("Luck7 megoldása.");
  863.             AbsztraktÁllapot k = new HuszárCsere();
  864.             startCsúcs = new Csúcs(k);
  865.  
  866.             //Console.WriteLine(k);
  867.             //bool b = k.SzuperOperátor(0);
  868.             //Console.WriteLine(b);
  869.             //Console.WriteLine(k);
  870.             //b = k.SzuperOperátor(0);
  871.             //Console.WriteLine(b);
  872.             //Console.WriteLine(k);
  873.             Console.WriteLine("A kereső egy 10 mélységi korlátos és emlékezetes backtrack.");
  874.             kereső = new BackTrack(startCsúcs, 10, true);
  875.             kereső.megoldásKiírása(kereső.Keresés());
  876.  
  877.             //Console.WriteLine("A kereső egy mélységi keresés körfigyeléssel.");
  878.             //kereső = new MélységiKeresés(startCsúcs, true);
  879.             //kereső.megoldásKiírása(kereső.Keresés());
  880.             //Console.WriteLine("A 3 szerzetes 3 kanibál problémát oldjuk meg.");
  881.             //startCsúcs = new Csúcs(new SzerzetesekÉsKannibálokÁllapot(3, 3));
  882.             //Console.WriteLine("A kereső egy 15 mélységi korlátos és emlékezetes backtrack.");
  883.             //kereső = new BackTrack(startCsúcs, 15, true);
  884.             //kereső.megoldásKiírása(kereső.Keresés());
  885.             //Console.WriteLine("A kereső egy mélységi keresés körfigyeléssel.");
  886.             //kereső = new MélységiKeresés(startCsúcs, true);
  887.             //kereső.megoldásKiírása(kereső.Keresés());
  888.  
  889.  
  890.  
  891.             Console.ReadLine();
  892.         }
  893.     }
  894. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement