Witam
To mój pierwszy post na tym forum, więc chyba jestem dość zuchwały, bo od razu wyskakuję ze sporym kodem ;)
Jestem na etapie odcinka 9 kursu C++ Mirosława Zelenta. Stosując nowe wiadomości, postanowiłem przerobić program rozwiązujący zadanie z odcinka 1 tego samego kursu (takie z Jasiem i cukierkami). Dodałem więc parę usprawnień i podzieliłem kod na podprogramy.
Wtedy zaczęły pojawiać się pomysły, żeby sprawę uogólnić - w końcu wiele jest zadań z takim rozwiązaniem, że najpierw gromadzi się dane, potem są obliczenia, a na końcu prezentuje się szukane, czyli wyniki tych obliczeń. Po pewnym czasie kombinowania powstał więc kod, który jest szablonem do stworzenia programu rozwiązującego jakieś konkretne zadanie takiego typu. Ten kod-szablon się kompiluje (przynajmniej za pomocą TDM-GCC 4.9.2) i robi tam jakieś przykładowe obliczenia, ale chodzi głównie o to, żeby można było w nim dość łatwo podmienić odpowiednie fragmenty, a dostanie się program, który rozwiązuje konkretne zadanie dla różnych wartości wejściowych. Jeśli ktoś ma ochotę ocenić ten mój kod albo się nim pobawić - zapraszam, wygląda on tak, a pod spodem napiszę, jak z niego korzystać:
#include <iostream> #include <cstdlib> #include <conio.h> using namespace std; bool place=0; //"miejsce" w programie (startowe lub obliczeniowe) int howmanyd=3, howmanys=4; //ile danych, ile szukanych float data[3], searched[4]; //dane, szukane string start="s", finish="e"; //ktorym klawiszem wracamy na start, ktorym konczymy program string hello(); //tresc powitania string ask(int n); //tresc pytajaca o wartosci danych bool check(int n); //czy dane sa prawidlowe? string wrong(int n); //podpowiedz w przypadku nieprawidlowych danych void calc(); //obliczenia prowadzace do nadania szukanym wartosci string result(int n); //tresc poprzedzajaca wartosci szukanych string keyboard(bool p); //tresc przedstawiajaca klawiszologie bool newplace(char k); //wartosc nowego miejsca w zaleznosci od znaku string bye(); //tresc pozegnania int main() { bool gvalue=1; //straznik prawidlowej wartosci char key; //ostatnio wcisniety klawisz do { switch(place) { case 0: { //jesli jestesmy na ekranie powitalnym system("cls"); cout<<hello(); break; } case 1: { //jesli jestesmy w miejscu prowadzenia obliczen system("cls"); for(int i=0; i<howmanyd; i++) { do { //pytaj o dane, czytaj je z klawiatury, w razie nieprawidlowych powtarzaj, //a w razie prawidlowych przechodz do nastepnych cout<<ask(i); if(!(cin>>data[i])) gvalue=0; if(check(i)!=1) cerr<<wrong(i)<<"\n"; } while(check(i)!=1&&gvalue==1); } calc(); //dokonaj obliczen for(int i=0; i<howmanys; i++) { //wyswietl wartosc kazdej szukanej cout<<result(i)<<searched[i]; } break; } } cout<<"\n"<<keyboard(place); //wyswietl klawiszologie dla danego miejsca key=getch(); //poczekaj na wpisanie znaku i zapisz go do zmiennej place=newplace(key); //zmien miejsce (lub pozostaw aktualne) w zaleznosci od znaku } while(key!=finish[0]); //jesli wybrano znak zakonczenia, przerwij petle cout<<"\n"<<bye(); system("pause"); //pozegnaj sie i poczekaj na dowolny klawisz return 0; } string hello() { //gromadzi tresc powitania i ja zwraca string text; text="\n\tOto tresc zadania, ktore rozwiazuje ten program:\n"; text=text+"\n\t[Tutaj jakas...]"; text=text+"\n\t[...tresc zadania]"; return text; } string ask(int n) { string text; switch(n) { case 0: text="\n\t[Tutaj nazwa pierwszej danej]: "; break; case 1: text="\n\t[Tutaj nazwa drugiej danej]: "; break; case 2: text="\n\t[Tutaj nazwa trzeciej danej]: "; break; //w razie wiekszej liczby danych tutaj kolejne case'y } return text; } bool check(int n) { bool b=0; switch(n) { //po spelnieniu warunkow dane staja sie prawidlowe case 0: if(data[n]>0) b=1; break; case 1: if(data[n]!=1) b=1; break; case 2: b=1; break; //w razie wiekszej liczby danych tutaj kolejne case'y } return b; } string wrong(int n) { string text; switch(n) { case 0: text="\t[Tutaj informacja, ze np. musi byc wieksza od 0]"; break; case 1: text="\t[Tutaj informacja, ze np. musi byc rozna od 1]"; break; case 2: break; //w razie wiekszej liczby danych tutaj kolejne case'y } return text; } void calc() { float a=data[0]; float b=data[1]; float c=data[2]; float x,y,z,p; //pomocnicze zmienne x=a+b; y=c/a; cout<<"\n\t[Tutaj mozna opisac, jakie obliczenia program wykonuje...]"; z=b*c; p=a*c; cout<<"\n\t[...tak zeby uzytkownik wiedzial, co doprowadzilo do takich a nie innych wynikow]\n"; //obliczenia (mniej lub bardziej rozbudowane) searched[0]=x; searched[1]=y; searched[2]=z; searched[3]=p; //nadaj szukanym obliczone wartosci } string result(int n) { string text; switch(n) { case 0: text="\n\t[Pierwsza szukana]: "; break; case 1: text="\n\t[Druga szukana]: "; break; case 2: text="\n\t[Trzecia szukana]: "; break; case 3: text="\n\t[Czwarta szukana]: "; break; //w razie wiekszej liczby szukanych tutaj kolejne case'y } return text; } string keyboard(bool p) { string text; switch(p) { case 0: { text="\n\tZeby wyjsc z programu, wcisnij "+finish; text=text+"\n\tZeby kontynuowac, wcisnij cokolwiek innego "; break; } case 1: { text="\n\tZeby wrocic na start, wcisnij "+start; text=text+"\n\tZeby wyjsc z programu, wcisnij "+finish; text=text+"\n\tZeby powtorzyc obliczenia, wcisnij cokolwiek innego "; break; } } return text; } bool newplace(char k) { bool p=1; switch(place) { case 0: break; case 1: if(k==start[0]) p=0; break; } return p; } string bye() { return "\n\tDo zobaczenia!\n\n\t"; }
Zatem - najpierw trzeba ustalić, jakie zadanie będzie rozwiązywał program. Liczbę danych i szukanych trzeba wpisać w 8 i 9 linii mojego kodu (pewnie jest sposób, żeby nie trzeba było tego zmieniać w dwóch miejscach, ale ja go na razie nie znam). Można też zmienić typ danych i szukanych (linia 9), wtedy trzeba ten sam typ zastosować wewnątrz procedury calc(), ale po kolei. Nad funkcją main() nie trzeba już nic więcej zmieniać, w niej samej zresztą też, przechodzimy więc do funkcji i procedur pod main'em.
Wewnątrz hello() wpisujemy w miejscu nawiasów kwadratowych treść zadania, jakie program będzie rozwiązywał. W ogóle wszystkie nawiasy kwadratowe wewnątrz string'ów w tym kodzie przeznaczone są do podmiany. Można też dodać więcej linii treści zadania.
Wewnątrz ask(int n), tak jak podpowiadają nawiasy, wpisujemy nazwy danych albo podobne teksty pytające o ich wartości. Liczba case'ów musi się zgadzać z liczbą danych wprowadzoną na początku (pamiętajmy że są one numerowane od 0).
Funkcja check(int n) sprawdza poprawność wprowadzanych danych, więc jeśli są jakieś ograniczenia, to tutaj je definiujemy. Numery case'ów są analogiczne do tych w ask(int n), a w każdym case'ie definiujemy odpowiednie ograniczenia wewnątrz if'ów. Jeśli więc np. druga dana musi być różna od 0, to w linii z case 1 wpisujemy if(data[n]!=0) b=1. Na końcu każdego case'a mamy b=1; break; , nawet jeśli nie ma żadnych warunków - wtedy po prostu nie wpisujemy instrukcji if.
Wewnątrz wrong(int n) wpisujemy info o nieprawidłowych danych dla każdej danej, która ma jakieś ograniczenia (numery case'ów również tutaj odpowiadają numerom danych).
Procedura calc() przeznaczona jest do wykonania wszystkich obliczeń i zapisania wyników do szukanych. W szablonie jest tylko przykład - zamiast niego trzeba zapisać rozwiązanie własnego zadania. Można utworzyć pomocnicze zmienne, a oprócz obliczeń program może wypisywać, co robi. Na końcu trzeba nadać szukanym obliczone wartości, bo właśnie zmienne searched zostaną za chwilę wyświetlone przez program.
Wewnątrz result(int n) musi być tyle case'ów, ile szukanych, na tej samej zasadzie jak to było z danymi. Wpisujemy tutaj ich nazwy lub treści odpowiedzi do zadania, które zakończą się w programie wartościami szukanych.
Ostatnich funkcji, tj. keyboard(bool p), newplace(char k) i bye() nie trzeba zmieniać.
Na koniec kod bazujący na powyższym szablonie, który rozwiązuje zadanie z Jasiem i cukierkami z odcinka 1 kursu Mirosława Zelenta. Chętnie się dowiem, co sądzicie o moim szablonie i jego przekształcaniu do konkretnych zadań. Pozdrawiam!
#include <iostream> #include <cstdlib> #include <conio.h> using namespace std; bool place=0; int howmanyd=2, howmanys=2; int data[2], searched[2]; string start="s", finish="e"; string hello(); string ask(int n); bool check(int n); string wrong(int n); void calc(); string result(int n); string keyboard(bool p); bool newplace(char k); string bye(); int main() { bool gvalue=1; char key; do { switch(place) { case 0: { system("cls"); cout<<hello(); break; } case 1: { system("cls"); for(int i=0; i<howmanyd; i++) { do { cout<<ask(i); if(!(cin>>data[i])) gvalue=0; if(check(i)!=1) cerr<<wrong(i)<<"\n"; } while(check(i)!=1&&gvalue==1); } calc(); for(int i=0; i<howmanys; i++) { cout<<result(i)<<searched[i]; } break; } } cout<<"\n"<<keyboard(place); key=getch(); place=newplace(key); } while(key!=finish[0]); cout<<"\n"<<bye(); system("pause"); return 0; } string hello() { string text; text="\n\tOto tresc zadania, ktore rozwiazuje ten program:\n"; text=text+"\n\tW klasie znajduje sie x uczniow. Jeden z nich, Jas, ma dzisiaj imieniny"; text=text+"\n\ti z tej okazji przyniosl do szkoly y cukierkow, ktore zamierza rozdac swoim kolezankom i kolegom."; text=text+"\n\tJas chce, zeby kazdy z tych uczniow dostal tyle samo cukierkow,"; text=text+"\n\tprzy czym nie ma mowy o dzieleniu cukierkow - kazdy musi dostac ich calkowita liczbe."; text=text+"\n\tPo ile cukierkow rozda Jas, trzymajac sie opisanych zasad?"; text=text+"\n\tIle cukierkow zostanie dla Jasia na wieczor?"; return text; } string ask(int n) { string text; switch(n) { case 0: text="\n\tLiczba uczniow w klasie (x): "; break; case 1: text="\n\tLiczba cukierkow (y): "; break; } return text; } bool check(int n) { bool b=0; switch(n) { case 0: if(data[n]>1) b=1; break; case 1: if(data[n]>=0) b=1; break; } return b; } string wrong(int n) { string text; switch(n) { case 0: text="\tMusi byc calkowita i wieksza od 1!"; break; case 1: text="\tMusi byc calkowita i nieujemna!"; break; } return text; } void calc() { int x=data[0]; int y=data[1]; int ile_dla_kazdego; int ile_zostanie; ile_dla_kazdego=y/(x-1); cout<<"\n\tLiczbe cukierkow dziele (bez reszty) przez liczbe wszystkich uczniow oprocz Jasia."; cout<<"\n\tW ten sposob dostaje liczbe cukierkow przeznaczona dla kazdego z tych uczniow."; cout<<"\n\ty/(x-1)="<<y<<"/"<<x-1<<"="<<ile_dla_kazdego; ile_zostanie=y-ile_dla_kazdego*(x-1); cout<<"\n\tNastepnie uzyskana liczbe mnoze przez liczbe uczniow oprocz Jasia"; cout<<"\n\ti to co mi wyjdzie odejmuje od poczatkowej liczby cukierkow."; cout<<"\n\t"<<ile_dla_kazdego<<"*"<<(x-1)<<"="<<ile_dla_kazdego*(x-1); cout<<"\n\t"<<y<<"-"<<ile_dla_kazdego*(x-1)<<"="<<ile_zostanie; cout<<"\n\tW ten sposob uzyskuje liczbe cukierkow, ktora zostanie dla Jasia.\n"; searched[0]=ile_dla_kazdego; searched[1]=ile_zostanie; } string result(int n) { string text; switch(n) { case 0: text="\n\tOdp1: Jas rozda kazdemu uczniowi cukierkow "; break; case 1: text="\n\tOdp2: dla Jasia na wieczor zostanie cukierkow "; break; } return text; } string keyboard(bool p) { string text; switch(p) { case 0: { text="\n\tZeby wyjsc z programu, wcisnij "+finish; text=text+"\n\tZeby kontynuowac, wcisnij cokolwiek innego "; break; } case 1: { text="\n\tZeby wrocic na start, wcisnij "+start; text=text+"\n\tZeby wyjsc z programu, wcisnij "+finish; text=text+"\n\tZeby powtorzyc obliczenia, wcisnij cokolwiek innego "; break; } } return text; } bool newplace(char k) { bool p=1; switch(place) { case 0: break; case 1: if(k==start[0]) p=0; break; } return p; } string bye() { return "\n\tDo zobaczenia!\n\n\t"; }
EDIT: zgodnie z podpowiedziami Pasjonatów poprawiłem oba kody (zmiana nazwy zmiennej end na finish), u mnie kompilują się one w Dev-C++ oraz code::blocks ze standardowymi kompilatorami. Działają niestety tylko pod Windowsem.