added SumOnce Option in ChristmasTree

This commit is contained in:
beo3000 2026-02-08 17:33:54 +01:00
parent d0e4d01985
commit c5d0f67c0d
4 changed files with 98 additions and 3 deletions

View File

@ -48,6 +48,7 @@ public class ChristmasTreeGameLogicService : IGameLogicService
CurrentTeamIndex = 0,
CurrentPlayerIndexInTeam = 0,
PlayerIndexPerTeam = playerIndexPerTeam,
EnableSumOnce = options.EnableSumOnce,
EnableContinueOnMiss = options.EnableContinueOnMiss,
MaxContinueThrows = options.MaxContinueThrows,
ContinueThrowsRemaining = 0,
@ -118,6 +119,50 @@ public class ChristmasTreeGameLogicService : IGameLogicService
return RotateToNextPlayer(model, triggers);
}
// Sum mode: second throw — try to cross first+second
if (model.IsInSumMode)
{
int sum = model.FirstThrowValue + pinsKnocked;
model = model with { IsInSumMode = false, FirstThrowValue = 0 };
bool crossedOwnSum = TryCrossNumber(teamTrees, playerTeamIndex, sum);
if (crossedOwnSum)
{
lastThrow = lastThrow with { CrossedOwnTree = true, PinsKnocked = sum };
teamTrees[playerTeamIndex] = teamTrees[playerTeamIndex] with
{
CrossedOutCount = teamTrees[playerTeamIndex].CrossedOutCount + 1
};
bool gameEndedSum = CheckGameEndCondition(teamTrees, model.EndCondition);
if (gameEndedSum)
{
lastThrow = lastThrow with { TriggeredGameEnd = true };
return HandleGameEnd(model, teamTrees, lastThrow, triggers);
}
model = model with { TeamTrees = teamTrees, LastThrow = lastThrow, IsInContinueMode = false, ContinueThrowsRemaining = 0 };
return RotateToNextPlayer(model, triggers);
}
var crossedOpponentsSum = TryCrossFromOpponents(teamTrees, playerTeamIndex, sum);
if (crossedOpponentsSum.Count > 0)
{
lastThrow = lastThrow with { CrossedOpponentTrees = true, OpponentTeamsCrossed = crossedOpponentsSum.ToArray(), PinsKnocked = sum };
bool gameEndedSum = CheckGameEndCondition(teamTrees, model.EndCondition);
if (gameEndedSum)
{
lastThrow = lastThrow with { TriggeredGameEnd = true };
return HandleGameEnd(model, teamTrees, lastThrow, triggers);
}
model = model with { TeamTrees = teamTrees, LastThrow = lastThrow, IsInContinueMode = false, ContinueThrowsRemaining = 0 };
return RotateToNextPlayer(model, triggers);
}
// Sum also not available → miss, rotate
lastThrow = lastThrow with { WasMiss = true };
model = model with { TeamTrees = teamTrees, LastThrow = lastThrow };
return RotateToNextPlayer(model, triggers);
}
// Try to cross number from own tree first
bool crossedOwn = TryCrossNumber(teamTrees, playerTeamIndex, pinsKnocked);
@ -181,6 +226,26 @@ public class ChristmasTreeGameLogicService : IGameLogicService
// Number not available anywhere = miss
lastThrow = lastThrow with { WasMiss = true };
// Sum-once: enter sum mode on first miss (non-gutter)
if (model.EnableSumOnce)
{
model = model with
{
TeamTrees = teamTrees,
LastThrow = lastThrow,
IsInSumMode = true,
FirstThrowValue = pinsKnocked
};
return (model, new ThrowResult
{
PointsScored = pinsKnocked,
ShouldRotatePlayer = false,
IsGameOver = false,
WinnerId = null,
Triggers = []
});
}
if (model.EnableContinueOnMiss)
{
return HandleContinueModeThrow(model, teamTrees, lastThrow, pinsKnocked, playerTeamIndex, true);

View File

@ -40,6 +40,21 @@ public record ChristmasTreeGameModel : IGameModel
/// </summary>
public Dictionary<int, int> PlayerIndexPerTeam { get; init; } = new();
/// <summary>
/// Whether sum-once variant is enabled.
/// </summary>
public bool EnableSumOnce { get; init; }
/// <summary>
/// Whether the current player is in sum mode (waiting for second throw to sum).
/// </summary>
public bool IsInSumMode { get; set; }
/// <summary>
/// Value of the first throw in sum mode.
/// </summary>
public int FirstThrowValue { get; set; }
/// <summary>
/// Whether continue-on-miss variant is enabled.
/// </summary>

View File

@ -63,10 +63,15 @@ public record ChristmasTreeGameSetup : GameSetupModelBase
/// </summary>
public int MaxContinueThrows { get; init; } = 3;
/// <summary>
/// When enabled, a miss (not gutter) allows one additional throw; the sum is tried.
/// </summary>
public bool EnableSumOnce { get; init; } = true;
/// <summary>
/// Condition that triggers game end.
/// </summary>
public GameEndCondition EndCondition { get; init; } = GameEndCondition.AllFivesGone;
public GameEndCondition EndCondition { get; init; } = GameEndCondition.TreeCleared;
/// <summary>
/// Creates a new setup with default values.
@ -77,7 +82,8 @@ public record ChristmasTreeGameSetup : GameSetupModelBase
TreeVariant variant = TreeVariant.Beginner,
bool enableContinueOnMiss = false,
int maxContinueThrows = 3,
GameEndCondition endCondition = GameEndCondition.AllFivesGone,
bool enableSumOnce = true,
GameEndCondition endCondition = GameEndCondition.TreeCleared,
IReadOnlyList<GameTeam>? teams = null) => new()
{
ThrowMode = throwMode,
@ -86,6 +92,7 @@ public record ChristmasTreeGameSetup : GameSetupModelBase
Variant = variant,
EnableContinueOnMiss = enableContinueOnMiss,
MaxContinueThrows = maxContinueThrows,
EnableSumOnce = enableSumOnce,
EndCondition = endCondition,
Teams = teams
};

View File

@ -30,6 +30,11 @@
<MudSelectItem Value="GameEndCondition.TreeCleared">Ein Baum komplett leer</MudSelectItem>
</MudSelect>
<MudSwitch T="bool"
@bind-Value="_options.EnableSumOnce"
Label="Am Ende 1x Summieren"
Color="Color.Primary" />
<MudSwitch T="bool"
@bind-Value="_options.EnableContinueOnMiss"
Label="Weiterkegeln bei Fehlwurf"
@ -111,6 +116,7 @@
_options = new ChristmasTreeSetupOptions
{
Variant = setup.Variant,
EnableSumOnce = setup.EnableSumOnce,
EnableContinueOnMiss = setup.EnableContinueOnMiss,
MaxContinueThrows = setup.MaxContinueThrows,
EndCondition = setup.EndCondition
@ -154,6 +160,7 @@
ThrowsPerRound = 1,
ParticipantsMode = ParticipantsMode.GameLogic,
Variant = _options.Variant,
EnableSumOnce = _options.EnableSumOnce,
EnableContinueOnMiss = _options.EnableContinueOnMiss,
MaxContinueThrows = _options.MaxContinueThrows,
EndCondition = _options.EndCondition,
@ -163,8 +170,9 @@
private class ChristmasTreeSetupOptions
{
public TreeVariant Variant { get; set; } = TreeVariant.Beginner;
public bool EnableSumOnce { get; set; } = true;
public bool EnableContinueOnMiss { get; set; } = false;
public int MaxContinueThrows { get; set; } = 3;
public GameEndCondition EndCondition { get; set; } = GameEndCondition.AllFivesGone;
public GameEndCondition EndCondition { get; set; } = GameEndCondition.TreeCleared;
}
}