Piętnastka - 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

//      G R A  W  P I Ę T N A S T K Ę
//            WERSJA FUNKCYJNA
//--------------------------------------------
// (C)2004 mgr Jerzy Wałaszek  I LO w Tarnowie

program Gra15;

uses Crt;

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

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

const
  cplansza : string[16] = 'ABCDEFGHIJKLMNO ';
var
  plansza : string[16]; // przechowuje planszę gry

// Procedura wyświetla stronę tytułową, czeka na dowolny
// klawisz i czyści ekran
//------------------------------------------------------
procedure StronaTytulowa;
begin
  TextAttr := $07; ClrScr;
  GotoXY(1,4);
  TextAttr := $8f;
  Centruj(PL('                                  '));
  Centruj(PL('  G R A  W  P I Ę T N A S T K Ę   '));
  Centruj(PL('  =============================   '));
  Centruj(PL('                                  '));
  TextAttr := $1b;
  Centruj(PL('                                  '));
  Centruj(PL('    (C)2004 mgr Jerzy Wałaszek    '));
  Centruj(PL('                                  '));
  TextAttr := $e4;
  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(' Czy potrafisz logicznie myśleć ? '));
  Centruj(PL('                                  '));
  TextAttr := $f4;
  Centruj(PL('        Gdy będziesz gotowy,      '));
  Centruj(PL('     naciśnij dowolny klawisz     '));
  Centruj(PL('                                  '));
  TextAttr := $0a; Ramka(23,3,58,22);
  while ReadKey = #0 do; // Oczekiwanie na dowolny klawisz
  TextAttr := $07; ClrScr;
end;

// Procedura wyświetla planszę
//------------------------------------------------------
procedure WyswietlPlansze;
var
  k,w,i,j : integer;
begin
  for i := 1 to 16 do
  begin
    if plansza[i] = ' ' then // określamy kolor segmentu
      TextAttr := $00
    else
    begin
      if plansza[i] = cplansza[i] then
        TextAttr := $2f
      else
        TextAttr := $e4;
    end;
    k := 33 + 4*((i - 1) mod 4); // wyznaczamy położenie segmentu
    w :=  6 + 4*((i - 1) div 4); // w oknie konsoli
    for j := 0 to 2 do           // wyświetlamy segment
    begin
      GotoXY(k,w + j);
      if j = 1 then
        write(' ',plansza[i],' ')
      else
        write('   ');
    end;
  end;
  TextAttr := $1b; Ramka(31,4,49,22);
end;

// Procedura znajduje puste miejsce i ustawia zmienne
// przekazane jej jako parametry:
// p   - pozycja pustego miejsca w zmiennej plansza
// x,y - pozycja pustego miejsca na planszy gry
//------------------------------------------------------
procedure Oblicz_pxy(var p,x,y : integer);
begin
  p := Pos(' ',plansza);  // znajdujemy pozycję pustego miejsca
  x := 1 + (p - 1) mod 4; // obliczamy współrzędne na planszy
  y := 1 + (p - 1) div 4;
end;

// Procedura przesuwa segment w prawo, o ile to jest
// możliwe. Jeśli nie, segment nie jest przesuwany.
//------------------------------------------------------
procedure Segment_w_prawo;
var
  p,x,y : integer;
begin
  Oblicz_pxy(p,x,y);
  if x > 1 then
  begin
    plansza[p] := plansza[p - 1];
    plansza[p - 1] := ' ';
  end;
end;

// Procedura przesuwa segment w lewo, o ile to jest
// możliwe. Jeśli nie, segment nie jest przesuwany.
//------------------------------------------------------
procedure Segment_w_lewo;
var
  p,x,y : integer;
begin
  Oblicz_pxy(p,x,y);
  if x < 4 then
  begin
    plansza[p] := plansza[p + 1];
    plansza[p + 1] := ' ';
  end;
end;

// Procedura przesuwa segment w górę, o ile to jest
// możliwe. Jeśli nie, segment nie jest przesuwany.
//------------------------------------------------------
procedure Segment_w_gore;
var
  p,x,y : integer;
begin
  Oblicz_pxy(p,x,y);
  if y < 4 then
  begin
    plansza[p] := plansza[p + 4];
    plansza[p + 4] := ' ';
  end;
end;

// Procedura przesuwa segment w dół, o ile to jest
// możliwe. Jeśli nie, segment nie jest przesuwany.
//------------------------------------------------------
procedure Segment_w_dol;
var
  p,x,y : integer;
begin
  Oblicz_pxy(p,x,y);
  if y > 1 then
  begin
    plansza[p] := plansza[p - 4];
    plansza[p - 4] := ' ';
  end;
end;

// Procedura tworzy planszę dla gry
//------------------------------------------------------
procedure GenerujPlansze;
var
  i : integer;
begin
  plansza := cplansza;
  for i := 1 to 1000 do
    case random(4) of
      0 : Segment_w_prawo;
      1 : Segment_w_lewo;
      2 : Segment_w_gore;
      3 : Segment_w_dol;
    end;
  WyswietlPlansze;
end;

// Procedura wykonuje ruch na planszy
//------------------------------------------------------
procedure WykonajRuch;
var
  c : char;
begin
  repeat
    c := ReadKey;
  until c <> #0;
  case c of
    #75 : Segment_w_lewo;  //strzałka w lewo
    #77 : Segment_w_prawo; //strzałka w prawo
    #72 : Segment_w_gore;  //strzałka w górę
    #80 : Segment_w_dol;   //strzałka w dół
  end;
  WyswietlPlansze;
end;

// Funkcja sprawdza, czy segmenty są ułożone
//------------------------------------------------------
function Ulozone : boolean;
begin
  if plansza = cplansza then
  begin
    TextAttr := $0c; GotoXY(1,2);
    Centruj('G R A T U L A C J E');
    Result := true;
  end
  else Result := false;
end;

// Funkcja sprawdza, czy gracz chce zakończyć grę
//------------------------------------------------------
function Koniec : boolean;
begin
  GotoXY(1,24); TextAttr := $0f;
  Centruj('Jeszcze raz ? [T] = Tak, [Inny] = Nie');
  Result := UpCase(ReadKey) <> 'T';
end;

var
  a : integer;
begin
  Randomize;
  a := TextAttr; CursorOff;
  repeat
    StronaTytulowa;
    GenerujPlansze;
    repeat
      WykonajRuch;
    until Ulozone;
  until Koniec;
  TextAttr := a; CursorOn; ClrScr;
end.

 

Program obiektowy w języku Pascal

Wersja obiektowa prawie niczym nie musi się różnić od wersji funkcyjnej. W sumie obiekty też tworzymy często metodą zstępującą. Zaletą programowania obiektowego jest mocniejsze powiązanie danych z operującymi na nich procedurami. Zwróć uwagę, iż obiekt ukrywa swoją implementację udostępniając na zewnątrz jedynie najistotniejsze procedury. Zasada taka nosi nazwę enkapsulacji (zawarcia w pigułce) - aby oglądać telewizor wystarczy znać funkcje klawiszy na odbiorniku. Nie jest nam potrzebna wiedza, co w środku odbiornika się właściwie dzieje, gdy dany klawisz zostaje naciśnięty.

 

//      G R A  W  P I Ę T N A S T K Ę
//             WERSJA OBIEKTOWA
//--------------------------------------------
// (C)2004 mgr Jerzy Wałaszek  I LO w Tarnowie

program Gra15;

uses Crt;

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

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

type
  TGra = class
    private
      cplansza : string[16];
      plansza  : string[16];
      a        : integer;
      procedure GenerujPlansze;
      function  Koniec : boolean;
      procedure Oblicz_pxy(var p,x,y : integer);
      procedure Segment_w_dol;
      procedure Segment_w_gore;
      procedure Segment_w_lewo;
      procedure Segment_w_prawo;
      procedure StronaTytulowa;
      function  Ulozone : boolean;
      procedure WykonajRuch;
      procedure WyswietlPlansze;
    public
      constructor Utworz;
      procedure   Graj;
      procedure   Zakoncz;
  end;

//------------------------------------------------------
// Definicje metod obiektu gry
//------------------------------------------------------

// Procedura wyświetla stronę tytułową, czeka na dowolny
// klawisz i czyści ekran
//------------------------------------------------------
procedure TGra.StronaTytulowa;
begin
  TextAttr := $07; ClrScr;
  GotoXY(1,4);
  TextAttr := $8f;
  Centruj(PL('                                  '));
  Centruj(PL('  G R A  W  P I Ę T N A S T K Ę   '));
  Centruj(PL('  =============================   '));
  Centruj(PL('                                  '));
  TextAttr := $1b;
  Centruj(PL('                                  '));
  Centruj(PL('    (C)2004 mgr Jerzy Wałaszek    '));
  Centruj(PL('                                  '));
  TextAttr := $e4;
  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(' Czy potrafisz logicznie myśleć ? '));
  Centruj(PL('                                  '));
  TextAttr := $f4;
  Centruj(PL('        Gdy będziesz gotowy,      '));
  Centruj(PL('     naciśnij dowolny klawisz     '));
  Centruj(PL('                                  '));
  TextAttr := $0a; Ramka(23,3,58,22);
  while ReadKey = #0 do; // Oczekiwanie na dowolny klawisz
  TextAttr := $07; ClrScr;
end;

// Procedura wyświetla planszę
//------------------------------------------------------
procedure TGra.WyswietlPlansze;
var
  k,w,i,j : integer;
begin
  for i := 1 to 16 do
  begin
    if plansza[i] = ' ' then // określamy kolor segmentu
      TextAttr := $00
    else
    begin
      if plansza[i] = cplansza[i] then
        TextAttr := $2f
      else
        TextAttr := $e4;
    end;
    k := 33 + 4*((i - 1) mod 4); // wyznaczamy położenie segmentu
    w :=  6 + 4*((i - 1) div 4); // w oknie konsoli
    for j := 0 to 2 do           // wyświetlamy segment
    begin
      GotoXY(k,w + j);
      if j = 1 then
        write(' ',plansza[i],' ')
      else
        write('   ');
    end;
  end;
  TextAttr := $1b; Ramka(31,4,49,22);
end;

// Procedura znajduje puste miejsce i ustawia zmienne
// przekazane jej jako parametry:
// p   - pozycja pustego miejsca w zmiennej plansza
// x,y - pozycja pustego miejsca na planszy gry
//------------------------------------------------------
procedure TGra.Oblicz_pxy(var p,x,y : integer);
begin
  p := Pos(' ',plansza);  // znajdujemy pozycję pustego miejsca
  x := 1 + (p - 1) mod 4; // obliczamy współrzędne na planszy
  y := 1 + (p - 1) div 4;
end;

// Procedura przesuwa segment w prawo, o ile to jest
// możliwe. Jeśli nie, segment nie jest przesuwany.
//------------------------------------------------------
procedure TGra.Segment_w_prawo;
var
  p,x,y : integer;
begin
  Oblicz_pxy(p,x,y);
  if x > 1 then
  begin
    plansza[p] := plansza[p - 1];
    plansza[p - 1] := ' ';
  end;
end;

// Procedura przesuwa segment w lewo, o ile to jest
// możliwe. Jeśli nie, segment nie jest przesuwany.
//------------------------------------------------------
procedure TGra.Segment_w_lewo;
var
  p,x,y : integer;
begin
  Oblicz_pxy(p,x,y);
  if x < 4 then
  begin
    plansza[p] := plansza[p + 1];
    plansza[p + 1] := ' ';
  end;
end;

// Procedura przesuwa segment w górę, o ile to jest
// możliwe. Jeśli nie, segment nie jest przesuwany.
//------------------------------------------------------
procedure TGra.Segment_w_gore;
var
  p,x,y : integer;
begin
  Oblicz_pxy(p,x,y);
  if y < 4 then
  begin
    plansza[p] := plansza[p + 4];
    plansza[p + 4] := ' ';
  end;
end;

// Procedura przesuwa segment w dół, o ile to jest
// możliwe. Jeśli nie, segment nie jest przesuwany.
//------------------------------------------------------
procedure TGra.Segment_w_dol;
var
  p,x,y : integer;
begin
  Oblicz_pxy(p,x,y);
  if y > 1 then
  begin
    plansza[p] := plansza[p - 4];
    plansza[p - 4] := ' ';
  end;
end;

// Procedura tworzy planszę dla gry
//------------------------------------------------------
procedure TGra.GenerujPlansze;
var
  i : integer;
begin
  plansza := cplansza;
  for i := 1 to 1000 do
    case random(4) of
      0 : Segment_w_prawo;
      1 : Segment_w_lewo;
      2 : Segment_w_gore;
      3 : Segment_w_dol;
    end;
  WyswietlPlansze;
end;

// Procedura wykonuje ruch na planszy
//------------------------------------------------------
procedure TGra.WykonajRuch;
var
  c : char;
begin
  repeat
    c := ReadKey;
  until c <> #0;
  case c of
    #75 : Segment_w_lewo;  //strzałka w lewo
    #77 : Segment_w_prawo; //strzałka w prawo
    #72 : Segment_w_gore;  //strzałka w górę
    #80 : Segment_w_dol;   //strzałka w dół
  end;
  WyswietlPlansze;
end;

// Funkcja sprawdza, czy segmenty są ułożone
//------------------------------------------------------
function TGra.Ulozone : boolean;
begin
  if plansza = cplansza then
  begin
    TextAttr := $0c; GotoXY(1,2);
    Centruj('G R A T U L A C J E');
    Result := true;
  end
  else Result := false;
end;

// Funkcja sprawdza, czy gracz chce zakończyć grę
//------------------------------------------------------
function TGra.Koniec : boolean;
begin
  GotoXY(1,24); TextAttr := $0f;
  Centruj('Jeszcze raz ? [T] = Tak, [Inny] = Nie');
  Result := UpCase(ReadKey) <> 'T';
end;

constructor TGra.Utworz;
begin
  Randomize;
  a := TextAttr; CursorOff;
  cplansza := 'ABCDEFGHIJKLMNO ';
end;

procedure TGra.Graj;
begin
  repeat
    StronaTytulowa;
    GenerujPlansze;
    repeat
      WykonajRuch;
    until Ulozone;
  until Koniec;
end;

procedure TGra.Zakoncz;
begin
  TextAttr := a; CursorOn; ClrScr;
end;

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

var
  Gra : TGra;
begin
  Gra := TGra.Utworz;
  Gra.Graj;
  Gra.Zakoncz;
end.

 

Program w języku C++

Program uruchomiono w środowisku Dev-C++.

//       G R A  W  P I Ę T N A S T K Ę
//--------------------------------------------
// (C)2004 mgr Jerzy Wałaszek  I LO w Tarnowie

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

using namespace std;

//----------------------------------------------------
// Deklaracja klasy gry
//----------------------------------------------------

class TGra
{
    string cplansza,plansza;
    void GenerujPlansze();
    int  Koniec();
    void Oblicz_pxy(int * p, int * x, int * y);
    void Segment_w_dol();
    void Segment_w_gore();
    void Segment_w_lewo();
    void Segment_w_prawo();
    void StronaTytulowa();
    int  Ulozone();
    void WykonajRuch();
    void WyswietlPlansze();
  public:
    TGra();
    ~TGra();
    void Graj();
};

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

//----------------------------------------------------
// Definicje metod klasy gry
//----------------------------------------------------

// Procedura wyświetla stronę tytułową, czeka na dowolny
// klawisz i czyści ekran
//------------------------------------------------------
void TGra::StronaTytulowa()
{
  textbackground(0); clrscr();
  gotoxy(1,4); textattr(0x8f);
  Centruj(PL("                                  "));
  Centruj(PL("  G R A  W  P I Ę T N A S T K Ę   "));
  Centruj(PL("  =============================   "));
  Centruj(PL("                                  "));
  textattr(0x1b);
  Centruj(PL("                                  "));
  Centruj(PL("    (C)2004 mgr Jerzy Wałaszek    "));
  Centruj(PL("                                  "));
  textattr(0xe4);
  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(" Czy potrafisz logicznie myśleć ? "));
  Centruj(PL("                                  "));
  textattr(0xf4);
  Centruj(PL("        Gdy będziesz gotowy,      "));
  Centruj(PL("     naciśnij dowolny klawisz     "));
  Centruj(PL("                                  "));
  textattr(0x0a); Ramka(23,3,58,22);
  while(getch() == 0); // Oczekiwanie na dowolny klawisz
  textattr(0x07); clrscr();
}

// Procedura wyświetla planszę
//------------------------------------------------------
void TGra::WyswietlPlansze()
{
  int k,w,i,j;

  for(i = 1; i <= 16; i++)
  {
    if(plansza[i] == ' ') // określamy kolor segmentu
      textattr(0x00);
    else
    {
      if(plansza[i] == cplansza[i])
        textattr(0x2f);
      else
        textattr(0xe4);
    };
    k = 33 + 4 * ((i - 1) % 4); // wyznaczamy położenie segmentu
    w =  6 + 4 * ((i - 1) / 4); // w oknie konsoli
    for(j = 0; j <= 2; j++)      // wyświetlamy segment
    {
      gotoxy(k,w + j);
      if(j == 1)
        cout << " " << plansza[i] << " ";
      else
        cout << "   ";
    };
  };
  textattr(0x1b); Ramka(31,4,49,22);
}

// Procedura znajduje puste miejsce i ustawia zmienne
// przekazane jej jako parametry:
// p   - pozycja pustego miejsca w zmiennej plansza
// x,y - pozycja pustego miejsca na planszy gry
//------------------------------------------------------
void TGra::Oblicz_pxy(int * p, int * x, int * y)
{
  int i;
  
  for(i = 1; plansza[i] != ' '; i++);
  * p = i;  // znajdujemy pozycję pustego miejsca
  * x = 1 + (* p - 1) % 4; // obliczamy współrzędne na planszy
  * y = 1 + (* p - 1) / 4;
}

// Procedura przesuwa segment w prawo, o ile to jest
// możliwe. Jeśli nie, segment nie jest przesuwany.
//------------------------------------------------------
void TGra::Segment_w_prawo()
{
  int p,x,y;

  Oblicz_pxy(&p,&x,&y);
  if(x > 1)
  {
    plansza[p] = plansza[p - 1];
    plansza[p - 1] = ' ';
  };
}

// Procedura przesuwa segment w lewo, o ile to jest
// możliwe. Jeśli nie, segment nie jest przesuwany.
//------------------------------------------------------
void TGra::Segment_w_lewo()
{
  int p,x,y;

  Oblicz_pxy(&p,&x,&y);
  if(x < 4)
  {
    plansza[p] = plansza[p + 1];
    plansza[p + 1] = ' ';
  };
}

// Procedura przesuwa segment w górę, o ile to jest
// możliwe. Jeśli nie, segment nie jest przesuwany.
//------------------------------------------------------
void TGra::Segment_w_gore()
{
  int p,x,y;

  Oblicz_pxy(&p,&x,&y);
  if(y < 4)
  {
    plansza[p] = plansza[p + 4];
    plansza[p + 4] = ' ';
  };
}

// Procedura przesuwa segment w dół, o ile to jest
// możliwe. Jeśli nie, segment nie jest przesuwany.
//------------------------------------------------------
void TGra::Segment_w_dol()
{
  int p,x,y;

  Oblicz_pxy(&p,&x,&y);
  if(y > 1)
  {
    plansza[p] = plansza[p - 4];
    plansza[p - 4] = ' ';
  };
}

// Procedura tworzy planszę dla gry
//------------------------------------------------------
void TGra::GenerujPlansze()
{
  int i;

  plansza = cplansza;
  for(i = 1; i <= 1000; i++)
    switch(rand() % 4)
    {
      case 0 : Segment_w_prawo(); break;
      case 1 : Segment_w_lewo();  break;
      case 2 : Segment_w_gore();  break;
      case 3 : Segment_w_dol();   break;
    };
  WyswietlPlansze();
}

// Procedura wykonuje ruch na planszy
//------------------------------------------------------
void TGra::WykonajRuch()
{
  char c;

  while((c = getch()) == '\0') ;
  switch(c)
  {
    case char(75) : Segment_w_lewo();  break; 
    case char(77) : Segment_w_prawo(); break;
    case char(72) : Segment_w_gore();  break;
    case char(80) : Segment_w_dol();   break;
  };
  WyswietlPlansze();
}

// Funkcja sprawdza, czy segmenty są ułożone
//------------------------------------------------------
int TGra::Ulozone()
{
  if(plansza == cplansza)
  {
    textattr(0x0c); gotoxy(1,2);
    Centruj("G R A T U L A C J E");
    return(true);
  }
  else return(false);
}

// Funkcja sprawdza, czy gracz chce zakończyć grę
//------------------------------------------------------
int TGra::Koniec()
{
  gotoxy(1,24); textattr(0x0f);
  Centruj("Jeszcze raz ? [T] = Tak, [Inny] = Nie");
  return(toupper(getch()) != 'T');
}

TGra::TGra() // konstruktor
{
  srand((unsigned)time(NULL));
  CursorOff();
  cplansza = "?ABCDEFGHIJKLMNO ";
}

TGra::~TGra() // destruktor
{
  CursorOn(); clrscr();
}

void TGra::Graj()
{
  do
  {
    StronaTytulowa();
    GenerujPlansze();
    do
    {
      WykonajRuch();
    } while(!Ulozone());
  } while(!Koniec());
}

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

int main()
{
  TGra Gra;

  Gra.Graj();
  return 0;
}

 

Dla ambitnych

  1. Dodaj do programu licznik ruchów gracza. Zbuduj listę wyników graczy posortowaną w zależności od ilości ruchów. Możesz dodatkowo punktować czas wykonania ruchu.
  2. Sprawdź, czy dowolna plansza utworzona poprzez losowe rozłożenie segmentów (tzn. nie za pomocą przesunięć na puste miejsce jak w naszym przykładzie) daje się zawsze ułożyć. Jeśli tak, to zmodyfikuj odpowiednio procedurę generacji nowej planszy, aby wykorzystać ten fakt.
  3. Opracuj algorytm układania segmentów na planszy. Spróbuj go zminimalizować.

 


   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