Robert Trafny

Delphi w przykładach dla początkujących

część 1

© Robert Trafny, 2018

Poradnik programowania w języku Delphi dla początkujących. Na przykładzie ponad 20 projektów Czytelnik poznaje programowanie od strony praktycznej. Książka zawiera pełne kody projektów wraz z obszernym komentarzem wyjaśniającym, rozszerzonym o potrzebną wiedzę teoretyczną, dzięki czemu można poznać i zrozumieć algorytmy programowania. Autor w sposób ciekawy i inspirujący opowiada o możliwościach, jakie daje programowanie, nie stroniąc od takich tematów, jak budowa robota czy androida.

ISBN 978-83-8126-883-7

Książka powstała w inteligentnym systemie wydawniczym Ridero

© Copyright by Robert Trafny

Tytuł: Delphi w przykładach dla początkujących część 1

Autor: Robert Trafny

Fotografia na okładce pochodzi z serwisu imageafter.com

Wydanie I

Wstęp

Oddajemy do rąk Czytelnika pierwszą część książki poświęconej programowaniu w języku Delphi. Nie należy jej traktować jako podręcznika, ponieważ nią nie jest. Ideą przewodnią całego cyklu jest prezentacja możliwości Delphi na podstawie konkretnych rozwiązań. Poprzez nie Czytelnik zapoznaje się ze sztuką programowania.

Każdy zamieszczony w tej książce program jest szczegółowo opisany i skomentowany. W ten sposób Czytelnik sukcesywnie zapoznaje się z nowymi rozwiązaniami i poleceniami Delphi, które później będzie mógł wykorzystać w swoich projektach.

Do tej pory powstało wiele książek i artykułów na temat podstaw Delphi, także w internecie nie brakuje materiałów na ten temat. Niniejsza książka jest odpowiedzią na powstały nie-dosyt, jak owe teoretyczne wiadomości wykorzystać w praktyce. Wychodząc naprzeciw początkującym programistom, zawarliśmy w książce projekty ponad dwudziestu różnych programów komputerowych, jak najbardziej stroniąc od powtarzania podstawowej wiedzy na temat programowania, którą bez problemu można pozyskać, chociażby z internetu. Opierając się na tym założeniu, oczekujemy od Czytelnika posiadania podstawowej wiedzy na temat programowania w języku Delphi. Zakładamy więc, iż Czytelnik wie, w jaki sposób utworzyć nowy projekt programu, w jaki sposób umieścić potrzebne komponenty na formie głównej oraz, w jaki sposób zmieniać właściwości komponentów.

Większość zamieszczonych w książce projektów jest w formie surowej, bez estetycznych upiększeń. Naszym celem bowiem było przedstawienie działających rozwiązań, zadbanie o poprawną pracę programów. W ten sposób też każdy programista powinien pracować nad swoim projektem. Najpierw tworzymy surowy szkic programu, zabiegając wyłącznie o to, aby wszystkie jego procedury działały bez zarzutu. Na samym końcu dopiero zaczynamy zajmować się estetyką programu, nadając kolory, style itd. My pominęliśmy ten etap, wychodząc z założenia, iż dla programisty liczyć się będzie tylko działające rozwiązanie. Z uwagi na to, iż o gustach się nie dyskutuje, przyjmujemy, że programista nada zaprezentowanym programom własną szatę graficzną, przystosowaną do indywidualnej wrażliwości estetycznej. Jako przykład poglądowy, w rozdziale pt. „Hot Spot” zamieszczamy w pełni opracowany projekt, także pod względem szaty graficznej, aby przedstawić jedną z propozycji zadbania o wygląd naszego programu.

Książka podzielona jest na dwa główne działy: Gry i zabawy oraz Programy użytkowe. Nie chcemy w naszym cyklu ograniczać Delphi tylko do programów użytkowych. Programowanie daje znacznie większe możliwości i nie chcemy mentalności początkującego programisty zamykać w tym ograniczonym wyobrażeniu. Zgodnie z tym założeniem w następnych częściach pojawią się kolejne działy, jak chociażby budowa robota czy androida, które odsłonią pełną ofertę możliwości, jaką daje programowanie w języku Delphi. Nabywając w ten sposób szerszego spojrzenia na temat programowania, staniemy się profesjonalnymi programistami, którzy nie będą bali się wyzwań. Tylko na tej podstawie możliwe są wszelkie innowacje i rewolucje technologiczne. Ktoś, kto boi się poszukiwać i z góry zakłada, że to się nie uda, nigdy nie stanie się autorem czegoś przełomowego. Jako przykład — choć może z nieco innej dziedziny — przywołamy Alberta Einsteina, który zapytany o to, w jaki sposób wpadł na pomysł swojej teorii względności, odpowiedział krótko, że nie bał się myśleć. Nie bójmy się zatem i my. Zastanawiajmy się, poszukujmy i pytajmy, jeżeli czegoś nie wiemy, bo tylko w ten sposób możemy się rozwijać, także jako programiści.

Mam nadzieję, że niniejsza książka będzie inspiracją dla Czytelników i zachętą do rozwijania własnych projektów. Tego wszystkim życzę z całego serca.

Robert Trafny

Gry i zabawy

Policz, ile to jest — wersja prosta

Rozdział poświęcony grom i zabawom wykonanych w środowisku Borland Turbo Delphi otwieramy, chyba najprostszym przykładem z możliwych (z punktu widzenia programistycznego), zabawą matematyczną polegającą na odgadnięciu poprawnego wyniku działania na dwóch liczbach.

Założenia i opis zabawy:

Po naciśnięciu przycisku START program wybierze dla nas jakieś działanie matematyczne z użyciem dwóch liczb, wyświetli je i poprosi o podanie właściwego wyniku. Ponieważ zależy nam na rozwijaniu swego umysłu, wszystkie obliczenia wykonujemy w pamięci. Z uwagi na ten wymóg, ograniczymy zakres używanych liczb do dwudziestu: program będzie wybierał liczby tylko z zakresu od 0 do 20. Oczywiście, programista może sobie ustalić ten zakres w sposób zupełnie indywidualny.

Kolejnym ograniczeniem, jakiego dokonamy, będzie wyeliminowanie z używanych działań, dzielenia. W ten sposób nie będziemy musieli obliczać w pamięci liczb ułamkowych. Trudno przecież w pamięci policzyć, ile to jest 19 podzielić przez 7. Nasz program będzie obsługiwał tylko dodawanie, odejmowanie i mnożenie.

Po obliczeniu w pamięci wyniku wpisujemy go w pole edycyjne programu i naciskamy przycisk Sprawdź. Program sprawdza poprawność wyniku i wyświetla odpowiedni komunikat informacyjny, czy dobrze, czy źle. Jeżeli odpowiedź jest poprawna, działanie jest usuwane z panelu programu. Inna sytuacja ma miejsce w przypadku podania niepoprawnej odpowiedzi. Działanie do policzenia nie znika, usuwany jest tylko podany przez nas wynik. W ten sposób możemy spróbować swoich sił jeszcze raz, a gdy się znowu nie uda, jeszcze raz i jeszcze raz. Decyzja będzie zależała od nas. Jeżeli będziemy chcieli zrezygnować z tego działania, wystarczy, że naciśniemy przycisk START, a program wymieni nam działanie na inne.

Wprowadzamy do programu także tabelę wyników, która będzie pokazywała, ile do tej pory udzieliliśmy odpowiedzi poprawnych, a ile niepoprawnych. Przy zamykaniu programu, pojawi się także komunikat, w którym w zależności od uzyskanych wyników, program nam pogratuluje lub zachęci do większego zaangażowania.

Jako rozszerzenie możliwości programu zadbamy o to, aby program informował nas, gdy nieopatrznie naciśniemy przycisk Sprawdź bez wpisania wyniku w polu edycyjnym oraz aby umożliwiał wpisywanie w tym polu tylko liczb, minusa (bo wyniki będą czasami liczbami ujemnymi) oraz pozwalał na używanie klawisza Backpace do kasowania wprowadzanych znaków w przypadku pomyłki.

Użyte komponenty:

Edit1 — pole edycyjne do wpisywania odpowiedzi,

Button1 — przycisk START,

Button2 — przycisk Sprawdź,

Label1 — wyświetla napis „Wyniki”,

Label2 — wyświetla napis „Poprawne:”,

Label3 — wyświetla napis „Niepoprawne:”,

Label4 — wyświetla ilość poprawnych odpowiedzi,

Label5 — wyświetla ilość niepoprawnych odpowiedzi,

Label6 — wyświetla działanie do policzenia.

Powyższe komponenty wstawiamy na formę główną i układamy względem siebie tak jak na rysunku poniżej:

Należy zwrócić uwagę, że numery komponentów lub formy głównej (TForm) mogą się w Waszych projektach różnić. Należy więc poszczególny kod przypisać do właściwych komponentów i nadać im właściwe nazwy. W naszym projekcie modyfikujemy nazwy poszczególnym komponentom w następujący sposób (właściwość Caption w Inspektorze Obiektów):

Komponent nazwa

Edit1 (usuwamy nazwę)

Button1 START

Button2 Sprawdź

Label1 Wyniki

Label2 Poprawne:

Label3 Niepoprawne:

Label4 0 (zero)

Label5 0 (zero)

Label6 Ile to jest:

W dalszej kolejności także przy pomocy Inspektora Obiektów zmieniamy inne właściwości tych komponentów, a więc: kolor, rozmiar, położenie itp.

Kod programu

unit Unit1;

interface

uses

Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls;

type

TForm1 = class(TForm)

Edit1: TEdit;

Button1: TButton;

Button2: TButton;

Label1: TLabel;

Label2: TLabel;

Label3: TLabel;

Label4: TLabel;

Label5: TLabel;

Label6: TLabel;

procedure Button1Click(Sender: TObject);

procedure Button2Click(Sender: TObject);

procedure Edit1KeyPress(Sender: TObject; var Key: Char);

procedure FormCreate(Sender: TObject);

procedure FormClose(Sender: TObject; var Action: TcloseAction);

private

{ Private declarations }

public

{ Public declarations }

end;

var

Form1: TForm1;

WYNIK: Integer; //zmienna przechowująca wynik działania

Poprawne: Integer; //zmienna przechowująca ilość poprawnych odpowiedzi

Niepoprawne: Integer; //zmienna przechowująca ilość niepoprawnych odpowiedzi

implementation

{$R *.dfm}

//przy uruchomieniu programu wyzeruj punktację

procedure TForm1.FormCreate(Sender: TObject);

begin

Poprawne:=0; //wyzeruj ilość poprawnych odpowiedzi

Niepoprawne:=0; //wyzeruj ilość niepoprawnych odpowiedzi

Label4.Caption:= „0”; //wyświetl „0” poprawnych odpowiedzi

Label5.Caption:= „0”; //wyświetl „0” niepoprawnych odpowiedzi

end;

//przy zamykaniu programu oceń uzyskane wyniki

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);

begin

if (Poprawne<Niepoprawne) or (Poprawne=Niepoprawne) then

begin

ShowMessage(„Musisz jeszcze trochę potrenować”);

end

else

ShowMessage(„Gratuluję! Uzyskałeś dobry wynik”);

end;

//pozwól na wpisywanie tylko liczb, minusa i Backpace w polu odpowiedzi

procedure TForm1.Edit1KeyPress(Sender: TObject; var Key: Char);

begin

if not (Key in [„0”. . „9”, #45,#8]) then

begin

Key:=#0;

ShowMessage(„To nie jest liczba”); //wyświetl komunikat o błędzie

end;

end;

//gdy naciśniesz przycisk START

procedure TForm1.Button1Click(Sender: TObject);

var

Liczba1: Integer; //zmienna przechowująca pierwszą liczbę

Liczba2: Integer; //zmienna przechowująca drugą liczbę

Dzialanie: Integer; //zmienna pomocnicza do losowania znaku działania

Znak: String; //zmienna przechowująca znak działania

begin

Edit1.Clear; //wyczyść pole edycyjne (Do podawania Odpowiedzi)

Randomize; //uruchom maszynę losującą

Liczba1:=Random(21); //losuj pierwszą liczbę

Liczba2:=Random(21); //losuj drugą liczbę

Dzialanie:=Random(3); //losuj znak działania matematycznego

case Dzialanie of //gdy zostanie wylosowana dana liczba to…

0: WYNIK:= Liczba1+Liczba2; //…wykonaj dodawanie

1: WYNIK:= Liczba1-Liczba2; //…wykonaj odejmowanie

2: WYNIK:= Liczba1*Liczba2; //…wykonaj mnożenie

end;

if Dzialanie=0 then

Znak:= '+'; //jeżeli wylosowano dodawanie to pokaż znak '+”

if Dzialanie=1 then

Znak:= '-'; //jeżeli wylosowano odejmowanie to pokaż znak '-”

if Dzialanie=2 then

Znak:= „x”; //jeżeli wylosowano mnożenie to pokaż znak „x”

Label6.Caption:=(„Ile jest: ' + IntToStr(Liczba1) + ' ' + znak + ' ' +IntToStr(Liczba2) + ”? ”); //wyświetl działanie

Edit1.SetFocus; //ustaw focus w Polu do Odpowiedzi

end;

//gdy naciśniesz przycisk Sprawdź

procedure TForm1.Button2Click(Sender: TObject);

Label KONIEC; //Etykieta do przechodzenia w inne miejsca kodu

var

Odp: String; //zmienna przechowująca naszą odpowiedź

begin

Odp:= Edit1.Text; //odczytaj podaną odpowiedź i przypisz ja do zmiennej

if Odp=„” then //gdy nie podano odpowiedzi monituj o wpisaniu wyniku

begin

ShowMessage(„Wpisz najpierw wynik”); //wyświetl komunikat informujący

Edit1.SetFocus; //ustaw focus w Polu do Odpowiedzi

goto KONIEC; //pomiń poniższy kod i przejdź od razu na koniec procedury

end;

if Odp=(IntToStr(WYNIK)) then //jeżeli odpowiedź jest poprawna to …

begin

ShowMessage(„Bardzo dobrze!”); //wyświetl komunikat o poprawnej odpowiedzi

Label6.Caption:= „Ile jest: '; //wyczyść działanie

Poprawne:=Poprawne +1; //dodaj punkt do poprawnych odpowiedzi

end //bez średnika

else //w przeciwnym wypadku …

begin

ShowMessage(„Niestety źle”); //wyświetl komunikat o złej odpowiedzi

Niepoprawne:=Niepoprawne +1; //dodaj punkt do niepoprawnych odpowiedzi

end;

Edit1.Clear; //wyczyść pole do podawania Odpowiedzi)

Edit1.SetFocus; //ustaw focus w Polu do Odpowiedzi

Label4.Caption:= IntToStr(Poprawne); //wyświetl ilość poprawnych odpowiedzi

Label5.Caption:= IntToStr(Niepoprawne); //wyświetl ilość niepoprawnych odpowiedzi

KONIEC: //etykieta do której przechodzi kod, gdy ktoś nie wpisze żadnej liczby

end;

end.

Komentarz

1. Zmienne globalne

Zazwyczaj w programach używamy zmiennych lokalnych, powiązanych tylko z daną procedurą. W ten sposób unikamy konfliktu logicznego, gdy w tym samym czasie jedną zmienną chcą wykorzystać dwie lub więcej procedur.

Czasami jednak zachodzi potrzeba dostępu do parametru z poziomu różnych procedur tak, jak w naszym programie: procedura dla przycisku START generuje wynik działania, który jest umieszczony w zmiennej globalnej WYNIK, a inna procedura, powiązana z obsługą przycisku Sprawdź, korzysta z tej zmiennej, aby porównać, czy udzielona odpowiedź jest poprawna. Gdyby zmienna WYNIK była zmienną lokalną, zamkniętą w jednej procedurze, nie udałoby się tego dokonać. Stąd też w naszym projekcie umieszczamy trzy zmienne globalne:

WYNIK — do przechowywania wyniku działania,

Poprawne — do przechowywania ilości poprawnych odpowiedzi,

Niepoprawne — do przechowywania ilości niepoprawnych odpowiedzi.

Umieszczamy je w sekcji między var a Implementation, po deklaracji zmiennej Form1: TForm1.

var

Form1: TForm1;

WYNIK: Integer; //zmienna przechowująca wynik działania

Poprawne: Integer; //zmienna przechowująca ilość poprawnych odpowiedzi

Niepoprawne: Integer; //zmienna przechowująca ilość niepoprawnych odpowiedzi

Wszystkie trzy zmienne będą przechowywać liczby, więc muszą być typu Integer.

2. Form Create

Poprawne:=0; //wyzeruj ilość poprawnych odpowiedzi

Niepoprawne:=0; //wyzeruj ilość niepoprawnych odpowiedzi

Label9.Caption:= „0”; //wyświetl „0” poprawnych odpowiedzi

Label10.Caption:= „0”; //wyświetl „0” niepoprawnych odpowiedzi

Procedura Form Create wykonuje napisany przez nas kod w chwili uruchomienia programu, więc w miejscu tym wyzerujemy tabelę wyników i wyświetlimy oba wyniki jako zerowe.

Aby utworzyć procedurę Form Create, klikamy na puste miejsce naszej formy, a następnie w Inspektorze Obiektów przechodzimy do zakładki Events i obok zdarzenia OnCreate klikamy dwa razy. Zostaniemy automatycznie przeniesieni do kodu z nowo utworzoną procedurą.

3. Form Close

if (Poprawne<Niepoprawne) or (Poprawne=Niepoprawne) then

begin

ShowMessage(„Musisz jeszcze trochę potrenować”);

end

else

ShowMessage(„Gratuluję! Uzyskałeś dobry wynik”);

Procedura Form Close realizowana jest w momencie zamykania programu i tworzymy ją tak samo, jak poprzednią, wybierając jednak zdarzenie OnClose. W sekcji tej umieściliśmy możliwość oceny naszych wyników w zabawie.

Na początku mamy instrukcję warunkową if...then (jeżeli…, to…) oraz warunek do spełnienia. Cały kod możemy przetłumaczyć następująco: Jeżeli (if) Ilość poprawnych odpowiedzi (Poprawne) jest mniejsza (<) od Ilości niepoprawnych odpowiedzi (Niepoprawne) lub (or) Ilość poprawnych (Poprawne) jest taka sama (=) jak Ilość niepoprawnych odpowiedzi (Niepoprawne) to wtedy (then) wyświetl komunikat (ShowMessage) o treści: „Musisz jeszcze trochę potrenować”, w przeciwnym razie (else) (czyli, gdy ilość poprawnych odpowiedzi jest większa od niepoprawnych) wyświetl komunikat: „Gratuluję! Uzyskałeś dobry wynik”.

W tego typu konstrukcji, gdzie używamy operatora else, pamiętajmy o tym, że przed nim polecenie występuje bez zwyczajowo wymaganego średnika (w tym przypadku słowo end). To częsty błąd początkujących programistów.

Kolejne niedopatrzenie, które często staje się udziałem początkujących programistów, jest podawanie warunku. W prostym przypadku instrukcji warunkowej wystarczy napisać tak:

if Poprawne < Niepoprawne then

(kod do wykonania)

Jeżeli jednak chcemy, aby zostało spełnionych kilka warunków, wtedy każdy z nich musimy ująć w nawias, na przykład tak:

if (Poprawne < Niepoprawne) and (Liczba1 = 5) then

(kod do wykonania)

4. Procedura Edit1KeyPress

if not (Key in [„0”. . „9”, #45,#8]) then

begin

Key:=#0;

ShowMessage(„To nie jest liczba”); //wyświetl komunikat o błędzie

end;

Aby utworzyć tę procedurę, klikamy na komponent Edit1, a następnie w Inspektorze Obiektów, w zakładce Events wybieramy zdarzenie OnKeyPress i otwieramy je podwójnym kliknięciem.

Jak sama nazwa wskazuje, procedurę tę wykorzystamy do kontroli wpisywania znaków w polu edycyjnym. Zgodnie z naszymi założeniami chcemy, aby była możliwość wpisywania tylko liczb, minusa i, aby aktywny był klawisz Backpace do kasowania źle wpisanych liczb.

Cały kod odczytamy tak: Jeżeli (if) naciśnięty klawisz (Key) nie jest (not) klawiszem liczb („0”.. „9”), minusem (#45- kod klawisza „minus”), ani Backpace (#8- kod klawisza Backpace), wtedy (then) nie reaguj (Key:#0) tylko wyświetl komunikat (ShowMessage) „To nie jest liczba”.

Z punktu widzenia programu procedura ta nie jest konieczna. Jest to tylko udogodnienie dla nas eliminujące pomyłki.

5. Gdy naciśniesz przycisk START

var

Liczba1: Integer; //zmienna przechowująca pierwszą liczbę

Liczba2: Integer; //zmienna przechowująca drugą liczbę

Dzialanie: Integer; //zmienna pomocnicza do losowania znaku działania

Znak: String; //zmienna przechowująca znak działania

Na początku procedury definiujemy zmienne lokalne, które będą nam potrzebne. Przede wszystkim musimy przygotować dwie zmienne na dwie liczby, które zostaną użyte w działaniu. Za każdym razem program będzie sobie jakieś dwie liczby losowo wybierał, musi więc mieć gdzie je zapisać. Stąd umieszczone zmienne Liczba1 i Liczba2 są typu Integer, a więc typu liczbowego.

Poza liczbami program będzie losował także znak działania (dodawanie, odejmowanie, mnożenie), który następnie będzie mógł wyświetlić w pytaniu. To implikuje użycie zmiennej typu String, a więc typu tekstowego. Zmiennej tej nadaliśmy nazwę „Znak”.

Ostatnia zmienna, czyli „Dzialanie” (nie możemy nadać nazwy „Działanie”, ponieważ Delphi nie używa polskich znaków dialektycznych) służy do wylosowania rodzaju działania (dodawanie, odejmowanie, mnożenie). Jest ona typu liczbowego, ponieważ za jej pomocą będziemy losowali liczbę, do której przypiszemy jedno z tych trzech działań:

Edit1.Clear; //wyczyść pole edycyjne (do podawania Odpowiedzi)

Randomize; //uruchom maszynę losującą

Liczba1:=Random(21); //losuj pierwszą liczbę

Liczba2:=Random(21); //losuj drugą liczbę

Dzialanie:=Random(3); //losuj znak działania matematycznego

case Dzialanie of //gdy zostanie wylosowana dana liczba to…

0: WYNIK:= Liczba1+Liczba2; //…wykonaj dodawanie

1: WYNIK:= Liczba1-Liczba2; //…wykonaj odejmowanie

2: WYNIK:= Liczba1*Liczba2; //…wykonaj mnożenie

Przechodząc do kodu wykonywalnego, po naciśnięciu przycisku START, następuje wyczyszczenie pola edycyjnego (Edit1.Clear), a następnie uruchomienie maszyny losującej (Randomize). Po jej uruchomieniu losujemy potrzebne nam elementy, a więc obie liczby z zakresu od 0 do 20 (Liczba:= Random(21)), oraz rodzaj działania (Dzialanie:=Random(3)). Delphi liczy liczby od zera, stąd też przy Random mamy liczbę 21, a nie 20, tak samo, jak w przypadku zmiennej Dzialanie mamy trzy liczby, ale liczone od zera, a więc: 0, 1, 2.

Dalsza część kodu informuje program, co ma zrobić, gdy zostanie wylosowana odpowiednia liczba dla zmiennej Dzialanie: Jeżeli zostało wylosowane zero, wtedy do zmiennej globalnej WYNIK ma zapisać wynik dodawania obu wcześniej wylosowanych liczb (Liczba1 i Liczba2). Gdy wylosowano 1 lub 2 to, odpowiednio, ma zapisać w zmiennej WYNIK wynik odejmowania lub mnożenia tychże liczb. W ten oto prosty sposób uzyskujemy dużą nieprzewidywalność kolejnego działania, jaki program wygeneruje.

Przypominamy, że przy mnożeniu wykorzystujemy klawisz „gwiazdka”, a przy dzieleniu „ukośnik”.

if Dzialanie=0 then

Znak:= '+'; //jeżeli wylosowano dodawanie to pokaz znak '+”

if Dzialanie=1 then

Znak:= '-'; //jeżeli wylosowano odejmowanie to pokaz znak '-”

if Dzialanie=2 then

Znak:= „x”; //jeżeli wylosowano mnożenie to pokaz znak „x”

W tej sekcji realizujemy dalszą procedurę związaną ze zmienną Dzialanie opartą na instrukcji warunkowej if...then, czyli: Jeżeli dla zmiennej Dzialanie wylosowano zero, wtedy do zmiennej Znak przypisz znak „+”. W podobny sposób odczytujemy informacje dla pozostałych wylosowanych możliwości.

Informacje powyższe potrzebne są nam do wyświetlenia odpowiedniego znaku na etykiecie Label6: Label6.Caption:=(„Ile jest: ' + IntToStr(Liczba1) + ' ' + znak + ' ' +IntToStr(Liczba2) + ”? ”);

Ponieważ etykieta Label6 musi przedstawić wiele różnych informacji, stąd też jest ona zbiorem tekstu i zmiennych. Jako że etykieta służy do wyświetlenia krótkiego tekstu, stąd też informacje wyświetlamy z pozycji kodu, zmieniając jej właściwość Caption. To samo robiliśmy wcześniej, przygotowując projekt z pozycji Inspektora Obiektów (Caption).

Ponieważ nazwa jest zbiorem różnych elementów, więc całość musimy ująć w nawias. W jego środku zwykły tekst umieszczamy w apostrofie, a zmienne dokładamy za pomocą znaku „+”. Gdybyśmy chcieli wyświetlić taki plus, musielibyśmy go także zawrzeć w apostrofie. Z uwagi na to, że liczby nie są typu tekstowego (string), tylko liczbowego (integer), musimy je przekonwertować do postaci string, stosując konwersję typu IntToStr. W ten sposób liczby będą mogły zostać wyświetlone, gdyż zostaną potraktowane jako znaki tekstowe. Proszę nie zapomnieć o spacji po słowie „jest” ani przed znakiem zapytania. To samo tyczy się pustych miejsc ujętych w apostrofy przed i za zmienną „Znak”. Są one potrzebne do tego, aby porobić odstępy między słowami i liczbami.

Na zakończenie kodu umieszczamy polecenie: Edit1.SetFocus; //ustaw focus w Polu do Odpowiedzi

Ta linia nie jest konieczna, ale jest użyteczna, ponieważ po wyświetleniu działania umieszcza kursor w polu edycyjnym. Bez tego kodu, po każdorazowym naciśnięciu przycisku START i wyświetleniu działania, musielibyśmy myszką klikać w pole edycyjne, aby wpisać wynik. Rozwiązanie, które tu stosujemy, umożliwia po wyświetleniu działania od razu wpisać z klawiatury wynik bez użycia myszki. To duże udogodnienie przy zabawie.

6. Gdy naciśniesz przycisk Sprawdź

Label KONIEC; //Etykieta do przechodzenia w inne miejsca kodu

var

Odp: String; //zmienna przechowująca naszą odpowiedź

Zanim zadeklarujemy zmienną Odp, deklarujemy element Label. Nie jest to jednak komponent Label służący do wyświetlania napisów, co widać w innym pokolorowaniu składni w kodzie. Element ten jest częścią instrukcji goto, przy pomocy której możemy przenieść się w inne miejsce kodu i służy do zadeklarowania nazwy, która będzie ten punkt określała. Może być ona dowolna. Starajmy się wybierać takie nazwy, które będą nas informowały o przeznaczeniu tych instrukcji. W późniejszym czasie, gdyby zaistniała potrzeba modyfikacji kodu, odpowiednie nazwy ułatwią nam rozeznanie się w tych tysiącach linii kodu.

Zadeklarujemy teraz zmienną, która będzie przechowywać naszą odpowiedź. Teoretycznie powinna być typu liczbowego (Integer), ponieważ w pole edycyjne Edit1 wpisujemy z klawiatury liczby. Niestety, pomimo wpisywania do komponentu Edit cyfr są one traktowane jako znaki tekstowe, a nie liczbowe, ponieważ komponent ten służy do wyświetlania znaków tekstowych. Nie jest to problem, ponieważ w dalszej części kodu będziemy mogli przekonwertować te wartości. Mając tę wiedzę, deklarujemy więc zmienną „Odp” typu tekstowego (String).

Odp:= Edit1.Text; //odczytaj podaną odpowiedź i przypisz ją do zmiennej

if Odp=„” then //gdy nie podano odpowiedzi monituj o wpisaniu wyniku

begin

ShowMessage(„Wpisz najpierw wynik”); //wyświetl komunikat informujący

Edit1.SetFocus; //ustaw focus w Polu do Odpowiedzi

goto KONIEC; //pomiń poniższy kod i przejdź od razu na koniec procedury

W pierwszej części kodu przypisujemy podaną przez nas odpowiedź (wpisaną do pola Edit) do zmiennej „Odp”. Tutaj wprowadzamy jedno z naszych wcześniejszych założeń, mianowicie chcemy, aby program informował nas o sytuacji, gdy naciśniemy przycisk „Sprawdź”, a w polu edycyjnym nie będzie wpisana żadna liczba. Jest to zadanie opcjonalne, niewpływające na poprawną pracę samej zabawy, ale warto zaopatrzyć w nie nasz program na wszelki wypadek. W sytuacji, gdy naciśniemy przycisk „Sprawdź”, a w polu edycyjnym nie będzie wpisana żadna liczba, bez tego kodu, program uzna to za błędną odpowiedź, ponieważ puste pole nie będzie pasowało do poprawnego wyniku.

Aby zrealizować nasze założenie, wprowadzamy instrukcję warunkową if: Jeżeli zmienna „Odp” nie zawiera żadnej wartości (if Odp = „” — normalnie, pomiędzy apostrofami powinien znaleźć się jakiś znak lub tekst), wtedy (then) wykonaj następujące instrukcje (begin… end): Wyświetl komunikat informujący o tym (ShowMessage), ustaw kursor (focus) ponownie na polu edycyjnym, oraz przejdź do punktu „KONIEC:”, aby pominąć wykonywanie dalszych instrukcji (goto KONIEC). Bez tego przejścia program, po wyświetleniu komunikatu zrealizowałby kolejne linie kodu, czyli porównałby naszą odpowiedź z poprawnym wynikiem i uznał ją za błędną.

W przypadku jakiejkolwiek instrukcji warunkowej, jeżeli chcemy, aby program wykonał kilka różnych operacji, musimy je wszystkie zawrzeć w bloku „begin… end”. Podobnie, jak w poprzednim przypadku, ustawiamy kursor na polu edycyjnym dla naszej wygody, aby nie trzeba było klikać na nie myszką.

if Odp= (IntToStr(WYNIK)) then //jeżeli odpowiedź jest poprawna to …

begin

ShowMessage(„Bardzo dobrze!”); //wyświetl komunikat o poprawnej odpowiedzi

Label11.Caption:= „Ile jest: '; //wyczyść działanie

Poprawne:= Poprawne +1; //dodaj punkt do poprawnych odpowiedzi

end //bez średnika

else //w przeciwnym wypadku …

begin

ShowMessage(„Niestety źle”); //wyświetl komunikat o złej odpowiedzi

Niepoprawne:= Niepoprawne +1; //dodaj punkt do niepoprawnych odpowiedzi

end;

Czas najwyższy ocenić naszą odpowiedź. W tym celu stosujemy instrukcję warunkową if...then: Jeżeli udzielona przez nas odpowiedź (Odp) jest taka sama (=) jak wynik działania (WYNIK), wtedy (then) wykonaj następujące instrukcje (begin… end): Wyświetl komunikat (ShowMessage) informujący o poprawnej odpowiedzi, pozostaw tylko napis „Ile jest:” (Label6.Caption) oraz zwiększ zmienną przechowującą ilość poprawnych odpowiedzi o 1 (Poprawne:= Poprawne+1), w przeciwnym wypadku (else) (czyli, gdy nasza odpowiedź będzie się różniła od poprawnego wyniku), wykonaj następujące instrukcje (begin… end): wyświetl komunikat o błędnej odpowiedzi (ShowMessage) oraz zwiększ zmienną przechowującą ilość niepoprawnych odpowiedzi o 1.

Konstrukcja typu Zmienna:=Zmienna+1 pozwala nam zapamiętywać wynik i powiększać go lub pomniejszać w trakcie działania programu. W ten sposób program „pamięta” nasz wynik.

Aby dopasować typy danych, wynik ze zmiennej WYNIK (typu Integer) konwertujemy do typu String za pomocą konwersji IntToStr.

Edit1.Clear; //wyczyść pole do podawania Odpowiedzi

Edit1.SetFocus; //ustaw focus w Polu do Odpowiedzi

Label9.Caption:= IntToStr(Poprawne); //wyświetl ilość poprawnych odpowiedzi

Label10.Caption:= IntToStr(Niepoprawne); //wyświetl ilość niepoprawnych odpowiedzi

KONIEC

Bez względu na udzieloną przez nas odpowiedź, po jej ocenie, wymazujemy ją z pola edycyjnego (Edit1.Clear) i ustawiamy na nim kursor (focus), przygotowując program na przyjęcie kolejnej odpowiedzi.

Na koniec wyświetlamy podsumowanie naszych wyników. W tym celu w komponencie Label4 wyświetlamy ilość poprawnych odpowiedzi, zmieniając jego nazwę (Caption) na wartość odpowiadającą zmiennej Poprawne. Ponieważ zmienna ta jest typu Integer, więc musimy zastosować konwersję, aby dostosować ją do charakteru tekstowego, jakim jest nazwa komponentu Label.

Powyższe zadanie powtarzamy dla komponentu Label5 wyświetlającego ilość niepoprawnych odpowiedzi, wiążąc jego nazwę (Caption) z wartością zmiennej Niepoprawne.

Na samym końcu umieszczamy etykietę KONIEC, czyli miejsce, do którego przechodzi instrukcja goto. Jest ona na samym końcu, więc cały kod pomiędzy instrukcjami „goto KONIEC” a „KONIEC” jest przez nią pomijany.

Zaprezentowany przez nas przykład prostej zabawy matematycznej możemy traktować jako punkt wyjścia dla bardziej rozbudowanych rozwiązań. Aby dać tego przykład, w dwóch kolejnych propozycjach rozwiniemy tę zabawę w dwóch różnych obszarach: w jednym, utrudnimy sobie liczenie, dokładając kolejne dwie liczby, a w drugim, zamiast wyświetlać komunikaty, program będzie je wypowiadał. Po zastosowaniu dodatkowych rozwiązań z tej książki możemy nawet sprawić, aby całkiem wyłączyć monitor i bawić się z komputerem tak, jak z żywym człowiekiem. To naprawdę zależy tylko od naszej inwencji.

Policz, ile to jest — wersja trudniejsza

Poniższy przykład jest trudniejszą wersją poprzednio zaprezentowanej gry. W tamtej działania odbywały się z użyciem dwóch liczb, a w tej, z użyciem aż czterech, na przykład: „Ile to jest: 2 +8 x 11 — 7?”. Wszystkie inne nasze założenia i rozwiązania pozostają bez zmian.

Kod programu

unit Unit1;

interface

uses

Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls;

type

TForm1 = class(TForm)

Edit1: TEdit;

Button1: TButton;

Button2: TButton;

Label1: TLabel;

Label2: TLabel;

Label3: TLabel;

Label4: TLabel;

Label5: TLabel;

Label6: TLabel;

procedure FormCreate(Sender: TObject);

procedure FormClose(Sender: TObject; var Action: TCloseAction);

procedure Edit1KeyPress(Sender: TObject; var Key: Char);

procedure Button1Click(Sender: TObject);

procedure Button2Click(Sender: Tobject);

private

{ Private declarations }

public

{ Public declarations }

end;

var

Form1: TForm1;

WYNIK: Integer; //zmienna przechowująca wynik działania

Poprawne: Integer; //zmienna przechowująca ilość poprawnych odpowiedzi

Niepoprawne: Integer; //zmienna przechowująca ilość niepoprawnych odpowiedzi

implementation

{$R *.dfm}

//przy uruchomieniu programu wyzeruj punktację

procedure TForm1.FormCreate(Sender: TObject);

begin

Poprawne:=0; //wyzeruj ilość poprawnych odpowiedzi

Niepoprawne:=0; //wyzeruj ilość niepoprawnych odpowiedzi

Label4.Caption:= „0”; //wyświetl „0” poprawnych odpowiedzi

Label5.Caption:= „0”; //wyświetl „0” niepoprawnych odpowiedzi

end;

//przy zamykaniu programu oceń uzyskane wyniki

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);

begin

if (Poprawne<Niepoprawne) or (Poprawne=Niepoprawne) then

begin

ShowMessage(„Musisz jeszcze trochę potrenować”);

end

else

ShowMessage(„Gratuluję! Uzyskałeś dobry wynik”);

end;

//pozwól na wpisywanie tylko liczb, minusa i Backpace w polu odpowiedzi

procedure TForm1.Edit1KeyPress(Sender: TObject; var Key: Char);

begin

if not (Key in [„0”. . „9”, #45,#8]) then

begin

Key:=#0;

ShowMessage(„To nie jest liczba”); //wyświetl komunikat o błędzie

end;

end;

//gdy naciśniesz przycisk START

procedure TForm1.Button1Click(Sender: TObject);

var

Liczba1: Integer; //zmienna przechowująca pierwszą liczbę

Liczba2: Integer; //zmienna przechowująca drugą liczbę

Liczba3: Integer; //zmienna przechowująca trzecią liczbę

Liczba4: Integer; //zmienna przechowująca czwartą liczbę

Dzialanie: Integer; //zmienna pomocnicza do losowania znaku działania

Znak1: String; //zmienna przechowująca pierwszy znak działania

Znak2: String; //zmienna przechowująca drugi znak działania

Znak3: String; //zmienna przechowująca trzeci znak działania

begin

Edit1.Clear; //wyczyść pole edycyjne (Do podawania Odpowiedzi)

Randomize; //uruchom maszynę losującą

Liczba1:=Random(21); //losuj pierwszą liczbę

Liczba2:=Random(21); //losuj drugą liczbę

Liczba3:=Random(21); //losuj trzecią liczbę

Liczba4:=Random(21); //losuj czwartą liczbę

//wygeneruj pierwszą część działania

Dzialanie:=Random(3); //losuj znak działania matematycznego

case Dzialanie of //gdy zostanie wylosowana dana liczba to…

0: WYNIK:= Liczba1+Liczba2; //…wykonaj dodawanie

1: WYNIK:= Liczba1-Liczba2; //…wykonaj odejmowanie

2: WYNIK:= Liczba1*Liczba2; //…wykonaj mnożenie

end;

if Dzialanie=0 then

Znak1:= '+'; //jeżeli wylosowano dodawanie to pokaż znak '+”

if Dzialanie=1 then

Znak1:= '-'; //jeżeli wylosowano odejmowanie to pokaż znak '-”

if Dzialanie=2 then

Znak1:= „x”; //jeżeli wylosowano mnożenie to pokaż znak „x”

//wygeneruj drugą część działania

Dzialanie:=Random(3); //losuj znak działania matematycznego

case Dzialanie of //gdy zostanie wylosowana dana liczba to…

0: WYNIK:= WYNIK+Liczba3; //…wykonaj dodawanie

1: WYNIK:= WYNIK-Liczba3; //…wykonaj odejmowanie

2: WYNIK:= WYNIK*Liczba3; //…wykonaj mnożenie

end;

if Dzialanie=0 then

Znak2:= '+'; //jeżeli wylosowano dodawanie to pokaż znak '+”

if Dzialanie=1 then

Znak2:= '-'; //jeżeli wylosowano odejmowanie to pokaż znak '-”

if Dzialanie=2 then

Znak2:= „x”; //jeżeli wylosowano mnożenie to pokaż znak „x”

//wygeneruj trzecią część działania

Dzialanie:=Random(3); //losuj znak działania matematycznego

case Dzialanie of //gdy zostanie wylosowana dana liczba to…

0: WYNIK:= WYNIK+Liczba4; //…wykonaj dodawanie

1: WYNIK:= WYNIK-Liczba4; //…wykonaj odejmowanie

2: WYNIK:= WYNIK*Liczba4; //…wykonaj mnożenie

end;

if Dzialanie=0 then

Znak3:= '+'; //jeżeli wylosowano dodawanie to pokaż znak '+”

if Dzialanie=1 then

Znak3:= '-'; //jeżeli wylosowano odejmowanie to pokaż znak '-”

if Dzialanie=2 then

Znak3:= „x”; //jeżeli wylosowano mnożenie to pokaż znak „x”

//wyświetl działanie

Label6.Caption:= („Ile jest: '+ IntToStr(Liczba1) + ' ' + znak1 + ' ' +IntToStr(Liczba2) + ' ' + znak2 + ' ' + IntToStr(Liczba3) + ' ' + znak3 + ' ' +IntToStr(Liczba4) + ”? ”);

Edit1.SetFocus; //ustaw focus w Polu do Odpowiedzi

end;

//gdy naciśniesz przycisk Sprawdź

procedure TForm1.Button2Click(Sender: TObject);

Label KONIEC; //Etykieta do przechodzenia w inne miejsca kodu

var

Odp: String; //zmienna przechowująca naszą odpowiedź

begin

Odp:= Edit1.Text; //odczytaj podaną odpowiedź i przypisz ją do zmiennej

if Odp=„” then //gdy nie podano odpowiedzi monituj o wpisaniu wyniku

begin

ShowMessage(„Wpisz najpierw wynik”); //wyświetl komunikat informujący

Edit1.SetFocus; //ustaw focus w Polu do Odpowiedzi

goto KONIEC; //pomiń poniższy kod i przejdź od razu na koniec procedury

end;

if Odp=(IntToStr(WYNIK)) then //jeżeli odpowiedź jest poprawna to …

begin

ShowMessage(„Bardzo dobrze!”); //wyświetl komunikat o poprawnej odpowiedzi

Label6.Caption:= „Ile jest:'; //wyczyść działanie

Poprawne:=Poprawne +1; //dodaj punkt do poprawnych odpowiedzi

end //bez średnika

else //w przeciwnym wypadku …

begin

ShowMessage(„Niestety źle”); //wyświetl komunikat o złej odpowiedzi

Niepoprawne:=Niepoprawne +1; //dodaj punkt do niepoprawnych odpowiedzi

end;

Edit1.Clear; //wyczyść pole do podawania Odpowiedzi)

Edit1.SetFocus; //ustaw focus w Polu do Odpowiedzi

Label4.Caption:= IntToStr(Poprawne); //wyświetl ilość poprawnych odpowiedzi

Label5.Caption:= IntToStr(Niepoprawne); //wyświetl ilość niepoprawnych odpowiedzi

KONIEC: //etykieta do której przechodzi kod, gdy ktoś nie wpisze żadnej liczby

end;

end.

Komentarz

W tej części pomijamy te elementy wraz z komentarzem, które zostały już opisane w poprzedniej wersji. Omówimy tylko te elementy, które się zmieniają.

Gdy naciśniemy przycisk START

Najważniejszą zmianą, jaką wprowadzamy to ilość liczb. Zamiast dwóch, mamy je teraz cztery. Sytuacja generalnie jednak nie zmienia się: wartość każdej z nich wyznaczamy losowo z przedziału od 0 do 20 za pomocą instrukcji Random(21). Nie zmienia się także procedura wyznaczająca znak działania, musimy ją tylko zastosować trzy razy, ponieważ tyle znaków będziemy potrzebować na obsługę czterech liczb. Każdy znak działania przypisujemy do innej zmiennej tekstowej (Znak1, Znak2, Znak3), dzięki czemu całe działanie będziemy mogli wyświetlić na etykiecie Label6.

Procedura dla przycisku „Sprawdź” nie zmienia się, gdyż w dalszym ciągu będzie ona sprawdzała wpisany przez nas wynik działania, bez względu na to, jakie działanie wygeneruje procedura przycisku START.

W następnym przykładzie ożywimy nieco nasz program i sprawimy, że przemówi on do nas ludzkim głosem.

Policz, ile to jest — wersja audio

Przedstawiamy jeszcze jedno rozwinięcie zabawy o nazwie „Policz, ile to jest”. Zmiana, jakiej dokonamy, będzie polegała na zamianie komunikatów tekstowych na słowne. Sprawimy, że program będzie z nami komunikował się, używając ludzkiej mowy. Będzie to z pewnością duże udogodnienie i atrakcja, zwłaszcza dla osób samotnych, którym brakuje rozmów z drugim człowiekiem. Przynajmniej komputer będzie do nich mówił…

Wracając do podstawowego kodu, czyli gry „Policz, ile to jest — wersja prosta”, musimy dokonać pewnych zmian. Przede wszystkim, z uwagi na to, że teraz program będzie zadawał nam pytania ludzkim głosem, możemy pozbyć się etykiety Label6, na której to zadanie było wyświetlane. Musimy także umieścić na formie komponent TMediaPlayer, który będzie odtwarzał odpowiednie pliki dźwiękowe. Oprócz niego skorzystamy także z prostszego odtwarzacza dźwięków, jakim jest PlaySound. Poznamy dzięki temu oba sposoby odtwarzania dźwięków w Delphi, a ponadto, wykorzystamy ich właściwości. Scharakteryzujmy zatem oba sposoby:

PlaySound

Jest to prosty odtwarzacz dźwięków, bez możliwości zarządzania tym dźwiękiem z pozycji programu. Kolejną jego wadą jest ograniczenie odtwarzanych formatów jedynie do plików wav. Trudno zatem używać go do bardziej rozbudowanych projektów, z uwagi na duży rozmiar tych plików w porównaniu z formatem mp3. Zazwyczaj stosuje się go do odtwarzania krótkich dźwięków tam, gdzie nie ma potrzeby używania bardziej rozbudowanego odtwarzacza. Tutaj też jest jego największa zaleta: jako mniej rozbudowany odtwarzacz, uruchamia się on znacznie szybciej niż MediaPlayer. Jeżeli tworzymy wypowiedź programu za pomocą kilku oddzielnych plików (tak jak w naszym przypadku) PlaySound szybciej i bardziej płynnie odtworzy je kolejno.

TMediaPlayer

Jako bardziej rozbudowany odtwarzacz, umożliwia on nie tylko odtwarzanie plików wav czy mp3, ale także zarządzanie dźwiękiem z pozycji programu, czyli na przykład Start, Stop, Pauza, Następny itp. Dużym mankamentem w przypadku plików mp3 jest brak regulacji siły głosu, stąd też do odtwarzania plików mp3 stosuje się często inne komponenty, które nie wchodzą w skład środowiska Delphi, trzeba je sobie osobno doinstalować.

Wracając do naszego programu, po umieszczeniu na formie komponentu TMediaPlayer, kompilator sam umieści odpowiednią informację o tym w sekcji uses, dodając moduł MPlayer. W przypadku korzystania z PlaySound sami musimy w tej sekcji umieścić informację, że będziemy korzystać z przeznaczonego do tego modułu. Dopisujemy zatem po przecinku nazwę MmSystem.

Jako że program ma mówić ludzką mową, musimy więc przygotować dla niego odpowiednie pliki dźwiękowe, z których będzie korzystał. Jakie pliki będą nam potrzebne? Po pierwsze, musimy posiadać pliki, z których będą wypowiadane liczby: dwadzieścia jeden oddzielnych plików, każdy przechowujący jedną liczbę, od zera do dwudziestu. Po drugie, musimy mieć trzy pliki określające działanie: plus, minus i razy. Musimy jeszcze mieć początek zdania, czyli formę zapytania „Ile jest?” oraz pliki z oceną naszej odpowiedzi: „Dobrze” i „Źle”.

W przypadku początku pytania, gdy za każdym razem program będzie mówił swoje „Ile jest”, prędzej czy później znudzi się nam ta monotonia. Wprowadzamy zatem założenie, że program będzie miał przygotowanych kilka różnych wersji tego pytania, nie tylko formę „Ile jest”, ale także inne, podobne wypowiedzi, na przykład takie: „Powiedz mi, ile jest”, „Ile to jest”, „Podaj mi wynik działania”, „Policz, ile to jest”. Przy każdorazowym uruchomieniu przycisku START program wylosuje jedną z tych form i odtworzy ją. Nada to większej „żywości” naszemu programowi. Programista może sobie przygotować znacznie szerszy wybór wypowiedzi, pamiętając jednak o tym, że w swoim programie musi podać, ile tych plików przygotował, aby program wiedział, z jakiego zakresu ma losować. Podobny zabieg możemy wykonać w przypadku wypowiedzi oceniającej naszą odpowiedź, a więc nie tylko „Dobrze”, ale także „Bardzo dobrze”, „Świetnie”, „Wyśmienicie”; tak samo: nie tylko „Źle”, ale i „Niestety źle”, „To nie jest dobra odpowiedź”, „Pomyliłeś się” itp. Im więcej wariantywnych wypowiedzi, tym zabawa będzie mniej monotonna i nudna.

Odpowiednie pliki możemy nagrać za pomocą swojego głosu lub poprosić koleżankę o miłym głosie, aby użyczyła go na potrzeby programu. Poszczególne kwestie nagrywamy do osobnych plików dźwiękowych: liczby, znaki i początek pytania tworzymy w formacie wav, a komunikaty i oceny możemy stworzyć w formacie mp3, aby zaoszczędzić miejsca na dysku.

Do przygotowania plików dźwiękowych możemy wykorzystać także odpowiedni program komputerowy, zwany syntezatorem mowy (np. Expressivo), który po wpisaniu w jego oknie tekstu, zamienia go na ludzką mowę, a następnie umożliwia zapisanie wypowiedzi w formie pliku dźwiękowego. Obecne syntezatory są już na tyle doskonałe, że wypowiadane przez nie słowa naprawdę niewiele różnią się od ludzkiej mowy.

Jeżeli planujemy wykorzystać możliwość mówienia programu do innych gier i zabaw, dobrze jest umieścić część plików dźwiękowych we wspólnym katalogu, na przykład o nazwie właśnie „WSPÓLNE”. Jakie będą to pliki? Ano wszystkie te, które powtarzają się w innych zabawach, a więc: liczby, znaki, komunikaty, oceny itp. Specyficzne wypowiedzi, które występują tylko dla jednej gry, umieszczamy w katalogu głównym lub jakimś innym konkretnej gry. Nazwy plików muszą być liczbami (począwszy od zera), ponieważ ułatwią one programowi losowanie pliku: Wystarczy, że program wylosuje jakąś liczbę i już wiadomo, jaki plik odtworzyć — oczywiście o tej samej liczbie w nazwie.

Własna procedura w Delphi

Z racji tego, że kod obsługujący odtwarzacz dźwięków zawiera wiele linii kodu, a ponadto za każdym razem linie te będą się powtarzać, więc, aby zmniejszyć ilość linii i zwiększyć przejrzystość kodu, utworzymy własną procedurę, którą nazwiemy „Wylosuj i odtwórz”. Będzie ona pobierała parametry z programu (ścieżkę dostępu do katalogu z plikami i ilość plików w tym katalogu) i na ich podstawie będzie odtwarzać określony plik.

Aby nasza procedura mogła być przez program wykorzystywana, musimy ją zadeklarować w sekcji „type”. W tym celu dopisujemy naszą deklarację (procedure) do innych procedur, podając jej nazwę. My, swoją procedurę nazwaliśmy „Wylosuj i odtwórz”, ale w tej postaci Delphi nam odrzuci. Wszelkie nazwy procedur muszą mieć postać jednoczłonową, stąd też deklarujemy naszą procedurę pod nazwą „Wylosuj_i_odtworz”. Nie trzeba chyba nikomu przypominać, że w kodzie nie korzystamy z polskich znaków dielektrycznych, możemy to zrobić jedynie w komentarzu. Opisem tej funkcji zajmiemy się w dalszej części, teraz, kończąc temat, dopowiemy jeszcze, jaki jest sens stosowania takich własnych procedur.

Wyobraźmy sobie program podobny do naszego, tylko bardziej rozbudowany, który wszelką komunikację z użytkownikiem prowadzi za pomocą plików dźwiękowych. Chcąc odtworzyć taki plik w komponencie MediaPlayer, musielibyśmy wpisać następujący kod:

MediaPlayer1.FileName:= 'C:\Katalog\Plik.mp3”;

MediaPlayer1.Open;

MediaPlayer1.Wait:=True;

MediaPlayer1.Play;

Kod ten musielibyśmy powtarzać za każdym razem, gdy będziemy generowali wypowiedź programu. Jest to dosyć czasochłonna praca, bardzo powiększająca ogólną objętość kodu. Lepiej więc taki kod zawrzeć w stworzonej przez nas procedurze, a potem odnosić się bezpośrednio do niej z różnych miejsc kodu. Teraz wystarczy tylko wpisać nazwę naszej procedury, czyli Wylosuj_i_odtworz, a program wykona przypisany do niej kod. Zabieg ten odchudzi nasz kod i uczyni go bardziej przejrzystym.

Kod programu

unit Unit1;

interface

uses

Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, MmSystem, MPlayer;

type

TForm1 = class(TForm)

Edit1: TEdit;

Button1: TButton;

Button2: TButton;

MediaPlayer1: TMediaPlayer;

Label1: TLabel;

Label2: TLabel;

Label3: TLabel;

Label4: TLabel;

Label5: TLabel;

procedure Button1Click(Sender: TObject);

procedure FormCreate(Sender: TObject);

procedure FormClose(Sender: TObject; var Action: TCloseAction);

procedure Edit1KeyPress(Sender: TObject; var Key: Char);

procedure Button2Click(Sender: TObject);

procedure Wylosuj_i_odtworz;

private

{ Private declarations }

public

{ Public declarations }

end;

var

Form1: TForm1;

WYNIK: Integer; //zmienna przechowująca wynik

Poprawne: Integer; //zmienna przechowująca ilość poprawnych odpowiedzi

Niepoprawne: Integer; //zmienna przechowująca ilość niepoprawnych odpowiedzi

Ilosc_plikow: Integer; //zmienna przechowująca ilość plików w katalogu

Katalog: String; //zmienna przechowująca ścieżkę dostępu do katalogu

implementation

{$R *.dfm}

//przy uruchomieniu programu wyzeruj punktację

procedure TForm1.FormCreate(Sender: TObject);

begin

Poprawne:=0; //wyzeruj ilość poprawnych odpowiedzi

Niepoprawne:=0; //wyzeruj ilość niepoprawnych odpowiedzi

Label4.Caption:= „0”; //wyświetl „0” poprawnych odpowiedzi

Label5.Caption:= „0”; //wyświetl „0” niepoprawnych odpowiedzi

end;

//przy zamykaniu programu oceń uzyskane wyniki

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);

begin

if (Poprawne<Niepoprawne) or (Poprawne=Niepoprawne) then

begin

ShowMessage(„Musisz jeszcze trochę potrenować”);

end //bez średnika

else //w przeciwnym wypadku…

ShowMessage(„Gratuluję! Uzyskałeś dobry wynik”);

end;

//pozwól na wpisywanie tylko liczb, minusa i Backpace w polu odpowiedzi

procedure TForm1.Edit1KeyPress(Sender: TObject; var Key: Char);

begin

if not (Key in [„0”. . „9”, #45,#8]) then

begin

Key:= #0;

ShowMessage(„To nie jest liczba”); //wyświetl komunikat o błędzie

end;

end;

// Procedura losująca i odtwarzająca plik dźwiękowy

var

Plik: Integer; //zmienna przechowująca numer pliku do odtworzenia

procedure TForm1.Wylosuj_i_odtworz;

begin

Randomize;

Plik:= Random(Ilosc_plikow); //wylosuj plik z katalogu

MediaPlayer1.FileName:= Katalog+IntToStr(Plik)+'.mp3”; //odtwórz plik

MediaPlayer1.Open; //otwórz pliku

MediaPlayer1.Wait:=True; //czekaj aż skończy się wybrzmiewać plik

MediaPlayer1.Play; //odtwórz plik

end;

//gdy naciśniesz przycisk START

procedure TForm1.Button1Click(Sender: TObject);

var

Liczba1: Integer; //zmienna przechowująca pierwszą liczbę

Liczba2: Integer; //zmienna przechowująca drugą liczbę

Dzialanie: Integer; //zmienna pomocnicza do losowania znaku działania

Numer_pliku: Integer; //zmienna przechowująca numer pliku „Ile jest”

Znak: String; //zmienna przechowująca znak działania

Sciezka1: String; //zmienna przechowująca ścieżkę dostępu do pliku dźwiękowego

Sciezka2: String; //zmienna przechowująca ścieżkę dostępu do pliku dźwiękowego

Sciezka3: String; //zmienna przechowująca ścieżkę dostępu do pliku dźwiękowego

Sciezka4: String; //zmienna przechowująca ścieżkę dostępu do pliku dźwiękowego

begin

Edit1.Clear; //wyczyść pole edycyjne (Do podawania Odpowiedzi)

Randomize; //uruchom maszynę losującą

Liczba1:=Random(21); //losuj pierwszą liczbę

Liczba2:=Random(21); //losuj drugą liczbę

Numer_pliku:=Random(5); //wylosuj numer pliku Ile jest

Dzialanie:=Random(3); //losuj znak działania matematycznego

case Dzialanie of //gdy zostanie wylosowana dana liczba to…

0: WYNIK:= Liczba1+Liczba2; //…wykonaj dodawanie

1: WYNIK:= Liczba1-Liczba2; //…wykonaj odejmowanie

2: WYNIK:= Liczba1*Liczba2; //…wykonaj mnożenie

end;

if Dzialanie=0 then

Znak:= '+'; //jeżeli wylosowano dodawanie to pokaz znak '+”

if Dzialanie=1 then

Znak:= '-'; //jeżeli wylosowano odejmowanie to pokaz znak '-”

if Dzialanie=2 then

Znak:= „x”; //jeżeli wylosowano mnożenie to pokaz znak „x”

//przypisz do zmiennych Sciezka ścieżki dostępu do plików

Sciezka1:=„c:\Gry\Policz ile jest\'+IntToStr(Numer_pliku)+”. wav”;

Sciezka2:= „c:\Gry\WSPOLNE\Liczby i znaki\'+IntToStr(Liczba1)+”. wav”;

Sciezka3:= „c:\Gry\WSPOLNE\Liczby i znaki\'+Znak+”. wav”;

Sciezka4:= „c:\Gry\WSPOLNE\Liczby i znaki\'+IntToStr(Liczba2)+”. wav”;

PlaySound(PChar(Sciezka1),0,SND_FILENAME); //odtwórz plik Ile jest

PlaySound(PChar(Sciezka2),0,SND_FILENAME); //odtwórz plik 1 liczba

PlaySound(PChar(Sciezka3),0,SND_FILENAME); //odtwórz plik Znak działania

PlaySound(PChar(Sciezka4),0,SND_FILENAME); //odtwórz plik 2 liczba

Edit1.SetFocus; //ustaw focus w Polu do Odpowiedzi

end;

//gdy naciśniesz przycisk Sprawdź

procedure TForm1.Button2Click(Sender: TObject);

Label KONIEC; //Etykieta do przechodzenia w inne miejsca kodu

var

Odp: String; //zmienna przechowująca naszą odpowiedź

begin

Odp:= Edit1.Text; //odczytaj podana odpowiedz i przypisz ja do zmiennej

if Odp=„” then //gdy nie podano odpowiedzi monituj o wpisaniu wyniku

begin

PlaySound(„c:\Gry\WSPOLNE\Komunikaty\WpiszLiczbe. wav”, 0,SND_FILENAME);

Edit1.SetFocus; //ustaw focus w Polu do Odpowiedzi

goto KONIEC; //pomiń poniższy kod i przejdź od razu na koniec procedury

end;

if Odp=(IntToStr(WYNIK)) then //jeżeli odpowiedź jest poprawna to …

begin

Ilosc_plikow:=7; //liczba plików w katalogu

Katalog:=„c:\Gry\WSPOLNE\Komunikaty\Dobrze\'; //ścieżka dostępu

Wylosuj_i_odtworz; //włącz procedurę odtwarzającą plik

Poprawne:=Poprawne +1; //dodaj punkt do poprawnych odpowiedzi

end //bez średnika

else //w przeciwnym wypadku …

begin

Ilosc_plikow:=8; //liczba plików w katalogu

Katalog:=„c:\Gry\WSPOLNE\Komunikaty\Zle\'; //ścieżka dostępu

Wylosuj_i_odtworz; //włącz procedurę odtwarzającą plik

Niepoprawne:=Niepoprawne +1; //dodaj punkt do niepoprawnych odpowiedzi

end;

Edit1.Clear; //wyczyść pole do podawania Odpowiedzi

Edit1.SetFocus; //ustaw focus w Polu do Odpowiedzi

Label4.Caption:= IntToStr(Poprawne); //wyświetl ilość poprawnych odpowiedzi

Label5.Caption:= IntToStr(Niepoprawne); //wyświetl ilość niepoprawnych odpowiedzi

KONIEC: //etykieta do której przechodzi kod, gdy ktoś nie wpisze żadnej liczby

end;

end.

Komentarz

1. Zmienne globalne

WYNIK: Integer; //zmienna przechowująca wynik

Poprawne: Integer; //zmienna przechowująca ilość poprawnych odpowiedzi

Niepoprawne: Integer; //zmienna przechowująca ilość niepoprawnych odpowiedzi

Ilosc_plikow: Integer; //zmienna przechowująca ilość plików w katalogu

Katalog: String; //zmienna przechowująca ścieżkę dostępu do katalogu

Poza znanymi nam już zmiennymi globalnymi deklarujemy dwie nowe, które będzie wykorzystywała nasza procedura „Wylosuj i odtwórz”. Jest to konieczne, ponieważ pliki dźwiękowe znajdują się w różnych katalogach (zmienna Katalog), a każdy z nich zawiera inną liczbę plików (zmienna Ilosc_plikow).

2. Procedura Wylosuj i odtwórz

Z uwagi na to, iż chcemy, aby program za każdym razem losował swoją wypowiedź jedną z wielu, stąd też na początku naszej procedury musimy uruchomić maszynę losującą (Randomize). W dalszej kolejności następuje losowanie numeru pliku do odtworzenia, dlatego właśnie plikom dźwiękowym nadaliśmy nazwy w postaci liczb. Ponieważ w tej chwili nie wiemy, z jakiego katalogu program skorzysta (bo to zależy od rodzaju wypowiedzi), więc w tej ogólnej postaci musimy wprowadzić pierwszą zmienną globalną, czyli Ilosc_plikow, którą wypełnimy bezpośrednio w danej procedurze. Nasza procedura pobierze ten parametr i wstawi u siebie, losując określony plik. Jako drugi parametr zostanie pobrana druga zmienna, Katalog, która będzie zawierać ścieżkę dostępu do konkretnego katalogu z wypowiedziami.

Po pobraniu potrzebnych informacji następuje uruchomienie odtwarzacza Media Player i wprowadzenie do niego ścieżki dostępu (czyli adresu miejsca na twardym dysku) pliku, która ma zostać odtworzony. Ścieżka ta w naszym przykładzie składa się z trzech części: ścieżki dostępu do katalogu, zmiennej „Plik”, która zawiera numer pliku do odtworzenia i części tekstowej (.mp3), aby powiązać zmienną „Plik” z plikiem dźwiękowym, ponieważ co prawda my nadaliśmy plikowi nazwę liczby, ale pełna nazwa pliku zawiera jeszcze jego rozszerzenie (w naszym przypadku. mp3), stąd też do zmiennej „Plik”, która przechowuje samą liczbę, dokładamy końcówkę „.mp3”.

Mając podaną poprawną ścieżkę dostępu, następuje załadowanie pliku do odtwarzacza (MediaPlayer1.Open) i jego odtworzenie (Play). Pomiędzy tymi poleceniami wstawiamy jeszcze polecenie MediaPlayer1.Wait: True, które aktywuje właściwość Wait (czekaj). Dzięki niej Media Player musi czekać z zamknięciem pliku do zakończenia jego odtwarzania. Funkcja ta przydaje się szczególnie mocno, gdy chcemy odtwarzać kilka plików po kolei. Bez tego polecenia Media Player uruchamiałby kolejne utwory i zaraz je zamykał, nie pozwalając im wybrzmieć.

3. Gdy naciśniesz przycisk START

var

Liczba1: Integer; //zmienna przechowująca pierwszą liczbę

Liczba2: Integer; //zmienna przechowująca drugą liczbę

Dzialanie: Integer; //zmienna pomocnicza do losowania znaku działania

Numer_pliku: Integer; //zmienna przechowująca numer pliku „Ile jest”

Znak: String; //zmienna przechowująca znak działania

Sciezka1: String; //zmienna przechowująca ścieżkę dostępu do pliku dźwiękowego

Sciezka2: String; //zmienna przechowująca ścieżkę dostępu do pliku dźwiękowego

Sciezka3: String; //zmienna przechowująca ścieżkę dostępu do pliku dźwiękowego

Sciezka4: String; //zmienna przechowująca ścieżkę dostępu do pliku dźwiękowego

W porównaniu z wersją prostą, w sekcji zmiennych (var) mamy umieszczone dodatkowe cztery zmienne typu string przechowujące ścieżkę dostępu do poszczególnych plików dźwiękowych oraz zmienną Numer_pliku, która przechowuje numer pliku do odtworzenia dla wypowiedzi „Ile jest”. Na ich podstawie program będzie tworzył swoją wypowiedź według następującego schematu: (Ile jest) (Liczba1) (znak) (Liczba2)

Kolejną sekcję po deklaracjach zmiennych nie komentujemy, ponieważ jest ona taka sama, jak w wersji oryginalnej. Jedyną zmianą jest dodanie linii Numer_pliku:=Random(5). Odpowiada ona za wylosowanie numeru pliku do odtworzenia dla początku wypowiedzi, to znaczy „Ile jest”. Wspominaliśmy już o tym, że robimy to po to, aby bardziej ożywić nasz program. Dzięki losowaniu odpowiedzi jednej z kilku możliwych uatrakcyjniamy program. W naszym przypadku w katalogu „Policz, ile to jest”, mamy przygotowanych pięć wariantów tej wypowiedzi, stąd też program losuje plik właśnie z tego przedziału.

//przypisz do zmiennych Sciezka ścieżki dostępu do plików

Sciezka1:=„c:\Gry\Policz ile jest\'+IntToStr(Numer_pliku)+”. wav”;

Sciezka2:= „c:\Gry\WSPOLNE\Liczby i znaki\'+IntToStr(Liczba1)+”. wav”;

Sciezka3:= „c:\Gry\WSPOLNE\Liczby i znaki\'+Znak+”. wav”;

Sciezka4:= „c:\Gry\WSPOLNE\Liczby i znaki\'+IntToStr(Liczba2)+”. wav”;

PlaySound(PChar(Sciezka1),0,SND_FILENAME); //odtwórz plik Ile jest

PlaySound(PChar(Sciezka2),0,SND_FILENAME); //odtwórz plik 1 liczba

PlaySound(PChar(Sciezka3),0,SND_FILENAME); //odtwórz plik Znak działania

PlaySound(PChar(Sciezka4),0,SND_FILENAME); //odtwórz plik 2 liczba

Edit1.SetFocus; //ustaw focus w Polu do Odpowiedzi

W przedstawionym powyżej fragmencie kodu najpierw tworzymy ścieżkę dostępu do odpowiednich katalogów i plików, gdyż funkcja PlaySound nie umożliwia łączenia tekstu ze zmiennymi, a to musimy zrobić, chcąc za każdym razem losować inny plik. W normalnych warunkach, w miejsce Pchar(sciezka) moglibyśmy wpisać pełną ścieżkę do pliku, na przykład: „C:\Gry\Policz ile to jest\1.wav”.

W pierwszej kolejności, do zmiennych „sciezka” przypisujemy ścieżkę dostępu do odpowiedniego katalogu, a następnie za pomocą zadeklarowanych wcześniej zmiennych (Numer_pliku, Liczba1 i 2, Znak) ustalamy konkretny plik do odtworzenia.

W schemacie wypowiedzi programu mamy cztery części, więc tyle też musimy mieć zmiennych. Zmienna „Sciezka1” przechowuje ścieżkę dostępu do plików odpowiedzialnych za pierwszą część wypowiedzi, czyli „Ile to jest”. Kolejne zmienne przechowują z kolei ścieżkę dostępu do wspólnego katalogu o nazwie „Liczby i znaki”, w którym zawarte są pliki umożliwiające wypowiadanie liczb i znaków matematycznych.

Mając już ustalone ścieżki dostępu plików do odtworzenia, nie pozostaje nic innego, jak ich załadowanie do funkcji PlaySound i odtworzenie. Przy wprowadzaniu zmiennej musimy użyć funkcji konwertującej PChar, aby typ zmiennej „Sciezka”, czyli string, był zrozumiały dla funkcji PlaySound. Na koniec, tradycyjnie już, ustawiamy kursor (focus) na polu do podawania odpowiedzi.

Jak widać z tego fragmentu, w porównaniu z wersją prostą programu, jest to tylko wymiana polecenia ShowMessage na zbiór poleceń PlaySound.

4. Gdy naciśniesz przycisk Sprawdź

Odp:= Edit1.Text; //odczytaj podaną odpowiedź i przypisz ją do zmiennej

if Odp=„” then //gdy nie podano odpowiedzi monituj o wpisaniu wyniku

begin PlaySound(„c:\Gry\WSPOLNE\Komunikaty\WpiszLiczbe. wav”, 0,SND_FILENAME);

Edit1.SetFocus; //ustaw focus w Polu do Odpowiedzi

goto KONIEC; //pomiń poniższy kod i przejdź od razu na koniec procedury

W sekcji tej wymieniamy tylko komunikat tekstowy (ShowMessage) na głosowy (PlaySound). Z uwagi na to, że komunikat ten rzadko kiedy będzie wykorzystywany, więc przygotowaliśmy tylko jedną jego wersję. Może to być proste stwierdzenie typu „Wpisz najpierw wynik” lub podobne. Skoro mamy tylko jeden plik do odtworzenia, więc w funkcji PlaySound wpiszemy pełną ścieżkę dostępu, nie zapominając, że musi się ona znaleźć pomiędzy apostrofami.

if Odp=(IntToStr(WYNIK)) then //jeżeli odpowiedź jest poprawna to …

begin

Ilosc_plikow:=7; //liczba plików w katalogu

Katalog:=„C:\Gry\WSPOLNE\Komunikaty\Dobrze\'; //ścieżka dostępu

Wylosuj_i_odtworz; //włącz procedurę odtwarzającą plik

Poprawne:=Poprawne +1; //dodaj punkt do poprawnych odpowiedzi

end //bez średnika

else //w przeciwnym wypadku …

begin

Ilosc_plikow:=8; //liczba plików w katalogu

Katalog:=„C:\Gry\WSPOLNE\Komunikaty\Zle\'; //ścieżka dostępu

Wylosuj_i_odtworz; //włącz procedurę odtwarzającą plik

Niepoprawne:=Niepoprawne +1; //dodaj punkt do niepoprawnych odpowiedzi

end;

Podobnie jak w poprzednim przypadku, w sekcji tej następuje tylko wymiana rodzaju komunikatu z tekstowego na głosowy. W tym jednak przypadku zastosujemy odtwarzacz MediaPlayer, aby móc skorzystać z plików mp3. Za każdym razem, chcąc z niego skorzystać, będziemy wykorzystywać stworzoną przez nas procedurę Wylosuj_i_odtworz. Wymaga ona podania dwóch parametrów: ścieżki dostępu do odpowiedniego katalogu oraz podania informacji, ile w tym katalogu znajduje się plików, toteż na początku deklarujemy obie zmienne globalne, a następnie wydajemy polecenie, aby program uruchomił naszą procedurę odtwarzającą. Wykona się ona poprawnie, ponieważ w zmiennych globalnych znajdzie potrzebne dla swego działania dane. Bez ich wcześniejszego zadeklarowania program zgłosiłby błąd.

Deklarując zmienną „Ilosc_plikow” musimy już wiedzieć, ile tych plików w danym katalogu jest. Musimy zatem przygotować je wcześniej, przed przystąpieniem do pisania kodu. Jeżeli do katalogu dołożymy nowe pliki, już po napisaniu kodu, program nie skorzysta z nich, ponieważ w swoim kodzie będzie posiadał stare dane. W tym przypadku będziemy musieli zmodyfikować kod, wpisując zaktualizowane deklaracje, ile w tej chwili znajduje się plików w katalogu, a następnie od nowa skompilować program.

W przykładzie rozwinięcia podstawowej wersji programu, jaki tutaj zaprezentowaliśmy, wymieniliśmy tylko część komunikatów na ich głosowe odpowiedniki. Nic jednak nie stoi na przeszkodzie, aby w sposób pokazany wyżej nie pozamieniać pozostałych komunikatów, chociażby tych, które przy wyłączeniu programu oceniają nasze wyniki. Możemy także nadać programowi cechę, aby po udzielonej odpowiedzi informował, jaki jest aktualny wynik lub wprowadzić inne elementy i rozwiązania, które zwiększą komfort pracy lub możliwości programu. Wszystko zależy od naszych oczekiwań.

Powtórz liczby

Jest to kolejna zabawa rozwijająca nasz umysł. W tej trenujemy i rozwijamy pamięć. Program będzie podawał szereg liczb, które będziemy musieli z pamięci powtórzyć.

Założenia i opis zabawy:

Podobnie jak w poprzednich przypadkach, przyjmujemy możliwość wpisywania odpowiedzi po raz drugi, gdy pierwsza nasza odpowiedź będzie błędna. Pozostawiamy także sprawdzone rozwiązania z poprzednich przykładów, czyli możliwość oceny naszych wyników przez program na zakończenie gry i wyświetlanie na bieżąco wyników, ile odpowiedzi udzieliliśmy poprawnych, a ile niepoprawnych.

Zachowujemy także ograniczenia dla pola do wpisywania odpowiedzi: dopuszczamy tylko możliwość wpisywania liczb oraz ich kasowanie. W poprzednich zabawach istniała możliwość wpisywania minusa, w tej zabawie minus nie jest nam potrzebny, więc usuwamy tę możliwość.

Aby ułatwić sobie zadanie, nie będziemy losować każdej liczby osobno. Wylosujemy jedną dużą liczbę, składającą się z pięciu znaków, które będziemy musieli wpisać jedna za drugą, tworząc w ten sposób na powrót jedną dużą liczbę. Jest to dobry kompromis między trudnością zabawy a naszą niewyćwiczoną pamięcią. Nic nie stoi jednak na przeszkodzie, aby zwiększyć ilość liczb do powtórzenia.

Potrzebne komponenty:

Generalnie będziemy używać tych samych komponentów, co w poprzednich zabawach, różnice będą tylko w sposobie ich oprogramowania.

Na formie głównej umieszczamy więc następujące komponenty, nadając im odpowiednie nazwy:

komponent Nazwa (Caption)

Edit1 (usuwamy nazwę)

Button1 START

Button2 Sprawdź

Label1 Powtórz liczby:

Label2 Wyniki

Label3 Poprawne:

Label4 Niepoprawne:

Label5 0

Label 6 0

Label7 00000

A oto interfejs programu i pełny kod zabawy:

Kod programu

unit Unit1;

interface

uses

Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls;

type

TForm1 = class(TForm)

Edit1: TEdit;

Button1: TButton;

Button2: TButton;

Label1: TLabel;

Label2: TLabel;

Label3: TLabel;

Label4: TLabel;

Label5: TLabel;

Label6: TLabel;

Label7: TLabel;

procedure Edit1KeyPress(Sender: TObject; var Key: Char);

procedure FormClose(Sender: TObject; var Action: TCloseAction);

procedure Button1Click(Sender: TObject);

procedure Button2Click(Sender: Tobject);

private

{ Private declarations }

public

{ Public declarations }

end;

var

Form1: TForm1;

WYNIK: Integer; //zmienna przechowująca liczby do powtórzenia

Poprawne: Integer; //zmienna przechowująca ilość poprawnych odpowiedzi

Niepoprawne: Integer; //zmienna przechowująca ilość niepoprawnych odpowiedzi

implementation

{$R *.dfm}

//pozwól na wpisywanie tylko liczb i Backpace w polu odpowiedzi

procedure TForm1.Edit1KeyPress(Sender: TObject; var Key: Char);

begin

if not (Key in [„0”. . „9”, #8]) then

begin

Key:=#0;

ShowMessage(„To nie jest liczba”); //wyświetl komunikat o błędzie

end;

end;

//przy zamykaniu programu oceń uzyskane wyniki

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);

begin //jeżeli uzyskałeś więcej złych odpowiedzi lub tyle samo co dobrych wtedy…

if (Poprawne<Niepoprawne) or (Poprawne=Niepoprawne) then

begin

ShowMessage(„Musisz jeszcze trochę potrenować”); //wyświetl komunikat

end //bez średnika

else //w przeciwnym wypadku…

ShowMessage(„Gratuluję! Uzyskałeś dobry wynik”); //wyświetl komunikat

end;

//gdy naciśniesz przycisk START

procedure TForm1.Button1Click(Sender: TObject);

begin

Edit1.Clear; //wyczyść pole edycyjne (Do podawania Odpowiedzi)

Randomize; //uruchom maszynę losującą

WYNIK:=Random(99999); //wylosuj plik do powtórzenia od 0 do 99999

Label7.Caption:=IntToStr(WYNIK); //wyświetl liczbę do powtórzenia

Label7.Update; //uaktualnij komponent label

Button2.Enabled:=false; //zablokuj przycisk Sprawdź

Sleep(3000); //czekaj 3 sekundy

Label7.Caption:=„powtórz”; //zamiast liczby wyświetl napis „powtórz”

Button2.Enabled:=true; //odblokuj przycisk Sprawdź

Edit1.SetFocus; //ustaw focus w Polu do Odpowiedzi

end;

//gdy naciśniesz przycisk Sprawdź

procedure TForm1.Button2Click(Sender: TObject);

Label KONIEC; //Etykieta do przechodzenia w inne miejsce kodu

var

Odp: String; //zmienna przechowująca naszą odpowiedź

begin

Odp:= Edit1.Text; //odczytaj podaną odpowiedź i przypisz ją do zmiennej

if Odp=„” then //gdy nie podano odpowiedzi monituj o błędzie

begin

ShowMessage(„Wpisz najpierw wynik”); //wyświetl komunikat informujący

Edit1.SetFocus; //ustaw focus w Polu do Odpowiedzi

goto KONIEC; //pomiń poniższy kod i przejdź od razu na koniec procedury

end;

if Odp=(IntToStr(WYNIK)) then //jeżeli odpowiedź jest poprawna to …

begin

ShowMessage(„Bardzo dobrze!”); //wyświetl komunikat o poprawnej odpowiedzi

Label7.Caption:= „00000: '; //wyczyść działanie

Poprawne:=Poprawne +1; //dodaj punkt do poprawnych odpowiedzi

end //bez średnika

else //w przeciwnym wypadku …

begin

ShowMessage(„Niestety źle”); //wyświetl komunikat o złej odpowiedzi

Niepoprawne:=Niepoprawne +1; //dodaj punkt do niepoprawnych odpowiedzi

end;

Edit1.Clear; //wyczyść pole do podawania Odpowiedzi)

Edit1.SetFocus; //ustaw focus w Polu do Odpowiedzi

Label5.Caption:= IntToStr(Poprawne); //wyświetl ilość poprawnych odpowiedzi

Label6.Caption:= IntToStr(Niepoprawne); //wyświetl ilość niepoprawnych odpowiedzi

KONIEC: //etykieta do której przechodzi kod, gdy ktoś nie wpisze żadnej liczby

end;

end.

Komentarz

1. Stałe elementy, znane z poprzednich zabaw

Pierwszą część kodu, aż do procedury opisującej przycisk START, nie komentujemy, gdyż znalazła ona swój opis w komentarzu do zabawy „Policz, ile to jest — wersja prosta”.

2. Gdy naciśniesz przycisk START

Edit1.Clear; //wyczyść pole edycyjne (Do podawania Odpowiedzi)

Randomize; //uruchom maszynę losującą

WYNIK:=Random(99999); //wylosuj plik do powtórzenia od 0 do 99999

Na początku procedury usuwamy naszą poprzednią odpowiedź z pola edycyjnego, a następnie uruchamiamy maszynę losującą, aby wylosowała liczby do powtórzenia. W naszej zabawie nie musimy losować każdej liczby osobno, choć oczywiście moglibyśmy. Upraszczamy jednak kod, losując jedną liczbę z zakresu od 0 do 99999. Zazwyczaj wylosowana zostanie liczba pięcioznakowa, czyli tyle, ile założyliśmy. Istnieje małe prawdopodobieństwo, że wylosowana liczba będzie jedno- czy powiedzmy dwuznakowa, taka możliwość istnieje, jednak możemy uznać to za bonus zabawy, że daje nam do powtórzenia prostą liczbę. Gdybyśmy chcieli, aby program za każdym razem przedstawiał pięć liczb, musielibyśmy każdą z nich losować i przedstawiać osobno, względnie musielibyśmy tę naszą jedną liczbę obarczyć kilkoma warunkami, aby program wymuszał użycie pięciu znaków.

Ponieważ w naszej zabawie używamy prostej formy, więc najprościej będzie po prostu wyświetlić ową liczbę na etykiecie programu, obok etykiety Label1, która przedstawia napis „Powtórz liczby”. Skoro wszystkie liczby do powtórzenia wyświetlamy jedna obok drugiej (jako jedną liczbę pięcioznakową), to i w takiej samej formie musimy wpisywać odpowiedź, w przeciwnym wypadku program potraktuje ją jako błędną.

Dla przejrzystości przedstawianych liczb możemy oddzielić je spacjami, używając metody WYNIK [pozycja liczby w szeregu], czyli na przykład, chcąc wyświetlić trzecią liczbę ze zmiennej WYNIK, piszemy: Wynik[3]. Spacje wyświetlamy na etykiecie, dodając segment typu (+' '+) — pomiędzy apostrofami umieszczamy jedno miejsce wolne, czyli właśnie spację. Chcąc teraz podać prawidłową odpowiedź, musimy i my podawać liczby, oddzielając je spacjami.

Label7.Caption:=IntToStr(WYNIK); //wyświetl liczbę do powtórzenia

Label7.Update; //uaktualnij komponent label

Button2.Enabled:=false; //zablokuj przycisk Sprawdź

Sleep(3000); //czekaj 3 sekundy

Label7.Caption:=„powtórz”; //zamiast liczby wyświetl napis „powtórz”

Button2.Enabled:=true; //odblokuj przycisk Sprawdź

Edit1.SetFocus; //ustaw focus w Polu do Odpowiedzi

W drugiej części kodu, którą powyżej prezentujemy, wyświetlamy nasze liczby jako jedną liczbę pięcioznakową. Druga linia (Label7.Update) odpowiada za aktualizację napisu etykiety, gdyż zmieniamy ją dwukrotnie w czasie pracy procedury. Teraz wprowadzamy blokadę na przycisk Sprawdź, aby nieuczciwy gracz nie mógł go użyć podczas wyświetlania liczb.

Czas wyświetlania ustaliliśmy na trzy sekundy. Należy w tym miejscu pamiętać, że maszyny mikroprocesorowe, w tym między innymi komputer, jako podstawowej jednostki czasu nie używają sekundy (sekunda dla procesora to kawał czasu), lecz milisekundy i w tych też jednostkach podajemy wszelkie wartości związane z czasem, a więc wartość „3 sekundy” podajemy jako 3000 (ms). Po tym czasie program realizuje kolejne polecenia kodu: w miejsce liczb do odgadnięcia wyświetla teraz napis zachęcający „Powtórz”, odblokowuje przycisk „Sprawdź” oraz, na samym końcu, umieszcza kursor (focus) na polu do wpisywania odpowiedzi, wyręczając nas od klikania w to miejsce myszką.

3. Gdy naciśniesz przycisk „Sprawdź”

Poza drobnymi szczegółami procedura obsługująca sprawdzenie naszej odpowiedzi nie różni się od rozwiązania stosowanego w poprzednich grach, więc nie będziemy jej ponownie opisywać.

W kolejnych dwóch propozycjach gier i zabaw, przedstawimy podobne projekty: pierwszy, zamiast liczb będzie oczekiwał od nas powtórzenia liter, a drugi, powtórzenia zarówno liter, jak i liczb.

Powtórz litery

Przedstawiona tu zabawa w założeniach podobna jest do tej, którą prezentowaliśmy poprzednio. W obu chodzi o to, aby powtórzyć ciąg znaków, jakie program dla nas wygeneruje. Pomimo tego podobieństwa, użycie liter jako znaków do odgadnięcia implikuje użycie bardziej skomplikowanej formy kodu. Uwarunkowane jest to naturą tychże znaków. W przypadku poprzedniej zabawy znakami tymi były liczby, więc program — jako maszyna matematyczna — nie miał problemu z ich obróbką. Wystarczyło wylosować jedną liczbę pięcioznakową, aby spełnić nasze oczekiwanie. W sytuacji, gdy mamy do czynienia z literami (a więc znakami niematematycznymi), program nie jest w stanie sam od siebie niczego wygenerować. Musimy mu z poziomu kodu zaimplementować jakiś zbiór znaków (w tym przypadku liter), aby mógł na nim dokonywać działań. Poprzez swoje funkcje Delphi zaczyna traktować te znaki w sposób matematyczny, pamiętając jednak, że są to znaki typu string.

Kod zabawy

unit Unit1;

interface

uses

Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls;

type

TForm1 = class(TForm)

Edit1: TEdit;

Button1: TButton;

Button2: TButton;

Label1: TLabel;

Label2: TLabel;

Label3: TLabel;

Label4: TLabel;

Label5: TLabel;

Label6: TLabel;

Label7: TLabel;

procedure FormClose(Sender: TObject; var Action: TCloseAction);

procedure Button1Click(Sender: TObject);

procedure Button2Click(Sender: Tobject);

private

{ Private declarations }

public

{ Public declarations }

end;

var

Form1: TForm1;

WYNIK: String; //zmienna przechowująca litery do odgadnięcia

Poprawne: Integer; //zmienna przechowująca ilość poprawnych odpowiedzi

Niepoprawne: Integer; //zmienna przechowująca ilość niepoprawnych odpowiedzi

implementation

{$R *.dfm}

//przy zamykaniu programu oceń uzyskane wyniki

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);

begin //jeżeli uzyskałeś więcej złych odpowiedzi lub tyle samo co dobrych wtedy…

if (Poprawne<Niepoprawne) or (Poprawne=Niepoprawne) then

begin

ShowMessage(„Musisz jeszcze trochę potrenować”); //wyświetl komunikat

end //bez średnika

else //w przeciwnym wypadku…

ShowMessage(„Gratuluję! Uzyskałeś dobry wynik”); //wyświetl komunikat

end;

//gdy naciśniesz przycisk START

procedure TForm1.Button1Click(Sender: TObject);

const

Tablica: array [1..23] of String =(„a”, „b”, „c”, „d”, „e”, „f”, „g”, „h”, „i”, „j”, „k”, „l”, „m”, „n”, „o”, „p”, „r”, „s”, „t”, „u”, „w”, „y”, „z”); //tablica liter

var

Litera1: String; //zmienna przechowująca pierwszą literę

Litera2: String; //zmienna przechowująca drugą literę

Litera3: String; //zmienna przechowująca trzecią literę

Litera4: String; //zmienna przechowująca czwartą literę

Litera5: String; //zmienna przechowująca piątą literę

Litera6: String; //zmienna przechowująca szóstą literę

begin

Edit1.Clear; //wyczyść pole edycyjne (Do podawania Odpowiedzi)

Randomize; //uruchom maszynę losującą

Litera1:= Tablica[Random(23)+1]; //wylosuj 1 literę

Litera2:= Tablica[Random(23)+1]; //wylosuj 2 literę

Litera3:= Tablica[Random(23)+1]; //wylosuj 3 literę

Litera4:= Tablica[Random(23)+1]; //wylosuj 4 literę

Litera5:= Tablica[Random(23)+1]; //wylosuj 5 literę

Litera6:= Tablica[Random(23)+1]; //wylosuj 6 literę

WYNIK:= (Litera1+Litera2+Litera3+Litera4+Litera5+Litera6);

//zapisz wylosowane litery do zmiennej globalnej

Label2.Caption:=WYNIK; //wyświetl liczbę do powtórzenia

Label2.Update; //uaktualnij komponent label

Button2.Enabled:=false; //zablokuj przycisk Sprawdź

Sleep(3000); //czekaj 3 sekundy

Label2.Caption:=„powtórz”; //zamiast liczby wyświetl napis „powtórz”

Button2.Enabled:=true; //odblokuj przycisk Sprawdź

Edit1.SetFocus; //ustaw focus w Polu do Odpowiedzi

end;

//gdy naciśniesz przycisk Sprawdź

procedure TForm1.Button2Click(Sender: TObject);

var

Odp: String; //zmienna przechowująca naszą odpowiedź

begin

Odp:= Edit1.Text; //odczytaj podaną odpowiedź i przypisz ją do zmiennej

if Odp=WYNIK then //jeżeli odpowiedź jest poprawna to …

begin

ShowMessage(„Bardzo dobrze!”); //wyświetl komunikat o poprawnej odpowiedzi

Label2.Caption:= ' — — — '; //wyczyść działanie

Poprawne:=Poprawne +1; //dodaj punkt do poprawnych odpowiedzi

end //bez średnika

else //w przeciwnym wypadku …

begin

ShowMessage(„Niestety źle”); //wyświetl komunikat o złej odpowiedzi

Niepoprawne:=Niepoprawne +1; //dodaj punkt do niepoprawnych odpowiedzi

end;

Edit1.Clear; //wyczyść pole do podawania Odpowiedzi)

Edit1.SetFocus; //ustaw focus w Polu do Odpowiedzi

Label6.Caption:= IntToStr(Poprawne); //wyświetl ilość poprawnych odpowiedzi

Label7.Caption:= IntToStr(Niepoprawne); //wyświetl ilość niepoprawnych odpowiedzi

end;

end.

Komentarz

1. Wstęp

Jak widzimy, komponenty użyte w tej zabawie pozostają te same, co w poprzedniej. Tutaj nic się nie zmienia. Zmianie ulegnie tylko część kodu obsługująca działanie programu. Przede wszystkim nie wprowadzamy procedury Edit1KeyPress ograniczającej rodzaj wpisywanych znaków w pole edycyjne przeznaczone do podania odpowiedzi. Musieliśmy usunąć to ograniczenie, aby można było wpisywać litery. Pozostałe rozwiązania pozostają niezmienione, aż do procedury obsługującej przycisk START.

2. Gdy naciśniesz przycisk START

Jak już wspominaliśmy, program jako maszyna matematyczna nie zna liter, musimy je dopiero zadeklarować. Wykorzystujemy do tego celu dwa nowe dla nas elementy: stałą i tablicę. Do tej pory nauczyliśmy się stosować zmienne jako miejsce przechowywania danych, które często się zmieniają. Tutaj sytuację mamy inną: z góry wiemy, jakie litery będą używane. Będzie to zatem stały element.

Konkretne litery, po wylosowaniu w dalszej części procedury zostaną przypisane do zmiennych Litera, w których to program będzie je przechowywał podobnie, jak robił to wcześniej z liczbami. Sekcja ta jest zatem bazą, z której program będzie czerpał litery. Pozostaje jeszcze kwestia ich implementacji. Moglibyśmy to zrobić analogicznie jak w przypadku zmiennych, czyli każdą z liter deklarując osobno, na przykład tak:

const

Znak1:= „a”;

Znak2:= „b”;

Znak3:= „c”;

(…)

Znak23:= „z”;

Powyższe rozwiązanie jak widzimy, generuje znaczny przyrost kodu i stratę naszego czasu. O wiele szybciej i prościej cały ten zbiór możemy zawrzeć w tablicy stałych:

const

Tablica: array [1..23] of String =(„a”, „b”, „c”, „d”, „e”, „f”, „g”, „h”, „i”, „j”, „k”, „l”, „m”, „n”, „o”, „p”, „r”, „s”, „t”, „u”, „w”, „y”, „z”); //tablica liter

Zamiast znacznika var (od angielskiej nazwy Zmienna) używamy tu znacznika const, czyli stała. W dalszej kolejności wprowadzamy nazwę tablicy. Nazwa może być dowolna, pamiętajmy jednak, że musi być ona jednoczłonowa. My przyjęliśmy prostą nazwę, czyli „Tablica”. Teraz musimy zadeklarować z ilu i z jakich elementów będzie się składała oraz po znaku równości, w nawiasie wymieniamy je, każdy element umieszczając w apostrofach i oddzielając go od innych elementów za pomocą przecinka. W naszym przypadku mamy 23 elementy (litery) typu string.

Chcąc skorzystać w procedurze z tak przygotowanego zbioru, używamy nazwy tablicy i numeru elementu, który chcemy użyć, przykładowo, chcąc użyć litery „c” odwołujemy się do niej w następujący sposób: Tablica[3]. Litera „c” jest trzecim elementem tego zbioru, więc i taką matematyczną nazwę będzie w tym przypadku posiadała.

Aby móc używać liter z naszej tablicy w tworzonej przez nas procedurze, musimy zadeklarować sześć zmiennych typu string (Litera1…6) do ich przechowywania. Ilość zmiennych uzależniona jest od ilości liter, jakie chcemy powtarzać. Przyjęliśmy, że powtórzenie sześciu liter z pamięci jest wystarczająco trudnym zadaniem, stąd też tyle zmiennych przygotowujemy.

W rozpoczynającej się procedurze następuje wylosowanie jednego z elementów tablicy liter i przypisanie go do zmiennej Litera: Litera1:= Tablica[Random(23)+1].

Każda ze zmiennych Litera przechowuje jedną literę do powtórzenia, wylosowaną z tego samego zbioru, czyli Tablica. Istnieje więc możliwość, że wśród tych liter niektóre mogą się powtarzać. WYNIK=(Litera1+Litera2+Litera3+Litera4+Litera5+Litera6);

Po przypisaniu liter do zmiennych następuje połączenie ich w jeden ciąg znaków i zapisanie do zmiennej globalnej WYNIK. Działanie to wymaga od nas, aby i my podali odpowiedź, wpisując jedna litera za drugą, bez oddzielania ich za pomocą spacji. Warto zwrócić uwagę na fakt, że litery jako znaki tekstowe nie wymagają od zmiennej WYNIK żadnej konwersji.

Dalsza część procedury, jak i dalszy kod pozostają bez zmian w stosunku do pierwowzoru, więc pomijamy ją w tym komentarzu. Zwracamy tylko uwagę, aby zmienną WYNIK nie konwertować przy sprawdzaniu odpowiedzi, gdyż przecież jest ona w tym projekcie zmienną typu string, a więc tego samego typu, co zmienna Odp.

W trzecim przykładzie zabawy z tej grupy napiszemy program łączący obie wcześniejsze zabawy, czyli będzie losował dla nas zarówno litery, jak i liczby

.

Powtórz liczby i litery

W tym przykładzie prezentujemy trzeci wariant zabawy, polegającej na powtórzeniu znaków wygenerowanych przez program. Uatrakcyjniamy nasz projekt i pozwalamy, aby program wybierał do powtórzenia zarówno litery, jak i liczby. Cały interfejs programu, jak i procedury początkowe pozostają bez zmian.

Kod programu

unit Unit1;

interface

uses

Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls;

type

TForm1 = class(TForm)

Edit1: TEdit;

Button1: TButton;

Button2: TButton;

Label1: TLabel;

Label2: TLabel;

Label3: TLabel;

Label4: TLabel;

Label5: TLabel;

Label6: TLabel;

Label7: TLabel;

procedure FormClose(Sender: TObject; var Action: TCloseAction);

procedure Button1Click(Sender: TObject);

procedure Button2Click(Sender: TObject);

private

{ Private declarations }

public

{ Public declarations }

end;

var

Form1: TForm1;

WYNIK: String; //zmienna przechowująca znaki do odgadnięcia

Poprawne: Integer; //zmienna przechowująca ilość poprawnych odpowiedzi

Niepoprawne: Integer; //zmienna przechowująca ilość niepoprawnych odpowiedzi

implementation

{$R *.dfm}

//przy zamykaniu programu oceń uzyskane wyniki

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);

begin

if (Poprawne<Niepoprawne) or (Poprawne=Niepoprawne) then

begin

ShowMessage(„Musisz jeszcze trochę potrenować”); //wyświetl komunikat

end //bez średnika

else //w przeciwnym wypadku…

ShowMessage(„Gratuluję! Uzyskałeś dobry wynik”); //wyświetl komunikat

end;

//gdy naciśniesz przycisk START

procedure TForm1.Button1Click(Sender: TObject);

const

Tablica: array [1..33] of String =(„a”, „b”, „c”, „d”, „e”, „f”, „g”, „h”, „i”, „j”, „k”, „l”, „m”, „n”, „o”, „p”, „r”, „s”, „t”, „u”, „w”, „y”, „z”, „1”, „2”, „3”, „4”, „5”, „6”, „7”, „8”, „9”, „0”);

var

Znak1: String; //zmienna przechowująca pierwszy znak

Znak2: String; //zmienna przechowująca drugi znak

Znak3: String; //zmienna przechowująca trzeci znak

Znak4: String; //zmienna przechowująca czwarty znak

Znak5: String; //zmienna przechowująca piąty znak

Znak6: String; //zmienna przechowująca szósty znak

begin

Edit1.Clear; //wyczyść pole edycyjne (Do podawania Odpowiedzi)

Randomize; //uruchom maszynę losującą

Znak1:= Tablica[Random(33)+1]; //wylosuj pierwszy znak do powtórzenia

Znak2:= Tablica[Random(33)+1]; //wylosuj drugi znak do powtórzenia

Znak3:= Tablica[Random(33)+1]; //wylosuj trzeci znak do powtórzenia

Znak4:= Tablica[Random(33)+1]; //wylosuj czwarty znak do powtórzenia

Znak5:= Tablica[Random(33)+1]; //wylosuj piąty znak do powtórzenia

Znak6:= Tablica[Random(33)+1]; //wylosuj szósty znak do powtórzenia

WYNIK:=(Znak1+Znak2+Znak3+Znak4+Znak5+Znak6); //zapisz wylosowane znaki do zmiennej globalnej

Label2.Caption:=WYNIK; //wyświetl znaki do powtórzenia

Label2.Update; //uaktualnij komponent label

Button2.Enabled:=false; //zablokuj przycisk Sprawdź

Sleep(3000); //czekaj 3 sekundy

Label2.Caption:=„powtórz”; //zamiast liczby wyświetl napis „powtórz”

Button2.Enabled:=true; //odblokuj przycisk Sprawdź

Edit1.SetFocus; //ustaw focus w Polu do Odpowiedzi

end;

//gdy naciśniesz przycisk Sprawdź

procedure TForm1.Button2Click(Sender: TObject);

var

Odp: String; //zmienna przechowująca naszą odpowiedź

begin

Odp:= Edit1.Text; //odczytaj podaną odpowiedź i przypisz ją do zmiennej

if Odp=WYNIK then //jeżeli odpowiedź jest poprawna to …

begin

ShowMessage(„Bardzo dobrze!”); //wyświetl komunikat o poprawnej odpowiedzi

Label2.Caption:= ' — — — '; //wyczyść działanie

Poprawne:=Poprawne +1; //dodaj punkt do poprawnych odpowiedzi

end //bez średnika

else //w przeciwnym wypadku …

begin

ShowMessage(„Niestety źle”); //wyświetl komunikat o złej odpowiedzi

Niepoprawne:=Niepoprawne +1; //dodaj punkt do niepoprawnych odpowiedzi

end;

Edit1.Clear; //wyczyść pole do podawania Odpowiedzi)

Edit1.SetFocus; //ustaw focus w Polu do Odpowiedzi

Label6.Caption:= IntToStr(Poprawne); //wyświetl ilość poprawnych odpowiedzi

Label7.Caption:= IntToStr(Niepoprawne); //wyświetl ilość niepoprawnych odpowiedzi

end;

end.

Komentarz

1. Gdy naciśniesz przycisk START

Chcąc używać razem litery i liczby, musimy je wszystkie umieścić w jednym zbiorze, w tym przypadku pozostajemy przy tablicy stałych o nazwie Tablica. Zauważmy, że tablica ta w dalszym ciągu jest typu string, co powoduje, że umieszczone w niej liczby będą traktowane jako znaki tekstowe, stąd też przypisujemy je do zmiennych Znak (typu string), podobnie jak litery, czyli bez konwersji. Z uwagi na to, że program odczytuje z pola edycyjnego odpowiedź także jako typ string, więc w naszym projekcie — pomimo stosowania liczb — ani razu nie użyjemy konwersji!

Po wzbogaceniu tablicy o nowe elementy musimy podać aktualną ilość znaków (w naszym przypadku „33”) oraz po kolei wymienić w apostrofach wszystkie te elementy.

Zmieniamy nazwy zmiennych lokalnych z „Litera” na bardziej uniwersalne, czyli „Znak”, ponieważ oprócz liter będą umieszczone w niej także liczby. Nie jest to oczywiście warunek. Możemy zmienne, jak i stałe nazywać dowolnie, według własnego uznania, najlepiej jednak tak, aby informowały, do czego służą.

Poza tą niewielką zmianą program niczym więcej nie różni się od poprzedniej wersji ani w budowie, ani w działaniu, więc kończymy komentarz do naszego potrójnego projektu pod wspólną nazwą „Powtórz za mną”. W kolejnym przykładzie zapoznamy się już z nowym typem zabawy.

Zgadnij liczbę

Matematyka, ze swoimi działaniami i liczbami, daje duże pole do popisu dla tworzenia wielu form gier i zabaw. Prezentujemy zatem kolejną, bardzo prościutką z punktu widzenia programistycznego zabawę, opartą właśnie na matematyce.

Założenia i opis programu:

Idea zabawy jest prosta: program losuje liczbę, lecz nie zdradza jej nam. Musimy ją w jak najmniejszej ilości prób odgadnąć. Za każdym razem, gdy podamy jakąś liczbę, program będzie nas nakierowywał, informując czy podana przez nas liczba jest większa, czy mniejsza od wylosowanej przez niego, a także będzie zliczał ilość naszych prób, zanim podamy właściwą odpowiedź.

Po odgadnięciu właściwej liczby program pogratuluje nam i poda informację, za którym razem udało się nam odgadnąć. Zakres stosowanych liczb ustalamy od 0 do 100, aby zabawa nie była zbyt łatwa.

Grę rozpoczynamy, naciskając przycisk „Zgadnij liczbę”. Po wpisaniu swojej liczby naciskamy przycisk „Sprawdź”, aby program ocenił naszą odpowiedź.

Potrzebne komponenty:

Button1 — przycisk „Zgadnij liczbę” (START)

Button2 — przycisk „Sprawdź”

Edit1 — pole edycyjne do wpisywania odpowiedzi

Label1 — etykieta do wyświetlania napisu „Ilość prób”

Label2 — etykieta do wyświetlania ilości prób

Powyższym komponentom nadajemy następujące nazwy, modyfikując właściwość Caption w Inspektorze Obiektów:

Komponent nazwa

Button1 Zgadnij liczbę

Button2 Sprawdź

Edit1 (kasujemy nazwę)

Label1 Ilość prób:

Label2 0

Oto interfejs programu i pełny kod zabawy:

Ilustracja 1: Program w trakcie działania

Kod programu

unit Unit1;

interface

uses

Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls;

type

TForm1 = class(TForm)

Button1: TButton;

Button2: TButton;

Edit1: TEdit;

Label1: TLabel;

Label2: Tlabel;

procedure Button1Click(Sender: TObject);

procedure Button2Click(Sender: TObject);

procedure Edit1KeyPress(Sender: TObject; var Key: Char);

private

{ Private declarations }

public

{ Public declarations }

end;

var

Form1: TForm1;

Liczba: Integer; //zmienna przechowująca liczbę do odgadnięcia

WYNIK: Integer; //zmienna przechowująca ilość prób

implementation

{$R *.dfm}

//pozwól na wpisywanie tylko liczb i Backpace w polu odpowiedzi

procedure TForm1.Edit1KeyPress(Sender: TObject; var Key: Char);

begin

if not (Key in [„0”. . „9”, #8]) then

begin

Key:=#0;

ShowMessage(„To nie jest liczba”); //wyświetl komunikat o błędzie

end;

end;

//gdy naciśniesz przycisk Zgadnij liczbę

procedure TForm1.Button1Click(Sender: TObject);

begin

Edit1.Clear; //wyczyść pole do podawania Odpowiedzi)

Randomize; //uruchom maszynę losującą

Liczba:=Random(101); //wylosuj liczbę do odgadnięcia z zakresu 0—100

Edit1.SetFocus; //ustaw focus w Polu do Odpowiedzi

end;

//gdy naciśniesz przycisk Sprawdź

procedure TForm1.Button2Click(Sender: TObject);

Label KONIEC; //Etykieta do przechodzenia w inne miejsca kodu

var

Odp: String; //zmienna przechowująca naszą odpowiedź

begin

Odp:= Edit1.Text; //odczytaj podaną odpowiedź i przypisz ją do zmiennej

if Odp=„” then //gdy nie podano odpowiedzi monituj o błędzie

begin

ShowMessage(„Wpisz najpierw wynik”); //wyświetl komunikat informujący

Edit1.SetFocus; //ustaw focus w Polu do Odpowiedzi

goto KONIEC; //pomiń poniższy kod i przejdź od razu na koniec procedury

end;

if StrToInt(Odp)>Liczba then //jeżeli Odpowiedź jest większa od liczby, to…

begin

ShowMessage(„Za dużo”); //wyświetl komunikat

WYNIK:= WYNIK +1; //dodaj punkt do ilości prób

end

else //a jeśli…

if StrToInt(Odp)<Liczba then //jeżeli Odpowiedź jest mniejsza od liczby, to…

begin

ShowMessage(„Za mało”); //wyświetl komunikat

WYNIK:= WYNIK +1; //dodaj punkt do ilości prób

end

else //w przeciwnym wypadku…

begin

ShowMessage(„To jest właśnie ta liczba. Gratuluję!”); //wyświetl komunikat

ShowMessage(„Potrzebowałeś na to ' + IntToStr(WYNIK) + ' prób”);

WYNIK:= 0; //wyzeruj licznik prób

end;

Edit1.Clear; //wyczyść pole edycyjne (Do podawania Odpowiedzi)

Edit1.SetFocus; //ustaw focus w Polu do Odpowiedzi

Label2.Caption:= IntToStr(WYNIK); //wyświetl ilość prób

KONIEC: //etykieta do której przechodzi kod, gdy ktoś nie wpisze żadnej liczby

end;

end.

Komentarz

1. Zmienne globalne i ograniczenia

Zmienne globalne zastosowane w tej zabawie niewiele różnią się od tych używanych w poprzednich. Pierwsza zmienna o nazwie „Liczba”, będzie przechowywać liczbę do odgadnięcia, a druga, o nazwie „WYNIK” będzie przechowywała ilość naszych prób, zanim odgadniemy właściwy wynik.

Procedura ograniczająca używanie klawiszy dla komponentu Edit jest taka sama, jak w poprzednich zabawach, więc komentarz do niej pominiemy.

2. Gdy naciśniesz przycisk Zgadnij liczbę

Edit1.Clear; //wyczyść pole do podawania Odpowiedzi)

Randomize; //uruchom maszynę losującą

Liczba:=Random(101); //wylosuj liczbę do odgadnięcia z zakresu 0—100

Edit1.SetFocus; //ustaw focus w Polu do Odpowiedzi

Po wyczyszczeniu pola edycyjnego uruchamiamy maszynę losującą, która losuje dla nas liczbę do odgadnięcia. Zgodnie z założeniem, ustalamy zakres liczb od 0 do 100. Przypominamy, że Delphi liczy od zera więc, aby liczba sto także była brana pod uwagę, musimy funkcji Random podać wartość 101 (Random(101)). Na koniec, tradycyjnie, ustawiamy kursor na polu edycyjnym, aby ułatwić sobie wpisywanie odpowiedzi.

3. Gdy naciśniesz przycisk Sprawdź

W pierwszej części procedury kod w ogóle nie zmienia się w stosunku do poprzednich zabaw, pomijamy więc komentarz.

Właściwa procedura sprawdzająca różni się znacznie od poprzednich rozwiązań, gdyż w tym przypadku program nie ma za zadanie tylko określić czy podana odpowiedź jest prawidłowa, ale dodatkowo musi nakierować gracza, czy podana przez niego liczba jest większa, czy mniejsza od liczby do odgadnięcia.

W bardziej zaawansowanym rozwiązaniu moglibyśmy także wprowadzić możliwość skonkretyzowania oceny: czy podana przez nas liczba jest dużo mniejsza (większa), czy tylko trochę. Wszystkie tego typu założenia realizujemy za pomocą instrukcji warunkowej if...then. Najpierw obliczamy wartość, o jak dużo pomyliliśmy się według metody Różnica = (Liczba do odgadnięcia) — (Podana przez nas liczba), a następnie konstruujemy podwójny warunek na przykład takiego typu:

if ([Podana przez nas liczba] > [Liczba do odgadnięcia]) and (Różnica > 10) then ShowMessage („O wiele za dużo”)

if ([Podana przez nas liczba] > [Liczba do odgadnięcia]) and (Różnica < 10) then ShowMessage („Trochę za dużo”)

W zabawie, którą tu przedstawiamy, ograniczyliśmy się do najprostszego przypadku, więc ocena naszej odpowiedzi jest bardzo prosta: Jeżeli podana przez nas liczba jest większa od liczby do odgadnięcia, to pokazany jest komunikat „Za dużo”:

if StrToInt(Odp)>Liczba then //jeżeli Odpowiedź jest większa od liczby, to…

begin

ShowMessage(„Za dużo”); //wyświetl komunikat

WYNIK:= WYNIK +1; //dodaj punkt do ilości prób

end

Jeżeli jest mniejsza, pokazany jest komunikat „Za mało”:

if StrToInt(Odp)<Liczba then //jeżeli Odpowiedź jest mniejsza od liczby, to…

begin

ShowMessage(„Za mało”); //wyświetl komunikat

WYNIK:= WYNIK +1; //dodaj punkt do ilości prób

end

W obu przypadkach nie odgadliśmy właściwego wyniku, więc zwiększamy o jeden licznik zliczający ilość naszych prób.

Poszczególne warunki procedury sprawdzającej łączymy za pomocą łącznika else, dlatego też dla ostatniego przypadku (czyli, gdy podaliśmy poprawny wynik) nie musimy pisać warunku sprawdzającego. Jest to oczywiste działanie, jeżeli przetłumaczymy ową procedurę na język ludzki: „Jeżeli podana przez nas liczba nie jest ani większa, ani mniejsza od liczby do odgadnięcia, wtedy musi być ona równa liczbie do odgadnięcia”.

W przypadku, gdy trafimy na właściwą odpowiedź, program podaje pierwszy komunikat, w którym gratuluje nam odgadnięcia wyniku, a po nim wyświetla drugi komunikat, w którym informuje nas, ile prób potrzebowaliśmy na dotarcie do właściwej odpowiedzi. Informację tę pobiera za zmiennej globalnej WYNIK:

ShowMessage(„To jest właśnie ta liczba. Gratuluję!”); //wyświetl komunikat

ShowMessage(„Potrzebowałeś na to ' + IntToStr(WYNIK) + ' prób”);

WYNIK:= 0; //wyzeruj licznik prób

Z uwagi na to, że próba zakończyła się sukcesem, po wyświetleniu komunikatów, zerujemy licznik zliczający ilość naszych prób i, po naciśnięciu przycisku „Zgadnij liczbę”, możemy bawić się dalej, odgadując kolejną liczbę.

Dalsza część kodu jest standardowa w naszych rozwiązaniach, wielokrotnie ją już stosowaliśmy i komentowaliśmy, więc nie będziemy się w komentarzu powtarzać.

Kto bliżej

Założenia i opis programu:

Zabawa przeznaczona jest dla dwóch uczestników, przy czym jednym z nich będzie sam program. Polega ona na podaniu liczby z zakresu od 0 do 50 i sprawdzeniu, który z graczy był bliżej liczby bazowej wylosowanej przed grą.

Zabawa rozpoczyna się z chwilą wpisania przez nas liczby w pole edycyjne i naciśnięciu przycisku „Potwierdź”. W tym momencie program wybiera dla siebie liczbę, a następnie drogą losową wybiera liczbę bazową. Teraz następuje ocena wyników. Program sprawdza, która z podanych liczb (nasza czy jego) była bliżej liczby bazowej. Kto był bliższej, ten wygrywa.

Wprowadzamy także tabelę wyników. W zależności od naszej woli, będzie ona wyświetlać albo ilość naszych poprawnych i niepoprawnych odpowiedzi, albo ilość punktów naszych i programu przyznanych za poprawną odpowiedź. W obu przypadkach kod procedury będzie ten sam, różnica będzie jedynie w nazwaniu etykiet Label 5 i 6.

Chcąc uzyskać niezawodność programu, musimy obwarować go kilkoma warunkami zabezpieczającymi. Z uwagi na to, że to gracz rozpoczyna zabawę, musimy zadbać o incydentalne przypadki, w których ktoś zamiast liczby wpisze literę lub inny znak nieliczbowy. Kolejny błąd programu może zostać wywołany sytuacją, w której ktoś naciśnie przycisk „Potwierdź” bez wpisania uprzednio liczby. Oba zabezpieczenia znamy już z poprzednich projektów, więc nie jest to dla nas żadna nowość. W tym jednak projekcie musimy jeszcze wprowadzić nadzór nad wpisywanymi liczbami przez gracza. Zabawę bowiem ograniczyliśmy do zakresu liczb od 0 do 50, a jeżeli komuś pomyli się i będzie myślał, że zakres ten wynosi od 0 do 100? Wtedy rzadko kiedy wygra, ponieważ pomiędzy jego liczbą a liczbą bazową będzie zbyt duża odległość. Musimy zatem ostrzec gracza o jego pomyłce, stąd też wprowadzamy te trzecie zabezpieczenie.

Potrzebne komponenty:

Będziemy potrzebować następujących komponentów:

Button1 — przycisk rozpoczynający zabawę,

Edit1 — pole edycyjne do wpisywania odpowiedzi,

Label1 — etykieta wyświetlająca napis „Podaj swoją liczbę”,

Label2 — etykieta wyświetlająca napis Liczba programu,

Label3 — etykieta wyświetlająca liczbę programu,

Label4 — etykieta wyświetlająca napis „Wyniki”,

Label5 — etykieta wyświetlająca napis „Poprawne”,

Label6 — etykieta wyświetlająca napis „Niepoprawne”,

Label7 — etykieta wyświetlająca ilość poprawnych odpowiedzi,

Label8 — etykieta wyświetlająca ilość niepoprawnych odpowiedzi,

Label9 — etykieta wyświetlająca napis „Liczba bazowa”,

Label10 — etykieta wyświetlająca liczbę bazową.

Poszczególnym komponentom nadajemy następujące nazwy:

komponent nazwa

Button1 Potwierdź

Edit1 (kasujemy nazwę)

Label1 Podaj swoją liczbę

Label2 Liczba Programu:

Label3 0

Label4 Wyniki

Label5 Poprawne:

Label6 Niepoprawne:

Label7 0

Label8 0

Label9 Liczba bazowa:

Label10 0

Interfejs programu przedstawiamy poniżej:

Kod programu

unit Unit1;

interface

uses

Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls;

type

TForm1 = class(TForm)

Button1: TButton;

Edit1: TEdit;

Label1: TLabel;

Label2: TLabel;

Label3: TLabel;

Label4: TLabel;

Label5: TLabel;

Label6: TLabel;

Label7: TLabel;

Label8: TLabel;

Label9: TLabel;

Label10: Tlabel;

procedure FormCreate(Sender: TObject);

procedure Button1Click(Sender: TObject);

procedure Edit1KeyPress(Sender: TObject; var Key: Char);

private

{ Private declarations }

public

{ Public declarations }

end;

var

Form1: TForm1;

Poprawne: Integer; //zmienna przechowująca ilość naszych wygranych

Niepoprawne: Integer; //zmienna przechowująca ilość wygranych programu

implementation

{$R *.dfm}

//wyzeruj wyniki przy uruchomieniu programu

procedure TForm1.FormCreate(Sender: TObject);

begin

Poprawne:=0; //wyzeruj ilość poprawnych odpowiedzi

Niepoprawne:=0; //wyzeruj ilość niepoprawnych odpowiedzi

end;

//pozwól na wpisywanie tylko liczb i użycie klawisza Backpace w polu odpowiedzi

procedure TForm1.Edit1KeyPress(Sender: TObject; var Key: Char);

begin

if not (Key in [„0”. . „9”, #8]) then

begin

Key:=#0;

ShowMessage(„To nie jest liczba”); //wyświetl komunikat o błędzie

end;

end;

//gdy naciśniesz przycisk Potwierdź

procedure TForm1.Button1Click(Sender: TObject);

Label KONIEC; //Etykieta do przechodzenia w inne miejsca kodu

var

Odp: String; //zmienna przechowująca naszą liczbę

Liczba: Integer; //zmienna przechowująca liczbę programu

Baza: Integer; //zmienna przechowująca liczbę bazową

Roznica_moja: Integer; //zmienna przechowująca różnicę moją do liczby bazowej

Roznica_programu: Integer; //zmienna przechowująca różnicę Programu do liczby bazowej

begin

Odp:= Edit1.Text; //odczytaj moją liczbę i przypisz ją do zmiennej

if Length(Edit1.Text)=0 then //gdy nie podano liczby monituj o jej wpisaniu

begin

ShowMessage(„Wpisz najpierw liczbę”); //wyświetl komunikat

Edit1.SetFocus; //ustaw focus w Polu do Odpowiedzi

goto KONIEC; //pomiń poniższy kod i przejdź od razu na koniec procedury

end;

if StrToInt(Odp)>50 then //monituj gdy przekroczono zakres liczb

begin

ShowMessage(„Liczba musi być z zakresu 0—50”); //wyświetl komunikat

Edit1.SetFocus; //ustaw focus w Polu do Odpowiedzi

goto KONIEC; //pomiń poniższy kod i przejdź od razu na koniec procedury

end;

Randomize;

Liczba:= Random(51); //wylosuj liczbę Programu

Baza:= Random(51); //wylosuj liczbę bazową

Label3.Caption:=IntToStr(Liczba); //wyświetl liczbę Programu

Label3.Update; //uaktualnij etykietę Label3

sleep(1000); //czekaj 1 sekundę

Label10.Caption:=IntToStr(Baza); //wyświetl liczbę bazową

//oceń wyniki

if (Baza>Liczba) or (Baza=Liczba) then

Roznica_programu:= Baza-Liczba //oblicz różnicę dla Programu

else

Roznica_programu:= Liczba-Baza; //oblicz różnicę dla Programu

if (Baza>StrToInt(Odp)) or (Baza=StrToInt(Odp)) then

Roznica_moja:= Baza-StrToInt(Odp) //oblicz różnicę dla mnie

else

Roznica_moja:= StrToInt(Odp) -Baza; //oblicz różnicę dla mnie

if Roznica_programu<Roznica_moja then //gdy liczba Programu jest bliższa liczbie bazowej od mojej

begin

ShowMessagePos(„Przegrałeś”, 285,280); //pokaż komunikat w miejscu o tych współrzędnych

Niepoprawne:=Niepoprawne+1; //zwiększ licznik Programu o 1

end //brak średnika

else //w przeciwnym wypadku…

if Roznica_programu>Roznica_moja then

begin

ShowMessagePos(„Wygrałeś”, 285,280); //pokaż komunikat w miejscu o tych współrzędnych

Poprawne:=Poprawne+1; //zwiększ mój licznik o 1

end

else //w przeciwnym wypadku…

if Roznica_programu=Roznica_moja then

begin

ShowMessagePos(„Jest remis”, 285,280); //pokaż komunikat w miejscu o tych współrzędnych

Poprawne:=Poprawne+1; //zwiększ mój licznik o 1

Niepoprawne:=Niepoprawne+1; //zwiększ licznik Programu o 1

end;

Edit1.Clear; //wyczyść pole do podawania Odpowiedzi

Edit1.SetFocus; //ustaw focus w Polu do Odpowiedzi

Label3.Caption:=„x”; //wyświetl znak „x” zamiast liczby Programu

Label10.Caption:=„x”; //wyświetl znak „x” zamiast liczby bazowej

Label7.Caption:= IntToStr(Poprawne); //wyświetl ilość poprawnych odpowiedzi

Label8.Caption:= IntToStr(Niepoprawne); //wyświetl ilość niepoprawnych odpowiedzi

KONIEC: //etykieta do której przechodzi kod, gdy ktoś nie wpisze żadnej liczby

end;

end.

Komentarz

1. Gdy naciśniesz przycisk „Potwierdź”

Label KONIEC; //Etykieta do przechodzenia w inne miejsca kodu

var

Odp: String; //zmienna przechowująca naszą liczbę

Liczba: Integer; //zmienna przechowująca liczbę programu

Baza: Integer; //zmienna przechowująca liczbę bazową

Roznica_moja: Integer; //zmienna przechowująca różnicę moją do liczby bazowej

Roznica_programu: Integer; //zmienna przechowująca różnicę Programu do liczby

Program nasz nie korzysta z procedur, które pobierają informacje z innych miejsc, więc wszystkie potrzebne zmienne deklarujemy jako zmienne lokalne. Komentarze przypisane do nich mówią same za siebie.

if StrToInt(Odp)>50 then //monituj gdy przekroczono zakres liczb

begin

ShowMessage(„Liczba musi być z zakresu 0—50”); //wyświetl komunikat

Edit1.SetFocus; //ustaw focus w Polu do Odpowiedzi

goto KONIEC; //pomiń poniższy kod i przejdź od razu na koniec procedury

end;

Powyższy warunek-zabezpieczenie informuje nas o sytuacji, w której wpiszemy liczbę większą od ustalonego zakresu, czyli powyżej pięćdziesięciu. Warunek ten nie pozwoli takiej liczby w ogóle wpisać w pole edycyjne. Jak widzimy, konstrukcja tego zabezpieczenia jest identyczna (poza treścią komunikatu) z poprzednią, wykorzystaną w sytuacji, gdy ktoś nic nie wpisze, a pomimo tego naciśnie przycisk „Potwierdź”.

Powyższe, dobrze znane nam zabezpieczenie, przedstawiamy tu w innej formie, aby pokazać nowe rozwiązanie oraz aby uświadomić młodym programistom, że często istnieje kilka równorzędnych rozwiązań danego polecenia.

Dotychczas stosowany przez nas warunek był następujący: if Odp=„” then

Tłumaczymy go następująco: Jeżeli zmienna „Odp” jest pustym ciągiem (czyli nie zawiera znaków), to wtedy…

Nowe rozwiązanie, jakie teraz zastosowaliśmy, czyli: if length(Edit1.Text)=0 then, mówi o tym samym, tylko inaczej: Jeżeli długość znaków wpisanych w pole edycyjne Edit1 równa jest zeru (innymi słowy, gdy nie ma ani jednego znaku), wtedy…

Którekolwiek z tych rozwiązań nie zastosujemy, uzyskamy ten sam efekt. Wybór należy do nas. Zazwyczaj stosuje się jednak pierwsze rozwiązanie, jako krótsze i bardziej czytelne (intuicyjne).

Label3.Caption:=IntToStr(Liczba); //wyświetl liczbę Programu

Label3.Update; //uaktualnij etykietę Label3

sleep(1000); //czekaj 1 sekundę

Label10.Caption:=IntToStr(Baza); //wyświetl liczbę bazową

Powyższą konstrukcję także już znamy. Wyświetla ona zaktualizowane napisy na etykietach. Gdybyśmy chcieli wyświetlić Liczbę Programu i liczbę bazową jednocześnie, wtedy polecenie Label3.Update nie byłoby potrzebne. My jednak chcemy uatrakcyjnić nasz program, aby najpierw wyświetlił liczbę Programu, a po sekundzie (sleep(1000)) liczbę bazową. W takim przypadku musimy już zastosować uaktualnienie komponentu Label.

Aby ocenić wyniki, musimy najpierw stwierdzić, jaka różnica dzieli liczbę wybraną przez nas od liczby bazowej oraz, jaka jest ta różnica w przypadku liczby podanej przez Program. Teoretycznie wydaje się to być proste: Wystarczy od większej liczby odjąć mniejszą, ale nie możemy zrobić tego tak prosto, na przykład od liczby bazowej odjąć naszą liczbę, ponieważ jeżeli nasza liczba będzie od niej większa, wynik będzie ujemny! Musimy tę okoliczność uwzględnić, budując warunek sprawdzający:

if (Baza>Liczba) or (Baza=Liczba) then

Roznica_programu:= Baza-Liczba //oblicz różnicę dla Programu

else

Roznica_programu:= Liczba-Baza; //oblicz różnicę dla Programu

Odczytujemy go następująco: Jeżeli liczba bazowa jest większa lub równa liczbie Programu, wtedy do zmiennej „Roznica_programu” przypisz wynik odejmowania: Liczba bazowa — Liczba Programu, w przeciwnym wypadku (czyli, gdy Liczba bazowa jest mniejsza od Liczby Programu) przypisz wynik odejmowania Liczba Programu — Liczba bazowa.

W oto prosty sposób rozwiązaliśmy problem z liczbami ujemnymi. Dopiero teraz możemy porównać oba wyniki, gdyż oba przedstawiają rzeczywistą odległość od liczby bazowej.

To samo rozwiązanie stosujemy oczywiście do określenia odległości od liczby bazowej naszej liczby. Jako że jest ona pobrana z pola edycyjnego, posiada typ string; przed obliczeniem różnicy należy więc zastosować konwersję typów (StrToInt), aby była traktowana jako liczba.

Mając już obliczone odległości od liczby bazowej, możemy przystąpić do właściwej oceny, kto w końcu wygrał. W tym celu stosujemy zwykłe porównanie obu różnic. Czyja różnica będzie mniejsza, ten wygrał, bo świadczy ona o tym, że liczba znajdowała się bliżej liczby bazowej.

Całą procedurę sprawdzającą ujmujemy w obrębie instrukcji warunkowej, która po ocenie wyników, wyświetli odpowiedni komunikat i przyzna punkty za wygraną:

if Roznica_programu<Roznica_moja then //gdy liczba Programu jest bliższa liczbie bazowej od mojej

begin

ShowMessagePos(„Przegrałeś”, 285,280); //pokaż komunikat

Niepoprawne:=Niepoprawne+1; //zwiększ licznik Programu o 1

end //brak średnika

else //w przeciwnym wypadku…

if Roznica_programu>Roznica_moja then

begin

ShowMessagePos(„Wygrałeś”, 285,280); //pokaż komunikat

Poprawne:=Poprawne+1; //zwiększ mój licznik o 1

end

Nie zapominamy oczywiście o przypadku, że zarówno my, jak i Program możemy mieć taką samą różnicę. Będziemy mieli wtedy do czynienia z remisem, a więc punkt za zwycięstwo będzie należał się obu graczom.

if Roznica_programu=Roznica_moja then

begin

ShowMessagePos(„Jest remis”, 285,280); //pokaż komunikat

Poprawne:=Poprawne+1; //zwiększ mój licznik o 1

Niepoprawne:=Niepoprawne+1; //zwiększ licznik Programu o 1

end;

W instrukcjach powyższych stosujemy rozszerzoną wersję komunikatu ShowMessage, która umożliwia wyświetlanie komunikatu w konkretnym miejscu na ekranie. Uczyniliśmy to po to, aby wyświetlający się komunikat nie przesłaniał liczb biorących udział w grze, czyli naszej, Programu i liczby bazowej.

Konstrukcja komunikatu ShowMessagePos jest prosta: po zawarciu w apostrofach treści do wyświetlenia, po przecinku podajemy dwie współrzędne, które określają miejsce wyświetlenia komunikatu. Należy pamiętać o tym, że obie współrzędne podają punkt względem granic programu, a nie monitora. Jak należy odczytywać owe współrzędne? Bardzo prosto. Rozmiar komunikatu posiada standardową wielkość, w razie potrzeby (wynikającej z długości tekstu do wyświetlenia) tylko automatycznie rozszerzaną, nie ma więc potrzeby deklarować 4x2 współrzędne dla wszystkich czterech rogów okna komunikatu. Wystarczy podać tylko współrzędne lewego górnego rogu, a cały komunikat automatycznie wyświetli się ze swoim oknem. Podział współrzędnych jest klasyczny, czyli x,y: pierwsza współrzędna podaje odległość od lewego boku programu, a druga, od górnego boku.

Współrzędne wyświetlającego się okna należy tak dobrać, aby tworzyło estetyczną całość z interfejsem programu i, aby nie przesłaniało liczb biorących udział w zabawie.

Po zamknięciu okna komunikatu następuje usunięcie tych liczb: pole edycyjne jest czyszczone, a w miejsce liczby Programu i liczby bazowej, zostaje wyświetlony znak „x”:

Label3.Caption:=„x”; //wyświetl znak „x” zamiast liczby Programu

Label10.Caption:=„x”; //wyświetl znak „x” zamiast liczby bazowej

Parzysta-nieparzysta

Następna zabawa, jaką prezentujemy, opiera się na rachunku prawdopodobieństwa. Program losuje liczbę, a my mamy odgadnąć, czy jest ona liczbą parzystą, czy nieparzystą. Teoretycznie (statystycznie) przy większej liczbie prób, wynik udzielonych poprawnie odpowiedzi, powinien kształtować się na poziomie 50%. Jeżeli więc uparcie będziemy trzymali się tylko jednej odpowiedzi, na przykład „parzyste”, to po kilkunastu próbach nasz wynik poprawnych odpowiedzi powinien uplasować się mniej więcej na tym poziomie. Przekonamy się jednak, że wykorzystując nasz rozum i intuicję, możemy ten wynik podnieść o kilkadziesiąt procent na naszą korzyść.

Założenia i opis programu:

Po naciśnięciu przycisku START program losuje liczbę z zakresu od 1 do 100 i zadaje nam pytanie, czy uważamy, że wylosowana liczba jest liczbą parzystą. Do udzielenia odpowiedzi będziemy mieli dwa przyciski do wyboru: Tak i Nie. Po naciśnięciu któregoś z nich program dokona oceny naszej odpowiedzi i poinformuje o wyniku stosownym komunikatem, dodając standardowo jeden punkt do tabeli wyników, albo do odpowiedzi poprawnych, albo do odpowiedzi niepoprawnych.

Po ocenie odpowiedzi, program obliczy ogólną wartość procentową poprawnych odpowiedzi i wyświetli ją w miejscu ukazującym nasz procentowy wynik. Jako uzupełnienie sprawimy, aby program wyświetlał także wylosowaną liczbę, abyśmy sami mogli przekonać się, czy dobrze odpowiedzieliśmy.

Nie zabraknie w naszej zabawie także tradycyjnej tabelki z wynikami, ile udzieliliśmy poprawnych, a ile niepoprawnych odpowiedzi.

Potrzebne komponenty:

Button1 — przycisk START

Label1 — etykieta wyświetlająca napis „Wyniki”,

Label2 — etykieta wyświetlająca napis „Poprawne”,

Label3 — etykieta wyświetlająca napis „Niepoprawne”,

Label4 — etykieta wyświetlająca ilość poprawnych odpowiedzi,

Label5 — etykieta wyświetlająca ilość niepoprawnych odpowiedzi,

Label6 — etykieta wyświetlająca napis „Wyniki”,

Label7 — etykieta wyświetlająca wylosowaną liczbę,

Label8 — etykieta wyświetlająca napis „Procent poprawnych odpowiedzi”,

Label9 — etykieta wyświetlająca Procent poprawnych odpowiedzi.

Poszczególnym komponentom nadajemy następujące nazwy, zmieniając ich właściwość Caption w Inspektorze Obiektów:

Komponent nazwa

Button1 START

Label1 Wyniki

Label2 Poprawne:

Label3 Niepoprawne:

Label4 0

Label5 0

Label6 Wylosowana liczba:

Label7 0

Label8 Procent poprawnych odpowiedzi:

Label9 0

Przy pomocy Inspektora Obiektów zmieniamy właściwości nazw, a więc na przykład wielkość czcionki i styl. Aby uatrakcyjnić wygląd programu, dla komponentów Label7 i Label9 ustalamy dużą czcionkę (powiedzmy 40 pkt) według własnego uznania. Cały interfejs programu może przybrać następujący wygląd:

Program w trakcie działania

Kod programu

unit Unit1;

interface

uses

Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls;

type

TForm1 = class(TForm)

Button1: TButton;

Label1: TLabel;

Label2: TLabel;

Label3: TLabel;

Label4: TLabel;

Label5: TLabel;

Label6: TLabel;

Label7: TLabel;

Label8: TLabel;

Label9: Tlabel;

procedure Button1Click(Sender: TObject);

procedure FormCreate(Sender: Tobject);

private

{ Private declarations }

public

{ Public declarations }

end;

var

Form1: TForm1;

Poprawne: Integer; //zmienna przechowująca ilość poprawnych odpowiedzi

Niepoprawne: Integer; //zmienna przechowująca ilość niepoprawnych odpowiedzi

implementation

{$R *.dfm}

//wyzeruj liczniki przy uruchomieniu programu

procedure TForm1.FormCreate(Sender: TObject);

begin

Poprawne:=0; //wyzeruj licznik

Niepoprawne:=0; //wyzeruj licznik

end;

//gdy naciśniesz przycisk START

procedure TForm1.Button1Click(Sender: TObject);

var

Liczba: Integer; //zmienna do losowania liczby

Results: Integer; //zmienna przechowująca informację który przycisk został naciśnięty w komunikacie

Procent: Integer; //zmienna przechowująca procent poprawnych odpowiedzi

begin

Randomize; //uruchom maszynę losującą

Liczba:=Random(101)+1; //wylosuj liczbę z zakresu 1—100

Results:=MessageBox(0,„Czy będzie liczba parzysta?”, „Pytanie”, MB_YESNO);

if Results=ID_YES then //jeżeli wybierzesz liczbę parzystą wtedy…

begin

if not Odd(Liczba) then //jeżeli liczba jest parzysta wtedy…

begin

ShowMessage(„Zgadłeś! Gratuluję!”); //pokaż komunikat

Poprawne:=Poprawne+1; //zwiększ licznik poprawnych odpowiedzi o 1

Procent:=(Poprawne*100)div(Poprawne+Niepoprawne);

//oblicz procent prawidłowych odpowiedzi

end //bez średnika

else //…a jeżeli jest to liczba nieparzysta to…

begin

ShowMessage(„Niestety źle”); //pokaż komunikat

Niepoprawne:=Niepoprawne+1; //zwiększ licznik niepoprawnych odpowiedzi o 1

Procent:=(Poprawne*100)div(Poprawne+Niepoprawne);

//oblicz procent prawidłowych odpowiedzi

end;

end;

if Results=ID_NO then //jeżeli wybierzesz liczbę nieparzystą wtedy…

begin

if Odd(Liczba) then //jeżeli liczba jest nieparzysta wtedy…

begin

ShowMessage(„Zgadłeś! Gratuluję!”);

Poprawne:=Poprawne+1;

Procent:=(Poprawne*100)div(Poprawne+Niepoprawne);

//oblicz procent prawidłowych odpowiedzi

end //bez średnika

else //…a jeżeli jest to liczba parzysta to…

begin

ShowMessage(„Niestety źle”);

Niepoprawne:=Niepoprawne+1;

Procent:=(Poprawne*100)div(Poprawne+Niepoprawne);

//oblicz procent prawidłowych odpowiedzi

end;

end;

Label7.Caption:=IntToStr(Liczba); //wyświetl wylosowaną liczbę

Label9.Caption:=IntToStr(Procent); //wyświetl procent poprawnych odpowiedzi

Label4.Caption:= IntToStr(Poprawne); //wyświetl ilość poprawnych odpowiedzi

Label5.Caption:= IntToStr(Niepoprawne); //wyświetl ilość niepoprawnych odpowiedzi

end;

end.

Komentarz

1. Procedura Form Create

Jak już wspominaliśmy w opisie zabawy „Policz, Ile to jest”, procedura ta wykonywana jest przy uruchamianiu programu. Zawrzemy w niej polecenie, aby program ustawił wartość zmiennych Poprawne i Niepoprawne jako zero. Jest to konieczne, aby program zliczający nasze odpowiedzi wiedział, jaki jest stan początkowy tych zmiennych. Bez tej informacji może podliczać błędnie.

Zerowania obu zmiennych nie możemy zawrzeć w procedurze START, ponieważ za każdym razem, gdy naciśniemy ten przycisk, program kasowałby nasz poprzedni wynik, a chodzi nam przecież o to, aby nasze poprzednie wyniki pamiętał i aktualizował.

2. Gdy naciśniesz przycisk START

var

Liczba: Integer; //zmienna do losowania liczby

Results: Integer; //zmienna przechowująca informację który przycisk został naciśnięty w komunikacie

Procent: Integer; //zmienna przechowująca procent poprawnych odpowiedzi

Zanim napiszemy kod naszej procedury, musimy najpierw zadeklarować zmienne lokalne, z których kod ten będzie korzystał.

Poza znaną nam już zmienną do przechowywania wyniku (w tym przypadku o nazwie Liczba), deklarujemy jeszcze jedną zmienną tego typu, do przechowywania informacji, ile procent poprawnych odpowiedzi uzyskaliśmy. Zupełną nowością jest zmienna Results, nomen omen, także typu liczbowego, czyli integer. Jest ona powiązana z komunikatem MessageBox i służy do przechowywania informacji, który z jego przycisków został naciśnięty (Tak czy Nie). Musi być ona typu integer, gdyż w tej formie komunikat MessageBox zwraca informację, jaki przycisk został naciśnięty. W formie, w jakiej my użyliśmy składni, nie wynika to jawnie, gdyż zamiast kolejnych liczb, wybraliśmy ich tekstowe odpowiedniki (ID_YES, ID_NO), aby kod był bardziej intuicyjny i czytelny.

Procedurę inicjującą zabawę rozpoczynamy od uruchomienia maszyny losującej, która wylosuje liczbę z przedziału od 1 do 100:

Randomize; //uruchom maszynę losującą

Liczba:=Random(101)+1; //wylosuj liczbę z zakresu 1—100

Z uwagi na to, iż liczba zero nie jest liczbą parzystą ani nieparzystą, więc eliminujemy jej występowanie, dodając czynnik „+1”: Nawet jeżeli zostanie wylosowane zero, to i tak zostanie ono powiększone o jeden, zatem do zmiennej Liczba nigdy ono nie trafi.

MessageBox

Po wylosowaniu liczby, na podstawie której program oceni, czy wypadła liczba parzysta, czy nieparzysta, zostanie wyświetlony komunikat o treści „Czy będzie liczba parzysta?”. Aby ułatwić sobie zadanie, zastosujemy tu inny typ komunikatu:

Results:=MessageBox(0,„Czy będzie liczba parzysta?”, „Pytanie”, MB_YESNO);

Do tej pory używaliśmy najprostszej jego wersji, czyli ShowMessage. Jego jedynym zadaniem było wyświetlanie informacji i wyłączenie się po naciśnięciu przycisku OK. Teraz użyliśmy komunikatu typu MessageBox. Jest on już bardziej rozbudowany. Potrafi podać nie tylko informację, ale także odpowiednio zareagować, w zależności od tego, który przycisk się naciśnie. W naszym przykładzie wykorzystamy akurat dwa przyciski: Tak i Nie, ale możemy umieścić także inne: Anuluj, Ponów próbę, Zakończ itd. Możemy także umieścić odpowiednie ikonki dobrze nam znane z komunikatów wyświetlanych przez system operacyjny. Są one takie same, gdyż przecież Delphi korzysta z tych samych zasobów, co system Windows. Te i inne jeszcze właściwości komunikatu programista sam wybiera, w zależności od jego potrzeb i oczekiwań.

Do obsługi komunikatu MessageBox wykorzystamy znaną nam instrukcję warunkową if...then. Cały przedstawiony na początku kod, nieco rozbudowany, możemy ująć w następujący schemat:

— Wyświetl komunikat MessageBox (Results:=MessageBox)

— Jeżeli naciśnięto przycisk Tak (if Results:=ID_YES) to wtedy (then) wykonaj następujące instrukcje (begin… end)

— Jeżeli naciśnięto przycisk Nie (if Results:=ID_NO) to wtedy (then) wykonaj następujące instrukcje (begin… end)

Instrukcje do wykonania w obu przypadkach są podobne. Nie jest to przypadkowe podobieństwo, przecież i w jednym i drugim przypadku sprawdzamy, czy udzielona przez nas odpowiedź odpowiada prawdzie: Jeżeli odpowiada, to wyświetlony zostaje komunikat ShowMessage o poprawności wyniku, zwiększamy ilość poprawnych odpowiedzi o jeden i obliczamy procent poprawnie udzielonych odpowiedzi; jeżeli nie odpowiada (else), to wtedy podobnie: wyświetlamy odpowiedni komunikat, zwiększamy ilość niepoprawnych wyników i obliczamy procent poprawnie udzielonych odpowiedzi, bo ten zmieni się, gdy udzielimy złą odpowiedź. Oto zbiór instrukcji obsługujących przycisk „Tak”:

if Results=ID_YES then //jeżeli wybierzesz liczbę parzystą wtedy…

begin

if not Odd(Liczba) then //jeżeli liczba jest parzysta wtedy…

begin

ShowMessage(„Zgadłeś! Gratuluję!”); //pokaż komunikat

Poprawne:=Poprawne+1; //zwiększ licznik poprawnych odpowiedzi o 1

Procent:=(Poprawne*100)div(Poprawne+Niepoprawne);

//oblicz procent prawidłowych odpowiedzi

end //bez średnika

else //…a jeżeli jest to liczba nieparzysta to…

begin

ShowMessage(„Niestety źle”); //pokaż komunikat

Niepoprawne:=Niepoprawne+1; //zwiększ licznik niepoprawnych

odpowiedzi o 1

Procent:=(Poprawne*100)div(Poprawne+Niepoprawne);

//oblicz procent prawidłowych odpowiedzi

end;

end;

Podobny schemat instrukcji zastosujemy do obsługi przycisku „Nie”. Zmienimy tylko warunek: W pierwszym porównywaliśmy, czy liczba jest parzysta (if not Odd(Liczba)), w tym — czy liczba jest nieparzysta (if Odd(Liczba)).

Uwagę poświećmy jeszcze poleceniu obliczającemu procent poprawnie udzielonych odpowiedzi: Procent:=(Poprawne*100)div(Poprawne+Niepoprawne);

Powyższy zapis to nic innego jak końcowe działanie matematyczne obliczające procent z danego zbioru. Zbiorem tym jest ogólna liczba wszystkich udzielonych odpowiedzi, poprawnych i niepoprawnych. Rozpisując owe działanie krok po kroku mamy następujące działania:

(Poprawne + Niepoprawne) = 100%

Poprawne = Procent do obliczenia

Z obu warunków (mnożąc po skosie) otrzymujemy równanie:

(Poprawne + Niepoprawne) x Procent = Poprawne x 100,

a stąd (po podzieleniu obu stron sumą Poprawnych i Niepoprawnych):

Procent do obliczenia = (Poprawne x 100)\(Poprawne + Niepoprawne)

Zamieniając teraz mnożenie i dzielenie (kreska ułamkowa) na znaki używane przez Delphi, czyli odpowiednio: gwiazdka (*) i słowo „div” oraz zapisując działanie w jednej linii, otrzymujemy właśnie polecenie: Procent:= (Poprawne*100) div (Poprawne+Niepoprawne);

Po ocenie naszej odpowiedzi następuje zaktualizowanie wyświetlanych informacji:

Label7.Caption:=IntToStr(Liczba); //wyświetl wylosowaną liczbę

Label9.Caption:=IntToStr(Procent); //wyświetl procent poprawnych odpowiedzi

Label4.Caption:= IntToStr(Poprawne); //wyświetl ilość poprawnych odpowiedzi

Label5.Caption:= IntToStr(Niepoprawne); //wyświetl ilość niepoprawnych odpowiedzi

W pierwszej kolejności wyświetlamy na etykiecie Label7 wylosowaną liczbę, na potwierdzenie słuszności oceny programu. Aktualizujemy także procent udzielonych poprawnie odpowiedzi, wyświetlając zawartość zmiennej Procent na etykiecie Label9. Na koniec, standardowo, podajemy aktualne wartości w tabeli wyników, ile udzieliliśmy odpowiedzi poprawnych, a ile niepoprawnych.

Na zakończenie zaznaczmy jeszcze tylko, że obsługę naszej zabawy nie musimy koniecznie powierzać rozwiązaniu opartemu na komunikacie MessageBox. Równie dobrze sprawdziłyby się dotychczasowe rozwiązania, jakie już poznaliśmy. Zamiast wyświetlać komunikat MessageBox z jego przyciskami „Tak” i „Nie”, moglibyśmy wyświetlić zapytanie na etykiecie lub zwykłym komunikacie ShowMessage, a do odpowiedzi „Tak” lub „Nie” posłużyłyby nam dwa przyciski (komponent Button), do których przypisalibyśmy kod, który powyżej wykorzystaliśmy do obsługi przycisków komunikatu. Jest to tylko kwestia wyboru programisty. W obu przypadkach program będzie działał tak samo.

Gra w kości

Oto kolejna gra dla dwóch użytkowników: nas i komputera. Nazwa gry wyjaśnia wszystko: jest to typowa gra w kości. Polega ona na rzucaniu przez graczy kostką do gry. Kto uzyska większą ilość oczek, ten wygrywa.

Założenia i opis zabawy:

W prezentowanej przez nas grze naszym przeciwnikiem jest komputer. Nie może więc on fizycznie rzucać kostką jak my. Musimy zatem sprawić, aby „rzucał” kostką w inny sposób. Najprostszym i najsensowniejszym rozwiązaniem będzie, gdy po prostu wylosuje jakąś liczbę z zakresu 1—6 i poda ją. Zobrazowanie tego możemy zrobić na kilka sposobów. My wybraliśmy metodę graficzną, aby gra była bardziej atrakcyjna. Program losuje swoją liczbę, a następnie wyświetla obrazek kostki do gry z odpowiadającą jej liczbą oczek.

Kolejne rozwiązanie, jakie będziemy chcieli użyć, to możliwość animacji obrazka wyświetlającego kostkę do gry. Chcemy, aby przed podaniem liczby oczek Programu, obrazek kostki zmieniał się, imitując kręcącą się kostkę, a dopiero po chwili wyświetlał właściwą ilość oczek. Do zrealizowania tego celu możemy użyć różnych rozwiązań, chociażby z użyciem formatu gif. My postanowiliśmy pójść inną drogą i będziemy w szybko zmieniającej się sekwencji pokazywać kolejne obrazki z odpowiadającymi im liczbą oczek. Po zakończeniu sekwencji chcemy, aby przez moment ukazał się obrazek startowy, a następnie, aby w jego miejsce ukazał się obrazek kostki do gry z wylosowaną przez program liczbą oczek.

Wprowadzamy jeszcze jedno założenie: chcemy, aby program wyświetlał swoje komunikaty w takim miejscu, aby nie przesłaniały one obrazka, ani naszej liczby. Założenie to zrealizujemy za pomocą metody ShowMessagePos, czyli nieco bardziej rozbudowanej wersji komunikatu ShowMessage.

Zasada działania programu jest bardzo prosta. Najpierw my rzucamy kostką i w pole edycyjne Edit1 wpisujemy uzyskaną liczbę oczek, a następnie klikamy na przycisk „Potwierdź”. Po jego naciśnięciu następuje wyświetlenie sekwencji obrazków imitującej kręcenie się kostki, a następnie wyświetlany jest obrazek z wylosowaną przez program jego liczbą oczek. Teraz następuje porównanie obu wyników i przyznanie punktacji za zwycięstwo. Punkty są podliczane i wyświetlane w tabeli wyników.

Chcąc w naszym programie używać obrazków, musimy je wcześniej przygotować. Tworzymy je w dowolnym programie graficznym lub korzystamy z gotowych obrazków, które adoptujemy do swoich oczekiwań. Mogą one być w formacie bitmapy lub jpg.

Pamiętajmy, że im większy ich rozmiar, tym dłużej może trwać ich wczytywanie do programu. Najlepiej, aby były o tej samej długości i szerokości, z zakresu 300—1200 px. Nie musimy martwić się ich dokładnym wymiarem, ponieważ zawrzemy w kodzie instrukcje, które dopasują te obrazki do okna programu w sposób automatyczny.

Przygotowane obrazki umieszczamy na przykład w katalogu głównym gry i nadajemy im nazwy w postaci liczb od 1 do 6, odpowiednio do liczby oczek, które wyświetlają. Obrazkowi startowemu, który nie zawiera liczby oczek, nadajemy nazwę „0” (zero).

Potrzebne komponenty:

Button1 — przycisk „Potwierdź”,

Edit1 — pole edycyjne do wpisywania naszej liczby oczek,

Label1 — etykieta wyświetlająca napis „Wynik Programu”,

Label2 — etykieta wyświetlająca napis „Rzuć kostką”

Label3 — etykieta wyświetlająca napis „Wyniki”,

Label4 — etykieta wyświetlająca napis „Poprawne”,

Label5 — etykieta wyświetlająca napis „Niepoprawne”,

Label6 — etykieta wyświetlająca ilość poprawnych odpowiedzi,

Label7 — etykieta wyświetlająca ilość niepoprawnych odpowiedzi.

Całość wstawiamy na formę główną programu, na przykład w takim ułożeniu:

Kod programu

unit Unit1;

interface

uses

Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, ExtCtrls, StdCtrls, jpeg;

type

TForm1 = class(TForm)

Edit1: TEdit;

Button1: Tbutton;

Image1: TImage;

Label1: TLabel;

Label2: TLabel;

Label3: TLabel;

Label4: TLabel;

Label5: TLabel;

Label6: TLabel;

Label7: TLabel;

procedure Button1Click(Sender: TObject);

procedure FormCreate(Sender: TObject);

procedure Edit1KeyPress(Sender: TObject; var Key: Char);

private

{ Private declarations }

public

{ Public declarations }

end;

var

Form1: TForm1;

Poprawne: Integer; //zmienna przechowująca ilość naszych wygranych

Niepoprawne: Integer; //zmienna przechowująca ilość wygranych programu

implementation

{$R *.dfm}

//wyświetl pustą kostkę przy uruchomieniu programu

procedure TForm1.FormCreate(Sender: TObject);

begin

Image1.Picture.LoadFromFile('C:\Gry\Kości\0.jpg”);

Image1.Width:=330; //szerokość okna do wyświetlania kostki

Image1.Height:=330; //długość okna do wyświetlania kostki

Image1.Proportional:=True; //zachowaj proporcje obrazu

Image1.Stretch:=True; //dopasuj rozmiar obrazu

Poprawne:=0; //wyzeruj ilość poprawnych odpowiedzi

Niepoprawne:=0; //wyzeruj ilość niepoprawnych odpowiedzi

end;

//ograniczenia przy wpisywaniu znaków w polu odpowiedzi

procedure TForm1.Edit1KeyPress(Sender: TObject; var Key: Char);

begin

if not (Key in [„1”. . „6”]) or (Length(Edit1.Text)>0) then

//pozwól na wpisywanie tylko liczb oczek kostki do gry

begin

Key:=#0;

ShowMessage(„To nie jest prawidłowa liczba oczek”); //wyświetl komunikat

Edit1.Text:=„”; //wyczyść pole edycyjne

end;

end;

//gdy naciśniesz przycisk Potwierdź

procedure TForm1.Button1Click(Sender: TObject);

Label KONIEC; //Etykieta do przechodzenia w inne miejsca kodu

var

Odp: String; //zmienna przechowująca naszą liczbę oczek

Liczba: Integer; //zmienna przechowująca liczbę oczek programu

i: Integer; //zmienna pomocnicza

begin

Odp:= Edit1.Text; //odczytaj podaną liczbę oczek i przypisz ją do zmiennej

if Length(Edit1.Text)=0 then //gdy nie podano liczby monituj o wpisaniu wyniku

begin

ShowMessage(„Wpisz najpierw liczbę oczek”); //wyświetl komunikat

Edit1.SetFocus; //ustaw focus w Polu do Odpowiedzi

goto KONIEC; //pomiń poniższy kod i przejdź od razu na koniec procedury

end;

for i:= 1 to 6 do //zrób efekt obrotu kostki do gry

begin

Image1.Picture. LoadFromFile(„C:\Gry\Kości\'+IntToStr(i)+ '.jpg”);

Image1.Width:=330; //szerokość okna do wyświetlania kostki

Image1.Height:=330; //długość okna do wyświetlania kostki

Image1.Proportional:=True; //zachowaj proporcje obrazu

Image1.Stretch:=True; //dopasuj rozmiar obrazu

sleep(100); //czekaj 100 milisekund

Image1.Update; //uaktualnij rysunek

end;

//wyświetl pustą kostkę do gry

Image1.Picture.LoadFromFile('C:\Gry\Kości\0.jpg”);

Image1.Width:=330; //szerokość okna do wyświetlania kostki

Image1.Height:=330; //długość okna do wyświetlania kostki

Image1.Proportional:=True; //zachowaj proporcje obrazu

Image1.Stretch:=True; //dopasuj rozmiar obrazu

Image1.Update; //uaktualnij rysunek

sleep(600); //czekaj 0,6 sekundy

Randomize; //uruchom maszynę losującą

Liczba:=Random(6)+1; //wylosuj liczbę oczek Programu

//wyświetl obrazek z liczbą oczek Programu

Image1.Picture.LoadFromFile('C:\Gry\Kości\'+IntToStr(Liczba)+'.jpg”);

Image1.Width:=330; //szerokość okna do wyświetlania kostki

Image1.Height:=330; //długość okna do wyświetlania kostki

Image1.Proportional:=True; //zachowaj proporcje obrazu

Image1.Stretch:=True; //dopasuj rozmiar obrazu

//oceń wyniki

if Liczba=StrToInt(Odp) then //gdy jest remis

begin

ShowMessagePos(„Jest remis”, 485,220); //pokaż komunikat w miejscu o tych współrzędnych

Poprawne:=Poprawne+1; //zwiększ mój licznik o 1

Niepoprawne:=Niepoprawne+1; //zwiększ licznik Programu o 1

end //brak średnika

else //w przeciwnym razie…

if Liczbathen //gdy mam więcej oczek

begin

ShowMessagePos(„Wygrałeś”, 485,220); //pokaż komunikat w miejscu o tych współrzędnych

Poprawne:=Poprawne+1; //zwiększ mój licznik o 1

end //brak średnika

else //w przeciwnym razie…

begin //gdy mam mniej oczek

ShowMessagePos(„Przegrałeś”, 485,220); //pokaż komunikat w miejscu o tych współrzędnych

Niepoprawne:=Niepoprawne+1; //zwiększ licznik Programu o 1

end;

Edit1.Clear; //wyczyść pole do podawania Odpowiedzi

Edit1.SetFocus; //ustaw focus w Polu do Odpowiedzi

Label6.Caption:= IntToStr(Poprawne); //wyświetl ilość poprawnych odpowiedzi

Label7.Caption:= IntToStr(Niepoprawne); //wyświetl ilość niepoprawnych odpowiedzi

KONIEC: //etykieta do której przechodzi kod, gdy ktoś nie wpisze żadnej liczby

end;

end.

Komentarz

1. Form Create

Image1.Picture.LoadFromFile('C:\Gry\Kości\0.jpg”);

Image1.Width:=330; //szerokość okna do wyświetlania kostki

Image1.Height:=330; //długość okna do wyświetlania kostki

Image1.Proportional:=True; //zachowaj proporcje obrazu

Image1.Stretch:=True; //dopasuj rozmiar obrazu

Poprawne:=0; //wyzeruj ilość poprawnych odpowiedzi

Niepoprawne:=0; //wyzeruj ilość niepoprawnych odpowiedzi

W sekcji tej, która realizuje instrukcje przy uruchomieniu programu, umieszczamy polecenie wyświetlenia obrazka startowego zamiast liczby oczek (pierwsza linia kodu). Wcześniej, przygotowując obrazki na potrzeby programu, nie dobieraliśmy ich wymiarów do okna Image1, dlatego teraz musimy o to zadbać. Służą do tego kolejne cztery linie: dwie pierwsze określają, do jakiego rozmiaru obrazek zostanie pomniejszony, następnie aktywujemy opcję, aby program zachował proporcje obrazu i dopasował go do okna, w którym będzie wyświetlany.

W sekcji tej standardowo deklarujemy także zmienne Poprawne i Niepoprawne o wartości zero, aby ustalić ich stan początkowy.

2. Edit1KeyPress

if not (Key in [„1”. . „6”]) or (Length(Edit1.Text)>0) then

//pozwól na wpisywanie tylko liczb oczek kostki do gry

begin

Key:=#0;

ShowMessage(„To nie jest prawidłowa liczba oczek”); //wyświetl komunikat

Edit1.Text:=„”; //wyczyść pole edycyjne

Sekcję tę bardzo dobrze znamy, gdyż często ją wykorzystujemy. Rozwiązanie, które stosujemy w tym przypadku, zabezpiecza nas przed dwoma zdarzeniami. Przede wszystkim ogranicza używanie liczb tylko do zakresu 1—6, czyli do ilości oczek występujących na kostce do gry. Gdyby ktoś zechciał wpisać cyfrę 7 lub inną (poza tym zakresem), to próba taka zostanie udaremniona przez program. Możemy używać tylko cyfr od jednego do sześciu, ale co w przypadku, gdy ktoś naciśnie dwie jedynki? Taka liczba także na jednej kostce nie występuje. Musimy więc i takie zabezpieczenie uczynić, stąd też druga część warunku do spełnienia. Mówi ona o tym, że program ma nie dopuścić do wpisania liczby wieloznakowej, ma pozwalać na wpisywanie jedynie liczb jednoznakowych. Oba warunki wystarczają do kontroli wpisywanych cyfr, aby zawsze mieściły się w zakresie określonym przez ilość oczek na kostce do gry.

3. Gdy naciśniesz przycisk Potwierdź

Jak widzimy po kodzie, procedurę tę wypełniają podobne instrukcje do wyświetlania obrazków, co w procedurze Form Create, nie będziemy więc ich ponownie komentować. Zatrzymamy się tylko nad rozwiązaniem, jakiego użyliśmy do imitacji obrotu kostką:

for i:= 1 to 6 do //zrób efekt obrotu kostki do gry

begin

Image1.Picture. LoadFromFile(„C:\Gry\Kości\'+IntToStr(i)+ '.jpg”);

Image1.Width:=330; //szerokość okna do wyświetlania kostki

Image1.Height:=330; //długość okna do wyświetlania kostki

Image1.Proportional:=True; //zachowaj proporcje obrazu

Image1.Stretch:=True; //dopasuj rozmiar obrazu

sleep(100); //czekaj 100 milisekund

Image1.Update; //uaktualnij rysunek

end;

Główna jego część nie różni się niczym od tej z procedury Form Create. Jej zadaniem w dalszym ciągu pozostaje wyświetlenie obrazka. Chcąc jednak uzyskać efekt ruchu, musimy wyświetlić w krótkim czasie wiele różnych obrazków. Najprościej uczynić to za pomocą konstrukcji for...to...do. Służy ona do tego, aby daną grupę poleceń (zawartych w bloku begin… end) wykonać wiele razy z rzędu.

Z warunków, jakie zadaliśmy, widzimy, że wykona ją sześć razy, po jednym razie dla każdego obrazka. Warto więc zwrócić uwagę, że w ścieżce dostępu do obrazka wstawiamy tę samą zmienną pomocniczą o nazwie „i”. Dzięki temu sprzężeniu, przy każdorazowym zwiększeniu zmiennej i zrealizowaniu procedury od nowa, zwiększa się numer kolejnego obrazka do wyświetlenia, będzie on już więc inny. Procedura ta będzie odliczała kolejne wznowienia od 1 do 6, a ponieważ numer obrazka sprzężony jest z tą samą zmienną, więc i w takiej też kolejności będą wyświetlane obrazki: od obrazka o nazwie „1”, przechowującego jedno oczko, aż do obrazka o nazwie „6”, przechowującego 6 oczek.

W procedurze tej zawarte jest polecenie „sleep”, które nakazuje programowi wstrzymanie owej procedury na określony czas. Przyjmując wartość 100 ms, uzyskujemy właśnie efekt szybkiego wyświetlania kostki do gry o różnej liczbie oczek. Zmieniając ten czas, zmieniamy także szybkość „kręcenia się” kostki. Kostka będzie mogła kręcić się szybciej lub wolniej, według naszego uznania. Aby kolejny obrazek mógł zostać wyświetlony, musimy cały komponent uaktualnić (update).

Koniec darmowego fragmentu książki.

Zachęcamy do zakupu pełnej wersji.