program Lora;
{verze 1.01; 2008-03-01}
{c 2008 Rudolf Rosa <rur@seznam.cz>, Matematicko-fyzikalni fakulta Univerzita Karlova v Praze, 1. roc., zimni semestr, programovani(IP), studium prezencni bakalarske, ID studia: 237976}
{zapoctovy program - NPRG030 - Programovani I - Doc. RNDr. Topfer Pavel, CSc.}
{oficialni Pravidla Lory viz http://www.volny.cz/petasites/Pravidla_Lory.htm}
{doporuceny kompilator: Free Pascal Compiler}
{opensource}

uses crt;

{###############
TYPE, CONST, VAR
###############}

type MiniPoleChar   = array [0..3] of char; {pro ulozeni nazvu barev}
     MalePoleChar   = array [0..7] of char; {pro ulozeni nazvu karet}
     KartaChar      = string [2]; {znakove oznaceni karty}
     MiniPoleByte   = array [0..3] of byte; {4 karty/skore/...}
     MalePoleByte   = array [0..7] of byte; {pro 8 karet}
     VsechnyKarty   = array [0..31] of byte; {pro vsechny karty}
     KartyPoCtyrech = array [0..3] of MalePoleByte; {pro vsechny karty ve 4 skupinkach}
     
     KartyM         = set of 0..31; {mnozina pro karty}
     KartyPoCtyrechM= array [0..3] of KartyM; {mnozina pro karty pro 4 hrace}
     
     Hry            = (C,F,P,V,B,Q,D,M);

const Barvy:   MiniPoleChar = ('c','k','z','z');  {cervene, kule, zelene, zaludy}
      Karty:   MalePoleChar = ('7','8','9','X','S','F','K','E');  {sedma, osma, devitka, desitka, spodek, filek, kral, eso}
      BarvyId: MiniPoleByte = (LightRed, LightMagenta, LightGreen, Brown);
      BarvyPrg:MiniPoleByte = (Black, Brown, Blue, White); {barvy programu: text; pozadi; pozadi karty; ladici informace}
      HraNazev: array [C..M] of string[16] = ('cervene','filky','prvni - posledni','vsechny','cerveny kral','kvarty','desitky','maturita');
      
      KartyPodleBarevM:     KartyPoCtyrechM = ([0,4, 8,12,16,20,24,28],[1,5, 9,13,17,21,25,29],[2,6,10,14,18,22,26,30],[3,7,11,15,19,23,27,31]); {mnoziny karet podle barev}
      KartyNecerveneM:      KartyM = [1,2,3,5,6,7,9,10,11,13,14,15,17,18,19,21,22,23,25,26,27,29,30,31];
      KartyFilkyM:          KartyM = [20..23];
      KartyDivokaKartaM:    KartyM = [20..31];  {v Qartach - zadna nizsi karta nez F}
      
      LADENI = false;  {standardne false; pokud je true, vypisuje ruzne dalsi informace}
      ZIVYHRAC = 1;  {standardne 1 (ceka se na vstup uzivatele); 2: hraje za nej random; 3: hraje za nej UI}

var Balicek: VsechnyKarty; {vsechny karty v balicku}
    Rozdani: KartyPoCtyrech; {karty hracu 0~3}
    RozdaniM: KartyPoCtyrechM; {karty hracu 0~3 jako mnoziny}
    KartyZahraneM: KartyM; {vsechny karty, ktere uz jsou na stole}
    Stych: MiniPoleByte; {aktualni stych (karty lezici na stole)}
    KartyVynesitelne: MalePoleByte; {karty, ktere muze Hrac vynest}
    KartyVynesitelnePocet: byte; {pocet karet v KartyVynesitelne}
    Pakl: VsechnyKarty; {odehrane karty pred hracem, otocene reversem vzhuru (stychy ktere hrac sebral; zarazka = hodnota 32)}
    
    Talie, {0~3}
    Vynos, {pokolikate se prave v dilci hre vynasi (0~7)}
    Karta, {karta, se kterou se prave pracuje}
    Hrac, HracPoradi, HracVynasejici: byte; {ten, ktery prave hraje; jako kolikaty hraje Hrac (vynasejici hrac ma poradi 0); ten, ktery vynaseji/vynasel}
    HracClovek: byte;  {ktery hrac je clovek; moznosti: 0, 1, 2, 3}
    PocetKaret: MiniPoleByte; {kolik ma hrac v ruce karet}
    
    SkoreCelkove, SkoreHra, CistaStovka : MiniPoleByte; {skore jednotlivych hracu; skore jednotlivych hracu ziskane v aktualni hre; zda hraci jdou na cistou stovku}
    SkoreStych, {bodove ohodnoceni aktualniho stychu}
    StychBarva: byte; {barva stychu}
    StychMaxTyp, StychMaxHrac: byte; {nejvyssi vynesena karta (barvy StychBarva) a kdo ji vynesl}
    
    Hra: Hry; {aktualni hra; pokud se hraje maturita: hra zvolena maturantem}
    Maturita: byte; {0 - nehraje se maturita; 1~3: kolikaty pokus}
    
    log: text; {log hry}

{###################
PROCEDUTRY A FUNKCE
###################}

procedure ok; {procedura pro ladeni - neni soucasti programu}
  begin
    writeln('ok');
  end;

function abs(cislo: integer):byte;
  begin
    if cislo<0 then cislo:=-cislo;
    abs:=cislo;
  end;

function karta2char(Karta: byte): KartaChar;
  begin
    if Karta=32 then karta2char:='__' else
    karta2char:=Barvy[Karta mod 4]+Karty[Karta div 4];
  end;
  
function vyJa(Hrac: byte): string[5];
  {je-li Hrac clovek, vraci VY, jinak PC (puvodne JA, odtud nazev procedury)}
  begin
    if Hrac=HracClovek then vyJa:=' (VY)' else vyJa:=' (PC)';
  end;

procedure zvuk;
  begin
    Sound(100); Delay(100); NoSound;
  end;

procedure cekejNaStisk;
  begin
    if ZIVYHRAC=1 then repeat readkey until not KeyPressed;  {ceka az user stiskne a pusti klavesu}
  end;

procedure nulujPole(var Pole: array of byte);
  {nastavi vsechny hodnoty v poli na 0}
  var i: byte;
  begin
    for i := 0 to High(Pole) do Pole[i] := 0;
  end;

{VYPISOVANI}
procedure writeKarta(Karta:byte);
  {vypise na obrazovku kartu}
  begin
    TextBackground(BarvyPrg[2]); TextColor(BarvyId[Karta mod 4]);
    write(karta2char(Karta));
    write(log,karta2char(Karta));
    TextBackground(BarvyPrg[1]); TextColor(BarvyPrg[0]);
    write(' ');
    write(log,' ');
  end;
  
procedure vypisKarty(Pole: MalePoleByte; Pocet: byte; VypisovatCislo: boolean);
  {vypise [Pocet] karet v poli}
  var i:byte;
  begin
    if Pocet>0 then for i := 0 to (Pocet-1) do begin
      if VypisovatCislo then write(i+1,':');
      writeKarta(Pole[i]);
    end;
  end;

procedure doplnMezerami;
  {vypise mezery az do konce aktualniho radku}
  var i: byte;
  begin
  for i:= WhereX to 80 do write(' ');
  end;
  
type Zpravy = (HrajeteJako, InformaceNaZacatkuStychu, InformaceNaZacatkuStychuQ, InformaceNaZacatkuHryD, KartaNesenaHracem, KartaNesenaHracemD, TukD, KonecStychu, KonecStychuQ, InfoSkore, Cista100, Cista100Info, MaturitaVyber, MaturitaVyberInfo, VyberteKartu, NevynasetDalsi, InfoPakl, NaTuhleSeKouka, VitezstviQ, VitezstviD, MaturantNeodmaturoval, Bedrnik, KonecLory);

procedure vypisZpravu(Typ: Zpravy);
  var i:byte;
  begin
    case Typ of
      HrajeteJako: begin
        writeln('Hrajete jako hrac ',HracClovek,'. Pro spusteni hry stisknete libovolnou klavesu.');
      end;
      InformaceNaZacatkuStychu: begin
        write('Hraje se ',Talie+1,'. talie, ');
        writeln(log); if Vynos=0 then write(log,'Hraje se ',Talie+1,'. talie, ');
        if Maturita>0 then write(Maturita,'. maturita hrace ',Talie,vyJa(Talie),', ');
        if Maturita>0 then write(log,Maturita,'. maturita hrace ',Talie,', ');
        writeln('hra ',HraNazev[Hra]); writeln;
        if Vynos=0 then writeln(log,'hra ',HraNazev[Hra]);
        if LADENI then begin {vypis karty hracu} for i:= 0 to 3 do begin write('Hrac ',i,vyJa(i),': ',PocetKaret[i],' '); vypisKarty(Rozdani[i],PocetKaret[i],false); writeln; end; end;
        write('Vase karty:  ');
        write(log,'Vase karty:  ');
        vypisKarty(Rozdani[HracClovek],PocetKaret[HracClovek],false); {vypise karty hrace HracClovek}
        writeln; writeln; writeln(log);
        vypisZpravu(InfoPakl);
        writeln; writeln;
        writeln(Vynos+1,'. stych, vynasi Hrac ',HracVynasejici,vyJa(HracVynasejici)); writeln;
        writeln(log,Vynos+1,'. stych, vynasi Hrac ',HracVynasejici); 
      end;
      InformaceNaZacatkuStychuQ: begin
        write('Hraje se ',Talie+1,'. talie, ');
        writeln(log); write(log,'Hraje se ',Talie+1,'. talie, ');
        if Maturita>0 then write(Maturita,'. maturita hrace ',Talie,vyJa(Talie),', ');
        writeln('hra ',HraNazev[Hra]); writeln;
        writeln(log,'hra ',HraNazev[Hra]); 
        writeln('Pocty karet hracu:');
        if LADENI then begin {vypis karty hracu} for i:= 0 to 3 do begin write('Hrac ',i,vyJa(i),': ',PocetKaret[i],' '); vypisKarty(Rozdani[i],PocetKaret[i],false); writeln; end; end else begin
        for i:= 0 to 3 do writeln('Hrac ',i,vyJa(i),': ',PocetKaret[i]); writeln; end;
        write('Vase karty:  ');
        write(log,'Vase karty:  ');
        vypisKarty(Rozdani[HracClovek],PocetKaret[HracClovek],false); {vypise karty hrace HracClovek}
        writeln; writeln; writeln(log);
        vypisZpravu(InfoPakl);
        writeln; writeln;
        writeln('Vynasi Hrac ',HracVynasejici,vyJa(HracVynasejici)); writeln;
        writeln(log,'Vynasi Hrac ',HracVynasejici); 
      end;
      InformaceNaZacatkuHryD: begin
        write('Hraje se ',Talie+1,'. talie, ');
        writeln(log); write(log,'Hraje se ',Talie+1,'. talie, ');
        if Maturita>0 then write(Maturita,'. maturita hrace ',Talie,vyJa(Talie),', ');
        writeln('hra ',HraNazev[Hra]); writeln;
        writeln(log,'hra ',HraNazev[Hra]); 
        writeln('Pocty karet hracu:');
        if LADENI then begin {vypis karty hracu} for i:= 0 to 3 do begin write('Hrac ',i,vyJa(i),': ',PocetKaret[i],' '); vypisKarty(Rozdani[i],PocetKaret[i],false); writeln; end; writeln; end else begin
        for i:= 0 to 3 do writeln('Hrac ',i,vyJa(i),': ',PocetKaret[i]); writeln; end;
        write('Vase karty:  ');
        write(log,'Vase karty:  ');
        vypisKarty(Rozdani[HracClovek],PocetKaret[HracClovek],false); {vypise karty hrace HracClovek}
        writeln(log);
        GotoXY(1,21);
        for i:= 0 to 3 do writeln('Hrac ',i,vyJa(i),': ');
      end;
      KartaNesenaHracem: begin
        write('Hrac ',Hrac,vyJa(Hrac),': ');
        write(log,'Hrac ',Hrac,': ');
        writeKarta(Karta);
        writeln; writeln(log);
      end;
      KartaNesenaHracemD: begin
        {karta na stul}
        write(log,'Hrac ',Hrac,': ');
        GotoXY( (2 + (Karta div 4)*3) , (13 + (Karta mod 4)*2) );
        writeKarta(Karta);
        {pocet karet hrace}
        GotoXY(14,(4+Hrac));
        write(PocetKaret[Hrac]);
        if LADENI then begin {vypise karty hrace} write(' ');vypisKarty(Rozdani[Hrac],PocetKaret[Hrac],false); doplnMezerami; end;
        {kdo co vynesl}
        write(log,'Hrac ',Hrac,': ');
        GotoXY(14+Vynos*3,21+Hrac);
        writeKarta(Karta);
        doplnMezerami; writeln(log);
        {karty cloveka}
        if Hrac=HracClovek then begin
          GotoXY(14,9);
          write(log,'Vase karty: ');
          vypisKarty(Rozdani[HracClovek],PocetKaret[HracClovek],false); {vypise karty hrace HracClovek}
          writeln(log);
          doplnMezerami;
        end;
      end;
      TukD: begin {tuk}
        GotoXY(14,21+Hrac);
        write('tuk');
        doplnMezerami;
        writeln(log,'Hrac ',Hrac,': tuk');
      end;
      KonecStychu: begin
        writeln; writeln;
        write(Vynos+1,'. stych bere hrac ',StychMaxHrac,vyJa(StychMaxHrac),' a ');
        case SkoreStych of
          0: write ('nedostava za nej zadne trestne body.');
          1: write ('dostava za nej 1 trestny bod.');
          2..4: write ('dostava za nej ',SkoreStych,' trestne body.');
          5..99: write ('dostava za nej ',SkoreStych,' trestnych bodu.');
        end;
        write(log,Vynos+1,'. stych bere hrac ',StychMaxHrac,'. Pocet ziskanych trestnych bodu: ',SkoreStych); writeln(log); 
      end;
      KonecStychuQ: begin
        writeln; writeln;
        writeln('Tento stych bere hrac ',StychMaxHrac,vyJa(StychMaxHrac),'.');
        writeln(log,'Tento stych bere hrac ',StychMaxHrac,'.');
        writeln;
      end;
      InfoSkore: begin
        zvuk;
        writeln;
        if (Maturita <> 0) AND (SkoreHra[Talie]=0) then writeln('Hrac ',Talie,vyJa(Talie),' odmaturoval! Gratuluji!');
        cekejNaStisk;
        clrscr;
        writeln; writeln('Skore:');
        for i:= 0 to 3 do writeln('Hrac ',i,vyJa(i),': v teto hre: ',SkoreHra[i],', celkem: ',SkoreCelkove[i],' ');
        writeln(log); writeln(log,'Skore:');
        for i:= 0 to 3 do writeln(log,'Hrac ',i,': v teto hre: ',SkoreHra[i],', celkem: ',SkoreCelkove[i],' ');
        writeln;
      end;
      Cista100: begin
        clrscr;
        writeln; write('Chcete nahlasit cistou stovku?   0:Ne  1:Ano');
      end;
      Cista100Info: begin
        writeln; writeln;
        write('Hrac ',HracClovek,vyJa(HracClovek),' ');
        if CistaStovka[HracClovek]=0 then write('ne');
        write('nahlasil cistou stovku.')
      end;
      MaturitaVyber: begin  {Maturant muze vybrat: C, F, V, B, Q, D. Pri treti maturite muze i P.}
        cekejNaStisk;
        clrscr;
        writeln;
        write(' Vase karty:  ');
        vypisKarty(Rozdani[HracClovek],PocetKaret[HracClovek],false); {vypise karty hrace HracClovek}
        writeln; writeln; writeln(' Vyberte hru pro maturitu:'); writeln;
        Hra := C;
        for Hra:= C to D do begin
          if (Hra<>P) OR (Maturita = 3) then begin writeln(' ',(ord(Hra)+1),': ',HraNazev[Hra]); writeln; end;   {pri treti maturite smi hrac vybrat cokoliv, jinak nesmi vybrat P}
        end;
      end;
      MaturitaVyberInfo: begin  {Maturant muze vybrat: C, F, V, B, Q, D. Pri treti maturite muze i P.}
        writeln; writeln; writeln(' Byla vybrana hra ',HraNazev[Hra],'.');
        writeln(log,' Byla vybrana hra ',HraNazev[Hra],'.');  
      end;
      VyberteKartu: begin
        if Hra=D then GotoXY(1,11);
        write('>Vyberte kartu:   ');
      end;
      NevynasetDalsi: begin
        write('0: nevynaset dalsi');
      end;
      InfoPakl: begin
        write('Vas pakl: ');
        write(log,'Vas pakl: ');
        i := 0;
        while Pakl[i]<>32 do begin
          writeKarta(Pakl[i]);
          inc(i);
        end;
        writeln;
      end;
      NaTuhleSeKouka: begin
        writeln('Na tuhle kartu se kouka!');
        writeln(log,'Na tuhle kartu se kouka!');
      end;
      VitezstviQ: begin
        writeln('Vitezem techto kvaret se stava Hrac ',Hrac,vyJa(Hrac),'.');
        writeln(log,'Vitezem techto kvaret se stava Hrac ',Hrac,'.');
      end;
      VitezstviD: begin
        GotoXY(1,11);
        if PocetKaret[Hrac]=0 then begin
          writeln('Hrac ',Hrac,vyJa(Hrac),' zavrel!');
          doplnMezerami;
          writeln(log,'Hrac ',Hrac,' zavrel!');
        end;
      end;
      MaturantNeodmaturoval: begin
        writeln;
        if Hra=D then GotoXY(1,11);
        writeln('Hrac ',Talie,vyJa(Talie),' neodmaturoval!');
        writeln('Hrac ',Talie,' dostava 8 trestnych bodu, ostatni hraci jsou bez trestnych bodu.');
        writeln(log,'Hrac ',Talie,' neodmaturoval! Hrac ',Talie,' dostava 8 trestnych bodu, ostatni hraci jsou bez trestnych bodu.');
        writeln;
      end;
      Bedrnik: begin
        writeln;
        writeln('Ve stychu byl Bedrnik! Hrac ',StychMaxHrac,vyJa(StychMaxHrac),' dostava 8 trestnych bodu.');
        if Vynos=0 then writeln('Fuuuj, Bedrnik v prvnim stychu!!!');  {to je nesportovni gesto}
        writeln(log,'Ve stychu byl Bedrnik! Hrac ',StychMaxHrac,' dostava 8 trestnych bodu.');
        writeln;
      end;
      KonecLory: begin
        zvuk; zvuk; zvuk;
        clrscr;
        writeln; writeln('Konec hry!');
        writeln; writeln('Konecne skore:');
        writeln(log); writeln(log); writeln(log,'Konec hry! Konecne skore:');
        for i:= 0 to 3 do begin
          writeln;
          write('Hrac ',i,vyJa(i),': ',SkoreCelkove[i]);
          if CistaStovka[i]=1 then begin
            write(' (cista stovka - ');
            if SkoreCelkove[i]=100 then write('uspesne!)') else write('neuspesne!)');
          end;
          writeln;
        end;
        for i:= 0 to 3 do writeln(log, 'Hrac ',i,vyJa(i),': ',SkoreCelkove[i]);
        writeln;
        cekejNaStisk;
        cekejNaStisk;
        writeln;
      end;
    end;
  end;

procedure zamichat;
  var i: integer;
      Karta,temp1,temp2: byte;
  begin
    for i := 0 to 1000 do
    begin {prohodi dve nahodne karty}
      temp1:=random(32);
      temp2:=random(32);
      Karta:=Balicek[temp1];
      Balicek[temp1]:=Balicek[temp2];
      Balicek[temp2]:=Karta;
    end;
  end;

procedure rozdat;
  {rozdava karty presne podle pravidel Lory, tedy po dvou}
  var Osmice, Barva, Typ, Karta: byte;
  begin
    for Hrac := 0 to 3 do RozdaniM[Hrac] := []; {mnoziny karet vsech hracu jsou prazdne}
    nulujPole(PocetKaret);
    {rozdat karty - do mnozin RozdaniM}
    for Osmice := 0 to 3 do begin {pro kazdou osmici karet}
      for Hrac := 0 to 3 do RozdaniM[Hrac] := RozdaniM[Hrac] + [Balicek[Osmice*8 + Hrac*2],Balicek[Osmice*8 + Hrac*2 + 1]]; {rozda hraci dve karty}
    end;
    {podle mnozin nastavi obsah pole Rozdani - tak aby v nem karty byly setrideny tak, jak je zvykem, tedy podle barvy (C,K,Z,Z) a podle typu vzestupne}
    for Barva := 0 to 3 do begin
      for Typ := 0 to 7 do begin
        Karta := Typ*4+Barva; 
        for Hrac := 0 to 3 do begin
          if Karta in RozdaniM[Hrac] then begin
            Rozdani[Hrac][PocetKaret[Hrac]] := Karta; {da kartu na prvni volnou pozici v poli karet hrace}
            inc(PocetKaret[Hrac]);  {inkrementuje pocet karet hrace}
          end;
        end;
      end;
    end;
  end;

procedure prihodit;
  {realizace prihozeni karty Karta hracem Hrac, ktery hraje jako HracPoradi-ty}
  var i,j: byte;
  begin
    if Hra <> D then Stych[HracPoradi] := Karta; {karta se objevuje ve stychu (u D nesmysl)}
    dec(PocetKaret[Hrac]);  {hrac ma o kartu mene}
    RozdaniM[Hrac]:=RozdaniM[Hrac]-[Karta];   {hrac prichazi o kartu}
    KartyZahraneM:=KartyZahraneM+[Karta];   {karta je zahrana}
    {prerovnavani - necht na pozicich 0..PocetKaret[Hrac] jsou karty ktere hrac ma}
    if PocetKaret[Hrac]>0 then begin  {pokud hrac nema zadne karty, neni co prerovnavat}
      i:=0;
      while Rozdani[Hrac][i] <> Karta do inc(i);  {i := pozice karty Karta v poli}
      for j:= i to (PocetKaret[Hrac]-1) do Rozdani[Hrac][j] := Rozdani[Hrac][j+1];  {karty za touto pozici se posunou o jednu doleva}
    end;
  end;

function predchoziD(Karta: byte): byte;
  {vrati kartu, ktera v desitkach bezprostredne predchazi karte Karta, nebo hodnotu 32}
  begin
    case (Karta div 4) of
      0..2: predchoziD:=Karta+4;  {o jednu vyssi}
      3: predchoziD:=32;  {je to desitka => neexistuje predchozi karta}
      4..7: predchoziD:=Karta-4;  {o jednu nizsi}
    end;
  end;

procedure pridejDoPaklu (Kolik: byte);
  {prida do Pakl Kolik karet ze Stych}
  var Zacatek,i: byte;
  begin
    Zacatek:= 0; while Pakl[Zacatek]<>32 do inc(Zacatek); {Zacatek = pozice zarazky}
    for i := 0 to (Kolik-1) do Pakl[Zacatek+i] := Stych[i]; {pridat do Pakl i-tou kartu ze Stych}
    Pakl[Zacatek+Kolik]:=32; {nova pozice zarazky}
  end;

procedure pridejDoKartyVynesitelne (Karta: byte);
  {prida do KartyVynesitelne kartu Karta}
  begin
    KartyVynesitelne[KartyVynesitelnePocet]:=Karta;
    inc(KartyVynesitelnePocet);
  end;

procedure pridejDoKartyVynesitelneVsechny;
  {prida do KartyVynesitelne vsechny karty hrace Hrac}
  begin
    KartyVynesitelne:=Rozdani[Hrac];
    KartyVynesitelnePocet:=PocetKaret[Hrac];
  end;

function readNumberChar(min,max: byte):byte;
  {precte znak a udela z nej cislo - znak musi byt vetsi nez min a mensi nez max}
  var znak: char;
  begin
    znak:=' '; {inicializace}
    while ( ord(znak)-ord('0') < min ) OR ( ord(znak)-ord('0') > max ) do znak:=readkey;
    readNumberChar:= ord(znak)-ord('0');
  end;

procedure skorePrepocti;
  {prepocitani celkoveho skore - pricteni skore za danou hru}
  var Hrac: byte;
  begin
    for Hrac:= 0 to 3 do inc(SkoreCelkove[Hrac],SkoreHra[Hrac]);
  end;

procedure vyberHru;
  {clovek maturant vybira hru}
  var HraCislo, i: byte;
  begin
    if ZIVYHRAC=1 then begin
      vypisZpravu(MaturitaVyber);
      if Maturita=3 then HraCislo:=readNumberChar(1,7) else begin  {pri treti maturite smi hrac vybrat cokoliv}
        repeat
          HraCislo:=readNumberChar(1,7);
        until (HraCislo <> 3); {hrac nesmi vybrat P}
      end;
      Hra:=C;
      for i := 2 to HraCislo do Hra:=succ(Hra);  {kolikata hra, tolikata hra}
      vypisZpravu(MaturitaVyberInfo);
    end else Hra:=B;
  end;

{################
UMELA INTELIGENCE
################}

procedure UI;
  {hlavni rozhodovaci procedura, vystupem je Karta, kterou nese Hrac}
  var UIKarty: MalePoleByte;  {obsahuje "skore" jednotlivych karet - karta s nejvyssim skore bude vynesena}
      KartaPoradi,  {poradi v poli KartyVynesitelne}
      i, temp, max, min: byte;
      {podminka: boolean;  podle potreby podminka pro neco}   
  
  {UI - VNITRNI PROCEDURY A FUNKCE}
  
  procedure podlejzat;
    {podlezam (nechci brat stych) - vynasim co nejvyssi nizsi, pripadne co nejnizsi vyssi; jsem-li posledni vynasejici a musim-li stych vzit, vynasim nejvyssi co muzu}
    var Karta, KartaPoradi: byte;
    begin
      for KartaPoradi := 0 to (KartyVynesitelnePocet-1) do begin
        Karta:=KartyVynesitelne[KartaPoradi];
        if (Karta div 4) < StychMaxTyp then begin  {podjlejzaci karta}
          UIKarty[KartaPoradi]:= 100+(Karta div 4);
          if (Hra=F) AND (Karta div 4 = 5) then inc(UIKarty[KartaPoradi],4);  {podlezt filkem}
          if (Hra=B) AND (Karta = 24) then inc(UIKarty[KartaPoradi],50);  {podlezt bedrnikem}
        end else begin  {prelejzaci karta}
          UIKarty[KartaPoradi]:= 50;
          if HracPoradi=3 then inc(UIKarty[KartaPoradi],(Karta div 4))  {budu to muset vzit => klidne co nejvyssi kartou}
          else dec(UIKarty[KartaPoradi],(Karta div 4));  {treba me jeste nekdo preleze => dam tam co nejnizsi kartu}
          if (Hra=F) AND (Karta div 4 = 5) then UIKarty[KartaPoradi]:= 0;  {filkem neprelejzat}
          if (Hra=B) AND (Karta = 24) then UIKarty[KartaPoradi]:= 0;  {bedrnikem neprelejzat}
        end;
      end;
    end;
  
  procedure ctitBarvu;
    {ctim barvu - pokud je to bezpecne, muzu stych vzit, jinak podlejzam}
    var Karta, KartaPoradi: byte;
    begin
      if (HracPoradi=3) AND (SkoreStych=0) then   {ve stychu neni trestna karta a ja jsem posledni}
        for KartaPoradi := 0 to KartyVynesitelnePocet-1 do begin
          Karta:=KartyVynesitelne[KartaPoradi];
          if NOT (((Hra=F) AND (Karta div 4 = 5)) OR ((Hra=B) AND (Karta = 24))) then  {pokud karta neni trestna}
            UIKarty[KartaPoradi]:= (KartyVynesitelne[KartaPoradi] div 4) + 1;  {muzu s ni vzit stych}
        end
      else podlejzat;  {stych muze byt trestny => podlejzam}
    end;
  
  function pocetVlastnichNizsichKaret(Karta, max: byte): byte;
    {pocet nizsich karet, ktere mam v ruce; maximalne do urovne max (napr. 3 = pro F hleda S, X a 9)}
    var vysledek: byte; {mezivysledek}
    begin
      vysledek:=0;
      while (Karta>3) and (max>0) do begin  {dokud nejsem na sedmicce}
        dec(max);
        dec(Karta,4); {o 1 nizsi karta}
        if (Karta in RozdaniM[Hrac]) then inc(vysledek); {Kartu mam v ruce}
      end;
      pocetVlastnichNizsichKaret:= vysledek;
    end;
  
  function pocetNizsichKaret(Karta, max: byte): byte;
    {pocet nizsich karet, ktere jsou jeste ve hre; maximalne do urovne max (napr. 3 = pro F hleda S, X a 9)}
    var vysledek: byte; {mezivysledek}
    begin
      vysledek:=0;
      while (Karta>3) and (max>0) do begin  {dokud nejsem na sedmicce}
        dec(max);
        dec(Karta,4); {o 1 nizsi karta}
        if not (Karta in KartyZahraneM) then inc(vysledek); {Karta nebyla jeste zahrana}
      end;
      pocetNizsichKaret:= vysledek;
    end;
  
  function pocetVyssichKaret(Karta, max: byte): byte;
    {pocet vyssich karet, ktere jsou jeste ve hre; maximalne do urovne max (napr. 3 = pro 9 hleda X, S a F)}
    var vysledek: byte; {mezivysledek}
    begin
      vysledek:=0;
      while (Karta<28) and (max>0) do begin  {dokud nejsem na esu}
        dec(max);
        inc(Karta,4); {o 1 vyssi karta}
        if not (Karta in KartyZahraneM) then inc(vysledek); {Karta nebyla jeste zahrana}
      end;
      pocetVyssichKaret:= vysledek;
    end;
  
  function pocetVlastnichVyssichKaret(Karta, max: byte): byte;
    {pocet vyssich karet, ktere jsou jeste ve hre; maximalne do urovne max (napr. 3 = pro 9 hleda X, S a F)}
    var vysledek: byte; {mezivysledek}
    begin
      vysledek:=0;
      while (Karta<28) and (max>0) do begin  {dokud nejsem na esu}
        dec(max);
        inc(Karta,4); {o 1 vyssi karta}
        if (Karta in RozdaniM[Hrac]) then inc(vysledek); {Karta nebyla jeste zahrana}
      end;
      pocetVlastnichVyssichKaret:= vysledek;
    end;
  
  function pocetNizsichKaretVsech(Karta: byte): byte;
    begin
      pocetNizsichKaretVsech:=pocetNizsichKaret(Karta,7);
    end;
  
  function pocetNizsichKaretVsechCizich(Karta: byte): byte;
    begin
      pocetNizsichKaretVsechCizich:=pocetNizsichKaret(Karta,7) - pocetVlastnichNizsichKaret(Karta,7);
    end;
  
  function pocetVyssichKaretVsech(Karta: byte): byte;
    begin
      pocetVyssichKaretVsech:=pocetVyssichKaret(Karta,7);
    end;
  
  function pocetVyssichKaretVsechCizich(Karta: byte): byte;
    begin
      pocetVyssichKaretVsechCizich:=pocetVyssichKaret(Karta,7) - pocetVlastnichVyssichKaret(Karta,7);
    end;
  
  procedure nejlepsiKartaProVynos;
    {typicky chci vynest co nejnizsi kartu; zaroven nechci vynest trestnou kartu nebo takovou kartu, ze by stych nikdo nemohl vzit}
    var Karta, KartaPoradi: byte;
    begin
      for KartaPoradi := 0 to (KartyVynesitelnePocet-1) do begin
        Karta:=KartyVynesitelne[KartaPoradi];
        UIKarty[KartaPoradi] := 50 + 3*pocetVyssichKaretVsechCizich(Karta) - pocetNizsichKaretVsechCizich(KartyVynesitelne[KartaPoradi]);  {cim vice je ve hre vyssich karet, tim je pro me karta nizsi, a naopak}
        if ( (Hra=F) AND ( (Karta div 4) = 5) ) OR ( (Hra=B) AND (Karta = 24) ) then dec(UIKarty[KartaPoradi],30);  {trestna karta}
        if ((RozdaniM[Hrac]-[Karta]) * KartyPodleBarevM[Karta mod 4])=[] then inc(UIKarty[KartaPoradi],2);  {karta je jedina sve barvy}
      end;
    end;
  
  procedure zbavovatSeKaret;
    {typicky chci vynest co nejvyssi kartu; je-li trestna nebo jedina sve barvy, tim lip}
    var Karta, KartaPoradi: byte;
    begin
      for KartaPoradi := 0 to (KartyVynesitelnePocet-1) do begin
        Karta:=KartyVynesitelne[KartaPoradi];
        UIKarty[KartaPoradi] := 50 + pocetNizsichKaretVsechCizich(Karta) - pocetVyssichKaretVsechCizich(KartyVynesitelne[KartaPoradi]);  {cim vice je ve hre vyssich karet, tim je pro me karta nizsi, a naopak}
        if (Hra=C) AND (Karta mod 4 = 0) then inc(UIKarty[KartaPoradi],4);  {cervena}
        if (Hra=F) AND (Karta div 4 = 5) then inc(UIKarty[KartaPoradi],4);  {filek}
        if (Hra=B) AND (Karta = 24) AND (Vynos <> 0) then inc(UIKarty[KartaPoradi],50);  {bedrnik}
        if (Hra=B) AND (Karta = 24) AND (Vynos = 0) then dec(UIKarty[KartaPoradi],30);  {bedrnik - nechci byt nesportovni, proto ho nehazim do prvniho stychu}
        if (Hra=B) AND (Karta < 24) AND (Karta mod 4 = 0) then dec(UIKarty[KartaPoradi],30);  {nezbavuju se karet, kterymi muzu podlezt bedrnika}
        if ((RozdaniM[Hrac]-[Karta]) * KartyPodleBarevM[Karta mod 4])=[] then inc(UIKarty[KartaPoradi],6);  {karta je jedina sve barvy}
      end;
    end;
  
  function DmuzuZavrit:boolean;
    {D - vyhodi true pokud Hrac muze zavrit, jinak false}
    var i,Karta:byte;
    begin
      for i := 0 to PocetKaret[Hrac] do begin
        Karta:=Rozdani[Hrac][i];
        if not ((Karta div 4 = 3) OR (predchoziD(Karta) in KartyZahraneM) OR (predchoziD(Karta) in RozdaniM[Hrac])) then begin  {pokud ne: karta je desitka / predchozi ke karte je na stole / pr.k. ke k. mam v ruce}
          DmuzuZavrit:=false; {nemuzu zavrit}
          exit; {ukonceni funkce}
        end;
      end;
      DmuzuZavrit:= true;  {cyklus nebyl ukoncen => muzu zavrit}
    end;
  
  function DzavislostP(Karta: byte):byte;
    {D - nejvyssi karta zavisla zprava na karte Karta: 0 = neni, 1..4 = S..E}
    var vysledek: byte; {mezivysledek}
    begin
      vysledek:=0;
      inc(Karta,4); {naseldujici karta}
      while Karta<32 do begin  {dokud nejsem za esem}
        if Karta in RozdaniM[Hrac] then vysledek:= (Karta div 4) - 3; {hrac ma kartu Karta - vysledek = normalizovany typ}
        inc(Karta,4);
      end;
      DzavislostP:= vysledek;
    end;
  
  function DzavislostL(Karta: byte):byte;
    {D - nejnizsi karta zavisla zleva na karte Karta: 0 = neni, 1..3 = 9..7}
    var vysledek: byte; {mezivysledek}
    begin
      vysledek:=0;
      while Karta>3 do begin  {dokud nejsem na sedmicce}
        dec(Karta,4); {nasledujici karta}
        if Karta in RozdaniM[Hrac] then vysledek:= 3 - (Karta div 4); {hrac ma kartu Karta - vysledek = normalizovany typ}
      end;
      DzavislostL:= vysledek;
    end;
  
  function Dzavislost(Karta: byte):byte;
    {D - existuje zavisla karta?}
    begin
      case (Karta div 4) of
        0..2: Dzavislost := DzavislostL(Karta);  {7..9}
        3: Dzavislost := DzavislostL(Karta)+DzavislostP(Karta);  {X}
        4..7: Dzavislost := DzavislostP(Karta);  {S..E}
      end;
    end;
  
  
  {UI - VLASTNI TELO PROCEDURY}
  begin
    {inicializace}
    nulujPole(UIKarty);
    if (Hra=D) AND (Vynos>0) then begin   {navic moznost nevynest nic}
      KartyVynesitelne[KartyVynesitelnePocet]:=32;
      inc(KartyVynesitelnePocet);
    end;
    if KartyVynesitelnePocet=1 then begin    {neni z ceho vybirat}
      Karta:=KartyVynesitelne[0];
      exit;
    end;
    {rozliseni podle her}
    case Hra of
      
      {CERVENY}
      C: begin
        if HracPoradi=0 then nejlepsiKartaProVynos {vynasim}
        else if (KartyVynesitelne[0] mod 4 = StychBarva) then ctitBarvu {prihazuju barvu}
             else zbavovatSeKaret  {nemam barvu}
      end;
      
      {FILKY}
      F: begin
        if HracPoradi=0 then nejlepsiKartaProVynos {vynasim}
        else if (KartyVynesitelne[0] mod 4 = StychBarva) then ctitBarvu {prihazuju barvu}
             else zbavovatSeKaret  {nemam barvu}
      end;
      
      {PR-PO}
      P: begin
        if Vynos in [1..4] then zbavovatSeKaret  {nebezepeci neni velke, muzu hrat divoceji}
        else begin  {hraju standardne - nechci brat stychy}
          if HracPoradi=0 then nejlepsiKartaProVynos {vynasim}
          else if (KartyVynesitelne[0] mod 4 = StychBarva) then ctitBarvu {prihazuju barvu}
               else zbavovatSeKaret  {nemam barvu}
        end;
      end;
      
      {VSECHNY}
      V: begin
        if HracPoradi=0 then nejlepsiKartaProVynos {vynasim}
        else if (KartyVynesitelne[0] mod 4 = StychBarva) then ctitBarvu {prihazuju barvu}
             else zbavovatSeKaret  {nemam barvu}
      end;
      
      {BEDRNIK}
      B: begin
        if HracPoradi=0 then nejlepsiKartaProVynos {vynasim}
        else if (KartyVynesitelne[0] mod 4 = StychBarva) then ctitBarvu {prihazuju barvu}
             else zbavovatSeKaret  {nemam barvu}
      end;
      
      {KVARTY}
      Q: begin
        for KartaPoradi := 0 to KartyVynesitelnePocet-1 do begin
          temp:=KartyVynesitelne[KartaPoradi]+12;  {jdu od nejvyssi mozne karty v potencialnim stychu, az najdu tu nejvyssi, ktera je jeste ve hre}
          while (temp>=32) OR (temp in KartyZahraneM) do dec(temp,4);  {karta by byla vyssi nez E nebo uz byla zahrana; az cyklus skonci, mam nejvyssi kartu potencialniho stychu}
          if temp in RozdaniM[Hrac] then UIKarty[KartaPoradi]:=100 {mam nejvyssi kartu v potencialnim stychu, takze ho beru}
          else UIKarty[KartaPoradi]:=50; {tenhle stych neberu}
          if (pocetVlastnichNizsichKaret(KartyVynesitelne[KartaPoradi],3) > 0)
            then dec(UIKarty[KartaPoradi],36)
            else dec( UIKarty[KartaPoradi] , 9*pocetNizsichKaret(KartyVynesitelne[KartaPoradi],3) );  {cim mene je ve hre predchazejicich karet, tim vetsi ma karta prednost}
          for i := 1 to 3 do
            if (KartyVynesitelne[KartaPoradi]+i*4 < 32) then
              if (KartyVynesitelne[KartaPoradi]+i*4 in RozdaniM[Hrac]) then
                inc(UIKarty[KartaPoradi],3) else dec(UIKarty[KartaPoradi]);  {cim vice karet vezme karta s sebou, tim lip; cim vice souperovych karet, tim hur} 
        end;
      end;
      
      {DESITKY}
      D: begin
        if DmuzuZavrit then begin  {muzu zavrit => pokazde muzu vynest libovolnou kartu - tak proc ne tu nultou}
          Karta:=KartyVynesitelne[0];
          exit;
        end;
        for KartaPoradi := 0 to KartyVynesitelnePocet-1 do begin
          Karta:=KartyVynesitelne[KartaPoradi];
          if Karta div 4 = 3 then begin {karta je desitka}
            UIKarty[KartaPoradi] := Dzavislost(Karta);  {cim vzdalenejsi zavisle karty, tim vetsi skore}
            if UIKarty[KartaPoradi]>0 then begin  {mam na ni zavisle karty}
              if (DzavislostL(Karta)>0) AND (DzavislostP(Karta)>0) then inc(UIKarty[KartaPoradi],40)  {oboustranna zavislost}
              else inc(UIKarty[KartaPoradi],20);  {jednostranna zavislost}
            end;
          end else begin
            if Karta = 32 then begin {"karta" je "nevynaset dalsi kartu"}
              min := 8;
              for i := 0 to 3 do if (i<>Hrac) AND (PocetKaret[i]<min) then min:=PocetKaret[i];   {minimalni pocet karet ostatnich hracu}
              if min<3 then begin
                UIKarty[KartaPoradi] := 30; {nektery hrac uz je blizko zavreni => chci se trochu zbavit karet}
              end else begin
                UIKarty[KartaPoradi] := 60; {hra se jeste neblizi ke konci => co nemusim, nevynasim}
              end;
            end else begin  {karta je normalni karta}
              if Dzavislost(Karta)>0 then begin  {na karte jsou zavisle jine me karty}
                UIKarty[KartaPoradi] := 100;
              end else begin   {na karte neni zadna moje karta zavisla}
                if (Karta div 4 = 0) OR (Karta div 4 = 7) then UIKarty[KartaPoradi] := 50  {je to 7 nebo E}
                else UIKarty[KartaPoradi] := 10 + ((abs(Karta-14)-2) div 4); {skore = 10 + (vzdalenost od X)}
              end;
            end;
          end;
        end;
      end;
    end;
    
    {vyber maximum}
    max:=0; {index maxima - pro zacatek necht je to prvni vynesitelna karta}
    for i := 1 to (KartyVynesitelnePocet-1) do if (UIKarty[i] > UIKarty[max]) then max := i;
    Karta:=KartyVynesitelne[max];   {vynest kartu s maximalnim ohodnocenim}
    
    if LADENI then begin
      temp:=WhereY;
      gotoXY(1,25);
      TextColor(BarvyPrg[3]);
      for i := 0 to (KartyVynesitelnePocet-1) do write(karta2char(KartyVynesitelne[i]),':',UIKarty[i],' ');
      TextColor(BarvyPrg[0]);
      doplnMezerami;
      cekejNaStisk;
      gotoXY(1,temp);
    end;
  end;

{########
SRDCE HRY
########}

procedure hratManualne;
  {necht Hrac vybere kartu z KartyVynesitelne -> vystup v Karta; 32 pokud uz nechce hrat (D)}
  var i:byte;
  begin
    case ZIVYHRAC of
      1: begin
        vypisZpravu(VyberteKartu);
        vypisKarty(KartyVynesitelne,KartyVynesitelnePocet,true);

        if (Hra=D) AND (Vynos>0) then begin
          vypisZpravu(NevynasetDalsi);  {hrac uz nejakou kartu vynesl => nemusi jiz vynaset dalsi}
          i:=readNumberChar(0,KartyVynesitelnePocet);
        end else i:=readNumberChar(1,KartyVynesitelnePocet);
        if i=0 then Karta:=32 else Karta:=KartyVynesitelne[i-1];
        GotoXY(1,WhereY);
        doplnMezerami;
        GotoXY(1,WhereY);
      end;
      2: Karta:=KartyVynesitelne[Random(KartyVynesitelnePocet)];
      3: UI;
    end;
  end;

procedure hratPrebijeci; {hrat nejakou prebijeci hru - C, F, P, V, B}
var j: byte;
begin
  {CYKLUS PRO KAZDY VYNOS}
  for Vynos:= 0 to 7 do begin {bude se vynaset 8x}
    {INICIALIZACE VYNOSU}
    cekejNaStisk;
    clrscr;
    vypisZpravu(InformaceNaZacatkuStychu);
    StychMaxTyp:=0; {jakoby sedmicka - urcite nebude nejvyssi karta nizsi nez 7}
    StychMaxHrac:=HracVynasejici; {nejvyssi kartu nejdriv urcite vynese prvni hrac}
    {SkoreStych}
    SkoreStych:=0;
    if Hra in [P,V] then begin {trestne body za stych}
      case Hra of
        P: if (Vynos = 0) OR (Vynos = 7) then SkoreStych:=4; {prvni/posledni stych po 4 bodech}
        V: SkoreStych:=1; {kazdy stych za 1 bod}
      end;
    end;
    
    {CYKLUS PRO VSECHNY HRACE}
    for HracPoradi:= 0 to 3 do begin {kolikaty hrac hraje}
      Hrac := (HracVynasejici + HracPoradi) mod 4; {ktery hrac hraje}
      {KartyVynesitelne = karty, ktere smi hrac vynest}
      KartyVynesitelnePocet:=0;
      if Hrac = HracVynasejici then begin {hrac vynasi}
        if (Hra in [C,B]) AND (RozdaniM[Hrac] * KartyNecerveneM <> []) then begin {plati pravidlo o prednostnim vynosu necervenych karet a hrac ma nejake necervene karty => hrac vynasi necervenou kartu}
          {do pole KartyVynesitelne da karty, ktere lze vynest}
          for j:= 0 to (PocetKaret[Hrac]-1) do begin
            if (Rozdani[Hrac][j] mod 4) <> 0 then pridejDoKartyVynesitelne(Rozdani[Hrac][j]); {neni-li karta cervena, muze ji hrac vynest}
          end;
        end else pridejDoKartyVynesitelneVsechny; {vynasi cokoliv}
      end else begin {hrac prihazuje}
        if (RozdaniM[Hrac] * KartyPodleBarevM[StychBarva] <> []) then begin {hrac cti barvu - ma karty stejne barvy jako je barva stychu}
        {vynasi kartu barvy stychu}
          {do pole KartyVynesitelne da karty, ktere lze vynest}
          for j:= 0 to (PocetKaret[Hrac]-1) do begin
            if (Rozdani[Hrac][j] mod 4) = StychBarva then pridejDoKartyVynesitelne(Rozdani[Hrac][j]);
          end;
        end else pridejDoKartyVynesitelneVsechny; {vynasi cokoliv}
      end;
      
      {HRAC VYBIRA KARTU Z POLE KartyVynesitelne}
      if Hrac=HracClovek then hratManualne else UI;
      
      {BARVA STYCHU}
      if HracPoradi=0 then StychBarva:=Karta mod 4; {pokud slo o vynos, je barva stychu dana vynesenou kartou}
      
      prihodit; {realizace prihozeni karty}
      
      {VYSTUP}
      vypisZpravu(KartaNesenaHracem);
      
      {StychMaxTyp, StychMaxHrac}
      if (Karta mod 4) = StychBarva then begin {byla ctena barva}
        if (Karta div 4) > StychMaxTyp then begin {karta prebiji - je nejvyssi dosud vynesena}
          StychMaxTyp := Karta div 4;
          StychMaxHrac:= Hrac;
        end;
      end;
      
      {SKORE pokud Karta je trestna}
      if Hra in [C,F,B] then begin {jedna se o trestnou kartu?}
        case Hra of
          C: if (Karta mod 4) = 0 then inc(SkoreStych  ); {karta je cervena -> 1 bod}
          F: if (Karta div 4) = 5 then inc(SkoreStych,2); {karta je filek -> 2 body}
          B: if  Karta        =24 then inc(SkoreStych,8); {karta je bedrnik -> 8 bodu}
        end;
      end;
    
    end;
    {KONEC - CYKLUS PRO VSECHNY HRACE}
    
    {HRAC StychMaxHrac (ten, ktery bere stych)}
    inc(SkoreHra[StychMaxHrac],SkoreStych); {ziskava trestne body za stych}
    if (StychMaxHrac=HracClovek) AND (PocetKaret[Hrac]>0) then pridejDoPaklu(4);  {hrac je clovek -> ma pakl; pokud uz hrac nema karty, neni treba provadet; nesene karty byly 4}
        
    {trestny bod maturanta?}
    if (Maturita <> 0) AND (SkoreHra[Talie]>0) then begin {hrala se maturita a maturant dostal bod; maturujici hrac = cislo Talie}
      vypisZpravu(MaturantNeodmaturoval);
      {vsichni maji 0 bodu, maturant ma 8 bodu}
      nulujPole(SkoreHra);
      SkoreHra[Talie] := 8;
      break;
    end;
    
    {bedrnik?}
    if (Hra = B) AND (SkoreStych>0) then begin {hral se bedrnik a byl odhozen}
      vypisZpravu(Bedrnik);
      break;
    end;
    
    {ZAKONCENI}
    HracVynasejici:=StychMaxHrac;
    vypisZpravu(KonecStychu);
  end; {KONEC - CYKLUS PRO KAZDY VYNOS}
end; {KONEC - procedure hratPrebijeci}

procedure hratQarty;
var j: byte;
label Vitezstvi;
begin
  {CYKLUS PRO KAZDY VYNOS}
  while (PocetKaret[0] <> 0) AND (PocetKaret[1] <> 0) AND (PocetKaret[2] <> 0) AND (PocetKaret[3] <> 0) do begin  {dokud maji vsichni hraci karty}
    {INICIALIZACE VYNOSU}
    cekejNaStisk;
    clrscr;
    vypisZpravu(InformaceNaZacatkuStychuQ);
    StychMaxHrac:=HracVynasejici; {nejvyssi kartu nejdriv urcite vynese prvni hrac}
    HracPoradi := 0;
    Hrac := HracVynasejici; {ktery hrac hraje}
    {KartyVynesitelne = karty, ktere smi hrac vynest}
    KartyVynesitelnePocet:=0;
    if (Hrac=Talie) AND (PocetKaret[Hrac]=8) then begin {jde o prvni vynos}
      if (RozdaniM[Hrac] - KartyDivokaKartaM = []) then begin {hrac ma divokou kartu - jen F, K a E}
        if (RozdaniM[Hrac] * KartyFilkyM = []) then begin {hrac ma kralovskou kvartu => zvitezi, vynasi libovolneho krale}
          for j:= 0 to (PocetKaret[Hrac]-1) do begin
            if (Rozdani[Hrac][j] div 4) = 6 then pridejDoKartyVynesitelne(Rozdani[Hrac][j]) {karta je kral - hrac ji muze vynest}
          end;
        end else begin {hrac ma divokou kartu => vynasi libovolneho filka}
          for j:= 0 to (PocetKaret[Hrac]-1) do begin
            if (Rozdani[Hrac][j] div 4) = 5 then pridejDoKartyVynesitelne(Rozdani[Hrac][j]) {karta je filek, hrac ji muze vynest}
          end;
        end;
      end else begin {hrac nema divokou kartu => vynasi cokoliv mensiho nez filka}
        for j:= 0 to (PocetKaret[Hrac]-1) do begin
          if Rozdani[Hrac][j] < 20 then pridejDoKartyVynesitelne(Rozdani[Hrac][j]) {karta je mensi nez filek, hrac ji muze vynest}
        end;
      end
    end else begin {nejde o prvni vynos, vynasi cokoliv}
      if PocetKaret[Hrac] = 1 then begin  {vynasejicimu hraci zbyla posledni karta -> na tu se "kouka" (nepriklada se na ni) a hrac vitezi}
        Karta:=Rozdani[Hrac][0];
        PocetKaret[Hrac]:=0;
        vypisZpravu(KartaNesenaHracem);
        vypisZpravu(NaTuhleSeKouka);
        goto Vitezstvi; {jde o urcitou nestandardni situaci, proto je pouzit skok}
      end else pridejDoKartyVynesitelneVsechny; {muze zahrat libovolnou kartu}
    end;
      
    {HRAC VYBIRA KARTU Z POLE KartyVynesitelne}
    if Hrac=HracClovek then hratManualne else UI;
    
    prihodit; {realizace prihozeni karty}
    
    {VYSTUP}
    vypisZpravu(KartaNesenaHracem);

    {CYKLUS PRO ZBYVAJICI KARTY}
    j:=0; {indikace breaku}
    for HracPoradi := 1 to 3 do begin
      inc(Karta,4);
      if (Karta > 31) OR NOT (Karta in (RozdaniM[0]+RozdaniM[1]+RozdaniM[2]+RozdaniM[3])) then begin j:=1; break; end; {dalsi karta by byla vyssi nez E, nebo ji nikdo uz nema}
      for Hrac := 0 to 3 do begin   {zjistujeme, ktery hrac ma Kartu}
        if (Karta in RozdaniM[Hrac]) then begin {ma ji}
          prihodit;
          StychMaxHrac:=Hrac;   {hrac vynesl soucasnou nejvyssi kartu ve stychu}
          vypisZpravu(KartaNesenaHracem);
        end;
      end;
    end;
    if j=1 then dec(HracPoradi); {byl break, poslednim hrajicim hracem byl tedy HracPoradi-1}
    
    {HRAC StychMaxHrac (ten, ktery bere stych)}
    if StychMaxHrac=HracClovek then pridejDoPaklu(HracPoradi+1);  {hrac je clovek -> ma pakl; neseno bylo HracPoradi+1 karet}
        
    {ZAKONCENI}
    HracVynasejici:=StychMaxHrac;
    vypisZpravu(KonecStychuQ);
  end; {KONEC - CYKLUS PRO KAZDY VYNOS}
  Vitezstvi:
  for Hrac:= 0 to 3 do begin
    SkoreHra[Hrac]:=PocetKaret[Hrac];
    if SkoreHra[Hrac]=0 then vypisZpravu(VitezstviQ);
  end;
  
  {trestny bod maturanta?}
  if (Maturita <> 0) AND (SkoreHra[Talie]>0) then begin {hrala se maturita a maturant dostal bod; maturujici hrac = cislo Talie}
    vypisZpravu(MaturantNeodmaturoval);
    {vsichni maji 0 bodu, maturant ma 8 bodu}
    nulujPole(SkoreHra);
    SkoreHra[Talie] := 8;
  end;
  
end;

procedure hratDesitky;
var j: byte;
begin
  {INICIALIZACE HRY}
  Hrac:=HracVynasejici;
  HracPoradi:=0;
  cekejNaStisk;
  clrscr;
  vypisZpravu(InformaceNaZacatkuHryD);
  {CYKLUS PRO KAZDY VYNOS}
  while (PocetKaret[0] <> 0) AND (PocetKaret[1] <> 0) AND (PocetKaret[2] <> 0) AND (PocetKaret[3] <> 0) do begin  {dokud maji vsichni hraci karty}
    
    Vynos:=0; {kolik karet jiz hrac vylozil}
    
    repeat  {v desitkach muze hrac vynaset karty, dokud muze}
      {KartyVynesitelne = karty, ktere smi hrac vynest}
      KartyVynesitelnePocet:=0;
      for j:= 0 to (PocetKaret[Hrac]-1) do begin
        if (Rozdani[Hrac][j] div 4 = 3) OR (predchoziD(Rozdani[Hrac][j]) in KartyZahraneM) then pridejDoKartyVynesitelne(Rozdani[Hrac][j]) {karta je desitka nebo predchozi karta je na stole}
      end;
      {vynest kartu}
      if KartyVynesitelnePocet=0 then begin
        {nemuze vynest}
        Karta:=32;
        if Vynos=0 then begin {tuk}
          vypisZpravu(TukD);
          inc(SkoreHra[Hrac]);
          if Hrac=HracClovek then cekejNaStisk;
        end;
      end else begin
        {HRAC VYBIRA KARTU Z POLE KartyVynesitelne}
        if Hrac=HracClovek then hratManualne else UI;
        if Karta<>32 then begin
          {PRIHOZENI}
          prihodit;
          vypisZpravu(KartaNesenaHracemD);
        end else begin
          {neprihozeni}
          if Vynos=0 then begin {tuk}
            vypisZpravu(TukD);
            inc(SkoreHra[Hrac]);
          end;
        end;
      end;
      inc(Vynos);
    until (Karta=32) OR (PocetKaret[Hrac]=0);
    
    {ZAKONCENI}
    if PocetKaret[Hrac]=0 then break;  {tim se dostaneme z cyklu ven => k vitezstvi}
    Hrac:= (Hrac+1) mod 4; {nasledujici hrac}
    HracPoradi:= (HracPoradi+1) mod 4; {nasledujici hrac}
    
    {trestny bod maturanta?}
    if (Maturita <> 0) AND (SkoreHra[Talie]>0) then break; {hrala se maturita a maturant dostal bod; maturujici hrac = cislo Talie}
  
  end; {KONEC - CYKLUS PRO KAZDY VYNOS}
  
  vypisZpravu(VitezstviD);
  
  for Hrac:= 0 to 3 do begin
    inc(SkoreHra[Hrac],PocetKaret[Hrac]);
  end;
  
  {trestny bod maturanta?}
  if (Maturita <> 0) AND (SkoreHra[Talie]>0) then begin {hrala se maturita a maturant dostal bod; maturujici hrac = cislo Talie}
    vypisZpravu(MaturantNeodmaturoval);
    {vsichni maji 0 bodu, maturant ma 8 bodu}
    nulujPole(SkoreHra);
    SkoreHra[Talie] := 8;
  end;
  
end;

{########################
ZACATEK HLAVNIHO PROGRAMU
########################}
begin
  
  {inicializace}
  randomize;
  TextColor(BarvyPrg[0]);
  TextBackground(BarvyPrg[1]);
  TextMode(C80);
  clrscr;
  assign(log,'lora.log');
  rewrite(log);
  
  for Karta := 0 to 31 do Balicek[Karta]:=Karta; {karty v balicku v poradi danem jejich cisly}
  nulujPole(SkoreCelkove);
  nulujPole(CistaStovka);
  
  HracClovek:=random(4);  {cislo hrace, ktery je clovek}
  vypisZpravu(HrajeteJako);
  
  {HLAVNI CYKLUS}
  for Talie:= 0 to 3 do begin
    {inicializace talie}
    Maturita:=0; {nehraje se maturita}
    Hra:= C;   {pocatecni hra !}
    while true do begin {cyklus pro kazdou dilci hru v talii Talie - puvodne to byl for-cyklus s iteracni promennou Hra, ale pak bylo nutne menit hodnotu iteracni promenne, coz se nelibi FPC}
      {inicializace hry}
      zamichat;
      rozdat;
      HracVynasejici:=Talie; {v 1. talii vynasi v kazde hre jako prvni 1. hrac, ve 2. talii 2. hrac... (BUNO)}
      nulujPole(SkoreHra);
      for Hrac := 0 to 3 do PocetKaret[Hrac] := 8; {hrac ma 8 karet}
      Pakl[0]:=32; {prazdny pakl - zarazka na zacatek}
      KartyZahraneM := []; {nebyly dosud zahrany zadne karty}
      {cista stovka}
      if (Hra=B) AND (Talie=2) then begin
        {clovek voli, zda se bude pokouset o cistou stovku}
        if ZIVYHRAC=1 then begin
          cekejNaStisk;
          vypisZpravu(Cista100);
          CistaStovka[HracClovek] := readNumberChar(0,1);
          vypisZpravu(Cista100Info);
        end else CistaStovka[HracClovek] := 0;
      end;
      {maturita}
      if Hra = M then begin  {maturant vybira hru}
        inc(Maturita);
        if Talie=HracClovek then vyberHru else Hra:=B;  {clovek vybira hru k maturite; pocitac vzdy vybira Bedrnika}
      end;
      {HRAT}
      case Hra of
        C..B: hratPrebijeci;  {bude se hrat nejaka prebijeci hra - C, F, P, V, B}
        Q: hratQarty;         {bude se hrat Q}
        D: hratDesitky;       {bude se hrat D}
      end;
      {ukonceni, nastaveni nasledujici hry}
      skorePrepocti;
      vypisZpravu(InfoSkore);
      {!break;}
      if (Maturita <> 0) then begin {hrala se maturita; maturujici hrac = cislo Talie}
        if (SkoreHra[Talie]=0) OR (Maturita = 3) then break {hrac odmaturoval nebo uz to byl treti pokus => konec talie}
        else Hra:=M; {hrac ma dalsi pokus}
      end else begin
        Hra:=Succ(Hra); {nehrala se maturita => normalne se pokracuje nasledujici hrou}
      end;
    end;
  end;
  
  vypisZpravu(KonecLory);
  Close(log);
end.

