[C++]Zadania z kalendarzem, matura z informatyki

Według kalendarza juliańskiego wprowadzonego przez Juliusza Cezara od roku 45 p.n.e., każdy rok nieprzestępny trwał 365 dni, a rok przestępny przypadający na dokładnie co 4 lata trwał 366 dni. Ustalenia te spowodowały, że na każde 128 lat pojawiła się różnica jednego dnia pomiędzy tym kalendarzem, a kalendarzem astronomicznym. Aby zlikwidować narastający błąd, w roku 1582 zastąpiono kalendarz juliański kalendarzem gregoriańskim. Nowy kalendarz obowiązuje od 4 października 1582 roku, kiedy po czwartku 4 października 1582 nastąpił piątek 15 października 1582 r. Latami przestępnymi w kalendarzu juliańskim były wszystkie lata, które dzielą się bez reszty przez 4. Według kalendarza gregoriańskiego latami przestępnymi są te, które dzielą się bez reszty przez 4, z wyjątkiem tych, które dzielą się bez reszty przez 100, a nie dzielą się bez reszty przez 400.

Tego typu zadanie było na pewnej maturze z informatyki, za 20 punktów – dlaczego by z samej ciekawości się nie dowiedzieć jak to się robi i jak działa?
Chciałbym to rozłożyć sobie na kilka wpisów, aby nie zamęczyć linijkami kodu, które się tu pojawią i przy okazji pochwalić się znalezionym kodem do kolorowania składni – mam nadzieję, że wam się spodoba i poprawi widoczność tekstu kodu źródłowego.

Dziś tylko krótka analiza czego od nas chcą- w końcu to podstawa do zdobycia kompletu punktów.

Część dalsza polecenia po jakże tym długim wstępie to:

Napisz program, który uwzględniając powyższy opis wyświetli wszystkie daty wypadające w podanym z klawiatury dniu tygodnia w lutym wskazanego roku.Rok powinien być z przedziału <1500,2005>
Powinno nam wyjść coś takiego, gdy podamy wtorek, 2000 :
01.02.2000
08.02.2000
15.02.2000
22.02.2000
29.02.2000.

Dodatkowym warunkiem będzie , że dni tygodnia podajemy bez polskich znaków.

No to dzieła!

Na początek zanim zabierzemy się za pisanie kodu źródłowego wybierzmy to co dla nas będzie ważne, przy budowie programu:

  • zakres dat to 1500 – 2005 włącznie
  • rok jest liczbą naturalną
  • do 4.10.1582 obowiązuje kalendarz juliański i jest to czwartek
  • w piątek następuje zmiana na kalendarz gregoriański i datę 15.10.1582
  • w juliańskim przestępne są wszystkie daty podzielne przez 4
  • w gregoriańskim latami przestępnymi są te, które dzielą się bez reszty przez 4, z wyjątkiem tych, które dzielą się bez reszty przez 100, a nie dzielą się bez reszty przez 400

Jako, że operujemy tylko na lutym sprawa się znacznie uprościła, bo nie musimy sprawdzać, czy ten miesiąc ma 30, czy 31 dni. Zostaje nam tylko zająć się warunkiem o roku przestępnym.

Teraz zaczniemy już powoli budować kod źródłowy.
Nie będzie zaskoczeniem dla nikogo, że potrzebny nam będzie notatnik, Dev-C++ lub inne odpowiedniki, które napiszą nam czysty kod źródłowy. Ja osobiście korzystam z Notepad++. Przy pracy przyda nam się znajomość pisania pętli w C++/Cpp.

Zróbmy na razie każdy punkt oddzielnie, a potem poskładamy to w całość – to według mnie najlepszy sposób, tym bardziej że warunki spisaliśmy sobie w takiej kolejności w jakiej pojawią się w kodzie źródłowym.

Zakres dat && rok jest liczbą naturalną

Te dwa warunki opłaca się zrobić za jednym zamachem, aby nie marnować czasu.

#include <iostream>
using namespace std;

int main()
{
 int rok;
 
 // Menu okna 
 cout<<"Podaj rok: ";
 cin>>rok;
 //
 if ((rok < 1500) || ( rok >2005 ))
 {
  cout<<"Podany rok nie miesci sie w zakresie - podaj liczbe z przedzialu <1500,2005>";
 }
 else
 {
  cout<<"Rok jest porpawny";
 }
 
}

Tak więc mamy załatwione dwie rzeczy za jednym zamachem. Jako, że nie chcemy aby podawano nam części dziesiątych roku ustawiliśmy, że będzie to liczba typu całkowitego (int ; ang. integer ). Dodatkowo zastrzegliśmy, że liczba nie może być większa niż 2500 ani mniejsza niż 1500 operatorem || ( symbol alternatywy ).

Punkt III – do 4.10.1582 mamy kalendarz juliański ; 4.10.1582 to czwartek

Musimy teraz sprawdzić, które daty to lata przestępne. W tym wypadku musimy po prostu sprawdzić, czy reszta z dzielenia przez 4 jest równa zero. Jako że mamy tu na razie małe program, z których skleimy potem jeden wielki trzeba będzie powtarzać nieustannie wczytanie biblioteki i deklaracje main().

Oto jak powinno wyglądać sprawdzenie, czy rok jest przestępny według zasad kalendarza juliańskiego dla dowolnej daty.

#include <iostream>
using namespace std;

int main()
{
 int rok;
 
 // Menu okna 
 cout<<"Podaj rok: ";
 cin>>rok;
 //
 if ((rok%4)==0)
 cout<<"Rok jest przestepny!";
}

Sztuka ustalenia daty
Nie bez powodu do wiadomości podano nam, że jest to akurat czwartek. Ten fakt ma nam bardzo ułatwić i uprościć operację w związku z ustaleniem daty.
Wiemy, że 4.10.1582 to czwartek.
Obliczmy różnicę w dniach między datą wprowadzoną, a 4.10.1582. Uzyskasz liczbę integer. Wykonaj opercją dzielenia modulo tej liczby przez 7. Teraz jeżeli wynik modulo to 0 – to dzień wprowadzony to czwartek, 1 – to piatek, 2 – to sobota, 3 – niedziela i.t.d.
Teraz musimy to odwrócić.
Jeżeli wiemy, że modulo z 7 da nam w czwartek 0, w piątek 1 itd. to jest to pewna zależność stałą, której nie zmienimy. Oto lista wyników dla dzielenia i odpowiednio dzień, który przypada:

  • czwartek = 0
  • piątek = 1
  • sobota = 2
  • niedziela = 3
  • poniedziałek = 4
  • wtorek = 5
  • środa = 6

Z tych informacji utworzymy odpowiednią tablicę, która nam uprości sprawę.

char dzien[15];

char *tydzien[]{"czwartek","piatek","sobota","niedziela","poniedzialek","wtorek","sroda"}

Tablica dzien przyda się do przechwycenia znaków z klawiatury. To jej użyjemy, gdy program poprosi o podanie dnia tygodnia.

Tablica tydzien zawiera wszystkie dni tygodnia. Kolejność nie jest przypadkowa.
„Program” pytający o dzień tygodnia będzie wyglądał następująco:

#include <iostream>
using namespace std;

int main()
{
char dzien[15];
char *tydzien[]{"czwartek","piatek","sobota","niedziela","poniedzialek","wtorek","sroda"}

cout<<"Podaj dzien tygodnia: ";
cin>> dzien;
}

W zasadzie w ten sposób udało nam się rozwiązać najtrudniejszy problem. Przy kalendarzu gregoriańskim posłużymy się podobną składnią dodając dodatkowe warunki odnośnie roku przestępnego. Pobieranie daty potrzebne będzie nam przy obu, więc nie ma sensu powtarzać.

Pytania i uwagi zostawcie w komentarzach.