Wstęp


W rozdziale

 

Celem artykułu nie jest udostępnianie gier - na pewno w Internecie znajdziecie ich więcej i będą dużo lepsze oraz ciekawsze. Nam chodzi o zademonstrowanie praktycznego zastosowania algorytmów i języka programowania do tworzenia gier logiczno zręcznościowych (wszyscy dobrze zarabiający programiści zaczynali od tego typu programów). Jeśli dokładnie prześledzisz przykłady, poznasz podstawowe metody programowania. Każdy rozdział podzielony jest logicznie na kilka sekcji. Na początku wyjaśniamy zasady danej gry. Następnie na ich podstawie tworzymy algorytm, który prezentujemy również w formie schematów blokowych. Według schematów blokowych piszemy programy w języku Pascal (czasem również w C++).

Powinieneś zapoznać się z algorytmem gry i schematami blokowymi i za ich pomocą próbować samodzielnie napisać program gry - może ci to nawet wyjść dużo lepiej niż nam. Do prezentowanych rozwiązań programów staraj się zaglądać tylko w ostateczności, gdy zupełnie nie wiesz jak zacząć. Bezmyślne kopiowanie naszych rozwiązań nic cię nie nauczy - lepiej dojdź do nich samodzielnie a nie pożałujesz włożonego w to wysiłku.

 

Uwagi na temat języków programowania

Prezentowane gry zostały zaimplementowane w dwóch językach programowania:

  • Dev-Pascal
  • Dev-C++

Oba środowiska są darmowo dostępne w sieci Internet. Zamiast Dev-Pascala można z powodzeniem stosować pakiet FreePascal.

 

Konsola znakowa

Ponieważ prezentowane gry przeznaczone są dla początkujących programistów, zdecydowaliśmy się oprzeć całkowicie na aplikacji konsoli. Jest to tryb znakowy, w którym program nie korzysta z graficznych funkcji systemu Windows. Dzięki temu możemy zająć się istotą algorytmu, a nie sposobami konwersacji z systemem operacyjnym, które w programach Windows zajmują nawet 80 - 90 % kodu. Oczywiście większość prezentowanych tutaj gier można również z powodzeniem zrealizować w wersji graficznej. W takim przypadku sam algorytm gry nie zmienia się, lecz zmianie ulegają procedury zapisujące elementy gry w okienku konsoli - zamiast zapisywania znaków, należy rysować grafikę.

Aby uzyskać dostęp do funkcji obsługujących konsolę w języku Pascal musimy dołączyć do naszego programu moduł Crt w sposób następujący:

 

program nazwa;

uses Crt;

...

 

Od tej chwili program może korzystać ze wszystkich funkcji modułu. Poniżej umieściłem tłumaczenie na język polski fragmentu instrukcji dla Free Pascala, który dotyczy modułu Crt.

 

Moduł Crt

Rozdział ten opisuje moduł CRT dla Free Pascala, zarówno w systemie DOS/Windows jak i Linux. Autorem pierwszej wersji dla DOS jest Florian Klämpfl. Moduł został przeniesiony do systemu Linux przez Marka Maya i rozbudowany przez  Michaëla Van Canneyta i Petera Vremana. Działa on w konsoli Linuxa oraz w oknach xterm i rxvt pod systemem X-Windows. Oba moduły działają identycznie, z wyjątkiem tego, iż pod Linuxem we wczesnej implementacji (wersje kompilatora 0.9.1  i wcześniejsze) moduł CRT automatycznie czyścił treść okna konsoli przy starcie programu.

Rozdział ten podzielony został na dwie części.

  • W pierwszej części wymieniono predefiniowane stałe, typy oraz zmienne.
  • W drugiej części opisano funkcje, które występują w części publicznej interfejsu modułu CRT.

Typy, zmienne, stałe

Definicje kolorów :

  Black        =   0;
  Blue         =   1;
  Green        =   2;
  Cyan         =   3;
  Red          =   4;
  Magenta      =   5;
  Brown        =   6;
  LightGray    =   7;
  DarkGray     =   8;
  LightBlue    =   9;
  LightGreen   =  10;
  LightCyan    =  11;
  LightRed     =  12;
  LightMagenta =  13;
  Yellow       =  14;
  White        =  15;
  Blink        = 128;

 

Różnorodne stałe:

 

TextAttr:    byte = $07;
  TextChar:    char = ' ';
  CheckBreak:  boolean = true;
  CheckEOF:    boolean = false;
  CheckSnow:   boolean = false;
  DirectVideo: boolean = false;
  LastMode:    word = 3;
  WindMin:     word = $0;
  WindMax:     word = $184f;
  ScreenWidth  = 80;
  ScreenHeight = 25;

 

Kilka zmiennych dla kompatybilności z Turbo Pascalem. Jednakże Free Pascal z nich nie korzysta

 

var
  checkbreak : boolean;
  checkeof :   boolean;
  checksnow :  boolean;

 

Poniższe stałe definiują tryby pracy ekranu w systemie DOS.

 

const
  bw40 = 0;
  co40 = 1;
  bw80 = 2;
  co80 = 3;
  mono = 7;

 

Zmienna TextAttr kontroluje atrybuty koloru, które są używane przy zapisie znaków na ekran.

 

var TextAttr : byte;

 

Zmienna DirectVideo kontroluje zapis na ekran. Jeśli zawiera true, to dostęp jest bezpośredni. Jeśli zawiera false, to wykorzystywane są procedury w BIOS. Zmienna ta działa jedynie w systemie DOS.

 

var DirectVideo : boolean;

 

Zmienna LastMode informuje nas o numerze ostatnio używanego trybu pracy ekranu. Zdefiniowana jest tylko w systemie DOS.

 

var LastMode : Word;

 

Procedury i funkcje

Prezentowane przykłady programów działają poprawnie tylko w przypadku uruchomienia ich z poziomu okienka poleceń. W przeciwnym razie okienko konsoli jest natychmiast zamykane po zakończeniu pracy programu. Aby temu zapobiec, dodaj na końcu swojego programu pustą instrukcję readln. Program nie zamknie wtedy swojego okienka konsoli aż naciśniesz klawisz Enter.

 

AssignCrt

Deklaracja:

procedure AssignCrt(var F: Text);

 

Opis:

Przypisuje do konsoli plik F. Zapis danych do pliku F zostaje przekierowany do okienka konsoli. Jeśli konsola zawiera okno, wszystko zostanie zapisane w oknie.

Zobacz również: Window

 

Przykład:

program Example1;

uses Crt;

var
  F : Text;
begin
  AssignCrt(F);
  Rewrite(F); { Nie zapomnij otworzyć do zapisu! }
  WriteLn(F,'To jest zapisywane do Przypisanego Pliku');
  Close(F);
end.

 

BigCursor

Deklaracja:

procedure BigCursor;

 

Opis:

Tworzy kursor o kształcie dużego prostokąta. Nie zaimplementowane w wersji Linux.

 

Zobacz również: CursorOn, CursorOff

 

ClrEol

Deklaracja:

procedure ClrEol ;

 

Opis:

ClrEol czyści bieżący wiersz poczynając od pozycji kursora aż do końca okna. Kursor nie zmienia swojej pozycji.

 

Zobacz również: DelLine, InsLine, ClrScr

 

Przykład:

program Example9;

uses Crt;

begin
  write('Ten wiersz zostanie usuniety od',
        ' pozycji kursora do prawego brzegu ekranu');
  GotoXY(31,WhereY);
  ReadKey;
  ClrEol;
  writeln;
end.

 

ClrScr

Deklaracja:

procedure ClrScr; 

 

Opis:

ClrScr czyści bieżące okno stosując aktualne kolory tekstu i tła. Kursor ustawiany jest w lewym górnym narożniku okna.

 

Zobacz również: Window

 

Przykład:

program Example8;

uses Crt;

begin
  writeln('Nacisnij dowolny klawisz, aby wyczyscic ekran');
  ReadKey;
  ClrScr;
  writeln('Teraz pociesz sie wyczyszczonym ekranem');
end.

 

CursorOff

Deklaracja:

procedure CursorOff;

 

Opis:

Wyłącza widok kursora. W wersji Linux nie zaimplementowane.

 

Zobacz również: CursorOn, BigCursor

 

CursorOn

Deklaracja:

procedure CursorOn; 
 

Opis:

Włącza widok kursora. W wersji Linux nie zaimplementowane.

 

Zobacz również: BigCursor, CursorOff

 

Delay

Deklaracja:

procedure Delay(DTime: Word); 

 

Opis:

Delay czeka przez zadaną liczbę milisekund (1/1000 sekundy). Czas ten jest tylko przybliżony i w przypadku  przeciążenia systemu może znacznie się różnić od wartości dokładnej. Zatem nie wykorzystuj jej do konstrukcji np. stopera lub zegara.

 

Zobacz również: Sound, NoSound

 

Przykład:

program Example15;

uses Crt;

var
  i : integer;

begin
  writeln('Odliczanie wsteczne');
  for i:=10 downto 1 do
  begin
    writeln(i);
    Delay(1000); {Czekaj przez 1 sekundę}
  end;     
  writeln('BUCH!!!'); 
end.

 

DelLine

Deklaracja:

procedure DelLine;

 

Opis:

DelLine usuwa bieżący wiersz. Wiersze leżące poniżej zostają przemieszczone w górę o 1 wiersz, a na spodzie bieżącego okna zostaje wstawiony pusty wiersz znaków. Kursor nie zmienia pozycji.

 

Zobacz również: ClrEol, InsLine, ClrScr

 

Przykład:

program Example10;

uses Crt;

begin
  ClrScr;
  writeln;
  writeln('Wiersz nr 1');
  writeln('Wiersz nr 2');
  writeln('Wiersz nr 2');
  writeln('Wiersz nr 3');
  writeln;
  writeln('Ups, Wiersz 2 jest wypisany dwa razy,',
          ' usunmy go z ekranu');
  GotoXY(1,3);
  ReadKey;
  DelLine;
  GotoXY(1,10);
end.

 

GotoXY

Deklaracja:

procedure GotoXY(X: byte; Y: byte); 

 

Opis:

Umieszcza kursor na pozycji (X,Y), X jest pozycją w poziomie a Y w pionie względem początku bieżącego okna. Początek ten znajduje się na współrzędnych (1,1) w lewym górnym narożniku okna.

 

Zobacz również: WhereX, WhereY, Window

 

Przykład:

program Example6;

uses Crt;

begin
  ClrScr;
  GotoXY(10,10);
  write('10,10');
  GotoXY(70,20);
  write('70,20');
  GotoXY(1,22);
end.

 

HighVideo

Deklaracja:

procedure HighVideo; 

 

Opis:

HighVideo przełącza wyświetlanie znaków w tryb podwyższonej jasności ustawiając bit wysokiej intensywności koloru w atrybucie wideo.

 

Zobacz również: TextColor, TextBackground, LowVideo, NormVideo

 

Przykład:

program Example14;

uses Crt;

begin
  LowVideo;
  writeln('To jest zapisane z niska intensywnoscia koloru');
  HighVideo;
  writeln('Teraz intensywnosc koloru jest wysoka');
  NormVideo;
  writeln('Kolor wrocil do normalnej wartosci');
end.

 

InsLine

Deklaracja:

 

procedure InsLine;

 

Opis:

InsLine wstawia pusty wiersz na bieżącej pozycji kursora. Wiersze leżące poniżej zostają opuszczone o jedną linijkę w dół. co powoduje zniknięcie ostatniego wiersza z okna. Kursor nie zmienia położenia.

 

Zobacz również: ClrEol, DelLine, ClrScr

 

Przykład:

program Example10;

uses Crt;

begin
  ClrScr;
  writeln;
  writeln('Wiersz nr 1');
  writeln('Wiersz nr 3');
  writeln;
  writeln('Ups, zapomnielismy o wierszu nr 2,' +
          ' wstawmy go na wlasciwe miejsce');
  GotoXY(1,3);
  ReadKey;
  InsLine;
  write('Wiersz nr 2');
  GotoXY(1,10);
end.

 

KeyPressed

Deklaracja:

function KeyPressed : boolean;

 

Opis:

Funkcja Keypressed skanuje bufor klawiatury sprawdzając, czy nie został naciśnięty klawisz. Jeśli tak, to zwraca w wyniku True, a False w przypadku przeciwnym. Nie są zgłaszane klawisze Shift, Alt i Ctrl. Kod klawisza nie zostaje usunięty z bufora i można go odczytać po wywołaniu tej funkcji za pomocą np. ReadKey.

 

Zobacz również: ReadKey

 

Przykład:

program Example2;

uses Crt;

begin
  writeln('Czekam na nacisniecie klawisza...');
  repeat
  until KeyPressed;
 { Klawisz nie został odczytany, 
   zatem powinien również pojawić się w wierszu polecenia}
end.

 

LowVideo

Deklaracja:

procedure LowVideo;

 

Opis:

LowVideo przełącza wyjście tekstu do koloru w normalnej intensywności zerując bit intensywności w atrybucie koloru wideo.

 

Zobacz również: TextColor, TextBackground, HighVideo, NormVideo

 

Przykład użycia jest w opisie procedury HighVideo.

 

NormVideo

Deklaracja:

procedure NormVideo;

 

Opis:

NormVideo przełącza na standardowe kolory, odczytane przy starcie z pozycji kursora.

 

Zobacz również: TextColor, TextBackground, LowVideo, HighVideo

 

Przykład użycia jest w opisie procedury HighVideo.

 

NoSound

Deklaracja:

procedure NoSound;

 

Opis:

Zatrzymuje dźwięk wydawany przez głośniczek w komputerze. W wersji Linux nie zaimplementowane

 

Zobacz również: Sound

 

Przykład:

program Example16;

uses Crt;

var
  i : longint;

begin
  writeln('Z glosniczka PC uslyszysz pewne piski');
  while (i<15000) do
  begin
    inc(i,500);
    Sound(i);
    Delay(100);
  end;
  writeln('Teraz cisza!'); 
  NoSound; {Zatrzymujemy hałas}      
end.

 

ReadKey

Deklaracja:

function ReadKey : Char;

 

Opis:

Funkcja ReadKey odczytuje z bufora klawiatury kod jednego klawisza i zwraca go jako swój wynik. Jeśli jest to klawisz sterujący lub funkcyjny, to zwraca kod ASCII 0. Drugi odczyt funkcją ReadKey da w takim przypadku kod matrycowy danego klawisza.

 

Uwagi

Odwzorowanie klawiszy pod systemem Linux może powodować zgłaszanie przez funkcję ReadKey złych kodów, zatem należy stosować ją z ostrożnością..

 

Zobacz również: KeyPressed

 

Przykład:

program Example3;

uses Crt;

var
  ch : char;

begin
  writeln('Nacisnij klawisze kursora w lewo lub w prawo,' +
          ' Esc=Koniec');
  repeat
    ch := ReadKey;
    case ch of
     #0 : begin
            ch := ReadKey; {Czytamy kod matrycowy}
            case ch of
             #75 : writeln('W lewo');
             #77 : writeln('W prawo');
	    end;
	  end;
    #27 : writeln('ESC');	  
    end;
  until ch = #27 {Esc}           
end.

 

Sound

Deklaracja:

procedure Sound(hz : word);

 

Opis:

Wytwarza pisk o częstotliwości hz z głośniczka PC. W wersji Linux nie jest to obsługiwane.

 

Zobacz również: NoSound

 

TextBackground

Deklaracja:

procedure TextBackground(CL: Byte);

 

Opis:

TextBackground ustawia kolor tła na CL. CL może być jedną z predefiniowanych stałych koloru.

 

Zobacz również: TextColor, HighVideo, LowVideo, NormVideo

 

Przykład:

program Example13;

uses Crt;

begin
  TextColor(White);
  writeln('To jest zapisywane ze standardowym kolorem tla');
  TextBackground(Green);
  writeln('Teraz tlo tekstu jest zielone');
  TextBackground(Brown);
  writeln('Teraz tlo tekstu jest brazowe');
  TextBackground(Black);
  writeln('I znow mamy tlo czarne');
end.

 

TextColor

Deklaracja:

procedure TextColor(CL: Byte);

 

Opis:

TextColor ustawia kolor tekstu na CL. CL może być jedną z predefiniowanych stałych koloru.

 

Zobacz również: TextBackground, HighVideo, LowVideo, NormVideo

 

Przykład:

program Example12;

uses Crt;

begin
  writeln('To jest zapisane w standardowym kolorze tekstu');
  TextColor(Red);
  writeln('Teraz na czerwono');
  TextColor(White);
  writeln('Teraz na bialo');
  TextColor(LightBlue);
  writeln('A teraz na jasno niebiesko');
end.

 

WhereX

Deklaracja:

function WhereX : byte;

 

Opis:

WhereX zwraca bieżącą współrzędną X pozycji kursora względem bieżącego okna. Początek jest na pozycji (1,1) w lewym górnym narożniku okna.

 

Zobacz również: GotoXY, WhereY, Window

 

Przykład:

program Example7;

uses Crt;

begin
  writeln('Pozycja kursora: X=',WhereX,' Y=',WhereY);
end.

 

WhereY

Deklaracja:

function WhereY : byte;

 

Opis:

WhereY zwraca bieżącą współrzędną Y kursora względem bieżącego okna. Początek jest na pozycji (1,1) w lewym górnym narożniku okna.

 

Zobacz również: GotoXY, WhereX, Window

 

Window

Deklaracja:

procedure Window(X1, Y1, X2, Y2: byte);

 

Opis:

Window tworzy okno tekstowe na ekranie konsoli, do którego będzie przesyłany tekst. Współrzędne (X1,Y1) określają lewy górny narożnik tego okna, a (X2,Y2) prawy dolny. Współrzędne te odnoszą się do ekranu, którego lewy górny narożnik znajduje się na pozycji (1,1). Dalsze operacje związane ze współrzędnymi, za wyjątkiem kolejnego wywołania procedury Window, są względem lewego górnego narożnika tego okna.

 

Zobacz również: GotoXY, WhereX, WhereY, ClrScr

 

Przykład:

program Example5;

uses Crt;

begin
  ClrScr;
  writeln('Tworzenie okna od 30,10 do 50,20');
  Window(30,10,50,20);
  writeln('Teraz zapisujemy tekst w tym malym oknie,' +
          ' ktore wlasnie stworzylismy.' +
          ' Nie mozemy wyjsc poza jego krawedzie' + 
          ' przy zapisie takiego dlugiego tekstu');
  write('Nacisnij dowolny klawisz, aby wyczyscic to okno');
  ReadKey;
  ClrScr;
  write('Okno jest wyczyszczone, nacisnij dowolny klawisz,' +
        ' aby powrocic do pelnego ekranu');
  ReadKey;
{Pełny ekran ma wymiary 80x25}  
  Window(1,1,80,25);
  Clrscr;
  writeln('Wrocilismy do pelnego ekranu');
end.

 

Generacja liczb pseudolosowych

W grach bardzo często musimy korzystać z sytuacji losowych. Dokonujemy tego przy pomocy liczb pseudolosowych. Do ich generacji wykorzystywać będziemy w Pascalu funkcję:

liczba_pseudolosowa := random(zakres);

 

Funkcja random zwraca wartość pseudolosową o wartości od 0 do zakres -1. Jeśli potrzebujemy zakresu od a do b, to korzystamy z następującego przepisu:

liczba_pseudolosowa := a + random(b - a + 1);

 

W programie korzystającym z liczb pseudolosowych należy na samym początku zainicjować generator tych liczb. Operację tą realizujemy poprzez wywołanie procedury randomize w sposób następujący:

program nazwa;
...
begin
  randomize; // zainicjowanie generatora liczb pseudolosowych
  ...        // dalsza część programu
end.

 

Jest to o tyle ważne, iż jeśli pominiemy inicjalizację generatora pseudolosowego, to przy każdym uruchomieniu programu dostaniemy identyczny ciąg liczb pseudolosowych. W konsekwencji gra może szybko się znudzić.

Zainteresowanych tym tematem odsyłam do naszego artykułu o liczbach pierwszych, gdzie dokładnie opisany został problem tworzenia liczb pseudolosowych.

 

Polskie znaki w konsoli

Ponieważ jesteśmy Polakami, powinniśmy pisać programy komunikujące się z użytkownikiem poprawnie po polsku. Tutaj niestety czeka nas niemiła niespodzianka. System Windows i konsola korzystają z innej definicji polskich literek. Jeśli pracujemy w edytorze DevPascala, to nasz tekst programu kodowany jest wg standardu Windows 1250. A gdy teraz tekst polski wyślemy, np. instrukcją writeln, do konsoli korzystającej ze standardu Latin II, zamiast polskich literek zobaczymy inne znaki. Rozwiązaniem jest specjalna funkcja, która konwertuje tekst ze standardu Windows 1250 na standard Latin II (oczywiście możesz pracować w edytorze znakowym Free Pascala, który znajduje się w katalogu bin instalacji DevPascala pod nazwą fp.exe, lecz to rozwiązanie, chociaż pozwala stosować bezproblemowo polskie znaki konsoli, posiada inne wady - np. późniejsza edycja plików w edytorach Windows).

 

program test;

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

begin
  writeln(PL('Sprawdźmy, czy piszę już w języku polskim.'));
  readln;
end.

 

Zasada działania funkcji PL jest bardzo prosta. Przegląda ona literka po literce otrzymany jako argument tekst. Jeśli natrafi na polski znak, to zmienia jego kod na Latin II. Dla pozostałych znaków funkcja jest przezroczysta. Poniżej umieściłem przykładowe zastosowanie tej funkcji. Dzięki niej możemy, jak widać, bezproblemowo pisać programy dla konsoli w edytorze pracującym w systemie Windows.

 


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

©2024 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