From aaefe84e57086e0ac0a849e60afe5821ca39f5d3 Mon Sep 17 00:00:00 2001 From: Markus Himmel Date: Fri, 26 Aug 2016 01:06:16 +0200 Subject: [PATCH] First barely functional version ConsoleInteraction is a giant mess --- Morris/ConsoleInteraction.cs | 92 ++++++++++++++++++++++++++++++++ Morris/CoordinateTranslator.cs | 96 ++++++++++++++++++++++++++++++++++ Morris/GameState.cs | 23 +++++--- Morris/Morris.csproj | 2 + Morris/Program.cs | 4 ++ 5 files changed, 210 insertions(+), 7 deletions(-) create mode 100644 Morris/ConsoleInteraction.cs create mode 100644 Morris/CoordinateTranslator.cs diff --git a/Morris/ConsoleInteraction.cs b/Morris/ConsoleInteraction.cs new file mode 100644 index 0000000..bc23780 --- /dev/null +++ b/Morris/ConsoleInteraction.cs @@ -0,0 +1,92 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Morris +{ + class ConsoleInteraction : IGameStateObserver, IMoveProvider + { + public void Notify(IReadOnlyGameState state) + { + // Ein mit Leerzeichen initialisiertes 8*8 Jagged Array + char[][] field = Enumerable.Repeat(0, 8).Select(_ => Enumerable.Repeat(' ', 8).ToArray()).ToArray(); + + for (int i = 0; i < GameState.FIELD_SIZE; i++) + { + var point = CoordinateTranslator.CoordinatesFromID(i); + switch (state.Board[i]) + { + case Occupation.Free: + field[point.Item1][point.Item2] = 'F'; + break; + + case Occupation.Black: + field[point.Item1][point.Item2] = 'B'; + break; + + case Occupation.White: + field[point.Item1][point.Item2] = 'W'; + break; + + } + } + + //for (int i = 0; i < GameState.FIELD_SIZE; i++) + //{ + // foreach (int j in GameState.GetConnected(i)) + // { + + // } + //} + + foreach (var row in field) + { + Console.WriteLine(new string(row)); + } + } + + + + public GameMove GetNextMove(IReadOnlyGameState state) + { + // So lange wieder fragen, bis ein Input eingegeben wird, der geparst werden kann + // Ob dieser Input dann einen gültigen Zug repräsentiert, ist wieder eine andere Frage + while (true) + { + try + { + Console.Write("Bitte gib einen Zug ein: "); + + // Eingabe parsen + var input = Console.ReadLine().Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); + var inputPositions = input.Skip(1).Select(pos => CoordinateTranslator.IDFromHumanReadable(pos)).ToArray(); + + switch (input[0]) + { + case "p": // place + return GameMove.Place(inputPositions[0]); + + case "pr": // place remove + return GameMove.PlaceRemove(inputPositions[0], inputPositions[1]); + + case "m": // move + return GameMove.Move(inputPositions[0], inputPositions[1]); + + case "mr": // move remove + return GameMove.MoveRemove(inputPositions[0], inputPositions[1], inputPositions[2]); + + default: + throw new InvalidOperationException(); + } + + } + catch + { + // Einfach nocheinmal versuchen... + } + } + } + } +} diff --git a/Morris/CoordinateTranslator.cs b/Morris/CoordinateTranslator.cs new file mode 100644 index 0000000..5acd7c1 --- /dev/null +++ b/Morris/CoordinateTranslator.cs @@ -0,0 +1,96 @@ +/* + * CoordinateTranslator.cs + * Copyright (c) 2016 Markus Himmel + * This file is distributed under the terms of the MIT license + */ + +using System; +using System.Collections.Generic; +using System.Linq; + +namespace Morris +{ + /// + /// Statische Klasse, die Methoden bereitstellt um Spielfeldpositionen zwischen verschiedenen Formaten zu überführen + /// + static class CoordinateTranslator + { + private static Dictionary humans = new Dictionary() + { + ["a1"] = 21, + ["a4"] = 9, + ["a7"] = 0, + ["b2"] = 18, + ["b4"] = 10, + ["b6"] = 3, + ["c3"] = 15, + ["c4"] = 11, + ["c5"] = 6, + ["d1"] = 22, + ["d2"] = 19, + ["d3"] = 16, + ["d5"] = 7, + ["d6"] = 4, + ["d7"] = 1, + ["e3"] = 17, + ["e4"] = 12, + ["e5"] = 8, + ["f2"] = 20, + ["f4"] = 13, + ["f6"] = 5, + ["g1"] = 23, + ["g4"] = 14, + ["g7"] = 2 + }; + + private static Dictionary ids = humans.ToDictionary(pair => pair.Value, pair => pair.Key); + + // Die XML-Kommentare sind hier ausgelassen, weil die Methodennamen ausreichend sprechend sein sollten + + public static Tuple CoordinatesFromHumanReadable(string human) + { + if (!humans.Keys.Contains(human)) + throw new ArgumentException("Dies ist keine gültige Positionsangabe"); + + return Tuple.Create(human[0] - 'a', human[1] - '1'); + } + + public static string HumanReadableFromCoordinates(Tuple coord) + { + string res = new string(new [] { 'a' + coord.Item1, '1' + (char)coord.Item2 }.Cast().ToArray()); + + if (humans.Keys.Contains(res)) + return res; + + throw new ArgumentException("Dies sind keine gültigen Koordinaten"); + } + + public static Tuple CoordinatesFromID(int id) + { + return CoordinatesFromHumanReadable(HumanReadableFromID(id)); + } + + public static int IDFromCoordinates(Tuple coord) + { + return IDFromHumanReadable(HumanReadableFromCoordinates(coord)); + } + + public static int IDFromHumanReadable(string human) + { + int result; + if (humans.TryGetValue(human, out result)) + return result; + + throw new ArgumentException("Dies ist keine gültige Positionsangabe"); + } + + public static string HumanReadableFromID(int ID) + { + string result; + if (ids.TryGetValue(ID, out result)) + return result; + + throw new ArgumentException("Dies ist eine gültige ID"); + } + } +} diff --git a/Morris/GameState.cs b/Morris/GameState.cs index 838ab84..0be5e8f 100644 --- a/Morris/GameState.cs +++ b/Morris/GameState.cs @@ -31,7 +31,7 @@ namespace Morris public const int FLYING_MAX = 3; // Jeder Eintrag repräsentiert eine mögliche Mühle - private static readonly int[][] mills = new[] + public static readonly ReadOnlyCollection> Mills = Array.AsReadOnly(new[] { // Horizontal new[] { 0, 1, 2 }, @@ -52,7 +52,7 @@ namespace Morris new[] { 8, 12, 17 }, new[] { 5, 12, 20 }, new[] { 2, 14, 23 } - }; + }.Select(mill => Array.AsReadOnly(mill)).ToArray()); // Gibt an, ob zwei Felder verbunden sind. // Wird aus den Daten in mills im statischen Konstruktor generiert @@ -61,9 +61,9 @@ namespace Morris static GameState() { connections = new bool[FIELD_SIZE, FIELD_SIZE]; - foreach (int[] mill in mills) + foreach (var mill in Mills) { - for (int i = 0; i < mill.Length - 1; i++) + for (int i = 0; i < mill.Count - 1; i++) { connections[mill[i], mill[i + 1]] = true; connections[mill[i + 1], mill[i]] = true; @@ -71,6 +71,15 @@ namespace Morris } } + /// + /// Gibt alle Felder zurück, die mit einem Feld verbunden sind + /// + /// Das zu untersuchende Feld + public static IEnumerable GetConnected(int ID) + { + return Enumerable.Range(0, FIELD_SIZE).Where(id => connections[ID, id]); + } + public GameState() { // Leeres Feld @@ -233,7 +242,7 @@ namespace Morris return MoveValidity.Invalid; // Darf keinen Stein mehr platzieren // 3.: Wurde eine Mühle geschlossen? - bool millClosed = mills.Any(mill => mill.Contains(move.To) && mill.All(point => (int)Board[point] == (int)NextToMove || point == move.To)); + bool millClosed = Mills.Any(mill => mill.Contains(move.To) && mill.All(point => (int)Board[point] == (int)NextToMove || point == move.To)); // 4.: Verifikation des Mühlenparameters if (millClosed) @@ -254,9 +263,9 @@ namespace Morris // Felder durch gegnerische Steine besetzt sind (die Mühle also geschlossen ist)" bool allInMill = Enumerable.Range(0, FIELD_SIZE) .Where(point => (int)Board[point] != (int)NextToMove.Opponent()) - .All(point => mills.Any(mill => mill.Contains(point) && mill.All(mp => (int)Board[point] == (int)NextToMove.Opponent()))); + .All(point => Mills.Any(mill => mill.Contains(point) && mill.All(mp => (int)Board[point] == (int)NextToMove.Opponent()))); - if (!allInMill && mills.Any(mill => mill.Contains(move.Remove.Value) && mill.All(point => (int)Board[point] == (int)NextToMove.Opponent()))) + if (!allInMill && Mills.Any(mill => mill.Contains(move.Remove.Value) && mill.All(point => (int)Board[point] == (int)NextToMove.Opponent()))) return MoveValidity.Invalid; // Versuch, einen Stein aus einer Mühle zu entfernen, obwohl Steine frei sind } else if (move.Remove.HasValue) diff --git a/Morris/Morris.csproj b/Morris/Morris.csproj index 96f53c7..b865345 100644 --- a/Morris/Morris.csproj +++ b/Morris/Morris.csproj @@ -43,6 +43,8 @@ + + diff --git a/Morris/Program.cs b/Morris/Program.cs index 38baa2d..b02db92 100644 --- a/Morris/Program.cs +++ b/Morris/Program.cs @@ -10,6 +10,10 @@ namespace Morris { static void Main(string[] args) { + var a = new ConsoleInteraction(); + var g = new Game(a, a); + g.AddObserver(a); + g.Run(); } } }