Wąż - programy


W tym rozdziale: Podrozdziały:

 

Prezentowane poniżej programy utworzono w następujących środowiskach programowania:

Jeśli stosujesz inne środowiska, to prawdopodobnie będziesz musiał przetworzyć odpowiednio kod programów.

 

Programy

Na podstawie opisanego algorytmu tworzymy program w języku Pascal. Poniżej przedstawiamy przykładowe zrzuty zawartości okienka konsoli oraz kod źródłowy programu.

 

obrazek
Strona tytułowa gry
obrazek
Przykładowa rozgrywka

 

Program w języku Pascal

//                 W Ą Ż
//            WERSJA FUNKCYJNA
//--------------------------------------------
// (C)2004 mgr Jerzy Wałaszek  I LO w Tarnowie

program Waz;

uses Crt, Windows;

//----------------------------------------------------
// PROCEDURY I FUNKCJE POMOCNICZE
//----------------------------------------------------

// Funkcja PL konwertuje tekst ze standardu Windows 1250
// na standard konsoli znakowej Latin II
//------------------------------------------------------
function PL(s : string) : string;
var
  i : integer;
  c : char;
begin
  for i := 1 to length(s) do
  begin
   case s[i] of
      'ą' : c := #165;
      'ć' : c := #134;
      'ę' : c := #169;
      'ł' : c := #136;
      'ń' : c := #228;
      'ó' : c := #162;
      'ś' : c := #152;
      'ż' : c := #190;
      'ź' : c := #171;
      'Ą' : c := #164;
      'Ć' : c := #143;
      'Ę' : c := #168;
      'Ł' : c := #157;
      'Ń' : c := #227;
      'Ó' : c := #224;
      'Ś' : c := #151;
      'Ż' : c := #189;
      'Ź' : c := #141;
      else
        c := s[i]; 
    end;
    s[i] := c;
  end;
  Result := s;
end;

// Procedura centruje w bieżącym wierszu
// tekst podany jako parametr
//----------------------------------------------------
procedure Centruj(t : string);
begin
  GotoXY(1 + (80-length(t)) div 2, WhereY);
  writeln(t);
end;

// Procedura rysuje pojedynczą ramkę ze znaków
// tabelek. Parametry określają współrzędne
// lewego górnego i prawego dolnego narożnika
//----------------------------------------------------
procedure Ramka(xp,yp,xk,yk : integer);
var
  i : integer;
begin
  GotoXY(xp,yp); write(#218);
  GotoXY(xp,yk); write(#192);
  GotoXY(xk,yp); write(#191);
  GotoXY(xk,yk); write(#217);
  for i := xp + 1 to xk - 1 do
  begin
    GotoXY(i,yp); write(#196);
    GotoXY(i,yk); write(#196);
  end;
  for i := yp + 1 to yk - 1 do
  begin
    GotoXY(xp,i); write(#179);
    GotoXY(xk,i); write(#179);
  end;
end;

// Funkcja odczytuje znak na pozycji p okna konsoli
// Uwaga - znaki ramki będą odczytane nieprawidłowo jako
// literki.
//------------------------------------------------------
function Znak_na_pozycji(p : COORD) : char;
var
  c : char;
  k : integer;
begin
  dec(p.x);
  dec(p.y);
  ReadConsoleOutputCharacter(GetStdHandle(STD_OUTPUT_HANDLE),
                             addr(c),1,p,k);
  Result := c;
end;

//------------------------------------------------------
// PROGRAM GRY
//------------------------------------------------------

const
  N = 1716;

var
  kolejka        : array[0..N-1] of COORD;
  pk,kk,kierunek : integer;
  glowa          : COORD;

//------------------------------------------------------
// Procedury i funkcje
//------------------------------------------------------

// Procedura umieszcza współrzędne p w kolejce
//------------------------------------------------------
procedure Zapisz(p : COORD);
begin
  pk := (pk + 1) mod N;
  kolejka[pk] := p;
end;

// Funkcja odczytuje współrzędne p z kolejki
//------------------------------------------------------
function Czytaj : COORD;
begin
  Result := kolejka[kk];
  kk := (kk + 1) mod N;
end;

// Funkcja przemieszcza głowę węża zgodnie z kierunkiem.
// Zwraca jako wynik znak, który znajdował się w oknie
// konsoli na pozycji zajętej obecnie przez głowę węża.
//------------------------------------------------------
function Ruch_glowy : char;
begin
  case kierunek of
    1 : dec(glowa.Y); // ruch w górę
    2 : inc(glowa.X); // ruch w prawo
    3 : inc(glowa.Y); // ruch w dół
    4 : dec(glowa.X); // ruch w lewo
  end;
  Result := Znak_na_pozycji(glowa);
  Zapisz(glowa);
  TextAttr := $2e; GotoXY(glowa.x,glowa.y); write('O');
end;

// Procedura usuwa z okna konsoli ogon węża
//------------------------------------------------------
procedure Usun_ogon;
var
  p : COORD;
begin
  p := Czytaj;
  TextAttr := $20; GotoXY(p.X,p.Y); write(' ');
end;

// Procedura generuje malinkę w wolnym miejscu pola gry.
//------------------------------------------------------
procedure Malinka;
var
  p : COORD;
begin
  repeat
    p.X := 2 + random(78); p.Y := 2 + random(22);
  until Znak_na_pozycji(p) = ' ';
  TextAttr := $2d; GotoXY(p.X,p.Y); write('*');
end;

// Procedura oblicza aktualną długość węża
//------------------------------------------------------
procedure Dlugosc;
var
  dk : integer;
begin
  if pk > kk then
    dk := pk - kk + 1
  else
    dk := N + pk - kk + 1;
  TextAttr := $0b; GotoXY(1,25);
  write(PL('Aktualna długość węża wynosi : '));
  TextAttr := $0f; write(dk);
end;

// Procedura wyświetla stronę tytułową, czeka na dowolny
// klawisz i czyści ekran
//------------------------------------------------------
procedure StronaTytulowa;
begin
  TextAttr := $07; ClrScr;
  GotoXY(1,4);
  TextAttr := $d0;
  Centruj(PL('                                  '));
  Centruj(PL('               W Ą Ż              '));
  Centruj(PL('                                  '));
  TextAttr := $71;
  Centruj(PL('                                  '));
  Centruj(PL('    (C)2004 mgr Jerzy Wałaszek    '));
  Centruj(PL('                                  '));
  TextAttr := $8e;
  Centruj(PL('                                  '));
  Centruj(PL('     I Liceum Ogólnokształcące    '));
  Centruj(PL('   im. Kazimierza  Brodzińskiego  '));
  Centruj(PL('             w Tarnowie           '));
  Centruj(PL('                                  '));
  TextAttr := $f1;
  Centruj(PL('                                  '));
  Centruj(PL('    Nakarm głodującego gada...    '));
  Centruj(PL('                                  '));
  TextAttr := $f4;
  Centruj(PL('        Gdy będziesz gotowy,      '));
  Centruj(PL('     naciśnij dowolny klawisz     '));
  Centruj(PL('                                  '));
  TextAttr := $0a; Ramka(23,3,58,21);
  while ReadKey = #0 do; // Oczekiwanie na dowolny klawisz
  TextAttr := $07; ClrScr;
end;

// Procedura rysuje pole gry. Umieszcza na nim węża w
// pozycji startowej na środku ekranu oraz generuje
// malinkę w przypadkowej lokacji pola gry.
//------------------------------------------------------
procedure Plansza;
var
  i,j : integer;
begin
  TextAttr := $2f;
  for i := 2 to 23 do
  begin
    GotoXY(2,i);
    for j := 1 to 78 do write(' ');
  end;
  Ramka(1,1,80,24);
  kierunek := 2; // ruch w prawo
  glowa.x := 38; glowa.y := 11;
  pk := N - 1; kk := 0;
  for i := 1 to 5 do Ruch_glowy;
  Dlugosc;
  Malinka;
end;

// Procedura odczytuje stan klawiatury i jeśli naciśnięto
// klawisz kursora, zmieniany jest odpowiednio kierunek
// ruchu węża
//------------------------------------------------------
procedure Czytaj_Klawiature;
var
  c : char;
begin
  if KeyPressed then
  begin
    repeat
      c := ReadKey;
    until c <> #0;
    case c of
      #75 : kierunek := 4; //strzałka w lewo
      #77 : kierunek := 2; //strzałka w prawo
      #72 : kierunek := 1; //strzałka w górę
      #80 : kierunek := 3; //strzałka w dół
    end;
  end;
end;

// Procedura przeprowadza rozgrywkę
//------------------------------------------------------
procedure Graj;
var
  c       : char;
  licznik : integer;
begin
  licznik := 0; c := ' ';
  repeat
    Czytaj_Klawiature; Delay(10); inc(licznik);
    if licznik = 15 then
    begin
      licznik := 0; c := Ruch_glowy;
      if c = '*' then
      begin
        c := ' '; Malinka; Dlugosc;
      end
      else Usun_ogon;
    end;
  until c <> ' ';
end;

// Funkcja wyświetla efekt śmierci węża oraz tekst
// końca gry. Następnie zadaje pytanie, czy gracz
// życzy sobie zakończyć grę. Zwraca false jeśli nie
// i true, jeśli tak
//------------------------------------------------------
function Koniec : boolean;
var
  p : COORD;
begin
  TextAttr := $2f;
  repeat
    Delay(50);
    p := Czytaj; GotoXY(p.X,p.Y); write('X');
  until kk = pk;
  TextAttr := $ce;
  GotoXY(1,11);
  Centruj('                            ');
  Centruj(PL('  G R A  S K O Ń C Z O N A  '));
  Centruj('                            ');
  Delay(500);
  while KeyPressed do //ignorujemy przypadkowe naciśnięcia klawiszy
  begin
    ReadKey; Delay(200);
  end;
  GotoXY(1,15); TextAttr := $2b;
  Centruj('Jeszcze raz ? [T] = Tak, [Inny] = Nie');
  Result := UpCase(ReadKey) <> 'T';
end;

//------------------------------------------------------
// Program główny
//------------------------------------------------------

var
  a : integer;
begin
  Randomize;
  a := TextAttr; CursorOff;
  repeat
    StronaTytulowa;
    Plansza;
    Graj;
  until Koniec;
  TextAttr := a; CursorOn; ClrScr;
end.

 

Program obiektowy w języku Pascal

//                 W Ą Ż
//            WERSJA OBIEKTOWA
//--------------------------------------------
// (C)2004 mgr Jerzy Wałaszek  I LO w Tarnowie

program Waz;

uses Crt, Windows;

//----------------------------------------------------
// PROCEDURY I FUNKCJE POMOCNICZE
//----------------------------------------------------

// Funkcja PL konwertuje tekst ze standardu Windows 1250
// na standard konsoli znakowej Latin II
//------------------------------------------------------
function PL(s : string) : string;
var
  i : integer;
  c : char;
begin
  for i := 1 to length(s) do
  begin
   case s[i] of
      'ą' : c := #165;
      'ć' : c := #134;
      'ę' : c := #169;
      'ł' : c := #136;
      'ń' : c := #228;
      'ó' : c := #162;
      'ś' : c := #152;
      'ż' : c := #190;
      'ź' : c := #171;
      'Ą' : c := #164;
      'Ć' : c := #143;
      'Ę' : c := #168;
      'Ł' : c := #157;
      'Ń' : c := #227;
      'Ó' : c := #224;
      'Ś' : c := #151;
      'Ż' : c := #189;
      'Ź' : c := #141;
      else
        c := s[i]; 
    end;
    s[i] := c;
  end;
  Result := s;
end;

// Procedura centruje w bieżącym wierszu
// tekst podany jako parametr
//----------------------------------------------------
procedure Centruj(t : string);
begin
  GotoXY(1 + (80-length(t)) div 2, WhereY);
  writeln(t);
end;

// Procedura rysuje pojedynczą ramkę ze znaków
// tabelek. Parametry określają współrzędne
// lewego górnego i prawego dolnego narożnika
//----------------------------------------------------
procedure Ramka(xp,yp,xk,yk : integer);
var
  i : integer;
begin
  GotoXY(xp,yp); write(#218);
  GotoXY(xp,yk); write(#192);
  GotoXY(xk,yp); write(#191);
  GotoXY(xk,yk); write(#217);
  for i := xp + 1 to xk - 1 do
  begin
    GotoXY(i,yp); write(#196);
    GotoXY(i,yk); write(#196);
  end;
  for i := yp + 1 to yk - 1 do
  begin
    GotoXY(xp,i); write(#179);
    GotoXY(xk,i); write(#179);
  end;
end;

// Funkcja odczytuje znak na pozycji p okna konsoli
// Uwaga - znaki ramki będą odczytane nieprawidłowo jako
// literki.
//------------------------------------------------------
function Znak_na_pozycji(p : COORD) : char;
var
  c : char;
  k : integer;
begin
  dec(p.x);
  dec(p.y);
  ReadConsoleOutputCharacter(GetStdHandle(STD_OUTPUT_HANDLE),
                             addr(c),1,p,k);
  Result := c;
end;

//------------------------------------------------------
// PROGRAM GRY
//------------------------------------------------------

const
  N = 1716;

type
  TKolejka = class
    private
      k     : array[0..N-1] of COORD;
      pk,kk : integer;
      procedure FZapisz(x : COORD);
      function  FCzytaj : COORD;
    public
      constructor Tworz;
      procedure   Inicjuj;
      property    d : COORD read FCzytaj write FZapisz;
  end;

  TWaz = class(TKolejka)
    private
      kierunek : integer;
      glowa    : COORD;
      c        : char; // znak pod głową węża
      procedure Czytaj_Klawiature;
      procedure Dlugosc;
      procedure Malinka;
      procedure Ruch_Glowy;
      procedure StronaTytulowa;
      procedure Usun_Ogon;
    public
      constructor Tworz;
      procedure   Inicjuj;
      procedure   Graj;
      function    Koniec : boolean;
    end;

//------------------------------------------------------
// Definicje metod obiektowych
//------------------------------------------------------

// Zapis do kolejki cyklicznej
//------------------------------------------------------
procedure TKolejka.FZapisz(x : COORD);
begin
  pk := (pk + 1) mod N;
  k[pk] := x;
end;

// Odczyt z kolejki cyklicznej
//------------------------------------------------------
function TKolejka.FCzytaj : COORD;
begin
  Result := k[kk];
  kk := (kk + 1) mod N;
end;

constructor TKolejka.Tworz;
begin
  Inicjuj;
end;

procedure TKolejka.Inicjuj;
begin
  kk := 0; pk := N - 1;
end;

constructor TWaz.Tworz;
begin

end;

// Procedura wyświetla stronę tytułową, czeka na dowolny
// klawisz i czyści ekran
//------------------------------------------------------
procedure TWaz.StronaTytulowa;
begin
  TextAttr := $07; ClrScr;
  GotoXY(1,4);
  TextAttr := $d0;
  Centruj(PL('                                  '));
  Centruj(PL('               W Ą Ż              '));
  Centruj(PL('                                  '));
  TextAttr := $71;
  Centruj(PL('                                  '));
  Centruj(PL('    (C)2004 mgr Jerzy Wałaszek    '));
  Centruj(PL('                                  '));
  TextAttr := $8e;
  Centruj(PL('                                  '));
  Centruj(PL('     I Liceum Ogólnokształcące    '));
  Centruj(PL('   im. Kazimierza  Brodzińskiego  '));
  Centruj(PL('             w Tarnowie           '));
  Centruj(PL('                                  '));
  TextAttr := $f1;
  Centruj(PL('                                  '));
  Centruj(PL('    Nakarm głodującego gada...    '));
  Centruj(PL('                                  '));
  TextAttr := $f4;
  Centruj(PL('        Gdy będziesz gotowy,      '));
  Centruj(PL('     naciśnij dowolny klawisz     '));
  Centruj(PL('                                  '));
  TextAttr := $0a; Ramka(23,3,58,21);
  while ReadKey = #0 do; // Oczekiwanie na dowolny klawisz
  TextAttr := $07; ClrScr;
end;

// Metoda przemieszcza głowę węża zgodnie z kierunkiem.
// W polu c umieszcza znak, który znajdował się w oknie
// konsoli na pozycji zajętej obecnie przez głowę węża.
//------------------------------------------------------
procedure TWaz.Ruch_glowy;
begin
  case kierunek of
    1 : dec(glowa.Y); // ruch w górę
    2 : inc(glowa.X); // ruch w prawo
    3 : inc(glowa.Y); // ruch w dół
    4 : dec(glowa.X); // ruch w lewo
  end;
  c := Znak_na_pozycji(glowa);
  d := glowa; // zapis do kolejki cyklicznej
  TextAttr := $2e; GotoXY(glowa.x,glowa.y); write('O');
end;

// Procedura usuwa z okna konsoli ogon węża
//------------------------------------------------------
procedure TWaz.Usun_ogon;
var
  p : COORD;
begin
  p := d; // odczyt kolejki cyklicznej
  TextAttr := $20; GotoXY(p.X,p.Y); write(' ');
end;

// Procedura generuje malinkę w wolnym miejscu pola gry.
//------------------------------------------------------
procedure TWaz.Malinka;
var
  p : COORD;
begin
  repeat
    p.X := 2 + random(78); p.Y := 2 + random(22);
  until Znak_na_pozycji(p) = ' ';
  TextAttr := $2d; GotoXY(p.X,p.Y); write('*');
end;

// Procedura oblicza aktualną długość węża
//------------------------------------------------------
procedure TWaz.Dlugosc;
var
  dk : integer;
begin
  if pk > kk then
    dk := pk - kk + 1
  else
    dk := N + pk - kk + 1;
  TextAttr := $0b; GotoXY(1,25);
  write(PL('Aktualna długość węża wynosi : '));
  TextAttr := $0f; write(dk);
end;

// Procedura odczytuje stan klawiatury i jeśli naciśnięto
// klawisz kursora, zmieniany jest odpowiednio kierunek
// ruchu węża
//------------------------------------------------------
procedure TWaz.Czytaj_Klawiature;
var
  klawisz : char;
begin
  if KeyPressed then
  begin
    repeat
      klawisz := ReadKey;
    until klawisz <> #0;
    case klawisz of
      #75 : kierunek := 4; //strzałka w lewo
      #77 : kierunek := 2; //strzałka w prawo
      #72 : kierunek := 1; //strzałka w górę
      #80 : kierunek := 3; //strzałka w dół
    end;
  end;
end;

// Procedura przeprowadza rozgrywkę
//------------------------------------------------------
procedure TWaz.Graj;
var
  licznik : integer;
begin
  licznik := 0; c := ' ';
  repeat
    Czytaj_Klawiature; Delay(10); inc(licznik);
    if licznik = 15 then
    begin
      licznik := 0; Ruch_glowy;
      if c = '*' then
      begin
        c := ' '; Malinka; Dlugosc;
      end
      else Usun_ogon;
    end;
  until c <> ' ';
end;

// Funkcja wyświetla efekt śmierci węża oraz tekst
// końca gry. Następnie zadaje pytanie, czy gracz
// życzy sobie zakończyć grę. Zwraca false jeśli nie
// i true, jeśli tak
//------------------------------------------------------
function TWaz.Koniec : boolean;
var
  p : COORD;
begin
  TextAttr := $2f;
  repeat
    Delay(50);
    p := d; GotoXY(p.X,p.Y); write('X');
  until kk = pk;
  TextAttr := $ce;
  GotoXY(1,11);
  Centruj('                            ');
  Centruj(PL('  G R A  S K O Ń C Z O N A  '));
  Centruj('                            ');
  Delay(500);
  while KeyPressed do //ignorujemy przypadkowe naciśnięcia klawiszy
  begin
    ReadKey; Delay(200);
  end;
  GotoXY(1,15); TextAttr := $2b;
  Centruj('Jeszcze raz ? [T] = Tak, [Inny] = Nie');
  Result := UpCase(ReadKey) <> 'T';
end;

// Inicjalizacja gry
//------------------------------------------------------
procedure TWaz.Inicjuj;
var
  i,j : integer;
begin
  inherited Inicjuj;
  StronaTytulowa;
  TextAttr := $2f;
  for i := 2 to 23 do
  begin
    GotoXY(2,i);
    for j := 1 to 78 do write(' ');
  end;
  Ramka(1,1,80,24);
  kierunek := 2; // ruch w prawo
  glowa.x := 38; glowa.y := 11;
  for i := 1 to 5 do Ruch_glowy;
  Dlugosc; Malinka;
end;

// Program główny
//------------------------------------------------------
var
  gra : TWaz;
  a   : integer;
begin
  Randomize;
  a := TextAttr; CursorOff;
  gra := TWaz.Tworz;
  with gra do
    repeat
      Inicjuj;
      Graj;
    until Koniec;
  TextAttr := a; CursorOn; ClrScr;
end.

 

Program w języku C++

Program uruchomiono w środowisku Dev-C++.

//                     W Ą Ż
//--------------------------------------------
// (C)2004 mgr Jerzy Wałaszek  I LO w Tarnowie

#include <conio.h>
#include <windows.h>
#include <iostream>

using namespace std;

//----------------------------------------------------
// Deklaracja klasy gry
//----------------------------------------------------
const int N = 1716;

class TWaz
{
  private:
    COORD k[N],glowa;
    int   pk,kk,kierunek;
    char  c;
    COORD Czytaj();
    void  Czytaj_Klawiature();
    void  Dlugosc();
    void  Malinka();
    void  Ruch_Glowy();
    void  StronaTytulowa();
    void  Usun_Ogon();
    void  Zapisz(COORD x);
  public:
    TWaz();
    ~TWaz();
    void Inicjuj();
    void Graj();
    int  Koniec();
};

//----------------------------------------------------
// PROCEDURY I FUNKCJE POMOCNICZE
//----------------------------------------------------

const int BLACK        = 0;
const int BLUE         = 1;
const int GREEN        = 2;
const int CYAN         = 3;
const int RED          = 4;
const int MAGENTA      = 5;
const int BROWN        = 6;
const int LIGHTGRAY    = 7;
const int DARKGRAY     = 8;
const int LIGHTBLUE    = 9;
const int LIGHTGREEN   = 10;
const int LIGHTCYAN    = 11;
const int LIGHTRED     = 12;
const int LIGHTMAGENTA = 13;
const int YELLOW       = 14;
const int WHITE        = 15;

static int __BACKGROUND = BLACK;
static int __FOREGROUND = LIGHTGRAY;

// Procedura ustawia pozycję wydruku w oknie konsoli
//----------------------------------------------------
void gotoxy(int x, int y)
{
  COORD c;

  c.X = x - 1;
  c.Y = y - 1;
  SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), c);
}

// Procedura ustawia kolor tła wydruku
//----------------------------------------------------
void textbackground(int color)
{
  __BACKGROUND = color;
  SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),
    __FOREGROUND + (color << 4));
}

// Procedura ustawia kolor tekstu
//----------------------------------------------------
void textcolor(int color)
{
  __FOREGROUND = color;
  SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),
    color + (__BACKGROUND << 4));
}

// Procedura ustawia atrybuty koloru tekstu i tła
//----------------------------------------------------
void textattr(int _attr)
{
  SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), _attr);
}

// Funkcja zwraca aktualną pozycję x kursora
//----------------------------------------------------
int wherex()
{
  CONSOLE_SCREEN_BUFFER_INFO info;

  GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &info);
  return info.dwCursorPosition.X + 1;
}

// Funkcja zwraca aktualną pozycję y kursora
//----------------------------------------------------
int wherey()
{
  CONSOLE_SCREEN_BUFFER_INFO info;

  GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &info);
  return info.dwCursorPosition.Y + 1;
}

// Procedura czyści zawartość okna konsoli
//----------------------------------------------------
void clrscr()
{
  DWORD written;

  FillConsoleOutputAttribute(GetStdHandle (STD_OUTPUT_HANDLE),
    __FOREGROUND + (__BACKGROUND << 4), 2000, (COORD){0, 0}, &written);
  FillConsoleOutputCharacter(GetStdHandle(STD_OUTPUT_HANDLE), ' ',
    2000, (COORD){0, 0}, &written);
  gotoxy(1, 1);
}

// Procedura ukrywa kursor okienka konsoli
//------------------------------------------------------
void CursorOff()
{
  CONSOLE_CURSOR_INFO Info;

  GetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), &Info); 
  Info.bVisible = 0;
  SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), &Info); 
};

// Procedura przywraca kursor okienka konsoli
//------------------------------------------------------
void CursorOn()
{
  CONSOLE_CURSOR_INFO Info;

  GetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), &Info); 
  Info.bVisible = -1;
  SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), &Info); 
};

// Funkcja PL konwertuje tekst ze standardu Windows 1250
// na standard konsoli znakowej Latin II
//------------------------------------------------------
string PL(string s)
{
  int i;
  char c;

  for(i = 0; i < s.length(); i++)
  {
    switch(s[i])
    {
      case 'ą' : c = char(165); break;
      case 'ć' : c = char(134); break;
      case 'ę' : c = char(169); break;
      case 'ł' : c = char(136); break;
      case 'ń' : c = char(228); break;
      case 'ó' : c = char(162); break;
      case 'ś' : c = char(152); break;
      case 'ż' : c = char(190); break;
      case 'ź' : c = char(171); break;
      case 'Ą' : c = char(164); break;
      case 'Ć' : c = char(143); break;
      case 'Ę' : c = char(168); break;
      case 'Ł' : c = char(157); break;
      case 'Ń' : c = char(227); break;
      case 'Ó' : c = char(224); break;
      case 'Ś' : c = char(151); break;
      case 'Ż' : c = char(189); break;
      case 'Ź' : c = char(141); break;
      default:   c = s[i]; 
    };
    s[i] = c;
  };
  return(s);
}

// Procedura centruje w bieżącym wierszu
// tekst podany jako parametr
//----------------------------------------------------
void Centruj(string t)
{
  gotoxy(1 + (80 - t.length()) / 2, wherey());
  cout << t << endl;
}

// Procedura rysuje pojedynczą ramkę ze znaków
// tabelek. Parametry określają współrzędne
// lewego górnego i prawego dolnego narożnika
//----------------------------------------------------
void Ramka(int xp,int yp,int xk,int yk)
{
  int i;

  gotoxy(xp,yp); putch(char(218));
  gotoxy(xp,yk); putch(char(192));
  gotoxy(xk,yp); putch(char(191));
  gotoxy(xk,yk); putch(char(217));
  for(i = xp + 1; i <= xk - 1; i++)
  {
    gotoxy(i,yp); putch(char(196));
    gotoxy(i,yk); putch(char(196));
  };
  for(i = yp + 1; i <= yk - 1; i++)
  {
    gotoxy(xp,i); putch(char(179));
    gotoxy(xk,i); putch(char(179));
  };
}

// Procedura wprowadza opóźnienie
// o zadaną ilość milisekund
//----------------------------------------------------
void Delay(int d)
{
  long start;

  start = GetTickCount();
  while((GetTickCount() - start) < d);
}

// Funkcja odczytuje znak na pozycji p okna konsoli
// Uwaga - znaki ramki będą odczytane nieprawidłowo jako
// literki.
//------------------------------------------------------
char Znak_na_pozycji(COORD p)
{
  char c;
  DWORD k;

  p.X--; p.Y--;
  ReadConsoleOutputCharacter(GetStdHandle(STD_OUTPUT_HANDLE),
                             &c,1,p,&k);
  return(c);
}

//----------------------------------------------------
// Definicje metod klas
//----------------------------------------------------

// Zapis do kolejki cyklicznej
//------------------------------------------------------
void TWaz::Zapisz(COORD x)
{
  pk = (pk + 1) % N; k[pk] = x;
}

// Odczyt z kolejki cyklicznej
//------------------------------------------------------
COORD TWaz::Czytaj()
{
  COORD result;
  
  result = k[kk]; kk = (kk + 1) % N; return(result);
}

// Konstruktor obiektu gry
//------------------------------------------------------
TWaz::TWaz()
{
  srand((unsigned)time(NULL)); CursorOff();
}

// Destruktor obiektu gry
//------------------------------------------------------
TWaz::~TWaz()
{
    CursorOn(); textattr(7); clrscr();
}

// Procedura wyświetla stronę tytułową, czeka na dowolny
// klawisz i czyści ekran
//------------------------------------------------------
void TWaz::StronaTytulowa()
{
  textbackground(0); clrscr();
  gotoxy(1,4); textattr(0xd0);
  Centruj(PL("                                  "));
  Centruj(PL("               W Ą Ż              "));
  Centruj(PL("                                  "));
  textattr(0x71);
  Centruj(PL("                                  "));
  Centruj(PL("    (C)2004 mgr Jerzy Wałaszek    "));
  Centruj(PL("                                  "));
  textattr(0x8e);
  Centruj(PL("                                  "));
  Centruj(PL("     I Liceum Ogólnokształcące    "));
  Centruj(PL("   im. Kazimierza  Brodzińskiego  "));
  Centruj(PL("             w Tarnowie           "));
  Centruj(PL("                                  "));
  textattr(0xf1);
  Centruj(PL("                                  "));
  Centruj(PL("    Nakarm głodującego gada...    "));
  Centruj(PL("                                  "));
  textattr(0xf4);
  Centruj(PL("        Gdy będziesz gotowy,      "));
  Centruj(PL("     naciśnij dowolny klawisz     "));
  Centruj(PL("                                  "));
  textattr(0x0a); Ramka(23,3,58,21);
  while(getch() == 0); // Oczekiwanie na dowolny klawisz
  textattr(0x07); clrscr();
}

// Metoda przemieszcza głowę węża zgodnie z kierunkiem.
// W polu c umieszcza znak, który znajdował się w oknie
// konsoli na pozycji zajętej obecnie przez głowę węża.
//------------------------------------------------------
void TWaz::Ruch_Glowy()
{
  switch(kierunek)
  {
    case 1 : glowa.Y--; break; // ruch w górę
    case 2 : glowa.X++; break; // ruch w prawo
    case 3 : glowa.Y++; break; // ruch w dół
    case 4 : glowa.X--; break; // ruch w lewo
  };
  c = Znak_na_pozycji(glowa);
  Zapisz(glowa);
  textattr(0x2e); gotoxy(glowa.X,glowa.Y); cout << "O";
}

// Procedura usuwa z okna konsoli ogon węża
//------------------------------------------------------
void TWaz::Usun_Ogon()
{
  COORD p;

  p = Czytaj();
  textattr(0x20); gotoxy(p.X,p.Y); cout << " ";
}

// Procedura generuje malinkę w wolnym miejscu pola gry.
//------------------------------------------------------
void TWaz::Malinka()
{
  COORD p;

  do
  {
    p.X = 2 + rand() % 78; p.Y = 2 + rand() % 22;
  } while(Znak_na_pozycji(p) != ' ');
  textattr(0x2d); gotoxy(p.X,p.Y); cout << "*";
}

// Procedura oblicza aktualną długość węża i wyświetla
// wynik na spodzie okienka konsoli
//------------------------------------------------------
void TWaz::Dlugosc()
{
  int dk;

  if(pk > kk) dk = pk - kk + 1; else dk = N + pk - kk + 1;
  textattr(0x0b); gotoxy(1,25);
  cout << PL("Aktualna długość węża wynosi : ");
  textattr(0x0f); cout << dk;
}

// Procedura odczytuje stan klawiatury i jeśli naciśnięto
// klawisz kursora, zmieniany jest odpowiednio kierunek
// ruchu węża
//------------------------------------------------------
void TWaz::Czytaj_Klawiature()
{
  char klawisz;

  if(kbhit()) while(!(klawisz = getch())) ;
  switch(klawisz)
  {
    case char(75) : kierunek = 4; break; //strzałka w lewo
    case char(77) : kierunek = 2; break; //strzałka w prawo
    case char(72) : kierunek = 1; break; //strzałka w górę
    case char(80) : kierunek = 3; break; //strzałka w dół
  };
}

// Procedura przeprowadza rozgrywkę
//------------------------------------------------------
void TWaz::Graj()
{
  int licznik;

  licznik = 0; c = ' ';
  do
  {
    Czytaj_Klawiature(); Delay(10);
    if(++licznik == 15)
    {
      licznik = 0; Ruch_Glowy();
      if(c == '*')
      {
        c = ' '; Malinka(); Dlugosc();
      }
      else Usun_Ogon();
    };
  } while(c == ' ');
}

// Funkcja wyświetla efekt śmierci węża oraz tekst
// końca gry. Następnie zadaje pytanie, czy gracz
// życzy sobie zakończyć grę. Zwraca false jeśli nie
// i true, jeśli tak
//------------------------------------------------------
int TWaz::Koniec()
{
  COORD p;

  textattr(0x2f);
  do
  {
    Delay(50);
    p = Czytaj(); gotoxy(p.X,p.Y); cout << "X";
  } while(kk != pk);
  textattr(0xce); gotoxy(1,11);
  Centruj("                            ");
  Centruj(PL("  G R A  S K O Ń C Z O N A  "));
  Centruj("                            ");
  Delay(500);
  while(kbhit()) //ignorujemy przypadkowe naciśnięcia klawiszy
  {
    getch(); Delay(200);
  };
  gotoxy(1,15); textattr(0x2b);
  Centruj("Jeszcze raz ? [T] = Tak, [Inny] = Nie");
  return(toupper(getch()) != 'T');
}

// Inicjalizacja gry
//------------------------------------------------------
void TWaz::Inicjuj()
{
  int i,j;

  kk = 0; pk = N - 1; StronaTytulowa(); textattr(0x2f);
  for(i = 2; i <= 23; i++)
  {
    gotoxy(2,i); for(j = 1; j <= 78; j++) cout << " ";
  };
  Ramka(1,1,80,24);
  kierunek = 2; // ruch w prawo
  glowa.X = 38; glowa.Y = 11;
  for(i = 1; i <= 5; i++) Ruch_Glowy();
  Dlugosc(); Malinka();
}

// Program główny
//------------------------------------------------------
int main()
{
  TWaz gra;
  
  do
  {
    gra.Inicjuj();
    gra.Graj();
  } while(!gra.Koniec());
  return(0);
}

 

Dla ambitnych

  1. Zmień program tak, aby zamiast malinek w postaci gwiazdek program wyświetlał cyferki od 1 do 9. Zjedzenie przez węża cyferki powinno powodować odpowiednie wydłużenie o tyle segmentów, ile wynosi wartość cyferki. Uważaj, zastanów się nad sposobem zwiększania liczby segmentów - wąż może zjeść kilka cyferek zanim rozciągnie się na odpowiednią długość.
  2. Zmień program tak, aby wąż poruszał się coraz szybciej w miarę jak nabiera długości. Szybkość dobierz tak, aby gra była wciąż grywalna nawet przy największej długości.
  3. Dorób listę graczy, którzy osiągnęli największe rozmiary gada. Lista powinna być odpowiednio posortowana.

 


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

©2021 mgr Jerzy Wałaszek

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

Pytania proszę przesyłać na adres email: i-lo@eduinf.waw.pl

W artykułach serwisu są używane cookies. Jeśli nie chcesz ich otrzymywać,
zablokuj je w swojej przeglądarce.
Informacje dodatkowe