Kolejka - gra Wąż

Zapoznaj się z materiałami przedstawionymi na poprzednich zajęciach koła:

 

Utwórz nowy katalog projektowy. Skopiuj do niego pliki biblioteki:

newconio.cpp  -  plik źródłowy biblioteki
newconio.h  - plik nagłówkowy dla biblioteki

Utwórz nowy projekt konsoli w Dev-C++. Do projektu dodaj plik źródłowy newconio.cpp z twojego katalogu projektowego.

 

Kolejka

Kolejka (ang. Queue) jest strukturą danych przechowującą elementy w kolejności ich wprowadzenia.

Elementy wprowadzane do kolejki są dopisywane do jej końca - długość kolejki rośnie.

Elementy pobierane są z kolejki z jej początku - długość kolejki maleje.

 

Naturalną strukturą danych do realizacji takiej kolejki jest lista, jednakże list jeszcze nie omawialiśmy na kole, zatem zrealizujemy kolejkę w znanej nam strukturze danych - tablicy. Oprócz samej tablicy będziemy potrzebowali dodatkowo dwóch zmiennych:

wpk - wskaźnik początku kolejki, zawiera indeks elementu, który jest początkiem kolejki
wkk - wskaźnik końca kolejki, zawiera indeks elementu, który jest końcem kolejki.

Przy dopisywaniu elementów do kolejki wskaźnik końca wkk będzie się przesuwał wzdłuż elementów tablicy. Problem pojawi się w momencie, gdy wkk osiągnie koniec tablicy. Wtedy przesunięcie wkk spowoduje wyjście z indeksem poza tablicę. W takim przypadku umówmy się, iż wkk wróci na początek tablicy, czyli do elementu o indeksie 0. To samo dotyczy wskaźnika początku kolejki wpk. Długość tablicy powinna być równa maksymalnej liczbie elementów, które chcemy przechowywać w kolejce, inaczej koniec kolejki nadpisze początek.

Jeśli kolejka przewija się przez koniec tablicy, to jej długość obliczona ze wzoru wkk - wpk + 1 jest ujemna (sprawdź!). W takim przypadku poprawną długość kolejki otrzymamy dodając do tego wyniku długość tablicy.

Algorytm wstawiania danej do kolejki

Dane wejściowe:

e  -  wprowadzany element
t[ ]  - tablica, w której realizowana jest kolejka
wkk  - wskaźnik końca kolejki

Dane wyjściowe:

t[ ]  - tablica z wstawionym do kolejki elementem e
wkk  - zmodyfikowany wskaźnik końca kolejki

Lista kroków

K01: wkk ← wkk + 1
K02: Jeśli wkk = długość t[ ], to wkk ← 0
K03: t[wkk] ← e
K04: Zakończ

 

Algorytm pobierania danej z kolejki

Dane wejściowe:

t[ ]  - tablica, w której realizowana jest kolejka
wpk  - wskaźnik początku kolejki

Dane wyjściowe:

e  -  element pobrany z początku kolejki
t[ ]  - tablica z usuniętym z początku kolejki elementem e
wpk  - zmodyfikowany wskaźnik początku kolejki

Lista kroków

K01: e ← t[wpk]
K02: wpk ← wpk + 1
K03: Jeśli wpk = długość tablicy, to wpk ← 0
K04: Zakończ
 

Gra Wąż

Gra toczy się na planszy obejmującej cały ekran. Po planszy przesuwa się wąż w kierunku, który określa gracz za pomocą klawiszy kursora. W trakcie gry na planszy pojawiają się w przypadkowych miejscach losowe cyferki od 1 do 9 oraz przeszkody. Wąż zjada cyferki i zwiększa swoją długość o wartość cyfry. Gra kończy się, gdy wąż uderzy w cokolwiek innego niż cyfra.

Wąż zrealizowany jest w formie kolejki, w której zapamiętujemy współrzędne segmentów węża. Głowa węża w trakcie ruchu dopisuje nowe współrzędne kolejki. Ogon węża pobiera współrzędne z kolejki i wypisuje na nich spację - dzięki temu ostatni segment znika, co daje wrażenie ruchu węża. Zjedzenie cyferki powoduje wstrzymanie pobierania ostatnich segmentów z kolejki, dzięki czemu długość węża przyrasta.

 

Program

// Wąż
// (C)2009 Koło informatyczne w I LO w Tarnowie
// Kurs programowania w C++ dla początkujących
//--------------------------------------------

#include "newconio.h"
#include <iostream>

using namespace std;

const int ROZMIAR = 4000;

// Zmienne globalne
//-----------------

int tw[ROZMIAR];      // przechowuje nr wierszy
int tk[ROZMIAR];      // przechowuje nr kolumn

int wpk,wkk;          // wskazuje początek i koniec kolejki

int kierunek;         // kierunek ruchu głowy węża:
                      // 0 - góra
                      // 1 - prawo
                      // 2 - dół
                      // 3 - lewo

int g_kolumna;        // kolumna głowy węża
int g_wiersz;         // wiersz głowy węża
int jedzenie;         // co wąż zjadł


// Start gry
//----------
void Start()
{
  _cinit();
  srand((unsigned)time(NULL));
  fullscreen(true); cursoroff(); textattr(0x4e); clrscr();
  fillframe(FRAME_SINGLE,0xe9,20,19,59,29);
  textattr(0xe1);
  center(21,_pl("(C)2009 I Liceum Ogólnokształcące"));
  center(22,_pl("im. Kazimierza Brodzińskiego"));
  center(23,"w Tarnowie");
  textattr(0xe0);
  center(25,_pl("KOŁO NAUKOWE INFORMATYKI"));
  textattr(0xe2);
  center(27,_pl("G-R-A   W-Ą-Ż"));
  fillrectattr(0,0,49,79,49);
  textattr(0x0f);
  center(49,_pl("Naciśnij dowolny klawisz, aby rozpocząć grę..."));
  while(!getch());
}

// Pyta, czy jeszcze jedna gra
//----------------------------
bool JeszczeRaz()
{
  fillrectattr(0xf4,0,49,79,49);
  textattr(0xf4);
  center(49,_pl("Czy chcesz ponownie zagrać? (T = TAK)"));

  char klawisz;

  while(!(klawisz = getch()));
  return (klawisz == 'T') || (klawisz == 't');
}

// Plansza gry
//------------
void Plansza()
{
  textattr(0x20); clrscr();
  frame(FRAME_DOUBLE,0x20,0,0,79,48);
  fillrectattr(0xf0,0,49,79,49);     
}

// Wprowadza opóźnienie. Rysuje głowę węża.
// Czyta klawisze kursora i ustawia kierunek
//------------------------------------------
void CzytajKlawisze()
{
  const char znak_glowy[] = {'^','>','v','<'};
  
  delay(1);

  putxy(znak_glowy[kierunek],0xc0,g_kolumna,g_wiersz);   

  if(kbhit())
  {
    int klawisz;
    
    while(!(klawisz = getch()));
    
    switch(klawisz)
    {
      case 72: kierunek = 0; break;
      case 77: kierunek = 1; break;
      case 80: kierunek = 2; break;
      case 75: kierunek = 3; break;               
    }
  }     
}

// Wykonuje ruch wężem
//--------------------
bool RuchWeza()
{
  if(jedzenie)
  {
    jedzenie--;
  }
  else
  {
    putxy(' ',0x20,tk[wkk],tw[wkk]);
    if(++wkk == ROZMIAR) wkk = 0;
  }

  putxy('*',0x4f,g_kolumna,g_wiersz);
  
  switch(kierunek)
  {
    case 0: g_wiersz--;  break;
    case 1: g_kolumna++; break;
    case 2: g_wiersz++;  break;
    case 3: g_kolumna--; break;
  }

// zapisujemy współrzędne głowy do kolejki
  
  if(++wpk == ROZMIAR) wpk = 0;
  tk[wpk] = g_kolumna;
  tw[wpk] = g_wiersz;

// odczytujemy znak pod głową węża

  int c = getchxy(g_kolumna,g_wiersz);
  
  if(c == 32) return true; // głowa na pustej pozycji
  
  c -= 48;
  
  if((c < 1) || (c > 9)) return false;
  
  jedzenie += c;
  return true;  
}

// Losuje cyferki dla węża
//------------------------
void LosujJedzenie()
{
  int w,k,j;
  
  j = 1 + rand() % 10;
  
  do
  {
    k = rand() % 80;
    w = rand() % 48;    
  } while(getchxy(k,w) != ' ');
  
  if(j == 10) putxy('*',0x24,k,w);
  else        putxy(j+48,0x20,k,w);
}

// Rysuje szkielet węża
//---------------------
void Szkielet()
{
  do
  {
    delay(10);
    if(--wpk < 0) wpk += ROZMIAR;
    putxy('+',0x2f,tk[wpk],tw[wpk]);
  } while(wpk != wkk);

  delay(500);

  while(kbhit())
  {
    while(!getch());
    delay(100);
  }
}

// Główna część programu
//----------------------
main()
{
  bool waz_zyje;
  int licznik, dlugosc;
  
  Start();
  
  do
  {
    Plansza();
    
    waz_zyje = true;
    kierunek = rand() % 4;
    jedzenie = 4 + rand() % 5;
    wpk = wkk = 0;
    tk[0] = g_kolumna = 39;
    tw[0] = g_wiersz = 24;
    licznik = 15;
    
    LosujJedzenie();
    
    do
    {
      CzytajKlawisze();

      if(!(--licznik))
      {
        if(!(rand() % 30)) LosujJedzenie();

        if(dlugosc > 200)      licznik = 7;
        else if(dlugosc > 150) licznik = 10;
        else if(dlugosc > 100) licznik = 12;
        else if(dlugosc >  50) licznik = 15;
        else if(dlugosc >  25) licznik = 20;
        else licznik = 25;

        waz_zyje = RuchWeza();
      }

      dlugosc = wpk - wkk;
      if(dlugosc < 0) dlugosc += ROZMIAR;
      gotoxy(31,49); textattr(0xf0); cout << _pl("Długość węża = ") << dlugosc;
    } while(waz_zyje);
    
    Szkielet();
    
    textattr(0x0c); gotoxy(30,24); cout << _pl("   Twój wynik : ") << dlugosc << "    ";
  } while(JeszczeRaz());

  fullscreen(false); cursoron(); textattr(7); clrscr();
}

 



List do administratora Serwisu Edukacyjnego Nauczycieli I LO

Twój email: (jeśli chcesz otrzymać odpowiedź)
Temat:
Uwaga: ← tutaj wpisz wyraz  ilo , inaczej list zostanie zignorowany

Poniżej wpisz swoje uwagi lub pytania dotyczące tego rozdziału (max. 2048 znaków).

Liczba znaków do wykorzystania: 2048

 

W związku z dużą liczbą listów do naszego serwisu edukacyjnego nie będziemy udzielać odpowiedzi na prośby rozwiązywania zadań, pisania programów zaliczeniowych, przesyłania materiałów czy też tłumaczenia zagadnień szeroko opisywanych w podręcznikach.



   I Liceum Ogólnokształcące   
im. Kazimierza Brodzińskiego
w Tarnowie

©2017 mgr Jerzy Wałaszek

Dokument ten rozpowszechniany jest zgodnie z zasadami licencji
GNU Free Documentation License.