// project created on 02.12.2005 at 23:00
#define DEBUG_THE_HELL_OUT_OF_IT
using System;

class MainClass
{

    // das kann sich aendern (harharhar...)
    const int ANZAHL_SPIELER     =   2;
    // Feldgroesse ast auch variabel, aber quadratisch bleibts...
    const int SPIELFELD_SCHRITTE = 25;
    // geforderter Mindestabstand vom Spielfeldrand zum Programmstart
    const int MIN_RAND_ABSTAND = 5;
    // geforderter Mindestabstand der Spieler zum Programmstart
    const int MIN_SPIELER_ABSTAND = 10;
    // Mindestnaehe fuer Spielende
    const int GEWINN_ABSTAND = 2;
    
    // unser Enumerationstyp fuer die Himmelsrichtungen und Infos
    enum Richtung {Keine, Raus, Nord, Ost, Sued, West};

    // unser Enumerationstyp fuer die Bewegungs-Returns
    enum MoveReturn {OK, Warnung, Plumps};
    
//***********************************************************************************
    // Unser Hauptprogramm
    public static void Main(string[] args)
        {
        // Koordinaten der Spieler: haesslich modelliert, aber sehr prozedural(!)
        int[] anSpielerX = new int [ANZAHL_SPIELER];
        int[] anSpielerY = new int [ANZAHL_SPIELER];
    
        Console.Write("\n\f");
        Console.WriteLine("*************************");
        Console.WriteLine("*** Die blinden Kühe! ***");
        Console.WriteLine("***       oder        ***");
        Console.WriteLine("***   Darkroom 2005   ***");
        Console.WriteLine("*************************\n");
        
        // jetzt kann das Spiel beginnen
        
        int nAktuellerSpieler = 0;
        int nVersuche         = 0;
        int nAbstand;
        
        // Methode fuer Faule. So lange neue Positionen berechnen, bis der Abstand gross genug ist.
        do 
            {
            SpielerPositionenBelegen(ref anSpielerX, ref anSpielerY);
        
            // Abstand des aktuellen Spielers vorab berechnen...
            nAbstand = SpielerAbstandBerechnen(nAktuellerSpieler, ref anSpielerX, ref anSpielerY);
            }
        while (nAbstand < MIN_SPIELER_ABSTAND);
        
        do
            {
            Richtung eAktuelleRichtung;
            MoveReturn eMoveRet;

#if DEBUG_THE_HELL_OUT_OF_IT        
        Console.WriteLine("Spieler 1 auf {0} / {1}", anSpielerX[0], anSpielerY[0]);
        Console.WriteLine("Spieler 2 auf {0} / {1}", anSpielerX[1], anSpielerY[1]);
#endif      
            Console.WriteLine("Der Abstand zum nächsten Spieler beträgt {0} Schritte", nAbstand);
                    
            eAktuelleRichtung = SchrittRichtungWaehlen(nAktuellerSpieler, 
                                                       ref anSpielerX, ref anSpielerY);
            
            // mit "q" gehts raus
            if (Richtung.Raus == eAktuelleRichtung)
                break;
            
            // dann wirlkich "gehen"                                           
            eMoveRet = SchrittInRichtungGehen(eAktuelleRichtung, nAktuellerSpieler, ref anSpielerX, ref anSpielerY);
            
            // if-else-if weil in einem switch der break nicht wie benoetigt funktioniert.
            if (MoveReturn.Warnung == eMoveRet)
                {
                Console.WriteLine("\n!!! WARNUNG Spieler {0}: Spielfeldrand erreicht !!!\n",
                                  nAktuellerSpieler);
                }
            else if (MoveReturn.Plumps == eMoveRet)
                {
                Console.WriteLine("*** Sorry, Spieler {0}, Du bist von der Erdscheibe gefallen!",
                                  nAktuellerSpieler);
                break;
                }
            
            // dann zuletzt den Abstand nachrechnen
            nAbstand = SpielerAbstandBerechnen(nAktuellerSpieler, ref anSpielerX, ref anSpielerY);

            // stylishes inkrement mit wrap
            if (++nAktuellerSpieler >= ANZAHL_SPIELER)
                nAktuellerSpieler = 0;
            
            nVersuche++;
            }
        while (nAbstand > GEWINN_ABSTAND);

// Das Spiel ist aus        
        // das if() muss aufgrund des break in der Schleife sein.
        if (nAbstand <= GEWINN_ABSTAND)
            Console.WriteLine("\n\n********* Ihr habt Euch nach {0} Versuchen gefunden! ***********", nVersuche);
        else
            Console.WriteLine("\n\n********* GAME OVER ***********");
        }
    
//***********************************************************************************
// Zufallspositionen fuer alle Spieler

    static void SpielerPositionenBelegen(ref int[] anX, ref int[] anY)
        {
        Random rndGen = new Random();
        
        // hier geht foreach net, weil wir schreibend zugreifen wollen.
        for (int i = 0; i < anX.Length; i++)
            {
            // wir "hoffen", dass das Y-Array gleich gross ist
            // die while() Bedingung ist ein Beispiel für vollstaendige Klammerung
            do
                {
                anX[i] = rndGen.Next(SPIELFELD_SCHRITTE);
                }
            while ((anX[i] < MIN_RAND_ABSTAND) || (anX[i] > (SPIELFELD_SCHRITTE - MIN_RAND_ABSTAND - 1)));

            do
                {
                anY[i] = rndGen.Next(SPIELFELD_SCHRITTE);
                }
            while ((anY[i] < MIN_RAND_ABSTAND) || (anY[i] > (SPIELFELD_SCHRITTE - MIN_RAND_ABSTAND - 1)));
            }
        }

//***********************************************************************************
// Abstand des Spielers von naehesten Kollegen

    static int SpielerAbstandBerechnen(int nSpieler, ref int[] anX, ref int[] anY)
        {
        int nMinAbstand = int.MaxValue; 
        
        // derzeit gibts nur zwei Spieler
        for (int i = 0; i < anX.Length; i++)
            {
            // mit mir selber brauch ich nicht zu vergleichen...
            if (i != nSpieler)
                {
                int nAbstand = (anX[i]-anX[nSpieler]) * (anX[i]-anX[nSpieler])
                             + (anY[i]-anY[nSpieler]) * (anY[i]-anY[nSpieler]);
                // das ist luxus. man koennte auch mit abstandsquadraten arbeiten...
                nAbstand = Convert.ToInt32(Math.Sqrt(nAbstand));
                
                if (nAbstand < nMinAbstand)
                     nMinAbstand = nAbstand;
                }
            }
        return nMinAbstand;
        }

//***********************************************************************************
// Menue fuer Richtungswahl und Beenden
    
    static Richtung SchrittRichtungWaehlen(int nSpieler, ref int[] anX, ref int[] anY)
        {
        Richtung eRichtung;
        
        do
            {
            Console.Write("Spieler {0}, welche Richtung wählst Du? ", nSpieler+1);
            
            string strRichtung = Console.ReadLine();
            
            switch (strRichtung)
                {
                case "n":
                case "N":
                    eRichtung = Richtung.Nord;
                    break;

                case "o":
                case "O":
                    eRichtung = Richtung.Ost;
                    break;
                    
                case "s":
                case "S":
                    eRichtung = Richtung.Sued;
                    break;
                    
                case "w":
                case "W":
                    eRichtung = Richtung.West;
                    break;

                case "q":
                case "Q":
                    eRichtung = Richtung.Raus;
                    break;

                default:
                    Console.WriteLine("Gültige Richtungen sind: N, O, S, W");
                    eRichtung = Richtung.Keine;
                    break;
                }
            }
        while (Richtung.Keine == eRichtung);            
        
        return eRichtung;
        }

//***********************************************************************************
// Einen Schritt machen. Unser Koordinatensystem ist mathematisch Q1 => Y+ ist Nord und X+ ist Ost
// return kann OK, Warnung oder Plumps sein. Warnung bei Erreichen des Randes, Plumps bei Überschreiten.

    static MoveReturn SchrittInRichtungGehen(Richtung eRichtung, int nSpieler, ref int[] anX, ref int[] anY)
        {
        MoveReturn eMoveRet = MoveReturn.OK; 
        
        switch (eRichtung)
            {
            case Richtung.Nord:
                anY[nSpieler]++;
                if (anY[nSpieler] >= (SPIELFELD_SCHRITTE - 1))
                    if (anY[nSpieler] == (SPIELFELD_SCHRITTE - 1))
                        eMoveRet = MoveReturn.Warnung;
                    else
                        eMoveRet = MoveReturn.Plumps;
                break;

            case Richtung.Sued:
                anY[nSpieler]--;
                if (anY[nSpieler] <= 0)
                    if (anY[nSpieler] == 0)
                        eMoveRet = MoveReturn.Warnung;
                    else
                        eMoveRet = MoveReturn.Plumps;
                break;

            case Richtung.Ost:
                anX[nSpieler]++;
                if (anX[nSpieler] >= (SPIELFELD_SCHRITTE - 1))
                    if (anX[nSpieler] == (SPIELFELD_SCHRITTE - 1))
                        eMoveRet = MoveReturn.Warnung;
                    else
                        eMoveRet = MoveReturn.Plumps;
                break;                  
                
            case Richtung.West:
                anX[nSpieler]--;
                if (anX[nSpieler] <= 0)
                    if (anX[nSpieler] == 0)
                        eMoveRet = MoveReturn.Warnung;
                    else
                        eMoveRet = MoveReturn.Plumps;
                break;
            }
            
        return eMoveRet;
        }

} // class

syntax highlighted by Code2HTML, v. 0.9.1