improvements

This commit is contained in:
Michal Vrba
2026-08-28 16:34:40 +02:00
parent 4803bc22a6
commit 02bca7c34a
212 changed files with 622 additions and 112 deletions
+127 -18
View File
@@ -25,6 +25,11 @@ public class GameEngine
State.Players = players;
State.Rules = rules;
State.IsGameOver = false;
State.IsMatchOver = false;
State.IsRoundOver = false;
State.MatchWinner = null;
State.RoundLoser = null;
State.RoundNumber = 1;
State.LastFinishedPlayer = null;
State.TurnCount = 1;
State.PendingDrawCount = 0;
@@ -35,6 +40,7 @@ public class GameEngine
foreach (var player in State.Players)
{
player.OlympicCardsCount = State.Rules.InitialCardCount;
player.Reset();
}
@@ -42,10 +48,10 @@ public class GameEngine
State.DrawDeck = _deckManager.CreateShuffledDeck();
State.DiscardPile.Clear();
// Rozdanie kariet každému hráčovi
for (int i = 0; i < State.Rules.InitialCardCount; i++)
// Rozdanie kariet každému aktívnemu hráčovi podľa jeho OlympicCardsCount
foreach (var player in State.ActiveTournamentPlayers)
{
foreach (var player in State.Players)
for (int i = 0; i < player.OlympicCardsCount; i++)
{
if (State.DrawDeck.Count > 0)
{
@@ -57,7 +63,6 @@ public class GameEngine
}
// Otočenie prvej karty na odhadzovaciu kôpku
// Ak je prvá karta sedma, eso alebo horník, v základnej hre ju berieme ako štartovaciu bez okamžitého trestu
var startCard = State.DrawDeck[0];
State.DrawDeck.RemoveAt(0);
State.DiscardPile.Add(startCard);
@@ -551,27 +556,131 @@ public class GameEngine
int remaining = State.ActivePlayersCount;
if (remaining <= 1)
{
State.IsGameOver = true;
State.TurnState = TurnState.GameOver;
// Zostávajúcemu hráčovi priradíme posledné miesto
var lastPlayer = State.Players.FirstOrDefault(p => !p.HasFinished);
// Zostávajúci hráč, ktorému ostali karty (porazený tohto kola)
var lastPlayer = State.ActiveTournamentPlayers.FirstOrDefault(p => !p.HasFinished);
if (lastPlayer != null)
{
lastPlayer.FinishedPosition = State.Players.Count;
lastPlayer.FinishedPosition = State.ActiveTournamentPlayers.Count;
State.RoundLoser = lastPlayer;
}
EmitEvent(new GameEvent(
GameEventType.GameOver,
null,
Message: "Koniec hry! Všetky pozície sú určené."
));
if (State.Rules.OlympicMode)
{
if (lastPlayer != null)
{
lastPlayer.OlympicCardsCount--;
if (lastPlayer.IsEliminated)
{
EmitEvent(new GameEvent(
GameEventType.PlayerEliminated,
lastPlayer,
Message: $"☠️ {lastPlayer.Name} stratil všetky karty a vypadáva z Olympijského turnaja!"
));
}
}
var remainingTournamentPlayers = State.ActiveTournamentPlayers;
if (remainingTournamentPlayers.Count <= 1)
{
// Koniec turnaja! Zostal iba 1 víťaz
State.IsGameOver = true;
State.IsMatchOver = true;
State.MatchWinner = remainingTournamentPlayers.FirstOrDefault() ?? lastPlayer;
State.TurnState = TurnState.GameOver;
EmitEvent(new GameEvent(
GameEventType.MatchWon,
State.MatchWinner,
Message: $"🥇 {State.MatchWinner?.Name} sa stal celkovým OLYMPIJSKÝM ŠAMPIÓNOM!"
));
}
else
{
// Koniec jedného kola, nasleduje ďalšie
State.IsRoundOver = true;
State.TurnState = TurnState.RoundOver;
EmitEvent(new GameEvent(
GameEventType.RoundOver,
lastPlayer,
ExtraData: State.RoundNumber,
Message: $"🏅 Kolo #{State.RoundNumber} sa skončilo! {lastPlayer?.Name} bude mať v ďalšom kole {lastPlayer?.OlympicCardsCount} kariet."
));
}
}
else
{
// Bežná jednoduchá hra
State.IsGameOver = true;
State.TurnState = TurnState.GameOver;
EmitEvent(new GameEvent(
GameEventType.GameOver,
null,
Message: "Koniec hry! Všetky pozície sú určené."
));
}
}
}
public void StartNextRound()
{
if (!State.Rules.OlympicMode || State.IsMatchOver) return;
State.RoundNumber++;
State.IsRoundOver = false;
State.IsGameOver = false;
State.RoundLoser = null;
State.TurnState = TurnState.Playing;
State.TurnCount = 1;
State.PendingDrawCount = 0;
State.PendingSkip = false;
State.ActiveSuit = null;
State.PendingHornikPlayer = null;
foreach (var p in State.Players)
{
p.Reset();
}
// Vytvorenie a zamiešanie nového balíčka
State.DrawDeck = _deckManager.CreateShuffledDeck();
State.DiscardPile.Clear();
// Rozdanie kariet len aktívnym (nevyradeným) hráčom podľa ich OlympicCardsCount
foreach (var player in State.ActiveTournamentPlayers)
{
for (int i = 0; i < player.OlympicCardsCount; i++)
{
if (State.DrawDeck.Count > 0)
{
var card = State.DrawDeck[0];
State.DrawDeck.RemoveAt(0);
player.Hand.Add(card);
}
}
}
// Otočenie prvej karty na odhadzovaciu kôpku
var startCard = State.DrawDeck[0];
State.DrawDeck.RemoveAt(0);
State.DiscardPile.Add(startCard);
// Nastavíme prvého hráča na prvého aktívneho
var firstActiveIndex = State.Players.FindIndex(p => !p.IsEliminated);
State.CurrentPlayerIndex = firstActiveIndex >= 0 ? firstActiveIndex : 0;
EmitEvent(new GameEvent(
GameEventType.GameStarted,
State.CurrentPlayer,
Card: startCard,
Message: $"🏅 Začalo sa Kolo #{State.RoundNumber} Olympijského Faraóna!"
));
}
private void AdvanceTurn()
{
if (State.IsGameOver) return;
if (State.IsGameOver || State.IsRoundOver) return;
int attempts = 0;
do
@@ -579,12 +688,12 @@ public class GameEngine
State.CurrentPlayerIndex = (State.CurrentPlayerIndex + 1) % State.Players.Count;
attempts++;
}
while (State.CurrentPlayer.HasFinished && attempts <= State.Players.Count);
while ((State.CurrentPlayer.HasFinished || State.CurrentPlayer.IsEliminated) && attempts <= State.Players.Count * 2);
State.TurnCount++;
// Ak hráme Pass & Play a nasledujúci hráč je človek a je zapnutá súkromná clona
if (State.Rules.PassAndPlayPrivacyScreen && State.CurrentPlayer.Type == PlayerType.Human && State.Players.Count(p => p.Type == PlayerType.Human) > 1)
if (State.Rules.PassAndPlayPrivacyScreen && State.CurrentPlayer.Type == PlayerType.Human && State.ActiveTournamentPlayers.Count(p => p.Type == PlayerType.Human) > 1)
{
State.TurnState = TurnState.PassScreen;
}
+4 -1
View File
@@ -13,7 +13,10 @@ public enum GameEventType
PlayerRevived,
PlayerFinished,
GameOver,
DeckReshuffled
DeckReshuffled,
RoundOver,
PlayerEliminated,
MatchWon
}
public record GameEvent(
+10 -1
View File
@@ -5,6 +5,7 @@ public enum TurnState
Playing,
SelectingSuit,
PassScreen,
RoundOver,
GameOver
}
@@ -25,7 +26,15 @@ public class GameState
public Player? PendingHornikPlayer { get; set; }
public Card? TopCard => DiscardPile.Count > 0 ? DiscardPile[^1] : null;
// Olympijský režim (Turnaj)
public int RoundNumber { get; set; } = 1;
public bool IsRoundOver { get; set; } = false;
public Player? RoundLoser { get; set; }
public Player? MatchWinner { get; set; }
public bool IsMatchOver { get; set; } = false;
public Player CurrentPlayer => Players.Count > 0 ? Players[CurrentPlayerIndex % Players.Count] : new Player();
public int ActivePlayersCount => Players.Count(p => !p.HasFinished);
public int ActivePlayersCount => Players.Where(p => !p.IsEliminated).Count(p => !p.HasFinished);
public List<Player> ActiveTournamentPlayers => Players.Where(p => !p.IsEliminated).ToList();
}
+10
View File
@@ -27,6 +27,16 @@ public class Player
public bool IsSkipped { get; set; }
/// <summary>
/// Počet kariet do ruky v Olympijskom režime (kto prehrá kolo, klesá o 1).
/// </summary>
public int OlympicCardsCount { get; set; } = 5;
/// <summary>
/// Či je hráč vyradený z Olympijského turnaja.
/// </summary>
public bool IsEliminated => OlympicCardsCount <= 0;
public Player() { }
public Player(string name, PlayerType type, string avatar = "👤", AIDifficulty difficulty = AIDifficulty.Medium)
+6
View File
@@ -41,4 +41,10 @@ public class RuleOptions
/// Zvolený vizuálny štýl balíčka ("original" alebo "spongebob").
/// </summary>
public string SelectedDeck { get; set; } = "original";
/// <summary>
/// Olympijský režim: Vyraďovací turnaj. Kto prehrá kolo, má v ďalšom o 1 kartu menej.
/// Hrá sa až kým nezostane iba jeden celkový víťaz.
/// </summary>
public bool OlympicMode { get; set; } = false;
}