Исходник Практикум: консольный календарь

Олдфаг
Статус
Оффлайн
Регистрация
18 Фев 2019
Сообщения
2,826
Реакции[?]
1,853
Поинты[?]
24K
В поисках нового материала для форума, я нашел одну интересную практическую работу по теме "Функции". Суть заключается в выводе календаря на указанный пользователем год. Думаю, это достаточно хорошее задание для только изучающих C++ людей. Вы можете попробовать свои силы и написать данный прак с нуля, но обязательно поделитесь результатом в теме, мне будет очень интересно :).
Задание имеет 2 уровня сложности: "easy" и "hard". Разница заключается только в формате вывода календаря.
1611933152221.png
1611943863932.png
Решать мы, конечно, будем hard версию :blush:.

В итоге вся "сложность" работы заключена в заполнении столбиком и выводе месяцев группами по 4. Думаю, вы понимаете, что создание подобного алгоритма не составляет труда, если знать лишь пару основных идей:
  1. 1 января 1 года - это понедельник (это можно использовать для определения дня недели даты)
  2. Максимальное занимаемое количество недель в месяце - 6, минимальное - 4 (необходимо для правильного "центрирования" месяцев)
Однако, вдобавок к обязательному стандарту вывода календаря, авторы задания предлагают написать 7 основных функций (практикум же), помогающих в написании алгоритма заполнения: проверка на високосный год, количество дней в году, количество дней в месяце, количество прошедших дней с 1го января, количество прошедших дней с 01.01.01, разница между двумя датами (в днях), день недели 1ой даты, зная день недели 2ой. Также в комментариях предлагается использовать структуру данных Date:
C++:
struct Date {
    long long Year;
    long long Month;
    long long Day;
};
В первую очередь я хочу предложить написать этот небольшой практикум именнно вам - и вы лишний раз испытаете свои знания, и я, может быть, найду что-нибудь для себя новое в других решениях.
Для особо умных: использовать сторонние классы, помимо iostream, iomanip и string, нельзя.

Мой вариант решения
C++:
#include <iostream>
#include <iomanip>
#include <string>

using namespace std;

struct Date {
    long long Year;
    long long Month;
    long long Day;
};

#pragma region Functions
bool IsLeap(Date date) {
    if (!(date.Year % 4)) {
        if (!(date.Year % 100))
            return false;
        if (!(date.Year % 400))
            return true;
        return true;
    }
    return false;
}
int YearDaysCount(Date date) {
    return IsLeap(date) ? 366 : 365;
}
int MonthDaysCount(Date date) {
    if (date.Month == 2)
        return IsLeap(date) ? 29 : 28;
    else if (date.Month == 1 || date.Month == 3 || date.Month == 5 || date.Month == 7 || date.Month == 8 || date.Month == 10 || date.Month == 12)
        return 31;
    return 30;
}
int DaysFromJan(Date date) {
    int TotalDays = date.Day - 1;
    for (int i = 0; i < date.Month - 1; i++)
        TotalDays += MonthDaysCount(Date{ date.Year, i + 1, 1 });
    return TotalDays;
}
long long DaysFrom1st(Date date) {
    int FromJan = DaysFromJan(Date{ date.Year, date.Month, date.Day });
    return (--date.Year) / 4 - date.Year / 100 + date.Year / 400 + date.Year * 365 + FromJan;
}
long long DatesDeltaDays(Date date1, Date date2) {
    auto _1 = DaysFrom1st(date1) - DaysFrom1st(date2);
    return _1;
}
int NextDateDayOfWeek(Date date1, Date date2, int dayOfWeek) {
    int tmp = (dayOfWeek + DatesDeltaDays(date1, date2) % 7) % 7;
    return tmp >= 1 ? tmp : 7 + tmp;
}
#pragma endregion

Date today = { 2021, 1, 22 };
string Months[]{ "Январь", "Февраль", "Март", "Апрель", "Май", "Июнь", "Июль", "Август", "Сентябрь", "Октябрь", "Ноябрь", "Декабрь" };
string Days[]{ "ПН", "ВТ", "СР", "ЧТ", "ПТ", "СБ", "ВС" };

int main() {
    setlocale(LC_ALL, "ru");
    while (1) {
        try {
            system("cls");
            int year = 0;
            bool spaces = false;
            char c;
            cout << "Введите год для отображения календаря: ";
            while (c = cin.get(), c != '\n') {
                if (year == -1)
                    continue;
                if (spaces) {
                    if (c == ' ')
                        continue;
                    else if (!year)
                        spaces = false;
                    else
                        year = -1;
                }
                else if (c == ' ') {
                    spaces = true;
                    continue;
                }
                if (c >= '0' && c <= '9')
                    year = year == 0 ? c - '0' : year * 10 + c - '0';
                else
                    year = -1;
            }
            if (year <= 0)
                throw exception("Неверный тип входных данных");
            Date newDate = { year, 1, 1 };
            int months[12][7][6] = { 0 };
            int _1stIndex = NextDateDayOfWeek(newDate, today, 5) - 1;
            for (int m = 0; m < 12; m++) {
                int day = 1;
                int week = 0;
                for (int i = 0; i < 7 && day <= MonthDaysCount(Date{ year, m + 1, 1 }); i++) {
                    if (!week && i < _1stIndex)
                        continue;
                    months[m][i][week] = day++;
                    if (i == 6) {
                        week++;
                        i = -1;
                    }
                }
                if (m != 11)
                    _1stIndex = NextDateDayOfWeek(Date{ year, m + 2, 1 }, today, 5) - 1;
            }
            system("cls");
            cout << "Календарь на " << year << " год\n\n";
            for (int j = 0; j < 12; j++) {
                cout << setw(26) << left << Months[j];
                if (!((j + 1) % 4)) {
                    cout << "\n";
                    for (int i = 0; i < 7; i++) {
                        cout << setw(3) << left << Days[i];
                        for (int m = j / 4 * 4; m < j + 1; m++) {
                            for (int z = 0; z < 6; z++)
                                cout << setw(3) << left << (months[m][i][z] ? to_string(months[m][i][z]) : "");
                            if (m != j)
                                cout << setw(0) << left << "     " << Days[i] + " ";
                        }
                        cout << "\n";
                    }
                    cout << "\n";
                }
            }
        }
        catch (exception ex) {
            cout << "Ошибка во время выполнения программы: " << ex.what() << "\n\n";
            goto end;
        }
    end:
        system("pause");
        continue;
    }
}
1611945012270.png
 
Последнее редактирование:
Участник
Статус
Оффлайн
Регистрация
3 Ноя 2020
Сообщения
874
Реакции[?]
181
Поинты[?]
0
В поисках нового материала для форума, я нашел одну интересную практическую работу по теме "Функции". Суть заключается в выводе календаря на указанный пользователем год. Думаю, это достаточно хорошее задание для только изучающих C++ людей. Вы можете попробовать свои силы и написать данный прак с нуля, но обязательно поделитесь результатом в теме, мне будет очень интересно :).
Задание имеет 2 уровня сложности: "easy" и "hard". Разница заключается только в формате вывода календаря.
Решать мы, конечно, будем hard версию :blush:.

В итоге вся "сложность" работы заключена в заполнении столбиком и выводе месяцев группами по 4. Думаю, вы понимаете, что создание подобного алгоритма не составляет труда, если знать лишь пару основных идей:
  1. 1 января 1 года - это понедельник (это можно использовать для определения дня недели даты)
  2. Максимальное занимаемое количество недель в месяце - 6, минимальное - 4 (необходимо для правильного "центрирования" месяцев)
Однако, вдобавок к обязательному стандарту вывода календаря, авторы задания предлагают написать 7 основных функций (практикум же), помогающих в написании алгоритма заполнения: проверка на високосный год, количество дней в году, количество дней в месяце, количество прошедших дней с 1го января, количество прошедших дней с 01.01.01, разница между двумя датами (в днях), день недели 1ой даты, зная день недели 2ой. Также в комментариях предлагается использовать структуру данных Date:
C++:
struct Date {
    long long Year;
    long long Month;
    long long Day;
};
В первую очередь я хочу предложить написать этот небольшой практикум именнно вам - и вы лишний раз испытаете свои знания, и я, может быть, найду что-нибудь для себя новое в других решениях.
Для особо умных: использовать сторонние классы, помимо iostream, iomanip и string, нельзя.

Мой вариант решения
C++:
#include <iostream>
#include <iomanip>
#include <string>

using namespace std;

struct Date {
    long long Year;
    long long Month;
    long long Day;
};

#pragma region Functions
bool IsLeap(Date date) {
    if (!(date.Year % 4)) {
        if (!(date.Year % 100))
            return false;
        if (!(date.Year % 400))
            return true;
        return true;
    }
    return false;
}
int YearDaysCount(Date date) {
    return IsLeap(date) ? 366 : 365;
}
int MonthDaysCount(Date date) {
    if (date.Month == 2)
        return IsLeap(date) ? 29 : 28;
    else if (date.Month == 1 || date.Month == 3 || date.Month == 5 || date.Month == 7 || date.Month == 8 || date.Month == 10 || date.Month == 12)
        return 31;
    return 30;
}
int DaysFromJan(Date date) {
    int TotalDays = date.Day - 1;
    for (int i = 0; i < date.Month - 1; i++)
        TotalDays += MonthDaysCount(Date{ date.Year, i + 1, 1 });
    return TotalDays;
}
long long DaysFrom1st(Date date) {
    int FromJan = DaysFromJan(Date{ date.Year, date.Month, date.Day });
    return (--date.Year) / 4 - date.Year / 100 + date.Year / 400 + date.Year * 365 + FromJan;
}
long long DatesDeltaDays(Date date1, Date date2) {
    auto _1 = DaysFrom1st(date1) - DaysFrom1st(date2);
    return _1;
}
int NextDateDayOfWeek(Date date1, Date date2, int dayOfWeek) {
    int tmp = (dayOfWeek + DatesDeltaDays(date1, date2) % 7) % 7;
    return tmp >= 1 ? tmp : 7 + tmp;
}
#pragma endregion

Date today = { 2021, 1, 22 };
string Months[]{ "Январь", "Февраль", "Март", "Апрель", "Май", "Июнь", "Июль", "Август", "Сентябрь", "Октябрь", "Ноябрь", "Декабрь" };
string Days[]{ "ПН", "ВТ", "СР", "ЧТ", "ПТ", "СБ", "ВС" };

int main() {
    setlocale(LC_ALL, "ru");
    while (1) {
        try {
            system("cls");
            int year = 0;
            bool spaces = false;
            char c;
            cout << "Введите год для отображения календаря: ";
            while (c = cin.get(), c != '\n') {
                if (year == -1)
                    continue;
                if (spaces) {
                    if (c == ' ')
                        continue;
                    else if (!year)
                        spaces = false;
                    else
                        year = -1;
                }
                else if (c == ' ') {
                    spaces = true;
                    continue;
                }
                if (c >= '0' && c <= '9')
                    year = year == 0 ? c - '0' : year * 10 + c - '0';
                else
                    year = -1;
            }
            if (year <= 0)
                throw exception("Неверный тип входных данных");
            Date newDate = { year, 1, 1 };
            int months[12][7][6] = { 0 };
            int _1stIndex = NextDateDayOfWeek(newDate, today, 5) - 1;
            for (int m = 0; m < 12; m++) {
                int day = 1;
                int week = 0;
                for (int i = 0; i < 7 && day <= MonthDaysCount(Date{ year, m + 1, 1 }); i++) {
                    if (!week && i < _1stIndex)
                        continue;
                    months[m][i][week] = day++;
                    if (i == 6) {
                        week++;
                        i = -1;
                    }
                }
                if (m != 11)
                    _1stIndex = NextDateDayOfWeek(Date{ year, m + 2, 1 }, today, 5) - 1;
            }
            system("cls");
            cout << "Календарь на " << year << " год\n\n";
            for (int j = 0; j < 12; j++) {
                cout << setw(26) << left << Months[j];
                if (!((j + 1) % 4)) {
                    cout << "\n";
                    for (int i = 0; i < 7; i++) {
                        cout << setw(3) << left << Days[i];
                        for (int m = j / 4 * 4; m < j + 1; m++) {
                            for (int z = 0; z < 6; z++)
                                cout << setw(3) << left << (months[m][i][z] ? to_string(months[m][i][z]) : "");
                            if (m != j)
                                cout << setw(0) << left << "     " << Days[i] + " ";
                        }
                        cout << "\n";
                    }
                    cout << "\n";
                }
            }
        }
        catch (exception ex) {
            cout << "Ошибка во время выполнения программы: " << ex.what() << "\n\n";
            goto end;
        }
    end:
        system("pause");
        continue;
    }
}
Чот я давно не увлекаюсь с++, надо будет попробовать написать, спасибо))
 
Олдфаг
Статус
Оффлайн
Регистрация
18 Фев 2019
Сообщения
2,826
Реакции[?]
1,853
Поинты[?]
24K
Участник
Статус
Оффлайн
Регистрация
3 Ноя 2020
Сообщения
874
Реакции[?]
181
Поинты[?]
0
Обязательно поделись кодом в теме, думаю, всем будет полезно :)
Надо визуалку скачать, немного потрениться, время будет, отпишу:))
у меня прост винда слетела, а на старом жд на визуалке не вариант вообще работать, тормозит жутко
 
Сверху Снизу