Anglická verze
logolink

< Zpět na seznam lekcí

Hra pexeso II

AlgortimyObsah lekce:

  • Zobrazení kartiček
  • Inicializace hodnot kartiček
  • Řešení inicializace hodnot kartiček pomocí procedury

Výpis hodnot pexesa

V předchozí části jsme se dostali do fáze, kdy máme nadefinovány všechny potřebné proměnné pro naše pexeso. Před tím, než si tyto proměnné naplníme hodnotami, se kterými budeme dále pracovat, si zkusíme naše pole s pexesem vypsat.

Pexeso máme uložené jako dvourozměrné pole struktur (ze kterých budeme vypisovat hodnotu obrazek). Struktura je datový typ struct, který může obsahovat v jedné proměnné několik dalších proměnných (v našem případě obrazek, viditelna a odebrana).

Pro vypsání našeho pole budeme potřebovat 2 vnořené cykly for, které nám budou procházet řádky a sloupce. Před vytvořením těchto cyklů si vytvoříme pomocné proměnné radek a sloupec, do kterých nám budou cykly for ukládat aktuální pozici v poli. Tyto dvě proměnné umístíme do části, kde jsme již definovali předchozí proměnné (za příkaz var), a to následovně.

Proměnné pro uložení řádku a sloupce
int radek, sloupec;

Když máme vytvořené proměnné, můžeme si vypsat, co naše pexeso aktuálně obsahuje. Pro vypsání obsahu dvourozměrného pole využijeme dva vnořené cykly for. První bude procházet jednotlivé řádky a druhý bude procházet hodnoty v každém řádku (tj. sloupce). Pro každou dvojici [radek][sloupec] je vypsána hodnota obrazek struktury p (doplněná o mezeru, aby byl výpis přehlednější).

Po opuštění vnitřního cyklu je ještě nutné zalomit řádek (příkaz printf("\n");).

U funkce printf, která nám hodnotu vypíše, přidáme ještě výpis mezery, abychom rozeznali jednotlivé vypsané hodnoty.

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

Po spuštění programu v této podobě pravděpodobně zjistíme, že hodnota obrazek není inicializována - program bude hlásit chybu u pokusu o vypsání hodnoty. Program proto upravíme a nastavíme výchozí hodnotu na 0.

Nastavení výchozích hodnot pexesa
        
for (radek = 0; radek < n; radek++)
{
    for (sloupec = 0; sloupec < n; sloupec++)
    {
        p[radek][sloupec].obrazek = 0;
    }
}
Pexeso - výchozí hodnota pole

Inicializace pexesa

V předchozím kroku jsme si ověřili, že všechny hodnoty obrázku v pexesu máme nastaveny na hodnotu 0. My ale potřebujeme, aby zde byly dvakrát hodnoty 1-18. Máme totiž pole 6x6 kartiček pexesa, což je celkem 36 kartiček a každá kartička se má vyskytovat dvakrát.

Úkol č. 1

Naším úkolem nyní bude nalezení způsobu, jak do pole našeho pexesa naskládat hodnoty 1-18 tak, aby se vyskytovala každá dvakrát.

Naskládání hodnot do pole pexesa můžeme provést několika způsoby (zatím nebudeme řešit zamíchání pexesa). Například můžeme naplnit pexeso hodnotami 1, 1, 2, 2, 3, 3, ... nebo postupně hodnotami 1 - 18 a 1 - 18.

1. varianta řešení

První varianta nám naplní pole posloupností 1-18, za kterou bude následovat další posloupnost 1-18. Toto řešení bude vypadat následovně:

Proměnná pocet
int pocet;
Nastavení výchozích hodnot u kartiček pexesa - varianta 1
pocet = 0;

for (radek = 0; radek < n; radek++)
{
    for (sloupec = 0; sloupec < n; sloupec++)
    {
        p[radek][sloupec].obrazek = 1 + pocet % 18;
        pocet = pocet + 1;
    }
}

V této variantě použijeme pomocnou proměnnou pocet, kterou budeme zvyšovat při každém průchodu cyklu. Tuto proměnnou si vytvoříme stejným způsobem, jako předchozí celočíselné proměnné radek a sloupec. Na počátku ji nastavíme na hodnotu 0 a v každém průchodu vnitřního cyklu ji zvýšíme o 1. Pro získání požadovaných hodnot použijeme operátor celočíselného dělení (div) a výsledek zvýšíme o 1. Když bychom použili pouze celočíselné dělení, vracela by nám naše operace výsledek od 0 do 17 (např. 0 mod 18 = 0, 5 mod 18 = 5, 17 mod 18 = 17 a 18 mod 18 = 0), proto k výsledku přičteme hodnotu 1 a získáme posloupnost čísel od 1 do 18, po kterých bude znovu následovat 1-18 (protože pocet bude růst až do hodnoty 35).

Pexeso - varianta 1

2. varianta řešení

I pro druhou variantu naplnění pole budeme potřebovat celočíselnou proměnnou pocet, která nám bude sloužit pro počítání počtu průchodů vnitřního cyklu. Naplnění hodnot pole v tomto případě může vypadat následovně:

Nastavení výchozích hodnot u kartiček pexesa - varianta 2
pocet = 1;
        
for (radek = 0; radek < n; radek++)
{
    for (sloupec = 0; sloupec < n; sloupec++)
    {
        pocet = pocet + 1;
        p[radek][sloupec].obrazek = pocet / 2;
    }
}

U tohoto způsobu naplnění pole (který je uveden výše) nejprve nastavíme proměnnou pocet na hodnotu 1 a následně ji zvýšíme při každém průchodu cyklu. Po zvýšení hodnoty této proměnné uložíme do p[radek][sloupec].obrazek výsledek celočíselného dělení proměnné pocet a hodnoty 2 (použití operátoru /). Tato operace nám bude postupně vracet hodnoty 1, 1, 2, 2, 3, 3, ..., 18, 18.

Pexeso - varianta 2

3. varianta řešení

U třetí varianty řešení opět budeme potřebovat proměnnou pocet, ale budeme ji zvyšovat pouze v každém druhém průchodu cyklu. Pro tuto variantu využijeme proměnnou sloupec a vytvoříme podmínku, kdy pokud zbytek po celočíselném dělení proměnné sloupec číslem 2 bude 1, zvýšíme proměnnou sloupec o 1. Kód programu v tomto případě bue vypadat následovně:

Nastavení výchozích hodnot u kartiček pexesa - varianta 3
pocet = 0;

for (radek = 0; radek < n; radek++)
{
    for (sloupec = 0; sloupec < n; sloupec++)
    {
        if ((sloupec % 2) == 1) pocet = pocet + 1;
        p[radek][sloupec].obrazek = pocet;
    }
}
Pexeso - varianta 3

4. varianta řešení

Pro zajímavost si můžeme uvěst i variantu, kde se obejdeme bez pomocné proměnné pocet. V této variantě místo proměnné počet vypočítáme aktuální průchod cyklu z čísla aktuálního řádku a sloupce. Proměnná n nám udává počet sloupců.

Nastavení výchozích hodnot u kartiček pexesa - varianta 4
for (radek = 0; radek < n; radek++)
{
    for (sloupec = 0; sloupec < n; sloupec++)
    {
        p[radek][sloupec].obrazek := ((radek*n + sloupec) mod 18) + 1;
    }
}
Pexeso - varianta 4

Na výše uvedených variantách jsme si ukázali, že většina úkolů v oblasti algoritmizace a programování nemá pouze jedno řešení, ale často existuje více cest, jak dojít k požadovanému cíli.

Vybranou variantu můžete doplnit před část programu pro zobrazení hodnot a program vyzkoušet v této úpravě.

V dalším kroku inicializace pexesa je třeba nastavit hodnoty i u proměnných viditelna a odebrana, které jsou součástí naší struktury. Ve výchozím stavu by neměla být viditelná žádná kartička, proto u proměnné viditelna nastavíme hodnotu 0. Stejnou hodnotu (0) nastavíme i u proměnné odebrana, protože na začátku hry jsou ve hře všechny kartičky.

Tyto dvě operace přidáme do cyklu, ve kterém jsme si nastavili výchozí hodnotu u proměnné obrazek (u varianty, kterou jsme si vybrali).

Nastavení výchozích hodnot u kartiček pexesa - doplnění
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;
    }
}

Aby náš program byl přehlednější, přesuneme si naši inicializaci do samostatné funkce. Nejprve si připomeňme, jak funkci zapsat.

Syntaxe funkce v C
datovytyp název (parametry funkce); //parametry jsou volitelné
{
  programový kód funkce;
  return návratováhodnota;
}

Do samostatné funkce inicializacepexesa přesuneme cyklus pro inicializaci pexesa a definici proměnných radek, sloupec a pocet. Takto umístěné proměnné označujeme termínem lokální proměnné. Tyto proměnné tedy budou viditelné pouze uvnitř naší funkce. Naopak proměnné, které jsme umístili na začátek našeho programu, jsou globální. Jsou tedy viditelné ve všech funkcích, které jsou obsaženy v našem programu.

Tato funkce nebude mít žádní vstupní parametry.

Funkce pro inicializaci pexesa
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;
        }
    }
}

Kompletní program tedy bude vypadat následovně:

Program doplněný o funkci pro inicializaci pexesa
#include "stdafx.h"
#define n 6
#define maxhracu 4

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

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

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;
        }
    }
}

int _tmain(int argc, _TCHAR* argv[])
{
  karticka p[n][n]; 
  hrac ph[maxhracu];
  int radek, sloupec, pocet;

  inicializacepexesa();

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

Po úspěšné inicializaci pole pexesa bude pexeso obsahovat hodnoty dle následujícího obrázku.

Pexeso - struktura

Výstup do prohlížeče

Pro zobrazení pexesa bude vhodnější zobrazení obrázků, než výpis čísel, který aktuálně máme. Proto v další části vytvoříme proceduru pro výpis do prohlížeče. Procedura nám vytvoří soubor ve formátu HTML, který bude zobrazovat jednotlivé kartičky pexesa, jména hráčů a počty bodů.

Pro kartičky pexesa použijeme obrázky ve formátu JPG o velikosti 100x100px. Tyto obrázky budou pojmenované 1.jpg až 18.jpg. Navíc bude potřeba jeden obrázek pro rubovou stranu kartiček. Tento obrázek bude mít stejné rozměry a bude pojmenován 0.jpg.

Domácí úkol 1

Abychom v příští části mohli pokračovat s tvorbou výstupu do prohlížeče, budeme potřebovat obrázky. Připravte proto 18 různých obrázků ve formátu JPG s rozměry 100x100 px. Tyto obrázky pojmenujte 1.jpg až 18.jpg. Dále si připravte obrázek pro rub kartiček pexesa se stejnými rozměry. Tento soubor pojmenujte 0.jpg.

Domácí úkol 2

Navrhněte algoritmus pro zamíchání kartiček pexesa a zkuste jej realizovat jako funkci v C.

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