Advertisement
csaki

HáromKancsóÁllapot

Feb 25th, 2014
158
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 11.00 KB | None | 0 0
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5.  
  6. namespace mesting_3kancso
  7. {
  8.     /// <summary>
  9.     /// Minden állapot osztály őse.
  10.     /// </summary>
  11.     abstract class AbsztraktÁllapot : ICloneable
  12.     {
  13.         public abstract bool ÁllapotE();
  14.  
  15.         public abstract bool CélÁllapotE();
  16.  
  17.         public abstract int OperátorokSzáma();
  18.  
  19.         // A szuper operátoron keresztül lehet elérni az összes operátort.
  20.         // Igazat ad vissza, ha az i. alap operátor alkalmazható a belső állapotra.
  21.         public abstract bool SzuperOperátor(int i);
  22.  
  23.         public virtual object Clone() { return MemberwiseClone(); }
  24.  
  25.         public override bool Equals(Object a) { return false; }
  26.  
  27.         public override int GetHashCode() { return base.GetHashCode(); }
  28.     }
  29.  
  30.  
  31.     /// <summary>
  32.     /// A csúcs tartalmaz egy állapotot, a csúcs mélységét, és a csúcs szülőjét.
  33.     /// Így egy csúcs egy egész utat reprezentál a start csúcsig.
  34.     /// </summary>
  35.     class Csúcs
  36.     {
  37.         // A csúcs tartalmaz egy állapotot, a mélységét és a szülőjét
  38.         AbsztraktÁllapot állapot;
  39.         int mélység;
  40.         Csúcs szülő; // A szülőkön felfelé haladva a start csúcsig jutok.
  41.         // Konstruktor:
  42.         // A belső állapotot beállítja a start csúcsra.
  43.         // A hívó felelőssége, hogy a kezdő állapottal hívja meg.
  44.         // A start csúcs mélysége 0, szülője nincs.
  45.         public Csúcs(AbsztraktÁllapot kezdőÁllapot)
  46.         {
  47.             állapot = kezdőÁllapot;
  48.             mélység = 0;
  49.             szülő = null;
  50.         }
  51.         // Egy új gyermek csúcsot készít.
  52.         // Erre még meg kell hívni egy alkalmazható operátor is, csak azután lesz kész.
  53.         public Csúcs(Csúcs szülő)
  54.         {
  55.             állapot = (AbsztraktÁllapot)szülő.állapot.Clone();
  56.             mélység = szülő.mélység + 1;
  57.             this.szülő = szülő;
  58.         }
  59.         public Csúcs GetSzülő() { return szülő; }
  60.         public int GetMélység() { return mélység; }
  61.         public bool TerminálisCsúcsE() { return állapot.CélÁllapotE(); }
  62.         public int OperátorokSzáma() { return állapot.OperátorokSzáma(); }
  63.         public bool SzuperOperátor(int i) { return állapot.SzuperOperátor(i); }
  64.         public override bool Equals(Object obj)
  65.         {
  66.             Csúcs cs = (Csúcs)obj;
  67.             return állapot.Equals(cs.állapot);
  68.         }
  69.         public override int GetHashCode() { return állapot.GetHashCode(); }
  70.         public override String ToString() { return állapot.ToString(); }
  71.         // Alkalmazza az összes alkalmazható operátort.
  72.         // Visszaadja az így előálló új csúcsokat.
  73.         public List<Csúcs> Kiterjesztes()
  74.         {
  75.             List<Csúcs> újCsúcsok = new List<Csúcs>();
  76.             for (int i = 0; i < OperátorokSzáma(); i++)
  77.             {
  78.                 // Új gyermek csúcsot készítek.
  79.                 Csúcs újCsúcs = new Csúcs(this);
  80.                 // Kiprobálom az i.dik alapoperátort. Alkalmazható?
  81.                 if (újCsúcs.SzuperOperátor(i))
  82.                 {
  83.                     // Ha igen, hozzáadom az újakhoz.
  84.                     újCsúcsok.Add(újCsúcs);
  85.                 }
  86.             }
  87.             return újCsúcsok;
  88.         }
  89.     }
  90.  
  91.     /// <summary>
  92.     /// Minden gráfkereső algoritmus őse.
  93.     /// A gráfkeresőknek csak a Keresés metódust kell megvalósítaniuk.
  94.     /// Ez visszaad egy terminális csúcsot, ha talált megoldást, egyébként null értékkel tér vissza.
  95.     /// A terminális csúcsból a szülő referenciákon felfelé haladva áll elő a megoldás.
  96.     /// </summary>
  97.     abstract class GráfKereső
  98.     {
  99.         private Csúcs startCsúcs; // A start csúcs csúcs.
  100.         // Minden gráfkereső a start csúcsból kezd el keresni.
  101.         public GráfKereső(Csúcs startCsúcs)
  102.         {
  103.             this.startCsúcs = startCsúcs;
  104.         }
  105.         // Jobb, ha a start csúcs privát, de a gyermek osztályok lekérhetik.
  106.         protected Csúcs GetStartCsúcs() { return startCsúcs; }
  107.         /// Ha van megoldás, azaz van olyan út az állapottér gráfban,
  108.         /// ami a start csúcsból egy terminális csúcsba vezet,
  109.         /// akkor visszaad egy megoldást, egyébként null.
  110.         /// A megoldást egy terminális csúcsként adja vissza.
  111.         /// Ezen csúcs szülő referenciáin felfelé haladva adódik a megoldás fordított sorrendben.
  112.         public abstract Csúcs Keresés();
  113.         /// <summary>
  114.         /// Kiíratja a megoldást egy terminális csúcs alapján.
  115.         /// Feltételezi, hogy a terminális csúcs szülő referenciáján felfelé haladva eljutunk a start csúcshoz.
  116.         /// A csúcsok sorrendjét megfordítja, hogy helyesen tudja kiírni a megoldást.
  117.         /// Ha a csúcs null, akkor kiírja, hogy nincs megoldás.
  118.         /// </summary>
  119.         /// <param name="egyTerminálisCsúcs">
  120.         /// A megoldást képviselő terminális csúcs vagy null.
  121.         /// </param>
  122.         public void megoldásKiírása(Csúcs egyTerminálisCsúcs)
  123.         {
  124.             if (egyTerminálisCsúcs == null)
  125.             {
  126.                 Console.WriteLine("Nincs megoldás");
  127.                 return;
  128.             }
  129.             // Meg kell fordítani a csúcsok sorrendjét.
  130.             Stack<Csúcs> megoldás = new Stack<Csúcs>();
  131.             Csúcs aktCsúcs = egyTerminálisCsúcs;
  132.             while (aktCsúcs != null)
  133.             {
  134.                 megoldás.Push(aktCsúcs);
  135.                 aktCsúcs = aktCsúcs.GetSzülő();
  136.             }
  137.             // Megfordítottuk, lehet kiírni.
  138.             foreach (Csúcs akt in megoldás) Console.WriteLine(akt);
  139.         }
  140.     }
  141.  
  142.     /// <summary>
  143.     /// A backtrack gráfkereső algoritmust megvalósító osztály.
  144.     /// A három alap backtrack algoritmust egyben tartalmazza. Ezek
  145.     /// - az alap backtrack
  146.     /// - mélységi korlátos backtrack
  147.     /// - emlékezetes backtrack
  148.     /// Az ág-korlátos backtrack nincs megvalósítva.
  149.     /// </summary>
  150.     class BackTrack : GráfKereső
  151.     {
  152.         int korlát; // Ha nem nulla, akkor mélységi korlátos kereső.
  153.         bool emlékezetes; // Ha igaz, emlékezetes kereső.
  154.         public BackTrack(Csúcs startCsúcs, int korlát, bool emlékezetes)
  155.             : base(startCsúcs)
  156.         {
  157.             this.korlát = korlát;
  158.             this.emlékezetes = emlékezetes;
  159.         }
  160.         // nincs mélységi korlát, se emlékezet
  161.         public BackTrack(Csúcs startCsúcs) : this(startCsúcs, 0, false) { }
  162.         // mélységi korlátos kereső
  163.         public BackTrack(Csúcs startCsúcs, int korlát) : this(startCsúcs, korlát, false) { }
  164.         // emlékezetes kereső
  165.         public BackTrack(Csúcs startCsúcs, bool emlékezetes) : this(startCsúcs, 0, emlékezetes) { }
  166.         // A keresés a start csúcsból indul.
  167.         // Egy terminális csúcsot ad vissza. A start csúcsból el lehet jutni ebbe a terminális csúcsba.
  168.         // Ha nincs ilyen, akkor null értéket ad vissza.
  169.         public override Csúcs Keresés() { return Keresés(GetStartCsúcs()); }
  170.         // A kereső algoritmus rekurzív megvalósítása.
  171.         // Mivel rekurzív, ezért a visszalépésnek a "return null" felel meg.
  172.         private Csúcs Keresés(Csúcs aktCsúcs)
  173.         {
  174.             int mélység = aktCsúcs.GetMélység();
  175.             // mélységi korlát vizsgálata
  176.             if (korlát > 0 && mélység >= korlát) return null;
  177.             // emlékezet használata kör kiszűréséhez
  178.             Csúcs aktSzülő = null;
  179.             if (emlékezetes) aktSzülő = aktCsúcs.GetSzülő();
  180.             while (aktSzülő != null)
  181.             {
  182.                 // Ellenőrzöm, hogy jártam-e ebben az állapotban. Ha igen, akkor visszalépés.
  183.                 if (aktCsúcs.Equals(aktSzülő)) return null;
  184.                 // Visszafelé haladás a szülői láncon.
  185.                 aktSzülő = aktSzülő.GetSzülő();
  186.             }
  187.             if (aktCsúcs.TerminálisCsúcsE())
  188.             {
  189.                 // Megvan a megoldás, vissza kell adni a terminális csúcsot.
  190.                 return aktCsúcs;
  191.             }
  192.             // Itt hívogatom az alapoperátorokat a szuper operátoron
  193.             // keresztül. Ha valamelyik alkalmazható, akkor új csúcsot
  194.             // készítek, és meghívom önmagamat rekurzívan.
  195.             for (int i = 0; i < aktCsúcs.OperátorokSzáma(); i++)
  196.             {
  197.                 // Elkészítem az új gyermek csúcsot.
  198.                 // Ez csak akkor lesz kész, ha alkalmazok rá egy alkalmazható operátort is.
  199.                 Csúcs újCsúcs = new Csúcs(aktCsúcs);
  200.                 // Kipróbálom az i.dik alapoperátort. Alkalmazható?
  201.                 if (újCsúcs.SzuperOperátor(i))
  202.                 {
  203.                     // Ha igen, rekurzívan meghívni önmagam az új csúcsra.
  204.                     // Ha nem null értéket ad vissza, akkor megvan a megoldás.
  205.                     // Ha null értéket, akkor ki kell próbálni a következő alapoperátort.
  206.                     Csúcs terminális = Keresés(újCsúcs);
  207.                     if (terminális != null)
  208.                     {
  209.                         // Visszaadom a megoldást képviselő terminális csúcsot.
  210.                         return terminális;
  211.                     }
  212.                     // Az else ágon kellene visszavonni az operátort.
  213.                     // Erre akkor van szükség, ha az új gyermeket létrehozásában nem lenne klónozást.
  214.                     // Mivel klónoztam, ezért ez a rész üres.
  215.                 }
  216.             }
  217.             // Ha kipróbáltam az összes operátort és egyik se vezetett megoldásra, akkor visszalépés.
  218.             // A visszalépés hatására eggyel feljebb a következő alapoperátor kerül sorra.
  219.             return null;
  220.         }
  221.     }
  222.  
  223.     struct Kancsó
  224.     {
  225.         public int Max;
  226.         public int Akt;
  227.     }
  228.  
  229.     class HáromKancsóÁllapot : AbsztraktÁllapot
  230.     {
  231.         Kancsó[] kancsók = new Kancsó[3];
  232.  
  233.         public HáromKancsóÁllapot()
  234.         {
  235.             kancsók[0].Max = 8;
  236.             kancsók[0].Akt = 8;
  237.             kancsók[1].Max = 5;
  238.             kancsók[1].Akt = 0;
  239.             kancsók[2].Max = 3;
  240.             kancsók[2].Akt = 0;
  241.         }
  242.  
  243.         public HáromKancsóÁllapot(HáromKancsóÁllapot másolandó)
  244.         {
  245.             kancsók[0].Max = másolandó.kancsók[0].Max;
  246.             kancsók[0].Akt = másolandó.kancsók[0].Akt;
  247.             kancsók[1].Max = másolandó.kancsók[1].Max;
  248.             kancsók[1].Akt = másolandó.kancsók[1].Akt;
  249.             kancsók[2].Max = másolandó.kancsók[2].Max;
  250.             kancsók[2].Akt = másolandó.kancsók[2].Akt;
  251.         }
  252.  
  253.         public override bool ÁllapotE()
  254.         {
  255.             return true;
  256.         }
  257.  
  258.         public override bool CélÁllapotE()
  259.         {
  260.             return kancsók[0].Akt == 4 || kancsók[1].Akt == 4 || kancsók[2].Akt == 4;
  261.         }
  262.  
  263.         public override int OperátorokSzáma()
  264.         {
  265.             return 6;
  266.         }
  267.  
  268.         public bool PreÁllapot(int honnan, int hova)
  269.         {
  270.             return honnan != hova && kancsók[honnan].Akt != 0 && kancsók[hova].Akt != kancsók[hova].Max;
  271.         }
  272.  
  273.         public override bool SzuperOperátor(int i)
  274.         {
  275.             switch (i)
  276.             {
  277.                 case 0: return Tölt(2, 1);
  278.                 case 1: return Tölt(2, 0);
  279.                 case 2: return Tölt(1, 0);
  280.                 case 3: return Tölt(1, 2);
  281.                 case 4: return Tölt(0, 1);
  282.                 case 5: return Tölt(0, 2);
  283.                 default: return false;
  284.             }
  285.         }
  286.         public bool Tölt(int honnan, int hova)
  287.         {
  288.             if (!PreÁllapot(honnan, hova)) return false;
  289.  
  290.             int szabad = kancsók[hova].Max - kancsók[hova].Akt;
  291.             if (kancsók[honnan].Akt < szabad)
  292.             {
  293.                 kancsók[hova].Akt += kancsók[honnan].Akt;
  294.                 kancsók[honnan].Akt = 0;
  295.             }
  296.             else
  297.             {
  298.                 kancsók[hova].Akt += szabad;
  299.                 kancsók[honnan].Akt -= szabad;
  300.             }
  301.  
  302.             return ÁllapotE();
  303.         }
  304.  
  305.         public override object Clone()
  306.         {
  307.             return new HáromKancsóÁllapot(this);
  308.         }
  309.  
  310.         public override string ToString()
  311.         {
  312.             StringBuilder sb = new StringBuilder();
  313.  
  314.             for (int i = 0; i < kancsók.Length; i++)
  315.             {
  316.                 sb.Append(String.Format("| {0}: {1} liter |", i+1, kancsók[i].Akt));
  317.             }
  318.  
  319.             return sb.ToString();
  320.         }
  321.     }
  322.  
  323.  
  324.     class Program
  325.     {
  326.         static void Main(string[] args)
  327.         {
  328.             Csúcs startCsúcs;
  329.             GráfKereső kereső;
  330.  
  331.             startCsúcs = new Csúcs(new HáromKancsóÁllapot());
  332.             kereső = new BackTrack(startCsúcs, 10, true);
  333.             kereső.megoldásKiírása(kereső.Keresés());
  334.  
  335.             Console.ReadLine();
  336.         }
  337.     }
  338. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement