Anglická verze
logolink

< Zpět na seznam lekcí

Hra pexeso IV

AlgortimyObsah lekce:

  • Otočení kartičky - dokončení
  • Inicializace hráčů
  • Zadání počtu hráčů
  • Zadání jmen hráčů

Ošetření problémů u otočení kartičky

Zatím máme dokončenu jednodušší verzi procedury pro otočení kartičky. Neošetřujeme však možné chyby, jako například pokus o znovu otočení stejné kartičky nebo zadání souřadnic mimo rozsah pole našeho pexesa. Proceduru otockarticku máme zatím v následující podobě:

Otočení kartičky
void otockarticku(int radek, int sloupec)
{
    p[radek][sloupec].viditelna = 1;
}

V této proceduře je dále nutné ošetřit některé chyby, ke kterým mohlo dojít. Jedná se zejména o následující:

  • Otočení již otočené kartičky
  • Otočení odebrané kartičky
  • Pokus o otočení kartičky mimo rozsah pole pexesa

Tyto tři problematické jevy ušetříme pomocí cyklu, který nám zopakuje zadání hodnot, pokud dojde k nějaké chybě.

Pro tento účel si vytvoříme pomocnou proměnnou kartickaok, která bude uchovávat informaci, zda má být cyklus spuštěn ještě jednou.

Po spuštění procedury se do této proměnné uloží hodnota 0, aby byl cyklus spuštěn alespoň jednou. Uvnitř tohoto cyklu následně bude uživatel vyzván k zadání hodnoty řádku a sloupce. Po zadání řádku a sloupce se ověří, zda kartička již nebyla otočena nebo odebrána. Pokud je tato podmínka splněna, uloží se do proměnné kartickaok hodnota 1 a cyklus je ukončen. Touto úpravou ošetříme dva body ze tří, které jsme stanovili v předchozím textu (konkrétně "Otočení odebrané kartičky" a "Pokus o otočení kartičky mimo rozsah pole pexesa").

Otočení kartičky
void otockarticku()
{
    int radek, sloupec;
    int kartickaok = 0;
    p[radek][sloupec].viditelna = 1;
    while (kartickaok == 0)
    {
         printf("Zadejte souradnice karticky (radek): ");
         scanf("%d", &radek);
         printf("Zadejte souradnice karticky (sloupec): ");
         scanf("%d", &sloupec);
         
         if ((p[radek][sloupec].odebrana == 0) && (p[radek][sloupec].viditelna == 0))
         {
         	kartickaok = 1;
            p[radek][sloupec].viditelna = 1;
         }
    }
}

Následně je nutné ještě ošetřit situaci, kdy uživatel zadá adresu kartičky mimo rozsah pole pexesa. Do našeho cyklu přidáme na místo po zadání hodnot řádku a sloupce postupně dva cykly: jeden, který zopakuje zadání čísla řádku v případě, že číslo řádku bude mimo povolený rozsah od 0 do n-1, a druhý, který zopakuje zadání čísla sloupce v případě, že číslo sloupce bude mimo povolený rozsah od 0 do n-1.

Po této úpravě bude kód procedury pro otočení kartičky vypadat následovně:

Otočení kartičky
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;
}

Protože v jazyce C nemůžeme pomocí slova return vracet 2 proměnné zároveň, tak vytvoříme 2 globální proměnné rx a sx, které použijeme pro předání hodnot. Druhou možností by bylo využití ukazatelů, to je však nad rámec tohoto kurzu.

Pro potřeby testování programu nyní ještě upravíme hlavní část programu, odkud voláme proceduru pro otočení kartičky pexesa. Nyní již totiž nebudeme načítat souřadnice kartičky v hlavní části programu, ale až v proceduře pro otočení kartičky.

Z hlavní části programu odstraníme následující řádky:

Odstraníme

printf("Zadejte souradnice 1. karticky (radek): ");
scanf("%d", radek1);
printf("Zadejte souradnice 1. karticky (sloupec): ");
scanf("%d", sloupec1);

printf("Zadejte souradnice 2. karticky (radek): ");
scanf("%d", radek2);
printf("Zadejte souradnice 2. karticky (sloupec): ");
scanf("%d", sloupec2);

A ponecháme pouze volání procedury otockarticku:

Ponecháme
otockarticku();
radek1 = rx;
sloupec1 = sx;
otockarticku();
radek2 = rx;
sloupec2 = sx;

Inicializace hráčů

V předchozích lekcích jsme zatím řešili pouze práci s kartičkami pexesa. Nyní se přesuneme k další části a tou jsou hráči. Nejprve je nutné pole hráčů inicializovat, tj. nastavit jeho výchozí hodnoty. Stejnou operaci jsme již dělali u kartiček pexesa, kde jsme je naplnili výchozími hodnotami obrázku a natavili vlastnosti stavu viditelnosti a odebrání kartičky.

Hráči jsou realizováni opět jako pole struktur, tj. pole datového typu rekord, které se skládá s následujících proměnných:

  • Jméno - jednoznačný identifikátor hráče. Bude datového typu string (umožní tedy uložit až 255 znaků).
  • Skóre - počet uhodnutých dvojic kartiček. Bude datového typu byte (skóre bude nabývat hodnot z intervalu 0-18).

Při inicializaci hráčů využijeme ještě funkci pro změnu obsahu řetězce - funkci strcpy(), Pro tuto funkci budeme muset přidat do záhlaví programu hlavičkový soubor string.h. To provedeme následovně:

Přidání hlavičkového souboru string.h
    #include <string.h>
    

U hráčů budeme postupovat tak, že pro celé pole hráčů nastavíme pro jméno hráče prázdnou hodnotu a pro skóre hodnotu 0. To vše v celém rozsahu pole (ten je dán proměnnou maxhracu).

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

Pomocí cyklu for postupně projdeme pole. Pro tento účel nám poslouží proměnná i, kterou postupně zvyšujeme od 1 do maxhracu a tím postupně procházíme pole ph (pole, ve kterém máme uložené hráče). U každého hráče takto nastavíme jméno na prázdný řetězec a skóre na 0.

Zadání počtu hráčů

Pro zadání počtu hráčů si nejprve vytvoříme globální proměnnou, do které následně uložíme počet hráčů. Proměnná můséí být globální, abychom k ní mohli přistupovat i z procedur, které budou řídit průběh hry.

Proměnnou pro počet hráčů pojmenujeme pocethracu. Bude se jednat o celočíselnou proměnnou typu int.

Nyní již k samotní proceduře. Její základní verzi zobrazuje níže uvedený kód.

Zadání počtu hráčů
void zadejpocethracu()
    {
         printf("Zadejte pocet hracu: ");
         scanf("%d",&pocethracu);
    }

Výše uvedená procedura vypadá velmi jednoduše. Pouze se vypíše text s požadavkem a načte se hodnota od uživatele.

Tato jednoduchá varianta má však i jeden nedostatek - uživateli je dovoleno zadat libovolnou hodnotu (i když máme definovanou horní hranici počtu hráčů - v proměnné maxhracu). Tento nedostatek lze odstranit pomocí cyklu while. Postup bude následující:

  • Nejprve načteme pomocí stávajícího řešení hodnotu pocethracu.
  • Následovat bude cyklus while, který bude prováděn tak dlouho, dokud proměnná pocethracu bude menší než 2 nebo větší než maxhracu. V tomto cyklu se vypíše informace o chybě a uživatel je vyzván pro zadání nového počtu hráčů.
Zadání počtu hráčů - finální verze
void zadejpocethracu()
    {
         printf("Zadejte pocet hracu: ");
         scanf("%d",&pocethracu);
         while ((pocethracu < 2) or (pocethracu > maxhracu))
         {
             printf("Zadejte znovu: ");
             scanf("%d",&pocethracu);         
         }
    }

Zadání jmen hráčů

Další procedurou, která se týká hráčů je zadání jmen hráčů. Jedná se o proceduru s jednoduchým cyklem for, který postupně projde pole hráčů od 1 do pocethracu (hodnota, kterou jsme získali v proceduře zadejpocethracu) a u každého hráče uživatele vyzve pro zadání jména hráče.

Zadání jmen hráčů
void zadejjmenahracu()
{
    int i;
    printf("Zadejte jmena hracu:\n");
    for (i = 0; i < pocethracu; i++)
    {
        scanf("%s", &ph[i].jmeno);
    }
}

Proceduru si můžeme ještě upravit, aby se u každého hráče zobrazila postupně informace "Zadejte jméno 1. hráče", "Zadejte jméno 2. hráče" apod.

Zadání jmen hráčů
    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);
    }
}

Doplnění volání procedur do hlavní části programu

Abychom mohli testovat chod programu je samozřejmě nutné doplnit volání jednotlivých procedur, které jsme vytvořili, do hlavní části programu. Pro úplnost proto uveďme kompletní program po doplnění úprav z této lekce.

Program po doplnění úprav
#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;
}

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

  int radek, sloupec, pocet;

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

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

   otockarticku();
   radek1 = rx;
   sloupec1 = sx;
   otockarticku();
   radek2 = rx;
   sloupec2 = sx;

  zobrazenipexesa();
  
  fflush(stdin);
  getchar();
  return 0;
 }
webdesign, xhtml, css, php - Mgr. Michal Mikláš