Add RandomBot, fix a bug in the game logic

This commit is contained in:
Markus Himmel
2016-08-27 16:27:04 +02:00
parent 244108a442
commit aa517fbd43
5 changed files with 57 additions and 2 deletions

View File

@@ -19,5 +19,15 @@ namespace Morris
// der .Opponent verwendet, ist einfacher zu erkennen (Kapselung).
return ~p;
}
private static Random rng = new Random();
/// <summary>
/// Gibt ein zufälliges Element der IList zurück
/// </summary>
public static T ChooseRandom<T>(this IList<T> it)
{
return it[rng.Next(it.Count)];
}
}
}

View File

@@ -244,7 +244,11 @@ 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 => // Es muss eine potentielle Mühle geben, die
mill.Contains(move.To) && // den neu gesetzten Stein enthält und
mill.All(point => // bei der alle Punkte
(!move.From.HasValue || point != move.From) && // nicht der Ursprungspunkt der aktuellen Steinbewegung sind und
(int)Board[point] == (int)NextToMove || point == move.To)); // entweder schon vom Spieler bestzt sind oder Ziel der aktuellen Steinbewegung sind.
// 4.: Verifikation des Mühlenparameters
if (millClosed)

View File

@@ -49,6 +49,7 @@
<Compile Include="Game.cs" />
<Compile Include="GameResult.cs" />
<Compile Include="GameState.cs" />
<Compile Include="RandomBot.cs" />
<None Include="LICENSE" />
<Compile Include="IGameStateObserver.cs" />
<Compile Include="IMoveProvider.cs" />

View File

@@ -11,7 +11,8 @@ namespace Morris
static void Main(string[] args)
{
var a = new ConsoleInteraction();
var g = new Game(a, a);
var b = new RandomBot();
var g = new Game(b, b);
g.AddObserver(a);
g.Run();
Console.ReadKey();

39
Morris/RandomBot.cs Normal file
View File

@@ -0,0 +1,39 @@
/*
* RandomBot.cs
* Copyright (c) 2016 Markus Himmel
* This fileis distributed under the terms of the MIT license
*/
using System;
using System.Linq;
namespace Morris
{
/// <summary>
/// Ein extrem einfacher KI-Spieler, der einen zufälligen gültigen Spielzug auswählt
/// </summary>
class RandomBot : IMoveProvider
{
// Anhand dieser Klasse können wir sehen, wie einfach es ist, einen Computerspieler zu implementieren.
// Es muss lediglich eine einzige, einfache Methode implementiert werden. Der Spielzustandparameter stellt
// Methoden wie BasicMoves und IsValidMove bereit, mit denen viele verschiedene Strategien sehr einfach
// implementiert werden können.
private Random rng = new Random();
public GameMove GetNextMove(IReadOnlyGameState state)
{
// Ein zufälliger Spielzug
GameMove chosen = state.BasicMoves().ToList().ChooseRandom();
// Wenn wir einen Stein entfernen dürfen, wählen wir einen zufälligen Punkt aus, auf dem sich ein gegnerischer Stein befindet
if (state.IsValidMove(chosen) == MoveValidity.ClosesMill)
return chosen.WithRemove(Enumerable
.Range(0, GameState.FIELD_SIZE)
.Where(d => (int)state.Board[d] == (int)state.NextToMove.Opponent())
.ToList().ChooseRandom());
return chosen;
}
}
}