Program pobierający datę i zwracający dzień w który ona wypadła

0

Bardzo proszę o jakieś wskazówki dotyczące kodu, moim zdaniem jest on trochę kodem spaghetti.
Póki co jego przejrzystość i optymalizacja jest szczytem moich słabych możliwości.

#include <iostream>
using namespace std;

int weekDay(int year, int month, int day);

int main()
{

    // Program pobiera date i wyswietla w jaki dzien tygodnia ona wypadla,ma on dzialac od lat 2000 do 2020

    int year,month,day;

    cout<<"Podaj prosze dzisiejsza date, w podanej kolejnosci:"<<endl;
    cout<<"Podaj rok"<<endl;
    cin>>year;
    cout<<"Podaj miesiac"<<endl;
    cin>>month;
    cout<<"Podaj dzien"<<endl;
    cin>>day;


    switch(weekDay(year,month,day))
    {
    case 1:
    {
        cout<<"Dzisiaj jest poniedzialek"<<endl;
        break;
    }

    case 2:
    {
        cout<<"Dzisiaj jest wtorek"<<endl;
        break;
    }

    case 3:
    {
        cout<<"Dzisiaj jest sroda"<<endl;
        break;
    }

    case 4:
    {
        cout<<"Dzisiaj jest czwartek"<<endl;
        break;
    }

    case 5:
    {
        cout<<"Dzisiaj jest piatek"<<endl;
        break;
    }

    case 6:
    {
        cout<<"Dzisiaj jest sobota"<<endl;
        break;
    }

    case 7:
    {
        cout<<"Dzisiaj jest niedziela"<<endl;
        break;
    }

    }

    return 0;

}



int weekDay(int year, int month, int day)
{
    int i = 2000;
    int years[2021];
    int months[13];
    int dzientygodnia=6;  //  (1 stycznia 2000 roku wypadl w sobote)

    for(i=2000; i<=2020; i++) //Wypelniam lata iloscia dni w zaleznosci od tego czy rok byl przestepny czy nie
    {
        if        (   (i%4 == 0 && i%100 != 0) || (i%400 == 0)           )
            years[i]=366;
        else
            years[i]=365;
    }

    // Nie wiedzialem jak to fajnie krocej zrobic, wiec tutaj troche spaghetti,prosze o sugestie
    //  Tutaj wypelniam miesiace iloscia dni w miesiacu,przy czym rozni sie miesiac months[2] ( luty) w zaleznosci od tego czy rok przestepny


    if   (   (year%4 == 0 && year%100 != 0) || (year%400 == 0)           )

    {
        int months [13] {0,31,29,31,30,31,30,31,31,30,31,30,31};
    }

    else

    {
        int months [13] {0,31,28,31,30,31,30,31,31,30,31,30,31};
    }


//Aby zwrocic numer okreslajacy dzien tygodnia licze ile dni uplynelo a potem modulo 7

    int ilosc_dni=0;

    i = 2000;

    for(i=2000; i<year; i++)
    {
        ilosc_dni+=years[i];
    }

    i = 0;

    for (i=0; i<month; i++)
    {
        ilosc_dni+=months[i];
    }

    ilosc_dni+=day-1;

    dzientygodnia=(dzientygodnia+ilosc_dni)%7;

    if(dzientygodnia==0) dzientygodnia=7;

    return dzientygodnia;

}

1
  1. Zamiast tego całego switcha wystarczy:
string weekDays[7] = { "niedziela", "poniedzialek", "wtorek", "sroda", "czwartek", "piatek", "sobota" };
cout << "Dzisiaj jest " << weekDays[weekDay(year, month, day)] << endl;
  1. Po co sprawdzasz czy rok się dzieli przez 100 i 400 skoro patrzysz między 2000 a 2020?

  2. Bezsensowna instrukcja przed pętlą:

i = 2000;             // po co to?
for(i = 2000; i < year; i++)  // używaj ++i

A najlepiej to wywalić to i na początku funkcji i zawsze używać lokalnej zmiennej w obrębie pętli:

for (int i = 2000; i < year; ++i)
  1. Zamiast takich cudów wystarczy dodać 1 jeśli rok jest przestępny a month jest większy równy od lutego
if ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0))
{
    int months[13]{ 0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
}
else
{
    int months[13]{ 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
}
  1. Nie ma powodu, żeby używać tablic do trzymania lat i miesięcy.
0

Dziękuje! Kod skrócony o połowę przy większej czytelności. (nie wszystko poprawiłem,nie wiem co z tą tablicą)
Mam tylko pytanie co do punktu nr 5. Wydawało mi się że tablica będzie lepsza niż na przykład zmienna ilosc_dni =( year-2000) * 366 - (year%4 + 1);

No i gdzie mam trzymać miesiące jeśli nie w tablicy? W sumie miesiące w jednym roku przyjmują tylko wartości 31,30 i 29 lub 28 ale czy z tablica nie jest bardziej intuicyjnie gdy np. miesiac[1] = 31?

2
zjm2014 napisał(a):

Dziękuje! Kod skrócony o połowę przy większej czytelności.
To może zajrzyj pod ten link:
http://4programmers.net/Forum/C_i_C++/209042-liczenie_dni_od_daty_urodzin?p=909342#id909342

0

Dobra trochę się zagalopowałem z tymi tablicami. Głównie chodziło mi o to:

for (i = 2000; i <= 2020; i++) //Wypelniam lata iloscia dni w zaleznosci od tego czy rok byl przestepny czy nie
{
    if ((i % 4 == 0 && i % 100 != 0) || (i % 400 == 0))
        years[i] = 366;
    else
        years[i] = 365;
}
for (i = 2000; i < year; i++) {
    ilosc_dni += years[i];
}

Tu nie trzeba tablicy i 2 pętli. A w przypadku miesięcy nie trzeba tablicy to trzymania faktu przestępności, ale rzeczywiście samą ilość dni każdego miesiąca wygodnie trzymać w tablicy.

0
_13th_Dragon napisał(a):
zjm2014 napisał(a):

Dziękuje! Kod skrócony o połowę przy większej czytelności.
To może zajrzyj pod ten link:
http://4programmers.net/Forum/C_i_C++/209042-liczenie_dni_od_daty_urodzin?p=909342#id909342

No rzeczywiście tamtym kodem pozamiatałeś :D Póki co jednak wole tak nie kompresować żeby móc się jakoś połapać w tym co piszę i samo to że ze 130 linijek zrobiło się 60 mnie cieszy,nie musi być w 15 jeszcze :P.

Twonek dziękuje za konstruktywną krytykę i pomoc

0

Można w jednej linijce:

int weekDay(int year, int month, int day)
{
    // 0 - niedziela, 1 - poniedziałek, ..., 6 - sobota
    return (day+=month<3?year--:year-2,23*month/9+day+4+year/4-year/100+year/400)%7;
}

1 użytkowników online, w tym zalogowanych: 0, gości: 1