csaki

Mestint - Malom játék (félkész)

May 6th, 2014
314
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 27.29 KB | None | 0 0
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5.  
  6. namespace Malomjáték
  7. {
  8.     // Az AbsztraktÁllapot 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.         // Jobb állás esetén nagyobb számot kell visszaadnia.
  25.         public virtual int GetHeurisztika() { return 0; }
  26.     }
  27.  
  28.     class bábu
  29.     {
  30.         //a bábu neve
  31.         string _név;
  32.         public string név
  33.         {
  34.             get { return _név; }
  35.             set { _név = value; }
  36.         }
  37.  
  38.         //ebben tárolom, hogy a táblán a legbelső/középső/külső "négyzetben" helyezkedik-e el a bábu
  39.         int _négyzet;
  40.         public int négyzet
  41.         {
  42.             get { return _négyzet; }
  43.             set
  44.             {
  45.                 Console.WriteLine("A négyzet megváltozott!: {0} {1}", _név, value);
  46.                 _négyzet = value;
  47.             }
  48.         }
  49.         // 2 különleges érték:
  50.         //-1: még nincs a táblán
  51.         //                       -2: már nincs a táblán (leütötték)
  52.  
  53.  
  54.         //ebben pedig, hogy az adott "négyzeten" belül pontosan hanyadik mezőn a lehetséges 8-ból
  55.         int _pozíció;
  56.         public int pozíció
  57.         {
  58.             get { return _pozíció; }
  59.             set {
  60.                 Console.WriteLine("A pozíció megváltozott!: {0} {1}", _név, value);
  61.                 _pozíció = value;
  62.             }
  63.         }
  64.  
  65.         //ha 0 akkor fehér a bábu, ha 1 akkor pedig fekete
  66.         int _Szín;
  67.         public int Szín
  68.         {
  69.             get { return _Szín; }
  70.             set { _Szín = value; }
  71.         }
  72.  
  73.         public bábu(string p_név, int p_négyzet, int p_pozíció, int p_szín)
  74.         {
  75.             név = p_név;
  76.             négyzet = p_négyzet;
  77.             pozíció = p_pozíció;
  78.             Szín = p_szín;
  79.         }
  80.  
  81.     } //bábu class vége
  82.  
  83.     struct Indexpár
  84.     {
  85.         public int négyzetI, pozícióI;
  86.         public Indexpár(int négyzetindex, int pozícióindex)
  87.         {
  88.             négyzetI = négyzetindex;
  89.             pozícióI = pozícióindex;
  90.         }
  91.         public override bool Equals(object obj)
  92.         {
  93.             Indexpár pindex = (Indexpár)obj;
  94.             return pindex.négyzetI == négyzetI && pindex.pozícióI == pozícióI;
  95.         }
  96.     }
  97.  
  98.     class MalomÁllapot : AbsztraktÁllapot
  99.     {
  100.         public bábu[,] tábla = new bábu[3, 8];
  101.         public bábu[] fehérbábuk = new bábu[9];
  102.         public bábu[] feketebábuk = new bábu[9];
  103.         public bool fehérlép;
  104.         public int fehérBábukKézben, fehérBábukTáblán, feketeBábukKézben, feketeBábukTáblán;
  105.         public int fehérfázis, feketefázis;
  106.         public int fázis
  107.         {
  108.             set
  109.             {
  110.                 if (fehérlép) fehérfázis = value;
  111.                 else feketefázis = value;
  112.             }
  113.             get
  114.             {
  115.                 return fehérlép ? fehérfázis : feketefázis;
  116.             }
  117.         }
  118.  
  119.         public MalomÁllapot()
  120.         {
  121.             for (int i = 0; i < fehérbábuk.Length; i++)
  122.             {
  123.                 fehérbábuk[i] = new bábu(String.Format("wh{0}", i + 1), -1, -1, 0);
  124.             }
  125.             for (int i = 0; i < feketebábuk.Length; i++)
  126.             {
  127.                 feketebábuk[i] = new bábu(String.Format("bk{0}", i + 1), -1, -1, 1);
  128.             }
  129.             fehérBábukKézben = 9;
  130.             fehérBábukTáblán = 0;
  131.             feketeBábukKézben = 9;
  132.             feketeBábukTáblán = 0;
  133.             fehérlép = false;
  134.             fehérfázis = 1;
  135.             feketefázis = 1;
  136.         }
  137.  
  138.         public MalomÁllapot(MalomÁllapot másolandó)
  139.         {
  140.             tábla = (bábu[,])másolandó.tábla.Clone();
  141.             fehérbábuk = (bábu[])másolandó.fehérbábuk.Clone();
  142.             feketebábuk = (bábu[])másolandó.feketebábuk.Clone();
  143.             feketeBábukKézben = másolandó.feketeBábukKézben;
  144.             fehérBábukKézben = másolandó.fehérBábukKézben;
  145.             fehérfázis = másolandó.fehérfázis;
  146.             feketefázis = másolandó.feketefázis;
  147.             fehérlép = másolandó.fehérlép;
  148.         }
  149.  
  150.         public override bool ÁllapotE()
  151.         {
  152.             return true;
  153.         }
  154.  
  155.         public override bool CélÁllapotE()
  156.         {
  157.             return (fehérBábukKézben == 0 && fehérBábukTáblán == 2) || (feketeBábukKézben == 0 && feketeBábukTáblán == 2); // || nemtudlépni();
  158.         }
  159.  
  160.         //private bool nemtudlépni()
  161.         //{
  162.         //  return ;
  163.         //}
  164.  
  165.         public override int OperátorokSzáma()
  166.         {
  167.             // hány bábumvan (9)
  168.             // hány négyzetre tehetem le(3)
  169.             // egy adott négyzeten belül hány pozícióra tehetem le (8)
  170.             // az ellenfél hány bábuja közül vehetek le egyet (9)
  171.             return 9 * 3 * 8 * 9;
  172.         }
  173.  
  174.         public override bool SzuperOperátor(int i)
  175.         {
  176.             int bábuIndex = i / (3 * 8 * 9);
  177.             int maradék = i % (3 * 8 * 9);
  178.             int négyzetIndex = maradék / (8 * 9);
  179.             maradék = maradék % (8 * 8);
  180.             int pozícióIndex = maradék / 9;
  181.             maradék = maradék % 9;
  182.             int melyikBábutVeszemLeHaMalomIndex = maradék;
  183.  
  184.             return Lépés(bábuIndex, négyzetIndex, pozícióIndex, melyikBábutVeszemLeHaMalomIndex);
  185.         }
  186.  
  187.         private bool Lépés(int bábuIndex, int négyzetIndex, int pozícióIndex, int melyikBábutVeszemLe)
  188.         {
  189.             if (!preLépés(bábuIndex, négyzetIndex, pozícióIndex, melyikBábutVeszemLe)) return false;
  190.  
  191.             if (fehérlép)
  192.             {
  193.                 if (fázis == 1)
  194.                 {
  195.                     tábla[négyzetIndex, pozícióIndex] = fehérbábuk[bábuIndex];
  196.                     fehérbábuk[bábuIndex].négyzet = négyzetIndex;
  197.                     fehérbábuk[bábuIndex].pozíció = pozícióIndex;
  198.                     fehérBábukTáblán++;
  199.                     fehérBábukKézben--;
  200.                     //a fekete játékosnál váltunk fázist amint elfogytak a bábuk, mert ő az utolsó az első fázisban
  201.                 }
  202.                 else if (fázis == 2)
  203.                 {
  204.                     //lépünk a bábuval
  205.                     tábla[négyzetIndex, pozícióIndex] = fehérbábuk[bábuIndex];
  206.                     //üressé tesszük a mezőt, ahonnan elléptünk
  207.                     tábla[fehérbábuk[bábuIndex].négyzet, fehérbábuk[bábuIndex].pozíció] = null;
  208.                     //a bábu objektumban is beállítjuk, hogy épp melyik mezőre lépett
  209.                     fehérbábuk[bábuIndex].négyzet = négyzetIndex;
  210.                     fehérbábuk[bábuIndex].pozíció = pozícióIndex;
  211.  
  212.                     //megnézzük, hogy a lépés malmot eredményezett-e
  213.                     bool malomvan = malomvane(fehérbábuk[bábuIndex].négyzet, fehérbábuk[bábuIndex].pozíció);
  214.  
  215.                     //ha malom van, akkor bizony levehetünk egy fekete bábut, ami épp nincs malomban!
  216.                     if (malomvan)
  217.                     {
  218.                         //ha malom van, akkor bekérem, hogy mit akar leütni
  219.                         Console.WriteLine("Add meg, hogy melyik fekete bábut szeretnéd levenni (a nevét, és nem lehet épp malomban!):");
  220.                         string leütöttbábunév = Console.ReadLine();
  221.                         //megkeresem a táblán, hogy jó bábut adott-e meg, és azt tényleg le lehet-e ütni
  222.                         int leütöttbábuindex = -1;
  223.                         for (int i = 0; i < fehérbábuk.Length; i++)
  224.                         {
  225.                             if (leütöttbábunév == feketebábuk[i].név) leütöttbábuindex = i;
  226.                         }
  227.  
  228.                         if (leüthetőe(leütöttbábuindex))
  229.                         {
  230.                             //leütjük
  231.                             tábla[feketebábuk[leütöttbábuindex].négyzet, feketebábuk[leütöttbábuindex].pozíció] = null;
  232.                             feketebábuk[leütöttbábuindex].négyzet = -2;
  233.                             feketeBábukTáblán--;
  234.                             //majd megnézzük, hogy a leütést követően 3 bábuja lett-e, mert ha igen, akkor bizony átlépünk a 3. fázisba
  235.                             if (feketeBábukTáblán == 3) feketefázis = 3;
  236.                         }
  237.                     } //ha malomvan, akkor leüt egy bábut if vége
  238.                     //a lépés/leütés-t követően átadjuk a lépést
  239.                     fehérlép = false;
  240.                 }
  241.                 else if (fázis == 3)
  242.                 {
  243.  
  244.                 }
  245.             }
  246.  
  247.             else //tehát a fekete következik
  248.             {
  249.                 if (fázis == 1)
  250.                 {
  251.                     //letesszük az adott bábut
  252.                     tábla[négyzetIndex, pozícióIndex] = feketebábuk[bábuIndex];
  253.                     feketebábuk[bábuIndex].négyzet = négyzetIndex;
  254.                     feketebábuk[bábuIndex].pozíció = pozícióIndex;
  255.                     feketeBábukTáblán++;
  256.                     feketeBábukKézben--;
  257.                     //amint letette a fekete játékos is az utolsó bábuját, fázistváltunk
  258.                     if (feketeBábukKézben == 0 && fehérBábukKézben == 0)
  259.                     {
  260.                         feketefázis = 2;
  261.                         fehérfázis = 2;
  262.                     }
  263.                 }
  264.                 else if (fázis == 2)
  265.                 {
  266.                     //lépünk a bábuval
  267.                     tábla[négyzetIndex, pozícióIndex] = feketebábuk[bábuIndex];
  268.                     //üressé tesszük a mezőt, ahonnan elléptünk
  269.                     tábla[feketebábuk[bábuIndex].négyzet, feketebábuk[bábuIndex].pozíció] = null;
  270.                     //a bábu objektumban is beállítjuk, hogy épp melyik mezőre lépett
  271.                     feketebábuk[bábuIndex].négyzet = négyzetIndex;
  272.                     feketebábuk[bábuIndex].pozíció = pozícióIndex;
  273.  
  274.                     if (malomvane(feketebábuk[bábuIndex].négyzet, feketebábuk[bábuIndex].pozíció))
  275.                     {
  276.                         bool leüthető = leüthetőe(melyikBábutVeszemLe);
  277.                         if (leüthető)
  278.                         {
  279.                             tábla[fehérbábuk[melyikBábutVeszemLe].négyzet, fehérbábuk[melyikBábutVeszemLe].pozíció] = null;
  280.                             fehérbábuk[melyikBábutVeszemLe].négyzet = -2;
  281.                             fehérBábukTáblán--;
  282.                             //majd megnézzük, hogy a leütést követően 3 bábuja lett-e, mert ha igen, akkor bizony átlépünk a 3. fázisba
  283.                             if (fehérBábukTáblán == 3) fehérfázis = 3;
  284.                         }
  285.                     } //ha malomvan, akkor leüt egy bábut if vége
  286.                     //a lépés/leütés-t követően átadjuk a lépést
  287.                     fehérlép = true;
  288.                 }
  289.                 else if (fázis == 3)
  290.                 {
  291.  
  292.                 }
  293.  
  294.             }
  295.  
  296.             return ÁllapotE();
  297.         }
  298.  
  299.         private bool preLépés(int bábuIndex, int négyzetIndex, int pozícióIndex, int melyikBábutVeszemLe)
  300.         {
  301.  
  302.             if (fázis == 1)
  303.             {
  304.                 bool temp = (fehérlép ? fehérbábuk[bábuIndex].négyzet : feketebábuk[bábuIndex].négyzet) == -1 &&
  305.                     (fehérlép ? fehérbábuk[bábuIndex].pozíció : feketebábuk[bábuIndex].pozíció) == -1 &&
  306.                     tábla[négyzetIndex, pozícióIndex] == null;
  307.                 return temp;
  308.             }
  309.             else if (fázis == 2)
  310.             {
  311.                 var lista = szomszédosÜresMezők(fehérlép ? fehérbábuk[bábuIndex].négyzet : feketebábuk[bábuIndex].négyzet, fehérlép ? fehérbábuk[bábuIndex].pozíció : feketebábuk[bábuIndex].pozíció);
  312.                 return lista.Contains(new Indexpár(négyzetIndex, pozícióIndex));
  313.             }
  314.             else
  315.             {
  316.                 return tábla[négyzetIndex, pozícióIndex] == null;
  317.             }
  318.         }
  319.  
  320.         private List<Indexpár> szomszédosÜresMezők(int négyzetI, int pozícióI)
  321.         {
  322.             List<Indexpár> lista = new List<Indexpár>();
  323.             Indexpár indexek;
  324.             if (pozícióI % 1 == 1) // kereszteződés
  325.             {
  326.                 indexek.négyzetI = négyzetI;
  327.                 indexek.pozícióI = pozícióI - 1;
  328.                 if (tábla[indexek.négyzetI, indexek.pozícióI] == null)
  329.                     lista.Add(indexek);
  330.                 indexek.pozícióI = pozícióI == tábla.GetLength(1) - 1 ? 0 : pozícióI + 1;
  331.                 if (tábla[indexek.négyzetI, indexek.pozícióI] == null)
  332.                     lista.Add(indexek);
  333.                 indexek.pozícióI = pozícióI;
  334.                 if (négyzetI == 0 || négyzetI == 2)
  335.                 {
  336.                     indexek.négyzetI = 1;
  337.                     if (tábla[indexek.négyzetI, indexek.pozícióI] == null)
  338.                         lista.Add(indexek);
  339.                 }
  340.                 else
  341.                 {
  342.                     indexek.négyzetI = 0;
  343.                     if (tábla[indexek.négyzetI, indexek.pozícióI] == null)
  344.                         lista.Add(indexek);
  345.                     indexek.négyzetI = 2;
  346.                     if (tábla[indexek.négyzetI, indexek.pozícióI] == null)
  347.                         lista.Add(indexek);
  348.                 }
  349.             }
  350.             else // sarok
  351.             {
  352.                 indexek.négyzetI = négyzetI;
  353.                 indexek.pozícióI = pozícióI == 0 ? tábla.GetLength(1) - 1 : pozícióI + 1;
  354.                 if (tábla[indexek.négyzetI, indexek.pozícióI] == null)
  355.                     lista.Add(indexek);
  356.                 indexek.pozícióI = pozícióI + 1;
  357.                 if (tábla[indexek.négyzetI, indexek.pozícióI] == null)
  358.                     lista.Add(indexek);
  359.             }
  360.             return lista.Count > 0 ? lista : null;
  361.         }
  362.  
  363.         // A 8 mező egy ponttól indul és a négyzeten végighaladva a vonalán számlálja a pontokat.
  364.         // Hasznos, mert így minden második csomópont kereszteződés.
  365.         private bool malomvane(int négyzetI, int pozícióI)
  366.         {
  367.             if (pozícióI % 2 == 1) // Keresztezősédben van
  368.             {
  369.                 // valamelyik oldal, előtte és utána lévő elemeket vizsgálom.
  370.                 // ha a szín megegyezik, akkor malom (a tömb utolsó eleme külön kezelve, az őt követő elem a nulladik)
  371.                 if (tábla[négyzetI, pozícióI - 1].Szín == tábla[négyzetI, pozícióI].Szín &&
  372.                     tábla[négyzetI, pozícióI].Szín == tábla[négyzetI, pozícióI != tábla.GetLength(1) - 1 ? pozícióI + 1 : 0].Szín)
  373.                     return true;
  374.  
  375.                 // Ha nem oldalon van malom, akkor még a közbenső utakon is meg kell nézni a bábukat.
  376.                 // Függően attól, hogy hanyadik négyzeten van a bábu, beállítom az x-et, amit mindig hozzáadok a négyzetindexhez
  377.                 int x = 0;
  378.                 switch (pozícióI)
  379.                 {
  380.                     case 0: break;
  381.                     case 1: x--; break;
  382.                     case 2: x -= 2; break;
  383.                     default: return false;
  384.                 }
  385.                 return tábla[négyzetI + x, pozícióI].Szín == tábla[négyzetI + x + 1, pozícióI].Szín &&
  386.                     tábla[négyzetI + x + 1, pozícióI].Szín == tábla[négyzetI + x + 2, pozícióI].Szín;
  387.             }
  388.             else // Sarkon van
  389.             {
  390.                 // Előtte lévő bábun van azonos szín? Első elem külön kezelve
  391.                 if (tábla[négyzetI, pozícióI == 0 ? tábla.GetLength(1) - 1 : pozícióI - 1].Szín == tábla[négyzetI, pozícióI].Szín)
  392.                 {
  393.                     return tábla[négyzetI, pozícióI == 0 ? tábla.GetLength(1) - 2 : pozícióI - 2].Szín == tábla[négyzetI, pozícióI - 1].Szín;
  394.                 }
  395.                 // És az utánakövetkezőben?
  396.                 else if (tábla[négyzetI, pozícióI + 1].Szín == tábla[négyzetI, pozícióI].Szín)
  397.                 {
  398.                     return tábla[négyzetI, pozícióI + 2 == tábla.GetLength(1) ? 0 : pozícióI + 2].Szín == tábla[négyzetI, pozícióI + 1].Szín;
  399.                 }
  400.             }
  401.             return false;
  402.         }
  403.  
  404.         private bool leüthetőe(int bábuindex)
  405.         {
  406.             return !malomvane(fehérlép ? fehérbábuk[bábuindex].négyzet : feketebábuk[bábuindex].négyzet, fehérlép ? fehérbábuk[bábuindex].pozíció : feketebábuk[bábuindex].pozíció);
  407.         }
  408.         public override object Clone()
  409.         {
  410.             return new MalomÁllapot(this);
  411.         }
  412.     }
  413.  
  414.  
  415.  
  416.     class Csúcs
  417.     {
  418.         AbsztraktÁllapot állapot;
  419.         int mélység;
  420.         Csúcs szülő;
  421.         // A szülőkön túl a gyermekeket is tartalmazza a Csúcs osztály.
  422.         List<Csúcs> gyermekek = new List<Csúcs>();
  423.         // Ez a mező tartalmazza, hogy melyik operátor segítségével jutottunk ebbe a csúcsba a szülő csúcsból.
  424.         // Ennek segítségével tudom megmondani, melyik az ajánlott lépés NegaMaxMódszer esetén.
  425.         int melyikOperátorralJutottamIde = -1; // ha -1, akkor még nincs beállítva
  426.         public Csúcs(AbsztraktÁllapot kezdőÁllapot)
  427.         {
  428.             állapot = kezdőÁllapot;
  429.             mélység = 0;
  430.             szülő = null;
  431.         }
  432.         public Csúcs(Csúcs szülő)
  433.         {
  434.             állapot = (AbsztraktÁllapot)szülő.állapot.Clone();
  435.             mélység = szülő.mélység + 1;
  436.             this.szülő = szülő;
  437.         }
  438.         // Erre a metódusra azért van szükség, hogy a kiterjesztés működjön a JátékCsúcsra is.
  439.         protected virtual Csúcs createGyermekCsúcs(Csúcs szülő) { return new Csúcs(szülő); }
  440.         public Csúcs GetSzülő() { return szülő; }
  441.         public int GetMélység() { return mélység; }
  442.         public bool TerminálisCsúcsE() { return állapot.CélÁllapotE(); }
  443.         public int OperátorokSzáma() { return állapot.OperátorokSzáma(); }
  444.         public bool SzuperOperátor(int i)
  445.         {
  446.             // megjegyzem, melyik operátorral jutottam ebbe az állapotba
  447.             melyikOperátorralJutottamIde = i;
  448.             return állapot.SzuperOperátor(i);
  449.         }
  450.         public override bool Equals(Object obj)
  451.         {
  452.             Csúcs cs = (Csúcs)obj;
  453.             return állapot.Equals(cs.állapot);
  454.         }
  455.         public override int GetHashCode() { return állapot.GetHashCode(); }
  456.         public override String ToString() { return állapot.ToString(); }
  457.         // Alkalmazza az összes alkalmazható operátort.
  458.         // Visszaadja az így előálló új csúcsokat.
  459.         public List<Csúcs> Kiterjesztés()
  460.         {
  461.             gyermekek = new List<Csúcs>();
  462.             for (int i = 0; i < OperátorokSzáma(); i++)
  463.             {
  464.                 // Új gyermek csúcsot készítek.
  465.                 // Ezzel a sorral nem működik a Kiterjesztés a JátékCsúcsban.
  466.                 // --- Csúcs újCsúcs = new Csúcs(this); ---
  467.                 // Ezért ezt használjuk:
  468.                 Csúcs újCsúcs = createGyermekCsúcs(this);
  469.                 // Kipróbálom az i.-dik alapoperátort. Alkalmazható?
  470.                 if (újCsúcs.SzuperOperátor(i))
  471.                 {
  472.                     // Ha igen, hozzáadom az újakhoz.
  473.                     gyermekek.Add(újCsúcs);
  474.                 }
  475.             }
  476.             return gyermekek;
  477.         }
  478.         // Visszaadja a csúcs heurisztikáját.
  479.         // Ha saját heurisztikát akarunk írni, akkor azt a saját állapot osztályunkba kell megírni.
  480.         public int GetHeurisztika() { return állapot.GetHeurisztika(); }
  481.         // Visszaadja melyik operátorral jutottunk ide.
  482.         // Ezzel az int értékkel kell majd meghívni a SzuperOperátor-t.
  483.         public int GetMelyikOperátorralJutottamIde() { return melyikOperátorralJutottamIde; }
  484.         // Nyomkövetéshez hasznos.
  485.         public void Kiir()
  486.         {
  487.             Console.WriteLine(this);
  488.             foreach (Csúcs gyermek in gyermekek) { gyermek.Kiir(); }
  489.         }
  490.     } // A
  491.     // játék csúcs a
  492.     // csúcs osztály kibővítése egy heurisztika értékkel.
  493.     // Ezt a fajta csúcsot fel lehet használni a best first algoritmushoz is.
  494.     class JátékCsúcs : Csúcs
  495.     {
  496.         int mennyireJó = -1; // mennyire jó, ha -1, akkor még nincs beállítva
  497.         // Konstruktor:
  498.         // A belső állapotot beállítja a start csúcsra.
  499.         // A hívó felelősége, hogy a kezdő állapottal hívja meg.
  500.         // A start csúcs mélysége 0, szülője nincs.
  501.         public JátékCsúcs(AbsztraktÁllapot kezdőÁllapot) :
  502.             base(kezdőÁllapot) { }
  503.         // Egy új gyermek csúcsot készít.
  504.         // Erre még meg kell hívni egy alkalmazható operátor is, csak azután lesz kész.
  505.         public JátékCsúcs(Csúcs szülő) : base(szülő) { }
  506.         // Erre a metódusra azért van szükség, hogy a kiterjesztés
  507.         // működjön a JátékCsúcsra is.
  508.         protected override Csúcs createGyermekCsúcs(Csúcs szülő)
  509.         {
  510.             return new JátékCsúcs(szülő);
  511.         }
  512.         // Visszaadja a csúcshoz tartozó heurisztikát.
  513.         // Ez a csúcsban lévő állapot heurisztikája
  514.         // megszorozva a paraméterben megkapott szor értékkel.
  515.         // NegaMax esetén a szor általában 1, ha az a játékos lép,
  516.         // akinek jó lépést keresünk, -1, ha az ellenfél lép.
  517.         // Mivel minden állapothoz csak egy heurisztika van, ami nem
  518.         // veszi figyelembe, hogy ki lép, ezért a MiniMax-nak is
  519.         // úgy kell használni ezt a metódust, mint a NegaMax-nak.
  520.         public int GetMennyireJó(int szor)
  521.         {
  522.             if (mennyireJó == -1) mennyireJó = GetHeurisztika() * szor;
  523.             return mennyireJó;
  524.         }
  525.     }
  526.  
  527.     // Ebből kell leszármaztatni a lépés ajánló algoritmusokat, mint a NegaMax módszer.
  528.     abstract class Stratégia
  529.     {
  530.         // Ha a start csúcs zsákutca, akkor null-t ad vissza.
  531.         // Egyébként azt a csúcsot, amibe a stratégia szerint érdemes lépni.
  532.         public abstract JátékCsúcs MitLépjek(JátékCsúcs start);
  533.     } // Egy lépést ajánl valamely játékosnak a
  534.     // NegaMax módszer alapján.
  535.     // Ehhez előre tekint és a heurisztika meghatározása után megkeresi a legkedvezőbb utat a játék fában.
  536.     // Ha a játékfa levelei terminális csúcsok, akkor a legkedvezőbb út a nyerő stratégia lesz.
  537.     class NegaMaxMódszer : Stratégia
  538.     {
  539.         int maxMélység; // Ennyi lépésre tekintünk előre.
  540.         // 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.
  541.         // Ezt a TicTacToe esetén figyelhetjük meg.
  542.         // Ugyanakkor minél több lépést generálunk, annál lassabb lesz az algoritmus.
  543.         // Ennek egy megoldása az Alfabéta-vágás, de ezt nem programoztuk le.
  544.         public NegaMaxMódszer(int intelligencia) { maxMélység = intelligencia; }
  545.         // Egy játékcsúcsot ad vissza.
  546.         // Ennek a GetMelyikOperátorralJutottamIde() függvénye mondja meg,
  547.         // melyik lépést ajánlja a NegaMax módszer.
  548.         // Ha zsákutcában van, akkor null-t ad vissza.
  549.         public override JátékCsúcs MitLépjek(JátékCsúcs start)
  550.         {
  551.             Csúcs levél = MaxLépés(start, start.GetMélység() + maxMélység);
  552.             if (levél == start) return null;
  553.             while (levél.GetSzülő() != start) { levél = levél.GetSzülő(); }
  554.             //levél.Kiir(); // Nyomkövetés esetén hasznos segítség
  555.             return (JátékCsúcs)levél;
  556.         }
  557.         // Feltételezi, hogy a start csúcsban a kérdező játékos kérdezi, mit lépjen.
  558.         // A kérdező játékos legjobb lépését, tehát a legnagyobb heurisztikájú
  559.         // csúcs felé vezető lépést választja.
  560.         // A gyermek csúcsok heurisztikáját NegaMax módszerrel számoljuk.
  561.         private JátékCsúcs MaxLépés(JátékCsúcs start, int maxMélység)
  562.         {
  563.             JátékCsúcs akt = start;
  564.             if (akt.GetMélység() == maxMélység) { return akt; }
  565.             if (akt.TerminálisCsúcsE()) { return akt; }
  566.             List<Csúcs> gyermekek = null;
  567.             gyermekek = akt.Kiterjesztés();
  568.             if (gyermekek.Count == 0) { return akt; }
  569.             JátékCsúcs elsőGyermek = (JátékCsúcs)gyermekek[0];
  570.             JátékCsúcs leg = MinLépés(elsőGyermek, maxMélység);
  571.             int h = leg.GetMennyireJó(+1);
  572.             for (int i = 1; i < gyermekek.Count; i++)
  573.             {
  574.                 JátékCsúcs gyermek = (JátékCsúcs)gyermekek[i];
  575.                 JátékCsúcs legE = MinLépés(gyermek, maxMélység);
  576.                 int hE = legE.GetMennyireJó(+1);
  577.                 if (hE > h) { h = hE; leg = legE; }
  578.             }
  579.             return leg;
  580.         }
  581.         // Felételezi, hogy a start csúcsban a a kérdező játékos ellenfele lép.
  582.         // Az ellenfél játékos legjobb lépését választja, tehát azt,
  583.         // ami a kérdező játékosnak a legrosszabb.
  584.         // Egybe lehetne vonni a MaxLépéssel, hiszen csak 5 helyen más.
  585.         // Ezek a sorokat megjelöltük.
  586.         private JátékCsúcs MinLépés(JátékCsúcs start, int maxMélység)
  587.         {
  588.             JátékCsúcs akt = start;
  589.             if (akt.GetMélység() == maxMélység) { return akt; }
  590.             if (akt.TerminálisCsúcsE()) { return akt; }
  591.             List<Csúcs> gyermekek = null;
  592.             gyermekek = akt.Kiterjesztés();
  593.             if (gyermekek.Count == 0) { return akt; }
  594.             JátékCsúcs elsőGyermek = (JátékCsúcs)gyermekek[0];
  595.             JátékCsúcs leg = MaxLépés(elsőGyermek, maxMélység); //más
  596.             int h = leg.GetMennyireJó(-1); // más
  597.             for (int i = 1; i < gyermekek.Count; i++)
  598.             {
  599.                 JátékCsúcs gyermek = (JátékCsúcs)gyermekek[i];
  600.                 JátékCsúcs legE = MaxLépés(gyermek, maxMélység); //más
  601.                 int hE = legE.GetMennyireJó(-1); //más
  602.                 if (hE < h) { h = hE; leg = legE; } //más
  603.             }
  604.             return leg;
  605.         }
  606.     }
  607.  
  608.     // Egy játékot vezényel le.
  609.     // Ez egybevonható a főprogramból, hiszen abból emeltük ki.
  610.     class Játék
  611.     {
  612.         AbsztraktÁllapot startÁllapot;
  613.         Stratégia strat;
  614.         public Játék(AbsztraktÁllapot startÁllapot, Stratégia strat)
  615.         {
  616.             this.startÁllapot = startÁllapot;
  617.             this.strat = strat;
  618.         }
  619.         private int[] bekérés(MalomÁllapot akt)
  620.         {
  621.             if (akt.fázis == 1)
  622.             {
  623.                 Console.WriteLine("Fehér játékos, add meg, hogy hová szeretnéd a {0}. bábudat elhelyezni a táblán:", akt.fehérBábukTáblán + 1);
  624.                 Console.WriteLine("1: belső négyzet, 2: középső négyzet, 3: külső négyzet");
  625.                 int négyzet = int.Parse(Console.ReadLine());
  626.                 Console.WriteLine("Add meg a négyzeten belüli pozíciót (1-8 -- bal felső sarokból, óramutató járásával megegyező irányban növekszik):");
  627.                 int pozíció = int.Parse(Console.ReadLine());
  628.  
  629.                 int[] adatok = new int[4];
  630.                 adatok[0] = akt.fehérBábukTáblán; //bábu index (hanyadik báburól van szó, azaz amit majd lerakunk
  631.                 adatok[1] = négyzet - 1; //négyzet pozíció
  632.                 adatok[2] = pozíció - 1; //négyzeten belüli pozíció
  633.                 adatok[3] = 0;
  634.                 return adatok;
  635.             }
  636.  
  637.             else if (akt.fázis == 2)
  638.             {
  639.                 Console.WriteLine("Add meg a bábu nevét, amelyikkel lépni szeretnél (és tudsz is) :");
  640.                 string babunev = Console.ReadLine();
  641.                 Console.WriteLine("Add meg, hogy hova szeretnél lépni vele (négyzet, 1-3) :");
  642.                 int negyzet = int.Parse(Console.ReadLine());
  643.                 Console.WriteLine("Add meg, hogy hova szeretnél lépni vele (négyzeten belüli pozíció, 1-8) :");
  644.                 int pozicio = int.Parse(Console.ReadLine());
  645.  
  646.                 int babuindex = -1;
  647.                 for (int i = 0; i < akt.fehérbábuk.Length; i++)
  648.                 {
  649.                     if (babunev == akt.fehérbábuk[i].név) babuindex = i;
  650.                 }
  651.  
  652.                 int[] adatok = new int[4];
  653.                 adatok[0] = babuindex;
  654.                 adatok[1] = negyzet - 1;
  655.                 adatok[2] = pozicio - 1;
  656.                 adatok[3] = 0; // temporary
  657.                 return adatok;
  658.             }
  659.  
  660.             else if (akt.fázis == 3)
  661.             {
  662.                 Console.WriteLine("Add meg a bábu nevét, amelyikkel ugrani szeretnél egy tetszőleges mezőre (és tudsz is) :");
  663.                 string babunev = Console.ReadLine();
  664.                 Console.WriteLine("Add meg, hogy hova szeretnél ugrani vele (négyzet, 1-3) :");
  665.                 int negyzet = int.Parse(Console.ReadLine());
  666.                 Console.WriteLine("Add meg, hogy hova szeretnél ugrani vele (négyzeten belüli pozíció, 1-8) :");
  667.                 int pozicio = int.Parse(Console.ReadLine());
  668.  
  669.                 int babuindex = -1;
  670.                 for (int i = 0; i < akt.fehérbábuk.Length; i++)
  671.                 {
  672.                     if (babunev == akt.fehérbábuk[i].név) babuindex = i;
  673.                 }
  674.  
  675.                 int[] adatok = new int[4];
  676.                 adatok[0] = babuindex;
  677.                 adatok[1] = negyzet - 1;
  678.                 adatok[2] = pozicio - 1;
  679.                 adatok[3] = 0; // temporary
  680.                 return adatok;
  681.             }
  682.             return null;
  683.         } //bekérés függvény vége
  684.  
  685.  
  686.  
  687.         public void start()
  688.         {
  689.             JátékCsúcs akt = new JátékCsúcs(startÁllapot);
  690.             Console.WriteLine("Játszhat a gép ellen!");
  691.             while (!akt.TerminálisCsúcsE())
  692.             {
  693.                 // Ellenfél lépése.
  694.                 Console.WriteLine("Jelenlegi állás: {0}", akt);
  695.                 akt = strat.MitLépjek(akt);
  696.                 int i = akt.GetMelyikOperátorralJutottamIde();
  697.                 Console.WriteLine("A gép ezt az operátort választotta: {0}", i);
  698.                 // Nyertes állás?
  699.                 if (akt.TerminálisCsúcsE()) break;
  700.                 // Saját lépésem.
  701.                 bool b = false;
  702.                 while (!b)
  703.                 {
  704.                     Console.WriteLine("Jelenlegi állás: {0}", akt);
  705.                     Console.WriteLine("Melyik operátort választja? (0,..,{0}): ", akt.OperátorokSzáma() - 1);
  706.                     int k = akt.OperátorokSzáma() - 1;
  707.                     try
  708.                     {
  709.                         //k = int.Parse(Console.ReadLine());
  710.                         int[] tomb = bekérés(startÁllapot as MalomÁllapot);
  711.                         // a b c d - d + c*9 + b*8*9 + a*3*8*9
  712.                         k = tomb[0] * 3 * 8 * 9 + tomb[1] * 8 * 9 + tomb[2] * 9 + tomb[3];
  713.                     }
  714.                     catch (Exception e)
  715.                     {
  716.                         Console.WriteLine("Hiba: {0}", e.ToString());
  717.                         Console.WriteLine("Érvénytelen lépés. Újra!");
  718.                         continue;
  719.                     }
  720.                     b = akt.SzuperOperátor(k);
  721.                     if (!b) Console.WriteLine("Ez az operátor nem alkalmazható. Újra!");
  722.                 }
  723.             }
  724.             Console.WriteLine("Jelenlegi állás: {0}", akt);
  725.             Console.WriteLine("Aki utoljára lépett, az nyert, vagy döntetlen.");
  726.         }
  727.     }
  728.  
  729.     // Főprogram.
  730.     class Program
  731.     {
  732.         static void Main(string[] args)
  733.         {
  734.             Stratégia stratégia = new NegaMaxMódszer(5); // 5 mélységbe tekint előre
  735.  
  736.             //AbsztraktÁllapot startFejben21Állapot = new Fejben21Állapot();
  737.             //Játék fejben21 = new Játék(startFejben21Állapot, strat);
  738.             //Console.WriteLine("A Fejben 21 játék kezdetét veszi!");
  739.             //fejben21.start();
  740.             //Console.ReadLine();
  741.  
  742.             var startMalomÁllapot = new MalomÁllapot();
  743.             var malom = new Játék(startMalomÁllapot, stratégia);
  744.             malom.start();
  745.             Console.ReadLine();
  746.         }
  747.     }
  748. }
Advertisement
Add Comment
Please, Sign In to add comment