dev foxhunt

This commit is contained in:
beo3000 2026-01-05 15:02:53 +01:00
parent 433b61618d
commit 187a7e14c8
3 changed files with 202 additions and 50 deletions

View File

@ -73,6 +73,8 @@ namespace Koogle.Application.Games.FoxHunt
var triggers = new List<TriggerEvent>(); var triggers = new List<TriggerEvent>();
var foxId = model.PlayerOrder[model.FoxIndex]; var foxId = model.PlayerOrder[model.FoxIndex];
var lastHunterId = GetPrev(model, model.FoxIndex);
var isLastHunter = lastHunterId == playerId;
if (model.FoxTurn) if (model.FoxTurn)
{ {
@ -81,15 +83,41 @@ namespace Koogle.Application.Games.FoxHunt
else else
{ {
playerStates[foxId].PinCountHunters+= afterThrow.PinsKnocked; playerStates[foxId].PinCountHunters+= afterThrow.PinsKnocked;
if (playerStates[foxId].PinCountHunters >= playerStates[foxId].PinCountFox )
{
// fox has been caught
isLastHunter = true;
playerStates[foxId].FoxCaught = true;
}
else
{
if (isLastHunter)
{
playerStates[foxId].FoxEscaped = true;
}
}
} }
// 5. Check GAME END
bool isGameOver = false;
Guid? winnerId = null;
var nextPlayerId = GetNextId(model, isLastHunter);
// Check GAME END
bool isGameOver = isLastHunter && model.FoxIndex == 0;
if (isGameOver)
{
// looking for winner(s)
var maxLeading = playerStates.Values.Where(s => !s.FoxCaught)
.Select(s => s.PinCountFox - s.PinCountHunters).Max();
foreach (var key in playerStates.Keys)
{
if (playerStates[key].PinCountFox - playerStates[key].PinCountHunters == maxLeading)
{
playerStates[key].IsWinner = true;
}
}
}
var nextPlayerId = GetNextId(model);
//var nextName = GetPlayerName(nextPlayerId).Result;
// Update model // Update model
model = model with model = model with
@ -105,7 +133,7 @@ namespace Koogle.Application.Games.FoxHunt
PointsScored = pinsKnocked, PointsScored = pinsKnocked,
ShouldRotatePlayer = true, ShouldRotatePlayer = true,
IsGameOver = isGameOver, IsGameOver = isGameOver,
WinnerId = winnerId, WinnerId = null,
Triggers = triggers, Triggers = triggers,
Overrides = isGameOver ? null : new GameLogicOverrides Overrides = isGameOver ? null : new GameLogicOverrides
{ {
@ -125,13 +153,22 @@ namespace Koogle.Application.Games.FoxHunt
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
/// <exception cref="InvalidOperationException"></exception> /// <exception cref="InvalidOperationException"></exception>
private Guid GetNextId(FoxHuntGameModel model) private Guid GetNextId(FoxHuntGameModel model, bool chooseNextFox)
{ {
// Abbruch: alle waren einmal Fuchs // Abbruch: alle waren einmal Fuchs
if (model.FoxIndex >= model.PlayerOrder.Length) if (model.FoxIndex >= model.PlayerOrder.Length)
throw new InvalidOperationException("Alle Spieler waren bereits Fuchs."); throw new InvalidOperationException("Alle Spieler waren bereits Fuchs.");
Guid foxId = model.PlayerOrder[model.FoxIndex]; var foxId = model.PlayerOrder[model.FoxIndex];
if (chooseNextFox)
{
model.FoxIndex = GetNextIndex(model, model.FoxIndex);
model.FoxTurnsRemaining = model.LeadingThrows - 1; // nächster Wurf zählt schon
model.FoxTurn = true;
model.NonFoxIndex = model.FoxIndex; // NonFoxIndex = FoxIndex -> Increment will choose next person after fox
return model.PlayerOrder[model.FoxIndex];
}
// 1⃣ Fuchs ist 2x hintereinander dran // 1⃣ Fuchs ist 2x hintereinander dran
if (model.FoxTurnsRemaining > 0) if (model.FoxTurnsRemaining > 0)
@ -146,33 +183,72 @@ namespace Koogle.Application.Games.FoxHunt
// 2⃣ Abwechselnd Nicht-Fuchs → Fuchs // 2⃣ Abwechselnd Nicht-Fuchs → Fuchs
if (!model.FoxTurn) if (!model.FoxTurn)
{ {
// nächsten Nicht-Fuchs suchen var nextNonFoxIndex = GetNextIndex(model, model.NonFoxIndex);
while (model.NonFoxIndex == model.FoxIndex) if (nextNonFoxIndex == model.FoxIndex)
model.NonFoxIndex++; {
throw new InvalidOperationException("this should never happen");
//nextNoneFoxIndex = GetNextIndex(model, model.NonFoxIndex);
}
model.NonFoxIndex = nextNonFoxIndex;
return model.PlayerOrder[nextNonFoxIndex];
if (model.NonFoxIndex < model.PlayerOrder.Length) // nächsten Nicht-Fuchs suchen
{ //while (model.NonFoxIndex == model.FoxIndex)
Guid next = model.PlayerOrder[model.NonFoxIndex]; // model.NonFoxIndex++;
model.NonFoxIndex++;
//model.FoxTurn = true; //if (model.NonFoxIndex < model.PlayerOrder.Length)
return next; //{
} // Guid next = model.PlayerOrder[model.NonFoxIndex];
else // model.NonFoxIndex++;
{ // //model.FoxTurn = true;
// Alle Nicht-Füchse durch → neuer Fuchs // return next;
model.FoxIndex++; //}
model.NonFoxIndex = 0; //else
model.FoxTurnsRemaining = model.LeadingThrows - 1; //{
model.FoxTurn = true; // // Alle Nicht-Füchse durch → neuer Fuchs
return GetNextId(model); // model.FoxIndex++;
} // model.NonFoxIndex = 0;
// model.FoxTurnsRemaining = model.LeadingThrows - 1;
// model.FoxTurn = true;
// return GetNextId(model);
//}
} }
// 3⃣ Fuchs-Zug im Wechsel // 3⃣ Fuchs-Zug im Wechsel
//model.FoxTurn = false; //model.FoxTurn = false;
return foxId; return foxId;
} }
private Guid GetPrev(FoxHuntGameModel model, int index)
{
if (index == 0)
{
return model.PlayerOrder[^1];
}
return model.PlayerOrder[index - 1];
}
private Guid GetNext(FoxHuntGameModel model, int index)
{
if (index == model.PlayerOrder.Length -1)
{
return model.PlayerOrder[0];
}
return model.PlayerOrder[index + 1];
}
private int GetNextIndex(FoxHuntGameModel model, int index)
{
if (index == model.PlayerOrder.Length - 1)
{
return 0;
}
return index + 1;
}
private static int GetNextActivePlayerIndex( private static int GetNextActivePlayerIndex(
Guid[] playerOrder, Guid[] playerOrder,
int currentIndex, int currentIndex,

View File

@ -35,5 +35,9 @@
public int PinCountFox { get; set; } public int PinCountFox { get; set; }
public int PinCountHunters { get; set; } public int PinCountHunters { get; set; }
public bool FoxCaught { get; set; }
public bool IsWinner { get; set; }
public bool FoxEscaped { get; set; }
} }
} }

View File

@ -1,18 +1,18 @@
@inherits Fluxor.Blazor.Web.Components.FluxorComponent @using System.Text.Json
@using System.Text.Json
@using Koogle.Application.Games.FoxHunt @using Koogle.Application.Games.FoxHunt
@using Koogle.Web.Store.DayState @using Koogle.Web.Store.DayState
@using Koogle.Web.Store.GameState @using Koogle.Web.Store.GameState
@using Koogle.Application.Games; @using Koogle.Application.Games;
@inherits Fluxor.Blazor.Web.Components.FluxorComponent
@implements IDisposable @implements IDisposable
@inject IState<GameState> GameState @inject IState<GameState> GameState
@inject IState<DayState> DayState @inject IState<DayState> DayState
<pre> @* <pre>
@_debug @_debug
</pre> </pre> *@
<MudPaper Class="pa-4"> <MudPaper Class="pa-4">
@if (_model == null) @if (_model == null)
@ -29,16 +29,16 @@
<MudText Typo="Typo.body1"> <MudText Typo="Typo.body1">
<strong>Vorsprung für den Fuchs:</strong> <strong>Vorsprung für den Fuchs:</strong>
<MudChip T="string" Size="Size.Small" Color="Color.Default" Variant="Variant.Outlined"> <MudChip T="string" Size="Size.Small" Color="Color.Default" Variant="Variant.Outlined">
@_model.LeadingThrows Vorsprung @_model.LeadingThrows Wurf
</MudChip> </MudChip>
</MudText> </MudText>
<MudText Typo="Typo.body1"> @* <MudText Typo="Typo.body1">
<strong>Füchse übrig:</strong> <strong>Füchse übrig:</strong>
<MudChip T="string" Size="Size.Small" Color="Color.Primary" Variant="Variant.Filled"> <MudChip T="string" Size="Size.Small" Color="Color.Primary" Variant="Variant.Filled">
0 0
</MudChip> </MudChip>
</MudText> </MudText>
</MudStack> *@ </MudStack>
</MudPaper> </MudPaper>
@* Last throw info *@ @* Last throw info *@
@ -70,12 +70,12 @@
Class="mb-4"> Class="mb-4">
<HeaderContent> <HeaderContent>
<MudTh>Spieler</MudTh> <MudTh>Spieler</MudTh>
<MudTh>Status</MudTh>
<MudTh Style="text-align: center">Xs</MudTh>
<MudTh Style="text-align: center">Eier</MudTh>
<MudTh Style="text-align: center">Status</MudTh> <MudTh Style="text-align: center">Status</MudTh>
<MudTh>Punkte</MudTh>
<MudTh Style="text-align: center">Ergebnis</MudTh>
</HeaderContent> </HeaderContent>
<RowTemplate> <RowTemplate>
<!-- Spieler -->
<MudTd> <MudTd>
@if (context.IsCurrentPlayer && !_model.IsGameOver) @if (context.IsCurrentPlayer && !_model.IsGameOver)
{ {
@ -89,14 +89,14 @@
} }
else else
{ {
<MudText Typo="Typo.body1" Style="@(context.IsEliminated ? "text-decoration: line-through; color: var(--mud-palette-text-disabled);" : "")"> <MudText Typo="Typo.body1">
@context.PlayerName @context.PlayerName
</MudText> </MudText>
} }
</MudTd> </MudTd>
<!-- Status -->
<MudTd Style="text-align: center"> <MudTd Style="text-align: center">
@if (context.IsWinner) @if (context.IsWinner)
{ {
@ -105,18 +105,56 @@
SIEGER SIEGER
</MudChip> </MudChip>
} }
else if (context.IsEliminated)
{
<MudChip T="string" Size="Size.Small" Color="Color.Error" Variant="Variant.Outlined">
☠️ Platz @context.FoxSurvivalOrder
</MudChip>
}
else if (context.IsCurrentPlayer) else if (context.IsCurrentPlayer)
{ {
<MudChip T="string" Size="Size.Small" Color="Color.Primary" Variant="Variant.Outlined"> <MudChip T="string" Size="Size.Small" Color="Color.Warning" Variant="Variant.Outlined">
Am Zug Am Zug
</MudChip> </MudChip>
} }
@if (context.IsFox)
{
<MudChip T="string" Size="Size.Small" Color="Color.Warning" Variant="Variant.Outlined">
Fuchs
</MudChip>
}
else
{
<MudChip T="string" Size="Size.Small" Color="Color.Info" Variant="Variant.Outlined">
Jäger
</MudChip>
}
</MudTd>
<!-- Punkte -->
<MudTd>
<MudText Typo="Typo.body1" Color="@(context.IsFox ? Color.Warning : Color.Secondary)">
@if (context.LeadingCount > 0)
{
@($"Fuchs: {context.PinCountFox} Jäger: {@context.PinCountHunters} Vorsprung: {@context.LeadingCount}");
}
else
{
@($"Fuchs: {context.PinCountFox} Jäger: {@context.PinCountHunters}")
}
</MudText>
</MudTd>
<!-- Fuchs gefangen -->
<MudTd Style="text-align: center">
@if (context.FoxCaught)
{
<MudChip T="string" Size="Size.Small" Color="Color.Error" Variant="Variant.Outlined">
☠️ @context.PlayerName ist ein toter Fuchs
</MudChip>
}
@if (context.FoxEscaped)
{
<MudChip T="string" Size="Size.Small" Color="Color.Success" Variant="Variant.Outlined">
🗸 Fuchs @context.PlayerName ist entkommen
</MudChip>
}
</MudTd> </MudTd>
</RowTemplate> </RowTemplate>
</MudTable> </MudTable>
@ -186,6 +224,35 @@
return; return;
} }
var currentPlayerId = gameState.Participants.CurrentPlayerId;
var persons = DayState.Value.AvailablePersons;
var foxId = _model.PlayerOrder[_model.FoxIndex];
foreach (var playerId in _model.PlayerOrder)
{
if (!_model.PlayerStates.TryGetValue(playerId, out var state))
continue;
var person = persons.FirstOrDefault(p => p.Id == playerId);
var playerName = person?.Name ?? "Unbekannt";
var foxModel = _model.PlayerStates[playerId];
// var eliminationOrder = _model.EliminatedPlayers.IndexOf(playerId);
_playerStats.Add(new PlayerStatsRow
{
PlayerId = playerId,
PlayerName = playerName,
IsCurrentPlayer = playerId == currentPlayerId,
IsFox = playerId == foxId,
FoxCaught = foxModel.FoxCaught,
IsWinner = foxModel.IsWinner,
PinCountFox = foxModel.PinCountFox,
PinCountHunters = foxModel.PinCountHunters,
LeadingCount = foxModel.PinCountFox - foxModel.PinCountHunters,
FoxEscaped = foxModel.FoxEscaped
});
}
} }
public void Dispose() public void Dispose()
@ -206,8 +273,13 @@
public string Status { get; init; } = ""; public string Status { get; init; } = "";
public bool IsWinner { get; init; } public bool IsWinner { get; init; }
public bool IsCurrentPlayer { get; init; } public bool IsCurrentPlayer { get; init; }
public bool IsEliminated { get; init; } public bool IsFox { get; init; }
public int FoxSurvivalOrder { get; init; } public int FoxSurvivalOrder { get; init; }
public bool FoxCaught { get; init; }
public int PinCountFox { get; set; }
public int PinCountHunters { get; set; }
public int LeadingCount { get; set; }
public bool FoxEscaped { get; set; }
} }
} }