diff --git a/OpenPolytopia.Common/Gameplay/Game.cs b/OpenPolytopia.Common/Gameplay/Game.cs
index 1ab3703..46126ac 100644
--- a/OpenPolytopia.Common/Gameplay/Game.cs
+++ b/OpenPolytopia.Common/Gameplay/Game.cs
@@ -102,7 +102,7 @@ public partial class Game {
/// than once, or a player's tribe isn't registered in
///
public Game(Grid grid, CityManager cityManager, TroopManager troopManager, TribeManager tribeManager,
- BuildingManager buildingManager, TechTreeDefinition techTreeDefinition, IReadOnlyList players,
+ BuildingManager buildingManager, TechTreeDefinition techTreeDefinition, IReadOnlyList players,
GameSettings? settings = null) {
ArgumentNullException.ThrowIfNull(grid);
ArgumentNullException.ThrowIfNull(cityManager);
diff --git a/OpenPolytopia.Common/Player.cs b/OpenPolytopia.Common/Player.cs
index 3f6915e..6307599 100644
--- a/OpenPolytopia.Common/Player.cs
+++ b/OpenPolytopia.Common/Player.cs
@@ -1,4 +1,12 @@
namespace OpenPolytopia.Common;
-public record Player(TribeType Tribe, int Id) {
+/// A participant independent of its human or future bot controller.
+public interface IPlayer {
+ /// The participant's tribe.
+ TribeType Tribe { get; }
+ /// The participant's id within a game.
+ int Id { get; }
}
+
+/// A human participant in a game.
+public record Player(TribeType Tribe, int Id) : IPlayer;
diff --git a/OpenPolytopia.Common/TerrainGeneration.cs b/OpenPolytopia.Common/TerrainGeneration.cs
index beb43f3..2d423b7 100644
--- a/OpenPolytopia.Common/TerrainGeneration.cs
+++ b/OpenPolytopia.Common/TerrainGeneration.cs
@@ -28,7 +28,7 @@ public class TerrainGeneration(
Grid grid,
CityManager cityManager,
TribeManager tribeManager,
- Player[] players,
+ IPlayer[] players,
int? seed = null) {
// base terrain rates, multiplied by every tribe's TerrainRate
private const float BASE_FOREST_RATE = 0.38f;
diff --git a/OpenPolytopia.UnitTest/PlayerAbstractionTest.cs b/OpenPolytopia.UnitTest/PlayerAbstractionTest.cs
new file mode 100644
index 0000000..34999e6
--- /dev/null
+++ b/OpenPolytopia.UnitTest/PlayerAbstractionTest.cs
@@ -0,0 +1,27 @@
+namespace OpenPolytopia;
+
+using Common;
+using Common.Gameplay;
+using Shouldly;
+using Xunit;
+
+public class PlayerAbstractionTest {
+ private sealed record TestBot(TribeType Tribe, int Id) : IPlayer;
+
+ [Fact]
+ public async System.Threading.Tasks.Task AlternateParticipantCanGenerateAndPlay() {
+ var pieces = GameTestFixture.BuildPieces();
+ IPlayer[] players = [new Player(TribeType.Imperius, 1), new TestBot(TribeType.Imperius, 2)];
+ var grid = new Grid(16);
+ var cities = new CityManager(grid);
+ await new TerrainGeneration(grid, cities, pieces.Tribes, players, 42).GenerateMapAsync();
+ var troops = new TroopManager(16);
+ troops.RegisterTroops(EmbeddedResources.LoadTroops()!);
+ var game = new Common.Gameplay.Game(grid, cities, troops, pieces.Tribes, pieces.Buildings,
+ pieces.TechTree, players);
+ game.Start();
+ game.EndTurn(1).Result.ShouldBe(GameActionResult.Ok);
+ game.CurrentPlayer.ShouldBe(2);
+ game.EndTurn(2).Result.ShouldBe(GameActionResult.Ok);
+ }
+}