Obsah lekce:
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ě:
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í:
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").
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ě:
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:
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:
otockarticku(); radek1 = rx; sloupec1 = sx; otockarticku(); radek2 = rx; sloupec2 = sx;
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:
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ě:
#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).
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.
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.
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í:
void zadejpocethracu() { printf("Zadejte pocet hracu: "); scanf("%d",&pocethracu); while ((pocethracu < 2) or (pocethracu > maxhracu)) { printf("Zadejte znovu: "); scanf("%d",&pocethracu); } }
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.
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.
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); } }
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.
#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; }