Tic Tac Toe

Vetvenie, cykly, polia (1D, 2D), parametre funkcií

O čom je lab

V rámci tohto cvičenia naprogramujete ďalšiu hru - zjednodušenú verziu hry Piškvorky (Tic Tac Toe).

Ciele

  • Rutinne pracovať s poliami.
  • Rutinne pracovať s vetvením a cyklením programov.
  • Osvojiť si prácu s parametrami funkcií.
  • Oboznámiť sa s dvojrozmerným poľom.

Postup

Krok 1: Piškvorky

V tomto kroku implementujete jednoduchú hru Piškvorky (jednorozmerné). Hrací plán je v tomto prípade jednorozmerné pole o dĺžke N. Hru hrajú dvaja hráči a obaja do tohto poľa zapisujú krížiky (znak X). Prvý, ktorému sa podarí vytvoriť aspoň tri krížiky vedľa seba, vyhráva.

Pre ladenie programu a odstraňovanie prípadných chýb použite nástroj cgdb z minulého cvičenia.

Úloha 1.1

Vytvorte funkciu void draw(const int size, char field[]), ktorá na obrazovku vykreslí aktuálny stav hracieho poľa.

Ak obsah poľa field bude nasledovný:

char field[] = { ' ', 'X', ' ', 'X', ' '};

tak funkcia na obrazovku vypíše obsah v nasledovnom tvare:

+-+-+-+-+-+
| |X| |X| |
+-+-+-+-+-+
 1 2 3 4 5

Okrem obsahu samotného poľa teda funkcia vypíše aj indexy jednotlivých prvkov. Pomocou týchto indexov budú môcť hráči do poľa vkladať svoje krížiky. Všimnite si, že indexovanie pre hráčov začína číslom 1.

Úloha 1.2

Upravte hlavnú funkciu programu tak, aby hráč najskôr zadal veľkosť hracieho poľa, ktoré sa následne zobrazí.

Pre veľkosť hracieho poľa platí, že jeho minimálna veľkosť je 4 a maximálna veľkosť je 9. Ak hráč zadá nesprávnu veľkosť hracieho poľa, voľbu musí zopakovať.

$ ./tictactoe
Enter the size of field: 3
Enter the size of field: 22
Enter the size of field: 7

+-+-+-+-+-+-+-+
| | | | | | | |
+-+-+-+-+-+-+-+
 1 2 3 4 5 6 7

Úloha 1.3

Vytvorte funkciu int add_cross(const int size, char field[], const int position), ktorá na pozíciu danú parametrom position hracieho poľa umiestni krížik.

V prípade, že sa na danej pozícii už krížik nachádza, funkcia vráti hodnotu 0. Ak je naopak toto miesto voľné, po úspešnom vložení krížika vráti funkcia hodnotu 1.

Úloha 1.4

Upravte funkciu int add_cross() tak, aby vrátila hodnotu -1, ak je hráčom daná pozícia mimo rozsahu hracieho poľa.

Úloha 1.5

Vytvorte funkciu int is_solved(const int size, char field[]), ktorá overí, či už hra nie je vyriešená.

Funkcia vráti hodnotu 1, ak sa v poli nachádzajú vedľa seba min. 3 krížiky. V opačnom prípade vráti hodnotu 0.

Úloha 1.6

Pomocou vytvorených funkcií implementujte hru.

Dialóg dvoch hráčov môže vyzerať nasledovne:

$ ./tictactoe
Enter the size of field: 9

+-+-+-+-+-+-+-+-+-+
| | | | | | | | | |
+-+-+-+-+-+-+-+-+-+
 1 2 3 4 5 6 7 8 9

Player A: 2

+-+-+-+-+-+-+-+-+-+
| |X| | | | | | | |
+-+-+-+-+-+-+-+-+-+
 1 2 3 4 5 6 7 8 9

Player B: 5

+-+-+-+-+-+-+-+-+-+
| |X| | |X| | | | |
+-+-+-+-+-+-+-+-+-+
 1 2 3 4 5 6 7 8 9

Player A: 9

+-+-+-+-+-+-+-+-+-+
| |X| | |X| | | |X|
+-+-+-+-+-+-+-+-+-+
 1 2 3 4 5 6 7 8 9

Player B: 10
Wrong position!
Player A: 2
X is already there!
Player B: 8

+-+-+-+-+-+-+-+-+-+
| |X| | |X| | |X|X|
+-+-+-+-+-+-+-+-+-+
 1 2 3 4 5 6 7 8 9

Player A: 7

+-+-+-+-+-+-+-+-+-+
| |X| | |X| |X|X|X|
+-+-+-+-+-+-+-+-+-+
 1 2 3 4 5 6 7 8 9

Player A wins!

Krok 2: 2D

V tomto kroku zmeníte hru tak, aby používala dvojrozmerné pole.

  • Program teda upravíte tak, aby pole field[] bolo dvojrozmerné. Hracie pole má byť štvorcové, t.j. jeho veľkosť bude rovnaká do výšky aj do šírky.
  • Hráč zadáva dve hodnoty. Prvá predstavuje pozíciu na osi x a druhá na osi y.
  • Os x je horizontálna os číslovaná zľava doprava od hodnoty 1. Zobrazuje sa pod hracím poľom. Os y je vertikálna os číslovaná zdola nahor od hodnoty 1. Zobrazuje sa naľavo vedľa hracieho poľa.
  • Hráčovi A sa zobrazujú krížiky X a hráčovi B sa zobrazujú krúžky O.
  • Dialóg dvoch hráčov môže vyzerať nasledovne:
$ ./tictactoe
Enter the size of field: 5

  +-+-+-+-+-+
5 | | | | | |
  +-+-+-+-+-+
4 | | | | | |
  +-+-+-+-+-+
3 | | | | | |
  +-+-+-+-+-+
2 | | | | | |
  +-+-+-+-+-+
1 | | | | | |
  +-+-+-+-+-+
   1 2 3 4 5

Player A: 0 3
Wrong position!
Player B: 3 3

  +-+-+-+-+-+
5 | | | | | |
  +-+-+-+-+-+
4 | | | | | |
  +-+-+-+-+-+
3 | | |O| | |
  +-+-+-+-+-+
2 | | | | | |
  +-+-+-+-+-+
1 | | | | | |
  +-+-+-+-+-+
   1 2 3 4 5

Player A: 2 2

  +-+-+-+-+-+
5 | | | | | |
  +-+-+-+-+-+
4 | | | | | |
  +-+-+-+-+-+
3 | | |O| | |
  +-+-+-+-+-+
2 | |X| | | |
  +-+-+-+-+-+
1 | | | | | |
  +-+-+-+-+-+
   1 2 3 4 5

Player B: 4 4

  +-+-+-+-+-+
5 | | | | | |
  +-+-+-+-+-+
4 | | | |O| |
  +-+-+-+-+-+
3 | | |O| | |
  +-+-+-+-+-+
2 | |X| | | |
  +-+-+-+-+-+
1 | | | | | |
  +-+-+-+-+-+
   1 2 3 4 5

Player A: 6 5
Wrong position!
Player B: 5 5

  +-+-+-+-+-+
5 | | | | |O|
  +-+-+-+-+-+
4 | | | |O| |
  +-+-+-+-+-+
3 | | |O| | |
  +-+-+-+-+-+
2 | |X| | | |
  +-+-+-+-+-+
1 | | | | | |
  +-+-+-+-+-+
   1 2 3 4 5

Player B wins!

Úloha 2.1

Upravte definíciu poľa field vo funkcii main() tak, aby pole bolo dvojrozmerné.

Obidva rozmery poľa sú rovnaké. To udáva premenná, v ktorej je uložený rozmer hracieho poľa. Tento rozmer zadal hráč.

Všetky prvky poľa na začiatku obsahuju znak ' ' (medzera).

Úloha 2.2

Upravte deklaráciu aj definíciu funkcie draw() tak, aby používala dvojrozmerné pole.

Deklarácia sa zmení nasledovne: void draw(const int size, char field[][size]), kde size je rozmer poľa (vertikálny aj horizontálny) a field je dvojrozmerné pole. Druhý rozmer (údaj v druhej zátvorke) je pri dvojrozmerných poliach povinný. Preto je parameter size uvedený ako prvý (v mieste svojho použitia už musí byť známy).

Funkcia má vykresliť hracie pole tak, aby os x bola číslovaná zľava doprava od hodnoty 1, zobrazená pod hracím poľom. Os y je číslovaná zdola nahor od hodnoty 1, zobrazená naľavo vedľa hracieho poľa.

Úloha 2.3

Upravte deklaráciu aj definíciu funkcie add_cross() tak, aby používala dvojrozmerné pole.

Deklarácia sa zmení nasledovne: int add_cross(const int size, char field[][size], const int x, const int y, const char player), kde size je rozmer poľa (vertikálny aj horizontálny) a field je dvojrozmerné pole. Parametre x a y predstavujú horizontálnu a vertikálnu súradnicu, na ktorú chce hráč pridať krížik alebo krúžok. Parameter player udáva, ktorý hráč je aktuálne na ťahu.

Funkcia má do poľa field pridať krížik (znak X), ak je na ťahu hráč A, a krúžok (znak O), ak je na ťahu hráč B. To, ktorý hráč je na ťahu, udáva parameter player.

Nezabudnite upraviť aj miesto volania funkcie (pribudli nám parametre).

Úloha 2.4

Upravte deklaráciu aj definíciu funkcie is_solved() tak, aby používala dvojrozmerné pole.

Deklarácia sa zmení nasledovne: int is_solved(const int size, char field[][size]), kde size je rozmer poľa (vertikálny aj horizontálny) a field je dvojrozmerné pole.

Funkcia má zistiť, či je hra vyhratá, ak sa v hracom poli vedľa seba nachádzajú tri krížiky resp. tri krúžky. To platí v štyroch smeroch: horizontálny (sú vedľa seba), vertikálny (sú nad resp. pod sebou), hlavná diagonála a vedľajšia diagonála.

Úloha 2.5

Overte funkčnosť Vášho riešenia.

Doplňujúce úlohy

Úloha A.1

Vytvorte funkciu void make_turn(const int size, char field[][size]). Táto funkcia bude predstavovať súpera proti hráčovi, ktorým bude samotný počítač.

Úloha A.2

Vytvorte funkcie int find_min(const int size, char field[][size]) a int find_max(const int size, char field[][size]), ktoré vrátia pozíciu najmenšieho a najväčšieho prvku v poli. Ak je takýchto prvkov v poli viac, vráťte prvý z nich.

Úloha A.3

Vytvorte funkciu int compare(const int size1, char field1[][size1], const int size2, char field2[][size2]), ktorá vráti hodnotu 1, ak sú obe polia rovnaké. V opačnom prípade vráti hodnotu 0.

Doplňujúce zdroje

  1. Break vs continue
  2. Functions vs parameters
  3. Viacrozmerné polia v jazyku C

Video

Cyklus while a cyklus for s Danielom