AI human mode

This commit is contained in:
Michal Vrba
2026-09-03 21:11:25 +02:00
parent 035da18584
commit 9005b4b9be
8 changed files with 1220 additions and 247 deletions
+284
View File
@@ -0,0 +1,284 @@
namespace Faraon.Core.AI;
using System;
using System.Collections.Generic;
using Faraon.Core.Models;
public static class AIDialogueService
{
private static readonly Random _rng = new();
// --- EASY (Začiatočník - prezrádza taktiku a neistotu) ---
private static readonly string[] EasyThinking =
[
"Mám ešte jedno eso, len neviem či ho dať teraz...",
"Keby mi radšej prišla zeleň, to by bolo super.",
"Dúfam, že po mne nikto nehodí sedmu!",
"Mám len samé vysoké karty, čo s tým...",
"Asi ti zmením farbu, táto sa mi veľmi nepáči.",
"Ktorú kartu dať skôr? Táto vyzerá celkom pekne.",
"Nemám veľa možností, toto snáď vyjde.",
"Mám tu jedného horníka, ale bojím sa ho použiť.",
"Ešteže mám túto záchrannú kartu...",
"Snáď nikto nezbadá, že mi ostala už len jedna karta!",
"Hm... pravidlá hovoria, že toto môžem zahrať, nie?",
"Tento ťah snáď nebude úplná katastrofa.",
"Čo ak zahrám toto a súper ma zničí?",
"Uff, dúfam, že nemáš sedmu na ruke."
];
// --- MEDIUM (Taktik - realistické premýšľanie) ---
private static readonly string[] MediumThinking =
[
"Skúsim ti podržať farbu, nech nemôžeš vyložiť.",
"Túto sedmu si radšej pošetrím na neskôr.",
"Pozrime sa, čo s týmto urobíš.",
"Ak teraz zahrám túto kartu, ďalší ťah mám voľný.",
"Idem po istote, netreba zbytočne riskovať.",
"Vidím, že zbieraš túto farbu, tak ti ju zmením.",
"Rýchle combo by ťa teraz mohlo prekvapiť.",
"Mením taktiku na rýchle vyprázdnenie ruky.",
"Kľúčové bude neprepustiť ťah bez tlaku.",
"Opatrný ťah, ešte nie je čas na otvorené finále.",
"Počítam karty, toto by malo bezpečne prejsť.",
"Skúsim ťa prinútiť potiahnuť z balíčka."
];
// --- HARD (Veľmajster - psychologické blufovanie a prevaha) ---
private static readonly string[] HardThinking =
[
"Presne do tejto pasce som ťa potreboval dostať.",
"Mám v ruke presne to, čo ťa bude bolieť.",
"Matematicky ti zostávajú maximálne dva ťahy.",
"Risk je zisk. Priprav sa na prekvapenie.",
"Túto hru mám už prečítanú od prvého kola.",
"Si si naozaj istý, že toto bol tvoj najlepší ťah?",
"Môj ďalší krok rozhodne o celom zápase.",
"Viem presne, aké karty ti ostali v ruke.",
"Pripravujem šach-mat, sleduj pozorne.",
"Všetko ide presne podľa môjho majstrovského plánu.",
"Tvoj osud je spečatený, žiadna záchrana nepríde.",
"Geniálny ťah si žiada trochu trpezlivosti."
];
// --- POSLEDNÁ KARTA (1 karta) ---
private static readonly string[] LastCardThoughts =
[
"Už mi chýba len jedna jediná karta!",
"Cítim vôňu víťazstva... už len krok!",
"Dúfam, že ma nikto nezablokuje v poslednej chvíli...",
"Kto ma teraz nezastaví, ten prehral zápas!",
"Už len jeden ťah a titul je môj!"
];
// --- ČELENIE SEDME (Facing Seven) ---
private static readonly string[] FacingSevenThoughts =
[
"Sedma?! Pozrime sa, či mám odpoveď...",
"Dúfam, že mám na ruke ďalšiu sedmu!",
"Toto bude bolieť, ak nemám obranu...",
"Ak mám Zeleného dolníka, tak sa vám vysmejem!"
];
// --- ČELENIE ESU (Facing Ace) ---
private static readonly string[] FacingAceThoughts =
[
"Eso? Skúsim to prebiť vlastným esom!",
"Zamrznúť teraz by bola veľká škoda...",
"Hľadám v ruke eso na prebitie..."
];
// --- BEŽNÉ LÍZANIE (Musí ťahať z balíčka) ---
private static readonly string[] MustDrawThoughts =
[
"Nič mi nesedí, musím líznuť z balíčka...",
"Snáď mi príde niečo poriadne...",
"Balíček, nesklam ma v tejto chvíli!",
"Škoda, tento ťah musím potiahnuť kartu."
];
// --- REAKCIE NA UDALOSTI ---
private static readonly string[] FreezeReactions =
[
"Brrr, to je ale poriadna zima!",
"Zamrzol som na jedno celé kolo...",
"Kto tu pustil túto sibírsku fujavicu?!",
"Počkaj, hneď ako rozmrznem, ti to vrátim!",
"Stojím, ale môj čas ešte len príde.",
"Mráz mi nevadí, aspoň lepšie premyslím stratégiu."
];
private static readonly string[] AceCounterReactions =
[
"Žiadne státie! Moje eso okamžite rozpúšťa ľad!",
"Na mňa si s mrazom neprídeš!",
"Vraciam ti to aj s úrokmi, stojíš ty!"
];
private static readonly string[] SmallPenaltyDrawReactions =
[
"Ejha, +3 karty? To ešte hravo zvládnem.",
"No pekne, sedma ma neobišla...",
"Dobre, beriem 3, ale vrátim vám ich dvojnásobne!"
];
private static readonly string[] BigPenaltyDrawReactions =
[
"Ejha, toľko kariet mi do ruky ani nevojde!",
"To je nejaká organizovaná pomsta?!",
"Kde mám teraz zohnať miesto na ruke pre toľko kariet?!",
"No výborne, zachvíľu budem mať celý balíček...",
"Tento masívny trest vám v ďalšom kole nezabudnem!"
];
private static readonly string[] SevenCanceledReactions =
[
"Haha, Zelený dolník vás zachránil!",
"Štít aktivovaný, dnes žiadne ťahanie sediem!",
"Itel Reding hovorí jasné: Dnes nie!",
"Sedmy vymazané na nulu, ideme ďalej!"
];
private static readonly string[] RevivedTargetReactions =
[
"Znova žijem! Pozor na mňa!",
"Červená sedma robí zázraky! Som späť v hre!",
"Ešte sme neskončili, návrat šampióna!"
];
private static readonly string[] RevivedSourceReactions =
[
"Nikam neodchádzaš, ešte si s tebou zahrám!",
"Vraciam ťa späť do hry, zábava pokračuje!",
"Predčasná radosť, poď pekne naspäť k stolu!"
];
private static readonly string[] SuitChangeReactions =
[
"Prepínam hru na moju obľúbenú farbu!",
"Uvidíme, či máte na túto farbu odpoveď...",
"Trochu to tu zamiešame a zmeníme smer!"
];
private static readonly string[] BurnReactions =
[
"BUM! Všetko zhorelo na prach!",
"Spálené! A ťahám znova!",
"Dokonalé 4 karty, stôl je čistý!"
];
public static string GetThinkingDialogue(Player player, GameState state)
{
if (player.Hand.Count == 1)
{
return PickRandom(LastCardThoughts);
}
if (state.PendingDrawCount > 0)
{
return PickRandom(FacingSevenThoughts);
}
if (state.PendingSkip)
{
return PickRandom(FacingAceThoughts);
}
return player.Difficulty switch
{
AIDifficulty.Easy => PickRandom(EasyThinking),
AIDifficulty.Hard => PickRandom(HardThinking),
_ => PickRandom(MediumThinking)
};
}
public static string GetMustDrawDialogue(Player player)
{
return PickRandom(MustDrawThoughts);
}
public static string GetEventReaction(GameEvent e, Player player)
{
return e.Type switch
{
GameEventType.AceSkipped when e.SourcePlayer == player => PickRandom(FreezeReactions),
GameEventType.AceCountered when e.SourcePlayer == player => PickRandom(AceCounterReactions),
GameEventType.SevenStacked when e.TargetPlayer == player || (e.ExtraData > 0 && e.SourcePlayer != player) =>
e.ExtraData >= 6 ? PickRandom(BigPenaltyDrawReactions) : PickRandom(SmallPenaltyDrawReactions),
GameEventType.SevenCanceled when e.SourcePlayer == player => PickRandom(SevenCanceledReactions),
GameEventType.PlayerRevived when e.TargetPlayer == player => PickRandom(RevivedTargetReactions),
GameEventType.PlayerRevived when e.SourcePlayer == player => PickRandom(RevivedSourceReactions),
GameEventType.SuitChanged when e.SourcePlayer == player => PickRandom(SuitChangeReactions),
GameEventType.CardsBurned when e.SourcePlayer == player => PickRandom(BurnReactions),
_ => ""
};
}
public record CardJoke(string Icon, string Category, string Setup, string Punchline);
// --- VTIPY: MASÍVNY TREST (9 - 12+ kariet) ---
private static readonly CardJoke[] MultiDrawJokes =
[
new("🎒", "KAUZÁLNY BATOH", "Pýta sa Faraón hráča pri stole: 'Prečo si prišiel na zápas s turistickým ruksakom?'", "– 'Aby sa mi tam zmestili všetky tie sedmičky z balíčka!'"),
new("🏢", "VRCHOL OPTIMIZMU", "Viete, čo je vrchol hráčskeho optimizmu?", "– Keď po 12 potiahnutých kartách zahlásiš: 'Počkajte, ešte dve kolá a končím!'"),
new("🏗️", "STAVEBNÝ ZÁMER", "Rozprávajú sa dvaja architekti pri stole:", "– 'Z toľkých kariet v ruke sa už dá postaviť pekný trojizbový byt aj s terasou!'"),
new("🍕", "RODINNÁ PIZZA", "Aký je rozdiel medzi rodinnou pizzou a hráčom s 12 kartami na ruke?", "– Rodinná pizza aspoň niekoho pri stole naozaj poteší!"),
new("📜", "DAŇ Z NEHNUTEĽNOSTI", "Dôležitý oznam od správcu turnaja:", "– Hráč s viac ako 10 kartami začína platiť daň za zastavanú plochu stola!")
];
// --- VTIPY: SPÁLENIE (4 rovnaké karty) ---
private static readonly CardJoke[] BurnJokes =
[
new("🎩", "ILUZIONISTA", "Kúzelník na javisku: 'A teraz sledujte pozorne, nechám zmiznúť 4 karty!'", "– Hráč z rohu kričí: 'Nič nové, to robím v každom kole spálením!'"),
new("🚒", "POŽIARNY POPLACH", "Hasiči práve vyhlásili výjazd k nášmu hernému stolu!", "– Niekto tu práve odpálil 4 rovnaké karty a stôl ľahol popolom!"),
new("🧙", "LEGENDA V OHNI", "Stretnú sa 4 rovnaké karty v balíčku a jedna hovorí:", "– 'Dnes z nás bude buď slávna legenda, alebo čistý popol!'"),
new("🔥", "ČISTÁ POÉZIA", "Spáliť 4 karty naraz jedným ťahom nie je len obyčajné šťastie...", "– ...je to čisté vizuálne umenie a nočná mora pre súperov!")
];
// --- VTIPY: DLHÁ HRA (TurnCount >= 28) ---
private static readonly CardJoke[] LongGameJokes =
[
new("⏳", "RODINNÝ DÔCHODOK", "Manželka volá kartárovi: 'Kedy už prídeš domov z toho zápasu?'", "– 'Drahá, ešte jedno kolo a môžeme ísť rovno spolu do dôchodku!'"),
new("🏛️", "PAMIATKOVÝ ÚRAD", "Táto partia trvá už tak neskutočne dlho...", "– ...že si na ďalší ťah budeme musieť pýtať povolenie od pamiatkárov!"),
new("🧔", "ČAS NA HOLENIE", "Začiatok zápasu: hladko oholení mladíci plní síl.", "– Aktuálny stav: fúzatí veteráni čakajúci na záchrannú zeleň!"),
new("🕰️", "ŠPORTOVÝ VÝKON", "Lekár sa pýta pacienta: 'Koľko hodín denne venujete športu?'", "– 'Už šiestu hodinu bez prestávky sedím pri napínavom Faraónovi!'")
];
// --- VTIPY: OŽIVENIE (Červená sedma) ---
private static readonly CardJoke[] ReviveJokes =
[
new("🧟", "ZÁKAZ ODCHODU", "Lekár konštatuje: 'Hráč úspešne vyhral a odchádza domov.'", "– Červená sedma na to: 'Ešte nie, kamarát! Poď pekne naspäť k stolu!'"),
new("⚡", "VZKRIESENIE ŠAMPIÓNA", "Viete, čo je rýchlejšie ako ranný pondelkový budík?", "– Hráč vrátený do hry Červenou sedmou s chuťou po veľkej pomste!")
];
public static CardJoke? GetContextualJoke(GameEventType? type, int extraData, int turnCount)
{
if (type == GameEventType.SevenStacked && extraData >= 9)
{
return PickRandom(MultiDrawJokes);
}
if (type == GameEventType.CardsBurned)
{
return PickRandom(BurnJokes);
}
if (type == GameEventType.PlayerRevived)
{
return PickRandom(ReviveJokes);
}
if (turnCount >= 28 && turnCount % 16 == 0)
{
return PickRandom(LongGameJokes);
}
return null;
}
private static T PickRandom<T>(T[] options)
{
if (options == null || options.Length == 0) return default!;
return options[_rng.Next(options.Length)];
}
}
+20 -8
View File
@@ -70,22 +70,29 @@ public class RuleOptions
public bool PassAndPlayPrivacyScreen { get; set; } = false;
/// <summary>
/// Úroveň rýchlosti hry (1 = 0.5x, 2 = 0.75x, 3 = 1x Normálna, 4 = 1.5x Rýchla, 5 = 2.5x Turbo).
/// Úroveň rýchlosti hry od -5 (Extra pomalá 0.2x) cez 0 (1x Normálna) až po +5 (Blesková 4x).
/// </summary>
public int SpeedLevel { get; set; } = 3;
public int SpeedLevel { get; set; } = 0;
/// <summary>
/// Rýchlosť AI ťahov v milisekundách podľa zvolenej úrovne rýchlosti.
/// Rýchlosť AI ťahov v milisekundách podľa zvolenej úrovne rýchlosti (-5 až +5).
/// </summary>
public int AIDelayMs
{
get => SpeedLevel switch
{
1 => 1600,
2 => 1200,
4 => 500,
5 => 200,
_ => 900
-5 => 3200,
-4 => 2600,
-3 => 2100,
-2 => 1700,
-1 => 1400,
0 => 1100,
1 => 850,
2 => 650,
3 => 450,
4 => 300,
5 => 150,
_ => 1100
};
set { }
}
@@ -100,4 +107,9 @@ public class RuleOptions
/// Hrá sa až kým nezostane iba jeden celkový víťaz.
/// </summary>
public bool OlympicMode { get; set; } = false;
/// <summary>
/// AI Human Mode: AI hráči zobrazujú premýšľacie bubliny s taktickými a zábavnými hláškami a reagujú na herné udalosti.
/// </summary>
public bool AIHumanMode { get; set; } = false;
}