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 foxId = model.PlayerOrder[model.FoxIndex];
var lastHunterId = GetPrev(model, model.FoxIndex);
var isLastHunter = lastHunterId == playerId;
if (model.FoxTurn)
{
@ -81,15 +83,41 @@ namespace Koogle.Application.Games.FoxHunt
else
{
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
model = model with
@ -105,7 +133,7 @@ namespace Koogle.Application.Games.FoxHunt
PointsScored = pinsKnocked,
ShouldRotatePlayer = true,
IsGameOver = isGameOver,
WinnerId = winnerId,
WinnerId = null,
Triggers = triggers,
Overrides = isGameOver ? null : new GameLogicOverrides
{
@ -125,13 +153,22 @@ namespace Koogle.Application.Games.FoxHunt
/// </summary>
/// <returns></returns>
/// <exception cref="InvalidOperationException"></exception>
private Guid GetNextId(FoxHuntGameModel model)
private Guid GetNextId(FoxHuntGameModel model, bool chooseNextFox)
{
// Abbruch: alle waren einmal Fuchs
if (model.FoxIndex >= model.PlayerOrder.Length)
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
if (model.FoxTurnsRemaining > 0)
@ -146,33 +183,72 @@ namespace Koogle.Application.Games.FoxHunt
// 2⃣ Abwechselnd Nicht-Fuchs → Fuchs
if (!model.FoxTurn)
{
// nächsten Nicht-Fuchs suchen
while (model.NonFoxIndex == model.FoxIndex)
model.NonFoxIndex++;
var nextNonFoxIndex = GetNextIndex(model, model.NonFoxIndex);
if (nextNonFoxIndex == model.FoxIndex)
{
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)
{
Guid next = model.PlayerOrder[model.NonFoxIndex];
model.NonFoxIndex++;
//model.FoxTurn = true;
return next;
}
else
{
// Alle Nicht-Füchse durch → neuer Fuchs
model.FoxIndex++;
model.NonFoxIndex = 0;
model.FoxTurnsRemaining = model.LeadingThrows - 1;
model.FoxTurn = true;
return GetNextId(model);
}
// nächsten Nicht-Fuchs suchen
//while (model.NonFoxIndex == model.FoxIndex)
// model.NonFoxIndex++;
//if (model.NonFoxIndex < model.PlayerOrder.Length)
//{
// Guid next = model.PlayerOrder[model.NonFoxIndex];
// model.NonFoxIndex++;
// //model.FoxTurn = true;
// return next;
//}
//else
//{
// // Alle Nicht-Füchse durch → neuer Fuchs
// model.FoxIndex++;
// model.NonFoxIndex = 0;
// model.FoxTurnsRemaining = model.LeadingThrows - 1;
// model.FoxTurn = true;
// return GetNextId(model);
//}
}
// 3⃣ Fuchs-Zug im Wechsel
//model.FoxTurn = false;
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(
Guid[] playerOrder,
int currentIndex,

View File

@ -35,5 +35,9 @@
public int PinCountFox { 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.Web.Store.DayState
@using Koogle.Web.Store.GameState
@using Koogle.Application.Games;
@inherits Fluxor.Blazor.Web.Components.FluxorComponent
@implements IDisposable
@inject IState<GameState> GameState
@inject IState<DayState> DayState
<pre>
@* <pre>
@_debug
</pre>
</pre> *@
<MudPaper Class="pa-4">
@if (_model == null)
@ -29,16 +29,16 @@
<MudText Typo="Typo.body1">
<strong>Vorsprung für den Fuchs:</strong>
<MudChip T="string" Size="Size.Small" Color="Color.Default" Variant="Variant.Outlined">
@_model.LeadingThrows Vorsprung
@_model.LeadingThrows Wurf
</MudChip>
</MudText>
<MudText Typo="Typo.body1">
@* <MudText Typo="Typo.body1">
<strong>Füchse übrig:</strong>
<MudChip T="string" Size="Size.Small" Color="Color.Primary" Variant="Variant.Filled">
0
</MudChip>
</MudText>
</MudStack>
*@ </MudStack>
</MudPaper>
@* Last throw info *@
@ -70,12 +70,12 @@
Class="mb-4">
<HeaderContent>
<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>Punkte</MudTh>
<MudTh Style="text-align: center">Ergebnis</MudTh>
</HeaderContent>
<RowTemplate>
<!-- Spieler -->
<MudTd>
@if (context.IsCurrentPlayer && !_model.IsGameOver)
{
@ -89,14 +89,14 @@
}
else
{
<MudText Typo="Typo.body1" Style="@(context.IsEliminated ? "text-decoration: line-through; color: var(--mud-palette-text-disabled);" : "")">
<MudText Typo="Typo.body1">
@context.PlayerName
</MudText>
}
</MudTd>
<!-- Status -->
<MudTd Style="text-align: center">
@if (context.IsWinner)
{
@ -105,18 +105,56 @@
SIEGER
</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)
{
<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
</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>
</RowTemplate>
</MudTable>
@ -186,6 +224,35 @@
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()
@ -206,8 +273,13 @@
public string Status { get; init; } = "";
public bool IsWinner { get; init; }
public bool IsCurrentPlayer { get; init; }
public bool IsEliminated { get; init; }
public bool IsFox { 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; }
}
}