From c8489094470d1595f39edd7ff17490d0436702bc Mon Sep 17 00:00:00 2001 From: Enn3Developer Date: Sat, 5 Sep 2026 10:36:44 +0200 Subject: [PATCH] refactor: decouple game participants from human players --- OpenPolytopia.Common/Gameplay/Game.cs | 2 +- OpenPolytopia.Common/Player.cs | 10 ++++++- OpenPolytopia.Common/TerrainGeneration.cs | 2 +- .../PlayerAbstractionTest.cs | 27 +++++++++++++++++++ 4 files changed, 38 insertions(+), 3 deletions(-) create mode 100644 OpenPolytopia.UnitTest/PlayerAbstractionTest.cs diff --git a/OpenPolytopia.Common/Gameplay/Game.cs b/OpenPolytopia.Common/Gameplay/Game.cs index 1ab3703f..46126acf 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 3f6915e6..63075991 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 beb43f3d..2d423b71 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 00000000..34999e61 --- /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); + } +}