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();
}
}
}