Skip to content

Commit

Permalink
Fix issue wih duplicate IDs by introducing the IdGen abstraction for …
Browse files Browse the repository at this point in the history
…generating all IDs
  • Loading branch information
Konrad Jamrozik committed Jun 14, 2024
1 parent 4e4fd0e commit e437389
Show file tree
Hide file tree
Showing 15 changed files with 119 additions and 39 deletions.
5 changes: 4 additions & 1 deletion src/game-lib/Controller/GameSessionController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -55,11 +55,14 @@ public GameSessionController(Configuration config, ILog log, GameSession gameSes
_log,
GameSession.RandomGen,
GameSession.EventIdGen,
GameSession.AgentIdGen,
GameSession.MissionIdGen,
() => GameSession.CurrentGameState);
_timeAdvancementController = new TimeAdvancementController(
_log,
GameSession.RandomGen,
GameSession.EventIdGen);
GameSession.EventIdGen,
GameSession.MissionSiteIdGen);
}

public GameStatePlayerView CurrentGameStatePlayerView
Expand Down
26 changes: 18 additions & 8 deletions src/game-lib/Controller/GameTurnController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,20 +9,30 @@ namespace UfoGameLib.Controller;
public class GameTurnController
{
private readonly ILog _log;
public RandomGen RandomGen { get; }
private readonly EventIdGen _eventIdGen;
private readonly AgentIdGen _agentIdGen;
private readonly MissionIdGen _missionIdGen;
private readonly Func<GameState> _gameState;
private GameState GameState => _gameState();
private readonly EventIdGen _eventIdGen;
private readonly List<PlayerActionEvent> _recordedPlayerActionEvents = new();

public GameTurnController(ILog log, RandomGen randomGen, EventIdGen eventIdGen, Func<GameState> gameState)
private readonly List<PlayerActionEvent> _recordedPlayerActionEvents = [];

public GameTurnController(
ILog log,
RandomGen randomGen,
EventIdGen eventIdGen,
AgentIdGen agentIdGen,
MissionIdGen missionIdGen,
Func<GameState> gameState)
{
_log = log;
RandomGen = randomGen;
_gameState = gameState;
_eventIdGen = eventIdGen;
_agentIdGen = agentIdGen;
_missionIdGen = missionIdGen;
_gameState = gameState;
}

public RandomGen RandomGen { get; }

public int CurrentTurn => GameState.Timeline.CurrentTurn;

Expand Down Expand Up @@ -60,7 +70,7 @@ public void LaunchMission(MissionSite site, int agentCount)
}

public PlayerActionEvent HireAgents(int count)
=> ExecuteAndRecordAction(new HireAgentsPlayerAction(_log, count));
=> ExecuteAndRecordAction(new HireAgentsPlayerAction(_log, _agentIdGen, count));

public PlayerActionEvent BuyTransportCapacity(int capacity)
=> ExecuteAndRecordAction(new BuyTransportCapacityPlayerAction(_log, capacity));
Expand All @@ -81,7 +91,7 @@ public PlayerActionEvent RecallAgents(Agents agents)
=> ExecuteAndRecordAction(new RecallAgentsPlayerAction(_log, agents));

public PlayerActionEvent LaunchMission(MissionSite site, Agents agents)
=> ExecuteAndRecordAction(new LaunchMissionPlayerAction(_log, site, agents));
=> ExecuteAndRecordAction(new LaunchMissionPlayerAction(_log, _missionIdGen, site, agents));

public List<PlayerActionEvent> GetAndDeleteRecordedPlayerActionEvents()
{
Expand Down
7 changes: 5 additions & 2 deletions src/game-lib/Controller/HireAgentsPlayerAction.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Lib.Contracts;
using UfoGameLib.Events;
using UfoGameLib.Lib;
using UfoGameLib.Model;
using UfoGameLib.State;
Expand All @@ -8,12 +9,14 @@ namespace UfoGameLib.Controller;
public class HireAgentsPlayerAction : PlayerAction
{
private readonly ILog _log;
private readonly AgentIdGen _agentIdGen;
private readonly int _count;

public HireAgentsPlayerAction(ILog log, int count)
public HireAgentsPlayerAction(ILog log, AgentIdGen agentIdGen, int count)
{
Contract.Assert(count >= 1);
_log = log;
_agentIdGen = agentIdGen;
_count = count;

}
Expand All @@ -26,7 +29,7 @@ protected override (List<int>? ids, int? targetId) ApplyImpl(GameState state)
state.Assets.Money -= totalHireCost;
for (int i = 0; i < _count; i++)
{
state.Assets.Agents.Add(new Agent(state.NextAgentId, state.Timeline.CurrentTurn));
state.Assets.Agents.Add(new Agent(_agentIdGen.Generate, state.Timeline.CurrentTurn));
}

return (ids: [state.Assets.Agents.Count], targetId: _count);
Expand Down
6 changes: 4 additions & 2 deletions src/game-lib/Controller/LaunchMissionPlayerAction.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,16 @@ namespace UfoGameLib.Controller;
public class LaunchMissionPlayerAction : PlayerAction
{
private readonly ILog _log;
private readonly MissionIdGen _missionIdGen;
private readonly MissionSite _site;
private readonly Agents _agents;

public LaunchMissionPlayerAction(ILog log, MissionSite site, Agents agents)
public LaunchMissionPlayerAction(ILog log, MissionIdGen missionIdGen, MissionSite site, Agents agents)
{
Contract.Assert(agents.Any());
agents.AssertCanBeSentOnMission();
_log = log;
_missionIdGen = missionIdGen;
_site = site;
_agents = agents;
}
Expand All @@ -33,7 +35,7 @@ protected override (List<int>? ids, int? targetId) ApplyImpl(GameState state)
$"_agents.Count: {_agents.Count} " +
$">= _site.RequiredSurvivingAgentsForSuccess: {_site.RequiredSurvivingAgentsForSuccess}");

int missionId = state.NextMissionId;
int missionId = _missionIdGen.Generate;
var mission = new Mission(missionId, _site, state.Timeline.CurrentTurn, _agents.Count);

Contract.Assert(_agents.All(agent => AgentSurvivalRoll.AgentCanSurvive(agent, mission)));
Expand Down
10 changes: 8 additions & 2 deletions src/game-lib/Controller/TimeAdvancementController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,18 @@ public class TimeAdvancementController
private readonly RandomGen _randomGen;
private readonly List<WorldEvent> _worldEvents;
private readonly EventIdGen _eventIdGen;
private readonly MissionSiteIdGen _missionSiteIdGen;

public TimeAdvancementController(ILog log, RandomGen randomGen, EventIdGen eventIdGen)
public TimeAdvancementController(
ILog log,
RandomGen randomGen,
EventIdGen eventIdGen,
MissionSiteIdGen missionSiteIdGen)
{
_log = log;
_randomGen = randomGen;
_eventIdGen = eventIdGen;
_missionSiteIdGen = missionSiteIdGen;
_worldEvents = new List<WorldEvent>();
}

Expand Down Expand Up @@ -211,7 +217,7 @@ private int UpdateActiveMissionSites(GameState state)
}
private void CreateMissionSites(GameState state)
{
List<MissionSite> missionSites = state.Factions.CreateMissionSites(_log, _randomGen, state);
List<MissionSite> missionSites = state.Factions.CreateMissionSites(_log, _randomGen, _missionSiteIdGen, state);
state.MissionSites.AddRange(missionSites);
}
}
12 changes: 4 additions & 8 deletions src/game-lib/Events/EventIdGen.cs
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
using Lib.Contracts;
using UfoGameLib.Lib;
using UfoGameLib.State;

namespace UfoGameLib.Events;

public class EventIdGen
public class EventIdGen : IdGen
{
private int _nextEventId;

public EventIdGen(List<GameSessionTurn> turns)
{
Contract.Assert(turns.Any());
// To compute starting next event ID we first need to determine if there are any events in the input
// game session turns. If yes, we consider as the starting next event ID to be (last event ID + 1).
// If not, we consider the last turn NextEventId value, if set.
Expand All @@ -28,10 +28,6 @@ public EventIdGen(List<GameSessionTurn> turns)
nextEventIdFromLastEvent is null || nextEventIdFromLastTurn is null ||
nextEventIdFromLastEvent == nextEventIdFromLastTurn,
$"nextEventIdFromLastEvent: {nextEventIdFromLastEvent}, nextEventIdFromLastTurn: {nextEventIdFromLastTurn}");
_nextEventId = nextEventIdFromLastEvent ?? nextEventIdFromLastTurn ?? 0;
NextId = nextEventIdFromLastEvent ?? nextEventIdFromLastTurn ?? 0;
}

public int Generate => _nextEventId++;

public int Value => _nextEventId;
}
10 changes: 10 additions & 0 deletions src/game-lib/Lib/IdGen.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
namespace UfoGameLib.Lib;

public class IdGen
{
protected int NextId;

public int Generate => NextId++;

public int Value => NextId;
}
12 changes: 12 additions & 0 deletions src/game-lib/Model/AgentIdGen.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using UfoGameLib.Lib;
using UfoGameLib.State;

namespace UfoGameLib.Model;

public class AgentIdGen : IdGen
{
public AgentIdGen(List<GameSessionTurn> turns)
{
NextId = turns.Last().EndState.AllAgents.Count;
}
}
9 changes: 6 additions & 3 deletions src/game-lib/Model/Faction.cs
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,11 @@ public static Faction Init(
public Faction DeepClone()
=> new(Id, Name, Power, MissionSiteCountdown, PowerIncrease, PowerAcceleration, IntelInvested);

public List<MissionSite> CreateMissionSites(ILog log, RandomGen randomGen, GameState state)
public List<MissionSite> CreateMissionSites(
ILog log,
RandomGen randomGen,
MissionSiteIdGen missionSiteIdGen,
GameState state)
{
Contract.Assert(MissionSiteCountdown >= 1);

Expand All @@ -69,8 +73,7 @@ public List<MissionSite> CreateMissionSites(ILog log, RandomGen randomGen, GameS
// kja2-simul-feat to make simulation more interesting: create easier missions from time to time and
// make AI player send less experienced soldiers on it.
List<MissionSite> sites = [];
// kja BUG ROOT CAUSE: this must increase the ID, right now it does not.
int siteId = state.NextMissionSiteId;
int siteId = missionSiteIdGen.Generate;
(int difficulty, int difficultyFromTurn, int roll) =
Ruleset.RollMissionSiteDifficulty(state.Timeline.CurrentTurn, randomGen);

Expand Down
8 changes: 6 additions & 2 deletions src/game-lib/Model/Factions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ public Factions(IEnumerable<Faction>? factions = null)
public Factions DeepClone()
=> new Factions(this.Select(faction => faction.DeepClone()));

public List<MissionSite> CreateMissionSites(ILog log, RandomGen randomGen, GameState state)
=> this.SelectMany(faction => faction.CreateMissionSites(log, randomGen, state)).ToList();
public List<MissionSite> CreateMissionSites(
ILog log,
RandomGen randomGen,
MissionSiteIdGen missionSiteIdGen,
GameState state)
=> this.SelectMany(faction => faction.CreateMissionSites(log, randomGen, missionSiteIdGen, state)).ToList();
}
14 changes: 14 additions & 0 deletions src/game-lib/Model/MissionIdGen.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using Lib.Contracts;
using UfoGameLib.Lib;
using UfoGameLib.State;

namespace UfoGameLib.Model;

public class MissionIdGen : IdGen
{
public MissionIdGen(List<GameSessionTurn> turns)
{
Contract.Assert(turns.Any());
NextId = turns.Last().EndState.Missions.Count;
}
}
14 changes: 14 additions & 0 deletions src/game-lib/Model/MissionSiteIdGen.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using Lib.Contracts;
using UfoGameLib.Lib;
using UfoGameLib.State;

namespace UfoGameLib.Model;

public class MissionSiteIdGen : IdGen
{
public MissionSiteIdGen(List<GameSessionTurn> turns)
{
Contract.Assert(turns.Any());
NextId = turns.Last().EndState.MissionSites.Count;
}
}
2 changes: 1 addition & 1 deletion src/game-lib/Model/Ruleset.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

namespace UfoGameLib.Model;

// kja convert "Ruleset" class into a namespace. Maybe introduce IRuleset "marker" interface?
// kja2-refactor convert "Ruleset" class into a namespace. Maybe introduce IRuleset "marker" interface?
public static class Ruleset
{
public const int InitialMoney = 500;
Expand Down
19 changes: 13 additions & 6 deletions src/game-lib/State/GameSession.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using Lib.Contracts;
using UfoGameLib.Events;
using UfoGameLib.Lib;
using UfoGameLib.Model;

namespace UfoGameLib.State;

Expand All @@ -27,22 +28,28 @@ public class GameSession

public readonly EventIdGen EventIdGen;

public readonly AgentIdGen AgentIdGen;

public readonly MissionIdGen MissionIdGen;

public readonly MissionSiteIdGen MissionSiteIdGen;

public GameSession(RandomGen randomGen, List<GameSessionTurn>? turns = null)
{
RandomGen = randomGen;
Turns = turns ?? [new GameSessionTurn(startState: GameState.NewInitialGameState(randomGen))];
Contract.Assert(Turns.Count >= 1);
Contract.Assert(Turns.Any());
Turns.ForEach(turn => turn.AssertInvariants());

EventIdGen = new EventIdGen(Turns);
AgentIdGen = new AgentIdGen(Turns);
MissionSiteIdGen = new MissionSiteIdGen(Turns);
MissionIdGen = new MissionIdGen(Turns);

}

public IReadOnlyList<GameState> GameStates
=> Turns.SelectMany<GameSessionTurn, GameState>(turn => [turn.StartState, turn.EndState])
.ToList()
.AsReadOnly();

public IReadOnlyList<GameEvent> GameEvents
=> Turns.SelectMany<GameSessionTurn, GameEvent>(turn => turn.GameEvents)
.ToList()
.AsReadOnly();
}
4 changes: 0 additions & 4 deletions src/game-lib/State/GameState.cs
Original file line number Diff line number Diff line change
Expand Up @@ -76,10 +76,6 @@ public void ToJsonFile(File file)

public bool IsGameWon => Assets.Intel >= Ruleset.IntelToWin;

public int NextAgentId => AllAgents.Count;
public int NextMissionId => Missions.Count;
public int NextMissionSiteId => MissionSites.Count;

public void Terminate(Agent agent, bool sack = false)
{
Assets.Agents.Remove(agent);
Expand Down

0 comments on commit e437389

Please sign in to comment.