keagle

Untitled

Apr 15th, 2013
44
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 15.80 KB | None | 0 0
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5.  
  6. namespace mestintApr15
  7. {
  8.     // Az AbsztraktÁllpot osztályt ki kellett bővíteni a GetHeurisztika metódussal.
  9.     // Egyébként megegyezik az előző fejezetben tárgyalt változattal.
  10.     abstract class AbsztraktÁllapot : ICloneable
  11.     {
  12.         public abstract bool ÁllapotE();
  13.         public abstract bool CélÁllapotE();
  14.         public abstract int OperátorokSzáma();
  15.         public abstract bool SzuperOperátor(int i);
  16.         public virtual object Clone() { return MemberwiseClone(); }
  17.         public override bool Equals(Object a) { return false; }
  18.         public override int GetHashCode() { return base.GetHashCode(); }
  19.         // Ez a metódus adja vissza, mennyire jó az adott állapot
  20.         // Ez csak egy hook, felül kell írni, ha
  21.         // kétszemélyes játékot vagy best-first algoritmus alkalmazunk,
  22.         // vagy bármilyen más algoritmust, ami heurisztikán alapszik.
  23.         // Más esetben, pl. backtrack esetén, nem kell felülírni.
  24.         public virtual int GetHeurisztika() { return 0; }
  25.     }
  26.  
  27.     class RokaKutyaJatek : AbsztraktÁllapot
  28.     {
  29.        
  30.         int rX, rY;
  31.         int[] kX, kY;
  32.         bool aRokaLep;
  33.  
  34.         //konstruktorral feltöltöm a táblát
  35.         public RokaKutyaJatek()
  36.         {
  37.             rX = 0;
  38.             rY = 2;
  39.             kX = new int[4];
  40.             kX[0] = 7;
  41.             kY[0] = 1;
  42.             kX[1] = 7;
  43.             kY[1] = 3;
  44.             kX[2] = 7;
  45.             kY[2] = 5;
  46.             kX[3] = 7;
  47.             kY[3] = 7;
  48.             aRokaLep = true;
  49.         }
  50.  
  51.         public override bool ÁllapotE()
  52.         {
  53.             return rX >= 0 && rX <= 7 && kX.Max() <= 7 && kX.Min() >= 0 && kY.Max() <= 7 && kY.Min() >= 0;
  54.         }
  55.         public override bool CélÁllapotE()
  56.         {
  57.             if (aRokaLep && rX >= kX.Max()) return true;
  58.             //if(!a mikor nyernek a kutyák
  59.             return false;
  60.         }
  61.         public override int OperátorokSzáma()
  62.         {
  63.             if (aRokaLep) return 4;
  64.             else return 8;
  65.         }
  66.         public override bool SzuperOperátor(int i)
  67.         {
  68.             if (aRokaLep)
  69.             {
  70.                 switch (i)
  71.                 {
  72.                     case 0: return rokaLepes(-1, -1);
  73.                     case 1: return rokaLepes(-1, 1);
  74.                     case 2: return rokaLepes(1, -1);
  75.                     case 3: return rokaLepes(1, 1);
  76.                     default: return false;
  77.                 }
  78.             }
  79.             else {
  80.                 switch(i)
  81.                 {
  82.                         case 0: return kutyaLepes(0,-1,-1);
  83.                         case 1: return kutyaLepes(0,-1,1);
  84.                         case 2: return kutyaLepes(1,-1,-1);
  85.                         case 3: return kutyaLepes(1,-1,1);
  86.                         case 4: return kutyaLepes(2, -1, -1);
  87.                         case 5: return kutyaLepes(2, -1, 1);
  88.                         case 6: return kutyaLepes(3, -1, -1);
  89.                         case 7: return kutyaLepes(3, -1, 1);
  90.                         default: return false;
  91.  
  92.                 }
  93.             }
  94.         }
  95.  
  96.         private bool rokaLepes(int relX, int relY)
  97.         {
  98.             if(preRokalepes(relX, relY);
  99.             {
  100.                 rX +=relX;
  101.                 rY += relY;
  102.                 aRokaLep = !aRokaLep;
  103.                 if(ÁllapotE()) return true;
  104.             }
  105.             return false;
  106.  
  107.         }
  108.         public override object Clone() { return MemberwiseClone(); }
  109.         public override bool Equals(Object a) { return false; }
  110.         public override int GetHashCode() { return base.GetHashCode(); }
  111.         public virtual int GetHeurisztika() { return 0; }
  112.        
  113.     }
  114.  
  115.    
  116.  
  117.     // Az előző fejezetben ismertetett Csúcs osztályt bővítettük
  118.     // egy-két metódussal, amely a két személyes játékok megvalósításához kell.
  119.     class Csúcs
  120.     {
  121.         AbsztraktÁllapot állapot;
  122.         int mélység;
  123.         Csúcs szülő;
  124.         // A szülőkön túl a gyermekeket is tartalmazza a Csúcs osztály.
  125.         List<Csúcs> gyermekek = new List<Csúcs>();
  126.         // Ez a mező tartalmazza, hogy melyik operátor segítségével jutottunk ebbe a csúcsba a szülő csúcsból.
  127.         // Ennek segítségével tudom megmondani, melyik az ajánlott lépés NegaMaxMódszer esetén.
  128.         int melyikOperátorralJutottamIde = -1; // ha -1, akkor még nincs beállítva
  129.         public Csúcs(AbsztraktÁllapot kezdőÁllapot)
  130.         {
  131.             állapot = kezdőÁllapot;
  132.             mélység = 0;
  133.             szülő = null;
  134.         }
  135.         public Csúcs(Csúcs szülő)
  136.         {
  137.             állapot = (AbsztraktÁllapot)szülő.állapot.Clone();
  138.             mélység = szülő.mélység + 1;
  139.             this.szülő = szülő;
  140.         }
  141.         // Erre a metódusra azért van szükség, hogy a kiterjesztés működjön a JátékCsúcsra is.
  142.         protected virtual Csúcs createGyermekCsúcs(Csúcs szülő) { return new Csúcs(szülő); }
  143.         public Csúcs GetSzülő() { return szülő; }
  144.         public int GetMélység() { return mélység; }
  145.         public bool TerminálisCsúcsE() { return állapot.CélÁllapotE(); }
  146.         public int OperátorokSzáma() { return állapot.OperátorokSzáma(); }
  147.         public bool SzuperOperátor(int i)
  148.         {
  149.             // megjegyzem, melyik operátorral jutottam ebbe az állapotba
  150.             melyikOperátorralJutottamIde = i;
  151.             return állapot.SzuperOperátor(i);
  152.         }
  153.         public override bool Equals(Object obj)
  154.         {
  155.             Csúcs cs = (Csúcs)obj;
  156.             return állapot.Equals(cs.állapot);
  157.         }
  158.         public override int GetHashCode() { return állapot.GetHashCode(); }
  159.         public override String ToString() { return állapot.ToString(); }
  160.         // Alkalmazza az összes alkalmazható operátort.
  161.         // Visszaadja az így előálló új csúcsokat.
  162.         public List<Csúcs> Kiterjesztés()
  163.         {
  164.             gyermekek = new List<Csúcs>();
  165.             for (int i = 0; i < OperátorokSzáma(); i++)
  166.             {
  167.                 // Új gyermek csúcsot készítek.
  168.                 // Ezzel a sorral nem működik a Kiterjesztés a JátékCsúcsban.
  169.                 // --- Csúcs újCsúcs = new Csúcs(this); ---
  170.                 // Ezért ezt használjuk:
  171.                 Csúcs újCsúcs = createGyermekCsúcs(this);
  172.                 // Kipróbálom az i.-dik alapoperátort. Alkalmazható?
  173.                 if (újCsúcs.SzuperOperátor(i))
  174.                 {
  175.                     // Ha igen, hozzáadom az újakhoz.
  176.                     gyermekek.Add(újCsúcs);
  177.                 }
  178.             }
  179.             return gyermekek;
  180.         }
  181.         // Visszaadja a csúcs heurisztikáját.
  182.         // Ha saját heurisztikát akarunk írni, akkor azt a saját állapot osztályunkba kell megírni.
  183.         public int GetHeurisztika() { return állapot.GetHeurisztika(); }
  184.         // Visszaadja melyik operátorral jutottunk ide.
  185.         // Ezzel az int értékkel kell majd meghívni a SzuperOperátor-t.
  186.         public int GetMelyikOperátorralJutottamIde() { return melyikOperátorralJutottamIde; }
  187.         // Nyomkövetéshez hasznos.
  188.         public void Kiir()
  189.         {
  190.             Console.WriteLine(this);
  191.             foreach (Csúcs gyermek in gyermekek) { gyermek.Kiir(); }
  192.         }
  193.     } // Ajáték csúcs acsúcs osztály kibővítése egy heurisztika értékkel.
  194.     // Ezt a fajta csúcsot fel lehet használni a best first algoritmushoz is.
  195.     class JátékCsúcs : Csúcs
  196.     {
  197.         int mennyireJó = -1; // mennyire jó, ha -1, akkor még nincs beállítva
  198.         // Konstruktor:
  199.         // A belső állapotot beállítja a start csúcsra.
  200.         // A hívó felelősége, hogy a kezdő állapottal hívja meg.
  201.         // A start csúcs mélysége 0, szülője nincs.
  202.         public JátékCsúcs(AbsztraktÁllapot kezdőÁllapot) :
  203.             base(kezdőÁllapot) { }
  204.         // Egy új gyermek csúcsot készít.
  205.         // Erre még meg kell hívni egy alkalmazható operátor is, csak azután lesz kész.
  206.         public JátékCsúcs(Csúcs szülő) : base(szülő) { }
  207.         // Erre a metódusra azért van szükség, hogy a kiterjesztés
  208.         // működjön a JátékCsúcsra is.
  209.         protected override Csúcs createGyermekCsúcs(Csúcs szülő)
  210.         {
  211.             return new JátékCsúcs(szülő);
  212.         }
  213.         // Visszaadja a csúcshoz tartozó heurisztikát.
  214.         // Ez a csúcsban lévő állapot heurisztikája
  215.         // megszorozva a paraméterben megkapott szor értékkel.
  216.         // NegaMax esetén a szor általában 1, ha az a játékos lép,
  217.         // akinek jó lépést keresünk, -1, ha az ellenfél lép.
  218.         // Mivel minden állapothoz csak egy heurisztika van, ami nem
  219.         // veszi figyelembe, hogy ki lép, ezért a MiniMax-nak is
  220.         // úgy kell használni ezt a metódust, mint a NegaMax-nak.
  221.         public int GetMennyireJó(int szor)
  222.         {
  223.             if (mennyireJó == -1) mennyireJó = GetHeurisztika() * szor;
  224.             return mennyireJó;
  225.         }
  226.     }
  227.     // Ebből kell leszármaztatni a lépés ajánló algoritmusokat, mint a NegaMax módszer.
  228.     abstract class Stratégia
  229.     {
  230.         // Ha a start csúcs zsákutca, akkor null-t ad vissza.
  231.         // Egyébként azt a csúcsot, amibe a stratégia szerint érdemes lépni.
  232.         public abstract JátékCsúcs MitLépjek(JátékCsúcs start);
  233.     } // Egy lépést ajánl valamely játékosnak a NegaMax módszer alapján.
  234.     // Ehhez előre tekint és a heurisztika meghatározása után megkeresi a legkedvezőbb utat a játék fában.
  235.     // Ha a játékfa levelei terminális csúcsok, akkor a legkedvezőbb út a nyerő stratégia lesz.
  236.     class NegaMaxMódszer : Stratégia
  237.     {
  238.         int maxMélység; // Ennyi lépésre tekintünk előre.
  239.         // Minél több lépésre tekintünk előre, annál intelligensebbnek tűnik a gép, hiszen jobb lépést választ.
  240.         // Ezt a TicTacToe esetén figyelhetjük meg.
  241.         // Ugyanakkor minél több lépést generálunk, annál lassabb lesz az algoritmus.
  242.         // Ennek egy megoldása az Alfabéta-vágás, de ezt nem programoztuk le.
  243.         public NegaMaxMódszer(int intelligencia) { maxMélység = intelligencia; }
  244.         // Egy játékcsúcsot ad vissza.
  245.         // Ennek a GetMelyikOperátorralJutottamIde() függvénye mondja meg,
  246.         // melyik lépést ajánlja a NegaMax módszer.
  247.         // Ha zsákutcában van, akkor null-t ad vissza.
  248.         public override JátékCsúcs MitLépjek(JátékCsúcs start)
  249.         {
  250.             Csúcs levél = MaxLépés(start, start.GetMélység() + maxMélység);
  251.             if (levél == start) return null;
  252.             while (levél.GetSzülő() != start) { levél = levél.GetSzülő(); }
  253.             //levél.Kiir(); // Nyomkövetés esetén hasznos segítség
  254.             return (JátékCsúcs)levél;
  255.         }
  256.         // Feltételezi, hogy a start csúcsban a kérdező játékos kérdezi, mit lépjen.
  257.         // A kérdező játékos legjobb lépését, tehát a legnagyobb heurisztikájú
  258.         // csúcs felé vezető lépést választja.
  259.         // A gyermek csúcsok heurisztikáját NegaMax módszerrel számoljuk.
  260.         private JátékCsúcs MaxLépés(JátékCsúcs start, int maxMélység)
  261.         {
  262.             JátékCsúcs akt = start;
  263.             if (akt.GetMélység() == maxMélység) { return akt; }
  264.             if (akt.TerminálisCsúcsE()) { return akt; }
  265.             List<Csúcs> gyermekek = null;
  266.             gyermekek = akt.Kiterjesztés();
  267.             if (gyermekek.Count == 0) { return akt; }
  268.             JátékCsúcs elsőGyermek = (JátékCsúcs)gyermekek[0];
  269.             JátékCsúcs leg = MinLépés(elsőGyermek, maxMélység);
  270.             int h = leg.GetMennyireJó(+1);
  271.             for (int i = 1; i < gyermekek.Count; i++)
  272.             {
  273.                 JátékCsúcs gyermek = (JátékCsúcs)gyermekek[i];
  274.                 JátékCsúcs legE = MinLépés(gyermek, maxMélység);
  275.                 int hE = legE.GetMennyireJó(+1);
  276.                 if (hE > h) { h = hE; leg = legE; }
  277.             }
  278.             return leg;
  279.         }
  280.         // Felételezi, hogy a start csúcsban a a kérdező játékos ellenfele lép.
  281.         // Az ellenfél játékos legjobb lépését választja, tehát azt,
  282.         // ami a kérdező játékosnak a legrosszabb.
  283.         // Egybe lehetne vonni a MaxLépéssel, hiszen csak 5 helyen más.
  284.         // Ezek a sorokat megjelöltük.
  285.         private JátékCsúcs MinLépés(JátékCsúcs start, int maxMélység)
  286.         {
  287.             JátékCsúcs akt = start;
  288.             if (akt.GetMélység() == maxMélység) { return akt; }
  289.             if (akt.TerminálisCsúcsE()) { return akt; }
  290.             List<Csúcs> gyermekek = null;
  291.             gyermekek = akt.Kiterjesztés();
  292.             if (gyermekek.Count == 0) { return akt; }
  293.             JátékCsúcs elsőGyermek = (JátékCsúcs)gyermekek[0];
  294.             JátékCsúcs leg = MaxLépés(elsőGyermek, maxMélység); //más
  295.             int h = leg.GetMennyireJó(-1); // más
  296.             for (int i = 1; i < gyermekek.Count; i++)
  297.             {
  298.                 JátékCsúcs gyermek = (JátékCsúcs)gyermekek[i];
  299.                 JátékCsúcs legE = MaxLépés(gyermek, maxMélység); //más
  300.                 int hE = legE.GetMennyireJó(-1); //más
  301.                 if (hE < h) { h = hE; leg = legE; } //más
  302.             }
  303.             return leg;
  304.         }
  305.     }
  306.  
  307.     // Egy játékot vezényel le.
  308.     // Ez egybevonható a főprogramból, hiszen abból emeltük ki.
  309.     class Játék
  310.     {
  311.         AbsztraktÁllapot startÁllapot;
  312.         Stratégia strat;
  313.         public Játék(AbsztraktÁllapot startÁllapot, Stratégia strat)
  314.         {
  315.             this.startÁllapot = startÁllapot;
  316.             this.strat = strat;
  317.         }
  318.         public void start()
  319.         {
  320.             JátékCsúcs akt = new JátékCsúcs(startÁllapot);
  321.             Console.WriteLine("Játszhat a gép ellen!");
  322.             while (!akt.TerminálisCsúcsE())
  323.             {
  324.                 // Ellenfél lépése.
  325.                 Console.WriteLine("Jelenlegi állás: {0}", akt);
  326.                 akt = strat.MitLépjek(akt);
  327.                 int i = akt.GetMelyikOperátorralJutottamIde();
  328.                 Console.WriteLine("A gép ezt az operátort választotta: {0}", i);
  329.                 // Nyertes állás?
  330.                 if (akt.TerminálisCsúcsE()) break;
  331.                 // Saját lépésem.
  332.                 bool b = false;
  333.                 while (!b)
  334.                 {
  335.                     Console.WriteLine("Jelenlegi állás: {0}", akt);
  336.                     Console.WriteLine("Melyik operátort választja? (0,..,{0}): ", akt.OperátorokSzáma() - 1);
  337.                     int k = 0;
  338.                     try
  339.                     {
  340.                         k = int.Parse(Console.ReadLine());
  341.                     }
  342.                     catch (Exception e)
  343.                     {
  344.                         Console.WriteLine("Hiba: {0}", e.ToString());
  345.                         Console.WriteLine("Érvénytelen lépés. Újra!");
  346.                         continue;
  347.                     }
  348.                     b = akt.SzuperOperátor(k);
  349.                     if (!b) Console.WriteLine("Ez az operátor nem alkalmazható. Újra!");
  350.                 }
  351.             }
  352.             Console.WriteLine("Jelenlegi állás: {0}", akt);
  353.             Console.WriteLine("Aki utoljára lépett, az nyert, vagy döntetlen.");
  354.         }
  355.     } // Főprogram.
  356.     class Program
  357.     {
  358.         static void Main(string[] args)
  359.         {
  360.  
  361.             Console.ReadLine();
  362.         }
  363.     }
  364. }
Advertisement
Add Comment
Please, Sign In to add comment