private void AdvanceTurn()
{
AddNewUpdateChunk();
foreach (var team in Teams)
if(team.Active.Move != null)
team.Active.Move.Init(team.Active);
AddNewUpdateChunk();
foreach (var team in Teams)
if(team.Active.Move != null)
team.Active.Move.OnTimeStep(team.Active);
AddNewUpdateChunk();
foreach (var team in Teams)
if(team.Active.Move != null)
team.Active.Move.OnAttack(team.Active, team.OtherTeam.Active);
AddNewUpdateChunk();
foreach (var team in Teams)
TransitionResources.Apply(team.Active);
AddNewUpdateChunk();
foreach (var team in Teams)
CheckFainted.Apply(team.Active);
AddNewUpdateChunk();
foreach (var team in Teams)
if (team.Active.Move != null && team.Active.Move.IsCompleted)
team.Active.Move.Remove(team);
AddNewUpdateChunk();
checkForceTie.Apply(this, updates);
}
Powtarzalność kodu jest widoczna na pierwszy rzut oka. Nie za bardzo mam pomysły, co z tym mądrego zrobić. Zdaję sobie sprawę, że idealnie winno to pewnie wyglądać tak:
private void AdvanceTurn()
{
InitMoves();
MovesOnTimestep();
MovesOnAttack();
ApplyTransitionResources();
ApplyCheckFainted();
RemoveCompletedMoves();
ApplyForceTieChecker();
}
Ale to tylko zepchnie problem, bo np. metoda MovesOnTimestep
będzie wyglądać tak:
private void MovesOnTimestep()
{
AddNewUpdateChunk();
foreach (var team in Teams)
if(team.Active.Move != null)
team.Active.Move.OnTimeStep(team.Active);
}
A metoda MovesOnAttack
będzie wyglądać dokładnie analogicznie, więc powtarzalność kodu pozostanie.
Problemów z powtarzalnością możnaby tu wymienić kilka:
Po pierwsze: bez przerwy wołane jest AddNewUpdateChunk
na początku. Ale ponieważ AddNewUpdateChunk
JUŻ jest pojedynczą metodą, to jedyny sposób na usunięcie powtarzalności, jaki widzę, to coś takiego:
private delegate void Del();
private void AdvanceTurn()
{
var l = new List<Del>{
InitMoves, MovesOnTimestep, MovesOnAttack,
ApplyTransitionResources, ApplyCheckFainted,
RemoveCompletedMoves, ApplyForceTieChecker
};
foreach(var m in l) {
AddNewUpdateChunk();
this.m();
}
}
Na razie wygląda pięknie - ale gdyby tylko do środka tej listy powędrowało wywołanie jakiejś nowej metody, która już nie chce być poprzedzona AddNewUpdateChunk();
, to natychmiast okazałoby się, że robiąc powyższe strzeliłem sobie w stopę.
Drugim powtarzalnym elementem są te iteracje po teamach i active. Tu już niemalże w ogóle nie widzę, co zrobić - przecież metoda musi jakoś zaznaczyć, czy iteruje, czy nie. Tzn jedyna mądra rzecz, jaką widzę, to zamknąć iterację po aktywnych stworkach w każdej drużynie w jednej linijce:
private IEnumerable<(Team, Species)> MonsWithNotNulledMoves => Teams.
Zip(Teams.Select(t => t.Active), (t, m) => (t, m)).
Where((t, m) => m.Move != null).
Select((t, m) => (t, m, m.Move)); // czy jakos tak
private void AdvanceTurn()
{
AddNewUpdateChunk();
foreach (var (_, mon, move) in MonsWithNotNulledMoves)
move.Init(mon);
AddNewUpdateChunk();
foreach (var (_, mon, move) in MonsWithNotNulledMoves)
move.OnTimeStep(mon);
AddNewUpdateChunk();
foreach (var (team, mon, move) in MonsWithNotNulledMoves)
move.OnAttack(mon, team.OtherTeam.Active);
AddNewUpdateChunk();
foreach (var team in Teams)
TransitionResources.Apply(team.Active);
AddNewUpdateChunk();
foreach (var team in Teams)
CheckFainted.Apply(team.Active);
AddNewUpdateChunk();
foreach (var (team, _, move) in MonsWithNotNulledMoves)
if (move.IsCompleted)
move.Remove(team);
AddNewUpdateChunk();
checkForceTie.Apply(this, updates);
}
No ale to jest tylko połowiczne rozwiązanie powtarzalności, większość powtarzalności zachodzi dalej...