mirror of
https://github.com/TwoFX/Morris.git
synced 2026-02-04 04:52:52 +00:00
Volle Logik bisa uf Unentschieden, Spielschleife
This commit is contained in:
@@ -8,8 +8,15 @@ namespace Morris
|
|||||||
{
|
{
|
||||||
internal static class ExtensionMethods
|
internal static class ExtensionMethods
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gibt den Gegner des Spielers zurück
|
||||||
|
/// </summary>
|
||||||
public static Player Opponent(this Player p)
|
public static Player Opponent(this Player p)
|
||||||
{
|
{
|
||||||
|
// Es ist in der Regel vermutlich einfacher ~player anstatt player.Opponent() zu
|
||||||
|
// schreiben, Änderungen am Schema von Player sind so jedoch von dem Code, der
|
||||||
|
// Player verwendet, wegabstrahiert und die semantische Bedeutung von Code,
|
||||||
|
// der .Opponent verwendet, ist einfacher zu erkennen (Kapselung).
|
||||||
return ~p;
|
return ~p;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
88
Morris/Game.cs
Normal file
88
Morris/Game.cs
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
/*
|
||||||
|
* Game.cs
|
||||||
|
* Copyright (c) 2016 Markus Himmel
|
||||||
|
* This file is distributed under the terms of the MIT license
|
||||||
|
*/
|
||||||
|
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Threading;
|
||||||
|
|
||||||
|
namespace Morris
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Repräsentiert ein einzelnes Mühlespiel
|
||||||
|
/// </summary>
|
||||||
|
class Game
|
||||||
|
{
|
||||||
|
private List<IGameStateObserver> observers = new List<IGameStateObserver>();
|
||||||
|
private GameState state;
|
||||||
|
private Dictionary<Player, IMoveProvider> providers;
|
||||||
|
|
||||||
|
public Game(IMoveProvider white, IMoveProvider black)
|
||||||
|
{
|
||||||
|
state = new GameState();
|
||||||
|
providers = new Dictionary<Player, IMoveProvider>()
|
||||||
|
{
|
||||||
|
[Player.White] = white,
|
||||||
|
[Player.Black] = black
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Spielt eine gesamte Runde Mühle
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="moveDelay">Die Zeit, in Millisekunden, die gewartet wird, bevor nach einem
|
||||||
|
/// erfolgreichem Zug der nächste Zug angefordert wird (damit KI vs. KI-Spiele in einem
|
||||||
|
/// angemessenen Tempo angesehen werden können)</param>
|
||||||
|
/// <returns>Das Spielergebnis</returns>
|
||||||
|
public GameResult Run(int moveDelay = 0)
|
||||||
|
{
|
||||||
|
notifyOberservers();
|
||||||
|
MoveResult res;
|
||||||
|
|
||||||
|
// Äußere Schleife läuft einmal pro tatsächlichem Zug
|
||||||
|
do
|
||||||
|
{
|
||||||
|
// Innere Schleife läuft einmal pro Zugversuch
|
||||||
|
do
|
||||||
|
{
|
||||||
|
res = state.TryApplyMove(providers[state.NextToMove].GetNextMove(state));
|
||||||
|
} while (res == MoveResult.InvalidMove);
|
||||||
|
|
||||||
|
notifyOberservers();
|
||||||
|
Thread.Sleep(moveDelay);
|
||||||
|
} while (state.Result == GameResult.Running);
|
||||||
|
|
||||||
|
return state.Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Registriert einen <see cref="IGameStateObserver"/> für kommende Spielereignisse
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="observer">Das zu notifizierende Objekt</param>
|
||||||
|
public void AddObserver(IGameStateObserver observer)
|
||||||
|
{
|
||||||
|
observers.Add(observer);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Meldet einen <see cref="IGameStateObserver"/> von kommenden Spielereignissen ab
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="observer">Das abzumeldende Objekt</param>
|
||||||
|
/// <returns>Wahr, wenn das Objekt tatsächlich entfernt wurde.
|
||||||
|
/// Falsch, wenn es nicht gefunden wurde.</returns>
|
||||||
|
public bool RemoveObserver(IGameStateObserver observer)
|
||||||
|
{
|
||||||
|
return observers.Remove(observer);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Meldet dem Spielzustand an alle Observer
|
||||||
|
private void notifyOberservers()
|
||||||
|
{
|
||||||
|
foreach (var observer in observers)
|
||||||
|
{
|
||||||
|
observer.Notify(state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -70,11 +70,34 @@ namespace Morris
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="from">Wo sich der Stein vor dem Zug befindet</param>
|
/// <param name="from">Wo sich der Stein vor dem Zug befindet</param>
|
||||||
/// <param name="to">Wo sich der Stein nach dem Zug befindet</param>
|
/// <param name="to">Wo sich der Stein nach dem Zug befindet</param>
|
||||||
/// <param name="remove">Welcher gegnerische Stein bewegt werden soll</param>
|
/// <param name="remove">Welcher gegnerische Stein entfernt werden soll</param>
|
||||||
/// <returns>Einen nicht zwangsläufig gültigen Spielzug</returns>
|
/// <returns>Einen nicht zwangsläufig gültigen Spielzug</returns>
|
||||||
public static GameMove MoveRemove(int from, int to, int remove)
|
public static GameMove MoveRemove(int from, int to, int remove)
|
||||||
{
|
{
|
||||||
return new GameMove(from, to, remove);
|
return new GameMove(from, to, remove);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Die nachfolgenden beiden Methoden existieren, weil GameMove immutable sein soll, damit es keine lustigen
|
||||||
|
// Aliasing-Bugs gibt, wenn MoveProviders komische Dinge mit den Zügen machen, die sie von GameState.BasicMoves
|
||||||
|
// zurückbekommen
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gibt eine Kopie des GameMove ohne Informationen zur Entfernung zurück
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>Eine neuen Spielzug</returns>
|
||||||
|
public GameMove WithoutRemove()
|
||||||
|
{
|
||||||
|
return new GameMove(From, To, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Erstellt eine Kopie des GameMove mit Zusatzinformation zur Entfernung eines gegnerischen Steins zurück
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="remove">Welcher gegnerische Stein entfernt werden soll</param>
|
||||||
|
/// <returns>Einen neuen Spielzug</returns>
|
||||||
|
public GameMove WithRemove(int remove)
|
||||||
|
{
|
||||||
|
return new GameMove(From, To, remove);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,8 +12,8 @@ namespace Morris
|
|||||||
public enum GameResult
|
public enum GameResult
|
||||||
{
|
{
|
||||||
Running,
|
Running,
|
||||||
WhiteVictory,
|
Draw,
|
||||||
BlackVictory,
|
WhiteVictory = Player.White,
|
||||||
Draw
|
BlackVictory = Player.Black
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Collections.ObjectModel;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
@@ -15,52 +16,19 @@ namespace Morris
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Repräsentiert eine Mühle-Spielsituation
|
/// Repräsentiert eine Mühle-Spielsituation
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class GameState
|
public class GameState : IReadOnlyGameState
|
||||||
{
|
{
|
||||||
public Occupation[] Board { get; private set; }
|
public Occupation[] Board { get; private set; }
|
||||||
public Player NextToMove { get; private set; }
|
public Player NextToMove { get; private set; }
|
||||||
public GameResult Result { get; private set; }
|
public GameResult Result { get; private set; }
|
||||||
|
|
||||||
private Dictionary<Player, Phase> playerPhase;
|
private Dictionary<Player, Phase> playerPhase;
|
||||||
|
private Dictionary<Player, int> stonesPlaced;
|
||||||
|
private Dictionary<Player, int> currentStones;
|
||||||
|
|
||||||
/// <summary>
|
public const int FIELD_SIZE = 24;
|
||||||
/// Gibt die Phase, in der sich ein Spieler befindet, zurück
|
public const int STONES_MAX = 9;
|
||||||
/// </summary>
|
public const int FLYING_MAX = 3;
|
||||||
/// <param name="player">Der Spieler, dessen Phase gesucht ist</param>
|
|
||||||
/// <returns>Eine Phase</returns>
|
|
||||||
public Phase GetPhase(Player player)
|
|
||||||
{
|
|
||||||
return playerPhase[player];
|
|
||||||
}
|
|
||||||
|
|
||||||
private const int FIELD_SIZE = 24;
|
|
||||||
|
|
||||||
static GameState()
|
|
||||||
{
|
|
||||||
|
|
||||||
connections = new bool[FIELD_SIZE, FIELD_SIZE];
|
|
||||||
foreach (int[] mill in mills)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < mill.Length - 1; i++)
|
|
||||||
{
|
|
||||||
connections[mill[i], mill[i + 1]] = true;
|
|
||||||
connections[mill[i + 1], mill[i]] = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public GameState()
|
|
||||||
{
|
|
||||||
// Leeres Feld
|
|
||||||
Board = Enumerable.Repeat(Occupation.Free, FIELD_SIZE).ToArray();
|
|
||||||
NextToMove = Player.White;
|
|
||||||
Result = GameResult.Running;
|
|
||||||
playerPhase = new Dictionary<Player, Phase>()
|
|
||||||
{
|
|
||||||
[Player.Black] = Phase.Placing,
|
|
||||||
[Player.White] = Phase.Placing
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// Jeder Eintrag repräsentiert eine mögliche Mühle
|
// Jeder Eintrag repräsentiert eine mögliche Mühle
|
||||||
private static readonly int[][] mills = new[]
|
private static readonly int[][] mills = new[]
|
||||||
@@ -90,6 +58,139 @@ namespace Morris
|
|||||||
// Wird aus den Daten in mills im statischen Konstruktor generiert
|
// Wird aus den Daten in mills im statischen Konstruktor generiert
|
||||||
private static bool[,] connections;
|
private static bool[,] connections;
|
||||||
|
|
||||||
|
static GameState()
|
||||||
|
{
|
||||||
|
connections = new bool[FIELD_SIZE, FIELD_SIZE];
|
||||||
|
foreach (int[] mill in mills)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < mill.Length - 1; i++)
|
||||||
|
{
|
||||||
|
connections[mill[i], mill[i + 1]] = true;
|
||||||
|
connections[mill[i + 1], mill[i]] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public GameState()
|
||||||
|
{
|
||||||
|
// Leeres Feld
|
||||||
|
Board = Enumerable.Repeat(Occupation.Free, FIELD_SIZE).ToArray();
|
||||||
|
NextToMove = Player.White;
|
||||||
|
Result = GameResult.Running;
|
||||||
|
|
||||||
|
playerPhase = new Dictionary<Player, Phase>()
|
||||||
|
{
|
||||||
|
[Player.Black] = Phase.Placing,
|
||||||
|
[Player.White] = Phase.Placing
|
||||||
|
};
|
||||||
|
|
||||||
|
stonesPlaced = new Dictionary<Player, int>()
|
||||||
|
{
|
||||||
|
[Player.Black] = 0,
|
||||||
|
[Player.White] = 0
|
||||||
|
};
|
||||||
|
|
||||||
|
currentStones = new Dictionary<Player, int>()
|
||||||
|
{
|
||||||
|
[Player.Black] = 0,
|
||||||
|
[Player.White] = 0
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
ReadOnlyCollection<Occupation> IReadOnlyGameState.Board
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return Array.AsReadOnly(Board);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Die folgenden drei Methoden existieren, weil selbst eine Setter-Only Property,
|
||||||
|
// die die zugrundeliegenden Dictionaries zurückgibt, modifizierbar wäre.
|
||||||
|
// IReadOnlyDictionary ist keine Lösung, weil es Nutzer dieser Klasse eigentlich
|
||||||
|
// nicht interessiert, wie diese Daten gespeichtert sind. In einer späteren Version
|
||||||
|
// könnte sich das auch ändern (weil Dictionaries ziemlich "overkill" zur Speicherung
|
||||||
|
// zweier Ganzzahlen sind).
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gibt die Phase, in der sich ein Spieler befindet, zurück
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="player">Der Spieler, dessen Phase gesucht ist</param>
|
||||||
|
/// <returns>Eine Phase</returns>
|
||||||
|
public Phase GetPhase(Player player)
|
||||||
|
{
|
||||||
|
return playerPhase[player];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gibt die von einem Spieler insgesamt gesetzten Steine zurück
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="player">Der Spieler, dessen gesetzten Steine gesucht sind</param>
|
||||||
|
/// <returns>Eine Zahl zwischen 0 und <see cref="STONES_MAX"/></returns>
|
||||||
|
public int GetStonesPlaced(Player player)
|
||||||
|
{
|
||||||
|
return stonesPlaced[player];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gibt die Zahl der Steine auf dem Spielfeld, die einem Spieler gehören, zurück
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="player">Der Spieler, dessen aktuelle Steinzahl gesucht ist</param>
|
||||||
|
/// <returns>Eine Zahl zwischen 0 und <see cref="STONES_MAX"/></returns>
|
||||||
|
public int GetCurrentStones(Player player)
|
||||||
|
{
|
||||||
|
return currentStones[player];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Gibt alle Paare von Spielfeldpositionen (p, p2) zurück, sodass
|
||||||
|
// p vom aktuellen Spieler belegt ist und p2 frei ist und
|
||||||
|
// zusätzlich pred(p, p2) erfüllt ist.
|
||||||
|
// Hilfsmethode für BasicMoves; in C# 7 könnte man da eine coole
|
||||||
|
// lokale Funktion draus machen, das hier ist aber ein
|
||||||
|
// C# 6-Projekt...
|
||||||
|
private IEnumerable<GameMove> pairs(Func<int, int, bool> pred)
|
||||||
|
{
|
||||||
|
return Enumerable.Range(0, FIELD_SIZE)
|
||||||
|
.Where(p => (int)Board[p] == (int)NextToMove)
|
||||||
|
.SelectMany(p => Enumerable.Range(0, FIELD_SIZE)
|
||||||
|
.Where(p2 => Board[p2] == Occupation.Free && pred(p, p2))
|
||||||
|
.Select(p2 => GameMove.Move(p, p2)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gibt alle möglichen Spielzüge für den Spieler, der aktuell am Zug ist,
|
||||||
|
/// ohne Informationen über zu entfernende gegnerische Steine zurück.
|
||||||
|
///
|
||||||
|
/// Für von dieser Methode zurückgegebene Züge kann mithilfe von
|
||||||
|
/// <see cref="IsValidMove(GameMove)"/> bestimmt werden, ob ein Stein
|
||||||
|
/// entfernt werden darf.
|
||||||
|
/// </summary>
|
||||||
|
public IEnumerable<GameMove> BasicMoves()
|
||||||
|
{
|
||||||
|
switch (playerPhase[NextToMove])
|
||||||
|
{
|
||||||
|
case Phase.Placing:
|
||||||
|
// Ein neuer Zug für alle freien Felder
|
||||||
|
return Enumerable.Range(0, FIELD_SIZE)
|
||||||
|
.Where(p => Board[p] == Occupation.Free)
|
||||||
|
.Select(p => GameMove.Place(p));
|
||||||
|
|
||||||
|
case Phase.Moving:
|
||||||
|
// Ein neuer Zug für jedes Paar von Positionen (p, p2), bei dem
|
||||||
|
// p vom aktuellen Spieler belegt ist und p2 frei und mit p
|
||||||
|
// verbunden ist
|
||||||
|
return pairs((p, p2) => connections[p, p2]);
|
||||||
|
|
||||||
|
case Phase.Flying:
|
||||||
|
// Ein neuer Zug für jedes Paar von Positionen (p, p2), bei dem
|
||||||
|
// p vom aktuellen Spieler belegt ist und p2 frei ist
|
||||||
|
return pairs((p, p2) => true);
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new InvalidOperationException("Sollte nie erreicht werden");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Bestimmt, ob ein Zug in der aktuellen Spielsituation gültig ist
|
/// Bestimmt, ob ein Zug in der aktuellen Spielsituation gültig ist
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -186,20 +287,33 @@ namespace Morris
|
|||||||
// ggf. wegbewegter Stein
|
// ggf. wegbewegter Stein
|
||||||
if (move.From.HasValue)
|
if (move.From.HasValue)
|
||||||
Board[move.From.Value] = Occupation.Free;
|
Board[move.From.Value] = Occupation.Free;
|
||||||
|
else if (++stonesPlaced[NextToMove] == STONES_MAX)
|
||||||
|
playerPhase[NextToMove] = Phase.Moving;
|
||||||
|
|
||||||
// Hinbewegter Stein
|
// Hinbewegter Stein
|
||||||
Board[move.To] = (Occupation)NextToMove;
|
Board[move.To] = (Occupation)NextToMove;
|
||||||
|
|
||||||
// ggf. entfernter Stein
|
// ggf. entfernter Stein
|
||||||
if (move.Remove.HasValue)
|
if (move.Remove.HasValue)
|
||||||
|
{
|
||||||
Board[move.Remove.Value] = Occupation.Free;
|
Board[move.Remove.Value] = Occupation.Free;
|
||||||
|
if (--currentStones[NextToMove.Opponent()] == FLYING_MAX)
|
||||||
|
playerPhase[NextToMove.Opponent()] = Phase.Flying;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Gegner hat nur noch zwei Steine
|
||||||
|
if (currentStones[NextToMove.Opponent()] == 2)
|
||||||
|
Result = (GameResult)NextToMove;
|
||||||
|
|
||||||
// Gegner ist jetzt dran
|
// Gegner ist jetzt dran
|
||||||
NextToMove = NextToMove.Opponent();
|
NextToMove = NextToMove.Opponent();
|
||||||
|
|
||||||
|
// Wenn der (jetzt) aktuelle Spieler keine gültigen Züge hat,
|
||||||
|
// hat er verloren
|
||||||
|
if (!BasicMoves().Any())
|
||||||
|
Result = (GameResult)NextToMove.Opponent();
|
||||||
|
|
||||||
return MoveResult.OK;
|
return MoveResult.OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,21 @@
|
|||||||
using System;
|
/*
|
||||||
using System.Collections.Generic;
|
* IGameStateObserver.cs
|
||||||
using System.Linq;
|
* Copyright (c) 2016 Markus Himmel
|
||||||
using System.Text;
|
* This file is distributed under the terms of the MIT license
|
||||||
using System.Threading.Tasks;
|
*/
|
||||||
|
|
||||||
namespace Morris
|
namespace Morris
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Eine Entität, die ein Spiel "abbonieren" kann und dann über Änderungen
|
||||||
|
/// des Spielzustands in Kenntnis gesetzt wird
|
||||||
|
/// </summary>
|
||||||
interface IGameStateObserver
|
interface IGameStateObserver
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Wird aufgerufen, wenn sich der aktuelle Spielzustand geändert hat
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="state">Lesesicht auf den aktuellen Spielzustand</param>
|
||||||
|
void Notify(IReadOnlyGameState state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,18 +4,14 @@
|
|||||||
* This file is distributed under the terms of the MIT license
|
* This file is distributed under the terms of the MIT license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using System.Collections.ObjectModel;
|
using System.Collections.ObjectModel;
|
||||||
|
|
||||||
namespace Morris
|
namespace Morris
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Eine schreibgeschützte Sicht auf ein Spielfeld, anhand der ein <see cref="IMoveProvider"/>
|
/// Eine schreibgeschützte Sicht auf ein Spielfeld, anhand der ein <see cref="IMoveProvider"/>
|
||||||
/// einen Nachfolgezug bestimmen soll
|
/// einen Nachfolgezug bestimmen soll und ein <see cref="IGameStateObserver"/> die Spielsituation
|
||||||
|
/// komsumieren kann
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface IReadOnlyGameState
|
public interface IReadOnlyGameState
|
||||||
{
|
{
|
||||||
@@ -38,6 +34,7 @@ namespace Morris
|
|||||||
|
|
||||||
|
|
||||||
// Methoden, die Auskunft über die Spielsituation geben
|
// Methoden, die Auskunft über die Spielsituation geben
|
||||||
|
// (siehe hierzu auch den Kommentar in GameState.cs)
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gibt die Phase, in der sich ein Spieler befindet, zurück
|
/// Gibt die Phase, in der sich ein Spieler befindet, zurück
|
||||||
@@ -46,6 +43,19 @@ namespace Morris
|
|||||||
/// <returns>Eine Phase</returns>
|
/// <returns>Eine Phase</returns>
|
||||||
Phase GetPhase(Player player);
|
Phase GetPhase(Player player);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gibt die von einem Spieler insgesamt gesetzten Steine zurück
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="player">Der Spieler, dessen gesetzten Steine gesucht sind</param>
|
||||||
|
/// <returns>Eine Zahl zwischen 0 und <see cref="STONES_MAX"/></returns>
|
||||||
|
int GetStonesPlaced(Player player);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gibt die Zahl der Steine auf dem Spielfeld, die einem Spieler gehören, zurück
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="player">Der Spieler, dessen aktuelle Steinzahl gesucht ist</param>
|
||||||
|
/// <returns>Eine Zahl zwischen 0 und <see cref="STONES_MAX"/></returns>
|
||||||
|
int GetCurrentStones(Player player);
|
||||||
|
|
||||||
// Methoden zur Vereinfachung der Arbeit von IMoveProvider
|
// Methoden zur Vereinfachung der Arbeit von IMoveProvider
|
||||||
|
|
||||||
|
|||||||
@@ -44,6 +44,7 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Include="ExtensionMethods.cs" />
|
<Compile Include="ExtensionMethods.cs" />
|
||||||
|
<Compile Include="Game.cs" />
|
||||||
<Compile Include="GameResult.cs" />
|
<Compile Include="GameResult.cs" />
|
||||||
<Compile Include="GameState.cs" />
|
<Compile Include="GameState.cs" />
|
||||||
<None Include="LICENSE" />
|
<None Include="LICENSE" />
|
||||||
|
|||||||
Reference in New Issue
Block a user