Hledání min v konzoli

Hru Hledání min, jejíž zpracování pro WPF, jsem popsal nedávno, jsem z jinou skupinou vytvořil znovu, tentokrát jako konzolovou aplikaci. 

 

Oproti WPF nelze používat myš a souřadnice pro odkrytí pole se musí zadávat z klávesnice. Grafika také není zrovna ohromující, ale hrát se to dá...

Hledání min v konzolové aplikaci

Základní algoritmy zůstávají stejné. Většina jich byla popsána již v předchozím článku o WPF verzi, takže zde již pouze uvedu celý kód aplikace. Rozdíly budou popsány v komentářích.

class Program
{
    static Random random = new Random();
 
    static void Main(string[] args)
    {
        int n = 10, m = 10;          // Rozměry minového pole (N = řádky, M = sloupce)
        int pocetMin = 10;           // Počet min
        // 0 - nic, 1-8 číslo, 9 - mina, záporná verze čísla (pro 0 je -10) = odkryté pole
        int[,] miny = new int[n, m]; // Deklarace pole
 
        // Rozmístění min
        for (int k = 0; k < pocetMin; k++)
        {
            int i = random.Next(n);  // Náhodný řádek
            int j = random.Next(m);  // Náhodný sloupec
            while (miny[i, j] == 9)  // Je-li tam již jiná mina, vybrat jiné souřadnice
            {
                i = random.Next(n);
                j = random.Next(m);
            }
            miny[i, j] = 9;          // Umístění miny (9)
        }
 
        // Očíslování položek sousedících s minami
        for (int i = 0; i < n; i++)                            // Pro všechny řádky
            for (int j = 0; j < m; j++)                        // v každém sloupci
                if (miny[i, j] != 9)                           // není-li zde mina
                    for (int x = -1; x <= 1; x++)              // projít od pole o 1 vlevo do o 1 vpravo
                        for (int y = -1; y <= 1; y++)          // a také pro o 1 řádek nad až po 1 řádek pod
                            if (j + x >= 0 && i + y >= 0 &&    // nepřekročili-li se levé hranice plochy
                                j + x < m && i + y < n &&      // ani pravé hranice plochy
                                (x != 0 || y != 0))            // a aktuálně řešená buňka se nepočítá 
                                if (miny[i + y, j + x] == 9)   // je-li v sousedící buňce mina
                                    miny[i, j]++;              // zvýšit číslo v této buňky o +1
 
        VypisMinovePole(miny);
 
        short konec = 0;                   // -1 = prohra, +1 = výhra, 0 = hra pokračuje
        while (konec == 0)                 // Herní smyčka
        {
            int x = -1, y = -1;
            bool platneSouradnice = false; // Přáznak, byly-li zadány platné souřadnice
            while (!platneSouradnice)      // Opakování dokud nejsou zadány platné souřadnice 
                try
                {
                    Console.Write("X: ");
                    x = Convert.ToInt32(Console.ReadLine()); // X (index sloupce)
                    Console.Write("Y: ");
                    y = Convert.ToInt32(Console.ReadLine()); // Y (index řádku)
                    Console.WriteLine();
                    if (x >= 0 && x < m && y >= 0 && y < n)  // Ověření, jsou-li souřadnice v rozsahu pole
                        if (miny[y, x] >= 0)                 // Ověření, není-li na souřadnicích již odkryté pole
                            platneSouradnice = true;
                        else
                            Console.WriteLine("Pole na zadaných souřadnicích je již odkryto...");
                    else
                        Console.WriteLine("Byly zadány souřadnice mimo rozsah pole...");
                }
                catch {
                    Console.WriteLine("Souřadnice musí být platné celé číslo..."); // Zadáno neplatné číslo
                }
 
            // Odkrývání pole podle typu
            if (miny[y, x] == 9)                     // Mina = konec hry (prohra) a odkrytí všech polí
            {
                for (int i = 0; i < n; i++)
                    for (int j = 0; j < m; j++)
                        if (miny[i, j] >= 1 && miny[i, j] <= 9)
                            miny[i, j] *= -1;        // Odkrytí neprázdného pole 
                        else if (miny[i, j] == 0) 
                            miny[i, j] = -10;        // Odkrytí prázdného pole
                konec = -1;                          // Konec hry prohrou
            }
            else if (miny[y, x] >= 0)                // Prázdné pole či pole s číslem odkryje metoda Odkryj
                Odkryj(y, x, miny);
 
            VypisMinovePole(miny);                   // Vypsání nové podoby herní plochy
 
            // Ověření konce výhrou (jsou-li odkryta všechna pole kromě min)
            if (konec == 0)
                if (JeVseOdkryto(miny))
                    konec = 1;
        }                                            // Konec herní smyčky
 
        // Oznámení výhry či prohry
        if (konec < 0)
            Console.WriteLine("Prohál jsi!");
        else
            Console.WriteLine("Vyhrál jsi!");
 
        Console.ReadLine();
    }
  
    // Kontrola, jsou-li již všechna pole (kromě min) odkryta nebo ne
    static bool JeVseOdkryto(int[,] miny)
    {
        for (int i = 0; i < miny.GetLength(0); i++)
            for (int j = 0; j < miny.GetLength(1); j++)
                if (miny[i, j] >= 0 && miny[i, j] != 9)
                    return false;
        return true;
    }
   
    // Odkryje pole na zadaných souřadnicích a všechny jeho sousedy
    static void Odkryj(int i, int j, int[,] miny)
    {
        if (j >= 0 && i >= 0 &&
            j < miny.GetLength(1) && i < miny.GetLength(0)) // Jsou-li zadané souřadnice v ploše minového pole
            if (miny[i, j] == 0)                            // a je-li v daném poli prázdno a není dosud odkryto
            {
                miny[i, j] = -10;                           // Odkrytí pole
                // Odkrytí i všech sousedních polí rekurzivním voláním, jež odkryje i jejich sousední pole
                for (int x = -1; x <= 1; x++)               // Projít od pole o 1 vlevo do o 1 vpravo
                    for (int y = -1; y <= 1; y++)           // a také pro o 1 řádek nad až po 1 řádek pod
                        Odkryj(i + y, j + x, miny);         // toto pole odkrýt 
            }
            else
                if (miny[i, j] > 0 && miny[i, j] < 9)       // Není-li pole prázdné, odkrýt jej ale jeho sousedy již ne
                    miny[i, j] *= -1;                       // Odkrytí pole - nastavit mu jeho zápornou hodnotu
    }
   
    // Vypíše aktuální stav minového pole do konzolového výstupu
    static void VypisMinovePole(int[,] miny)
    {
        // Vypsání záhlaví sloupců
        int sirkaZnaku = miny.GetLength(1) > 10 ? 2 : 1;  // Je-li počet sloupců dvojciferné číslo, přidá mezeru před ta jednociferná
        Console.Write("   | ");
        for (int j = 0; j < miny.GetLength(1); j++)
            Console.Write("{0} ", j.ToString().PadLeft(sirkaZnaku));
        Console.WriteLine();
        Console.WriteLine("---+-".PadRight(miny.GetLength(1) * (sirkaZnaku + 1)+4, '-'));
        // Vypsání řádků
        for (int i = 0; i < miny.GetLength(0); i++)
        {
            // Vypsání sloupce s číslem řádku
            Console.Write("{0} |", i.ToString().PadLeft(2));
            if (sirkaZnaku > 1)
                Console.Write(" "); 
            // Vypsání minového pole
            for (int j = 0; j < miny.GetLength(1); j++)
            {
                Console.Write(" ");
                if (miny[i, j] >= 0)                              // Neodkryté pole
                    VypisZnakSBarvou('#', ConsoleColor.Black);
                else if (miny[i, j] == -10)                       // Prázdné odkryté pole 
                    VypisZnakSBarvou('0', ConsoleColor.DarkGray);
                else if (miny[i, j] == -9)                        // Odkrytá mina
                    VypisZnakSBarvou('X', ConsoleColor.Red);
                else                                              // Odkryté pole s číslem
                    VypisZnakSBarvou((-miny[i, j]).ToString()[0], ConsoleColor.DarkCyan);
                if (sirkaZnaku > 1)
                    Console.Write(" ");
            }
            Console.WriteLine();
        }
        Console.WriteLine();
    }
  
    // Vypíše do konzole jeden znak podbarvený zadanou barvou
    static void VypisZnakSBarvou(char znak, ConsoleColor barva)
    {
        Console.BackgroundColor = barva;              // Nastavení barvy pozadí
        Console.Write(znak);                          // Vypsání znaku
        Console.BackgroundColor = ConsoleColor.Black; // Vrácení barvy pozadí na černou
    }
}

 

 

on 19 březen 2014