Anglická verze
logolink

< Zpět na seznam lekcí

Hra pexeso V

AlgortimyObsah lekce:

  • Porovnání kartiček
  • Průběh hry

Porovnání kartiček

Před vytvoření popisu algoritmu pro průběh hry je třeba vytvořit ještě jednu proceduru a touto procedurou bude porovnání kartiček. Po otočení dvojice kartiček je třeba zjistit, zda jsou kartičky shodné a v případě, že shodné jsou, tyto kartičky odebrat a upravit skóre daného hráče.

Potřebnou proceduru pojmenujeme porovnejkarticky a na vstupu budou 4 vstupní hodnoty:

  • Souřadnice dvou kartiček k porovnání (celočíselné proměnné typu int, označíme je x1, y1, x2 a y2).

Tato funkce bude mít i návratovou hodnotu. Tou bude informace, zda jsou kartičky shodné nebo ne.

Základ funkce pro porovnání kartiček
int porovnejkarticky(int x1, int x2, int y1, int y2)
{
  if (p[x1][y1].obrazek==p[x2][y2].obrazek) return 1;
  else return 0;
}

Do této funkce zatím pouze doplníme podmínku, která porovná dvě kartičky pexesa a pokud je hodnota obrazek shodná, procedura uloží do proměnné shodne hodnotu 1 (pravda), v opačném případě doplní do této proměnné hodnotu 0 (nepravda).

Následně proceduru ještě rozšíříme. V případě, že jsou kartičky shodné, tak se provedou dvě úpravy hodnot u těchto kartiček:

  • Hodnota viditelna se nastaví zpět na 0.
  • Hodnota odebrana se změní na 1.
Funkce pro porovnání kartiček
int porovnejkarticky(int x1, int x2, int y1, int y2)
{
  p[x1][y1].viditelna=0;
  p[x2][y2].viditelna=0;
  if (p[x1][y1].obrazek==p[x2][y2].obrazek) 
  {
       p[x1][y1].odebrana=1;
       p[x2][y2].odebrana=1;
       return 1;
  }
  else return 0;
}

Kromě přidání několika piřazení hodnot bylo nutné příkazy v bloku IF umístit do bloku { ... }. Důvodem je použití více příkazů u větve IF. V případě jednoho příkazu je možné používat bez { ... } tak, jako v předchozím příkladu.

Průběh hry

Pro správnou funkci programu Pexeso chybí již jen jedna funkce. Touto procedurou je část programu, která bude řídit průběh hry. Funkci si pojmenujeme hra.

Funkce hra nebude mít žádné vstupní parametry, ale bude nutné si definovat několik lokálních proměnných:

  • hrac - určuje číslo hráče, který je na řadě
  • radek1, sloupec1 - souřadnice 1. otočené kartičky
  • radek2, sloupec2 - souřadnice 2. otočené kartičky
  • shodnekarticky - uložení informace, zda jsou otočené kartičky shodné
  • konechry - pomocná proměnná, která bude řídit cyklus průběhu hry

Uveďme si tedy nejprve základní kostru funkce hra doplněnou o tyto lokální proměnné. Následně si doplníme i další příkazy a funkce této procedury.

Procedura pro řízení běhu hry
void hra()
{
     int konechry, shodnekarticky;
     int hrac, radek1, radek2, sloupec1, sloupec2;

}

Následně již můžeme definovat průběh hry. Základem bude cyklus while, který bude prováděn, pokud proměnná konechry bude mít hodnotu 0. Jakmile se změní na 1, hra bude ukončena.

Před spuštěním tohoto cyklu je třeba nastavit proměnnou konechry na hodnotu 0 a také je tžeba nastavit výchozí hodnotu pro proměnnou hrac. Tato proměnná bude určovat, který hráč je na řadě a na počátku bude mít hodnotu 0.

Procedura pro řízení běhu hry
void hra()
{
     int konechry, shodnekarticky;
     int hrac, radek1, radek2, sloupec1, sloupec2;
     
     hrac = 0;
     konechry = 0;
     
     while (konechry == 0)
     {
     		zobrazenipexesa();
            otockarticku();
            zobrazenipexesa();
            otockarticku();
            zobrazenipexesa();
            shodnekarticky = porovnejkarticky(radek1,sloupec1,radek2,sloupec2);
            if (shodnekarticky == 1)
            {
                 ph[hrac].skore = ph[hrac].skore + 1;
            }
            else
            {
               if (hrac != pocethracu-1)
               {
                   hrac = hrac + 1;
               }
               else
               {
                   hrac = 0;
               }
            }
            fflush(stdin);
            getchar();
     }
}

Uvnitř cyklu, který bude řídit průběh hry dojde postupně k otočení dvou kartiček (dvě volání funkce otockarticku). Tato funkce zajistí otočení kartičky a uložení jejich souřadnic do proměnných radek1, sloupec1 (případně radek2, sloupec2). Následně jsou kartičky porovnány prostřednictvím procedury porovnejkarticku (výsledkem je proměnná shodnekarticky, do které bude uložena informace, zda jsou kartičky shodné, či nikoliv).

Následně je spuštěna podmínka, která ověří, zda jsou kartičky shodné. Pokud jsou shodné, zvýší skóre aktuálního hráče o 1 (ph[hrac].skore = ph[hrac].skore+1;), v opačném případě se zvýší číslo hráče o 1 (nebo se změní na 1, pokud byl na řadě poslední hráč v pořadí).

Důležité je ještě volání funkce zobrazenipexesa po každé změně (otočení kartičky, vyhodnocení stejných kartiček, ...).

Tento cyklus se opakuje, pokud ve hře zůstávají nějaké kartičky.

Pro správnou funkci programu doplníme ještě ošetření konce hry (změna proměnné konechry na hodnotu true).

Procedura pro řízení běhu hry s ošetřením konce hry
void hra()
{
     int konechry, shodnekarticky;
     int hrac, radek1, radek2, sloupec1, sloupec2;
     int pocet;
     
     hrac = 0;
     konechry = 0;
     
     while (konechry == 0)
     {
     		zobrazenipexesa();
            otockarticku();
            radek1 = rx;
            sloupec1 = sx;
            zobrazenipexesa();
            otockarticku();
            radek2 = rx;
            sloupec2 = sx;
            zobrazenipexesa();
            shodnekarticky = porovnejkarticky(radek1,sloupec1,radek2,sloupec2);
            if (shodnekarticky == 1)
            {
                 ph[hrac].skore = ph[hrac].skore + 1;
                 pocet = 0;
                 for (int i = 0; i < pocethracu; i++)
                 {
                     pocet = pocet + ph[i].skore;
                 }
                 
                if (pocet == (n*n / 2))
                konechry = true;
            }
            else
            {
               if (hrac != pocethracu-1)
               {
                   hrac = hrac + 1;
               }
               else
               {
                   hrac = 0;
               }
            }
            fflush(stdin);
            getchar();
     }
}

Následně v hlavní části programu odstraníme všechny pokusné výpisy a nahradíme je voláním procedury hra. Po této úpravě bude tato část kódu vypadat následovně:

Volání procedury hra v hlavní části programu
 ..
 
 int _tmain(int argc, _TCHAR* argv[])
{

  int radek, sloupec, pocet;

  inicializacepexesa();
  zamichanipexesa();
  inicializacehracu();
  zadejpocethracu();
  zadejpocethracu();
  
  hra();
  
  fflush(stdin);
  getchar();
  
  ...
  

Kompletní kód programu

Aktuálně je již program plně funkční. Pro kompletaci programu chybí již jen výstup do prohlížeče, aby bylo pexeso lépe vzualizováno. Tomuto úkolu bude věnována příští lekce.

Pro úplnost je opět vhodné uvěst kompletní kód našeho programu.

Program po doplnění úprav
program pexeso1;
#include "stdafx.h"
#include <string.h>
#define n 6
#define maxhracu 4

typedef struct {
  int obrazek;
  int viditelna;
  int odebrana;
} karticka;              

typedef struct {
  char jmeno[255];
  int skore;
} hrac;

karticka p[n][n]; 
hrac ph[maxhracu];
int rx, sx;

void inicializacehracu()
{
    int i;
    for (i = 0; i < maxhracu; i++)
    {
        strcpy("",ph[i].jmeno);
        ph[i].skore=0;
    }
} 

void zadejpocethracu()
{
         printf("Zadejte pocet hracu: ");
         scanf("%d",&pocethracu);
         while ((pocethracu < 2) or (pocethracu > maxhracu))
         {
             printf("Zadejte znovu: ");
             scanf("%d",&pocethracu);         
         }
}
    
void zadejjmenahracu()
{
    int i;
    printf("Zadejte jmena hracu:\n");
    for (i = 0; i < pocethracu; i++)
    {
        printf("Zadejte jmeno %d. hrace: ", i+1);
        scanf("%s", &ph[i].jmeno);
    }
}

void inicializacepexesa()
{
	int radek, sloupec, pocet;
    pocet = 1;
        
    for (radek = 0; radek < n; radek++)
    {
        for (sloupec = 0; sloupec < n; sloupec++)
        {
            pocet = pocet + 1;
            p[radek][sloupec].obrazek = pocet % 2;
            p[radek][sloupec].viditelna = 0;
            p[radek][sloupec].odebrana = 0;
        }
    }
}

void zamichanipexesa()
{
  int radek, sloupec;
  int r, s;
  int pom;
  
  for (radek = 0; radek < n; radek++)
  {
    for (sloupec = 0; sloupec < n; sloupec++)
    {
        r = rand()%n;
        s = rand()%n;
        pom = p[radek][sloupec].obrazek;
        p[radek][sloupec].obrazek = p[r][s].obrazek;
        p[r][s].obrazek = pom;
    } 
  }
}

void zobrazenipexesa()
{
  int radek, sloupec;

  for (radek = 0; radek < n; radek++)
  {
    for (sloupec = 0; sloupec < n; sloupec++)
    {
         if (p[radek][sloupec].odebrana == 1)
         {
            printf("X ");
         }
         else
         { 
            if (p[radek][sloupec].viditelna == 1)
            {
              printf("%d ", p[radek][sloupec].obrazek);  
            }
            else
            {
              printf("0 ");  
            }
         }            
    }
    printf("\n");
  }
}


void otockarticku()
{
    int radek, sloupec;
    int kartickaok = 0;
    p[radek][sloupec].viditelna = 1;
    while (kartickaok == 0)
    {
         printf("Zadejte souradnice karticky (radek): ");
         scanf("%d", &radek);
         
        while ((radek < 0) || (radek > n-1))
        {
            printf("Zadejte znovu souradnice karticky (radek): ");
            scanf("%d", &radek);
        }
        
         printf("Zadejte souradnice karticky (sloupec): ");
         scanf("%d", &sloupec);
         
        while ((sloupec < 0) || (sloupec > n-1))
        {
            printf("Zadejte znovu souradnice karticky (sloupec): ");
            scanf("%d", &sloupec);
        }
         
         if ((p[radek][sloupec].odebrana == 0) && (p[radek][sloupec].viditelna == 0))
         {
         	kartickaok = 1;
            p[radek][sloupec].viditelna = 1;
         }
    }
    rx = radek;
    sx = sloupec;
}

void hra()
{
     int konechry, shodnekarticky;
     int hrac, radek1, radek2, sloupec1, sloupec2;
     int pocet;
     
     hrac = 0;
     konechry = 0;
     
     while (konechry == 0)
     {
     		zobrazenipexesa();
            otockarticku();
            radek1 = rx;
            sloupec1 = sx;
            zobrazenipexesa();
            otockarticku();
            radek2 = rx;
            sloupec2 = sx;
            zobrazenipexesa();
            shodnekarticky = porovnejkarticky(radek1,sloupec1,radek2,sloupec2);
            if (shodnekarticky == 1)
            {
                 ph[hrac].skore = ph[hrac].skore + 1;
                 pocet = 0;
                 for (int i = 0; i < pocethracu; i++)
                 {
                     pocet = pocet + ph[i].skore;
                 }
                 
                if (pocet == (n*n / 2))
                konechry = true;
            }
            else
            {
               if (hrac != pocethracu-1)
               {
                   hrac = hrac + 1;
               }
               else
               {
                   hrac = 0;
               }
            }
            fflush(stdin);
            getchar();
     }
}

int _tmain(int argc, _TCHAR* argv[])
{

  int radek, sloupec, pocet;

  inicializacepexesa();
  zamichanipexesa();
  inicializacehracu();
  zadejpocethracu();
  zadejjmenahracu();
  
  hra();

  zobrazenipexesa();
  
  fflush(stdin);
  getchar();
  return 0;
 }

Úkol

Upravte proceduru zobrazpexeso tak, aby zobrazovala i jména hráčů a počty jejich bodů. Do procedury hra přidejte informaci, který hráč je na řadě.

webdesign, xhtml, css, php - Mgr. Michal Mikláš