C# :: Aufgabe #217 :: Lösung #1

4 Lösungen Lösungen öffentlich
#217

Programmierung von MasterMind

Anfänger - C# von hollst - 02.07.2018 um 10:54 Uhr
MasterMind ist ein deduktives Spiel, das insbesondere Anfang der 70er Jahre sehr beliebt war.
Ziel des Spiels ist es, einen Geheimcode zu entschlüsseln.

In der klassischen Variante ordnet ein Spieler, genannt "codemaker", eine Sequenz von vier Symbolen
geheim an. Praktisch geschieht dies mittels unterschiedlich oder teilweise bzw. gänzlich
gleich gefärbter Pins oder Murmeln in einer Reihe, wobei maximal sechs Farben zur Verfügung stehen.

Ein zweiter Spieler, genannt "codebreaker", versucht durch Testmuster, gleichfalls bestehend aus vier gereihten
Symbolen (Pins/Murmeln), den Code zu erraten. Hätte der codebreaker 6 * 6 * 6 * 6 = 1.296 Versuche zur Verfügung,
wäre dies kein Problem, allerdings wird die Anzahl der Tests als Spielregel auf zwölf (manchmal weniger) begrenzt.

Als Responds auf ein Testmuster muss der codemaker zwei Informationen geben:

1.) Wieviele Symbole im Testmuster stehen an exakt der gleicher Stelle wie im Geheimmuster (im Falle vier, wäre das
Spiel für den codebreaker gewonnen) und
2.) wieviele Symbole (Pin-/Murmelfarben) sind sowohl im Geheim- als auch im Testmuster
vorhanden, allerdings nicht in übereinstimmender Position in der Reihe.

Die Programmieraufgabe bestehe nun darin, MasterMind interaktiv am PC zu simulieren, wobei der Computer als
codemaker fungiert, der zunächst per Zufallsgenerator das Geheimmuster erzeugt. Anschließend sind sukzessive
maximal zwölf Testmuster vom codebreaker (User) einzugeben und vom codemaker jeweils die zwei Fagen zu beantworten.


Anmerkung: MasterMind wurde auch von Mathematikern unter die Lupe genommen und bereits Mitte/Ende der 70er Jahre konnte
bewiesen werden, dass man es mit maximal fünf Testmustern lösen kann, sehr erstaunlich, oder? Daraufhin wurde
SuperMasterMind vorgeschlagen. Unterschied: Reihen mit fünf Symbolen und acht unterschiedlichen Pin-/Murmelfarben.

Wer MasterMind lediglich als schöne Spielerei ansieht, überlege bitte folgendes: Seit 1971 (release)
wurden bisher pro Jahr im Durchschnitt eine Million Spiele weltweit verkauft. Wärest Du der Erfinder und bekämest
als Lizenzgeber pro Exemplar 10 Cent, Du hättest finanziell ausgesorgt.
#1
vote_ok
von DBqFetti (2480 Punkte) - 05.07.2018 um 11:31 Uhr
Quellcode ausblenden C#-Code
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace TYP217 {
  enum Color { Red, Blue, Yellow, Green, White, Magenta, Cyan, DarkCyan }

  class Program {
    static readonly int[] colorMap = new int[] {
      (int)ConsoleColor.Red, (int)ConsoleColor.Blue, (int)ConsoleColor.Yellow,
      (int)ConsoleColor.Green, (int)ConsoleColor.White, (int)ConsoleColor.Magenta,
      (int)ConsoleColor.Cyan, (int)ConsoleColor.DarkCyan
    };
    static readonly Color maxC = (Color)6; //Enum.GetValues(typeof(Color)).Cast<Color>().Max();
    const int codeLength = 4;
    const char colorChar = (char)219;

    static void Main() {
      Console.OutputEncoding = Encoding.GetEncoding(1252);
      Console.Clear();
      Console.Write((new StringBuilder()).Append("\n-").Append('-', codeLength * 3));

      Color[] input = null;
      Color[] code = GetCode();

      for(int round = 0; round < 16; round++) {
        input = ReadInput(round, input);
        int same = CountSamePos(code, input);
        if(codeLength == same) {
          DrawHint(round, same, 0);
          break;
        }
        
        int diff = CountDiffPos(code, input);
        DrawHint(round, same, diff);
      }

      DrawCode(code);
      Console.ReadKey(true);
    }

    static Color[] ReadInput(int round, Color[] colors = null) {
      Color[] input = new Color[codeLength];
      Console.CursorTop = 17 - round;
      Console.CursorLeft = 0;

      for(int i = 0; i < codeLength; i++) {
        input[i] = colors?[i] ?? 0;
        Console.ForegroundColor = (ConsoleColor)colorMap[(int)input[i]];
        Console.Write(colorChar);
        Console.CursorLeft++;
      }

      Console.CursorLeft = 0;
      ConsoleKey key;
      do {
        key = Console.ReadKey(true).Key;
        int i = Console.CursorLeft / 2;

        if(key == ConsoleKey.UpArrow || key == ConsoleKey.DownArrow) {
          if(key == ConsoleKey.UpArrow) {
            input[i] = input[i] == maxC ? input[i] = 0 : input[i] + 1;
          } else {
            input[i] = input[i] == 0 ? input[i] = maxC : input[i] - 1;
          }

          Console.ForegroundColor = (ConsoleColor)colorMap[(int)input[i]];
          Console.Write(colorChar);
          Console.CursorLeft--;
        }

        int cursorMax = (codeLength * 2) - 2;
        if(key == ConsoleKey.LeftArrow || key == ConsoleKey.RightArrow) {
          if(key == ConsoleKey.LeftArrow) {
            Console.CursorLeft = Console.CursorLeft == 0 ? cursorMax : Console.CursorLeft - 2;
          } else {
            Console.CursorLeft = Console.CursorLeft == cursorMax ? 0 : Console.CursorLeft + 2;
          }
        }
      } while(key != ConsoleKey.Enter);

      Console.CursorLeft = 0;
      Console.ResetColor();

      return input;
    }

    static Color[] GetCode() {
      Random rnd = new Random();
      Color[] code = new Color[codeLength];
      for(int i = 0; i < codeLength; i++) code[i] = (Color)rnd.Next((int)maxC);

      return code;
    }

    static int CountSamePos(Color[] a, Color[] b) {
      if(a.Length != b.Length) throw new Exception();

      int result = 0;
      for(int i = 0; i < a.Length; i++) {
        if(a[i] == b[i]) result++;
      }

      return result;
    }

    static int CountDiffPos(Color[] a, Color[] b) {
      if(a.Length != b.Length) throw new Exception();
      List<Color> aDiff = new List<Color>();
      List<Color> bDiff = new List<Color>();
      for(int i = 0; i < a.Length; i++) {
        if(a[i] != b[i]) {
          aDiff.Add(a[i]);
          bDiff.Add(b[i]);
        }
      }

      int result = 0;
      foreach(Color color in aDiff.Concat(bDiff).Distinct()) {
        result += Math.Min(aDiff.Count(x => x == color), bDiff.Count(x => x == color));
            
      }

      return result;
    }

    static void DrawHint(int round, int same, int diff) {
      StringBuilder sb = new StringBuilder();
      Console.CursorTop = 17 - round;
      Console.CursorLeft = codeLength * 2;
      Console.BackgroundColor = ConsoleColor.White;

      Console.ForegroundColor = ConsoleColor.Black;
      Console.Write(sb.Append('*', same));
      sb.Clear();
      Console.ForegroundColor = ConsoleColor.Red;
      Console.Write(sb.Append('*', diff));

      while(Console.CursorLeft <= codeLength * 3) Console.Write(' ');

      Console.ResetColor();
    }

    static void DrawCode(Color[] code) {
      Console.CursorTop = 0;
      Console.CursorLeft = 0;

      for(int i = 0; i < codeLength; i++) {
        Console.ForegroundColor = (ConsoleColor)colorMap[(int)code[i]];
        Console.Write(colorChar);
        Console.CursorLeft++;
      }

      Console.ResetColor();
    }
  }
}

Kommentare:

Für diese Lösung gibt es noch keinen Kommentar

Bitte melden Sie sich an um eine Kommentar zu schreiben.
Kommentar schreiben