Модераторы: bsa

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Доработать календарь, Не реагирует на нажатие стрелок  
:(
    Опции темы
feodorv
Дата 4.5.2013, 15:31 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2214
Регистрация: 30.7.2011

Репутация: 12
Всего: 45



Так, например:
Код

inline int isLeapYear( int year )
{
  return ((year % 4) == 0 && ((year % 100) != 0 || (year % 400) == 0)) ? 1 : 0;
}


Добавлено через 1 минуту и 25 секунд
Или так...


--------------------
Напильник, велосипед, грабли и костыли - основные инструменты программиста...
PM MAIL   Вверх
feodorv
Дата 4.5.2013, 19:58 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2214
Регистрация: 30.7.2011

Репутация: 12
Всего: 45



Смотрю, энтузиазм угас)))

Вот моё видение программы:
Код

#include <iostream>
#include <windows.h>
#include <conio.h>

using namespace std;

const int DaysPerMonth[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
const int DayForw[] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
const int DayPerMonthLeap[] = { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
const int DayForwLeap[] = { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 };
const char cMonths[] = "Jan\0Feb\0Mar\0Apr\0May\0Jun\0Jul\0Aug\0Sep\0Oct\0Nov\0Dec";

inline int isLeapYear( int year )
{
  return (year % 4) == 0 && ((year % 100) != 0 || (year % 400) == 0);
}

int dayOfWeek( int month, int year)
{
  int weekDay = year - 1 + (isLeapYear(year) ? DayForwLeap[month-1] : DayForw[month-1]);
  --year;
  weekDay += year / 4 - year / 100 + year / 400;
  return weekDay % 7 + 1;
}

void showMonth( int month, int year)
{
  int weekDay = dayOfWeek( month, year);
  int dayMax = isLeapYear(year) ? DayPerMonthLeap[month-1] : DaysPerMonth[month-1];
  int day;

  system( "cls" );
  cout << "\t    ************ " << &cMonths[(month-1)*4] << " " << year << " ************" << endl << endl;
  cout << "\tMon\tTue\tWed\tThu\tFri\tSat\tSun" << endl << endl;

  for( day = 1; day < weekDay; day++) cout << "\t";

  for( day = 0; day < dayMax; weekDay++, day++)
  {
    cout << "\t" << day+1;
    if( weekDay == 7 )
    {
      weekDay = 0;
      cout << endl << endl;
    }
  }

  cout << endl << endl << "\t    ************ " << &cMonths[(month-1)*4] << " " << year << " ************" << endl;
}

void getCurrentMonth( int& month, int& year)
{
  SYSTEMTIME lt;

  GetLocalTime( &lt );

  month = lt.wMonth;
  year = lt.wYear;
}

void enterYearMonth( int& month, int& year)
{
  for( ;; )
  {
    cout << endl << "Please, enter the month & the year for calendar (mm yyyy): ";
    cin >> month >> year;
    if( cin.fail() )
    {
      cout << "Invalid input!\n\n";
      cin.clear();
      cin.sync();
    }
    else if( month > 12 || month < 1 )
      cout << "Month is incorrect!\n\n";
    else if( year <= 0 )
      cout << "Year is incorrect!\n\n";
    else
      return;
  }
}

int main( void )
{
  int month, year;

  getCurrentMonth( month, year);
  showMonth( month, year);

  for( ;; )
  {
    int key = _getch();
    if( key == 0 || key == 0xe0 ) key = _getch();

    if( key == 77 )
    {
      if( ++month > 12 )
      {
         month = 1;
         ++year;
      }
      showMonth( month, year);
    }
    else if( key == 75 )
    {
      if( month == 1 )
      {
         if( year > 1 )
         {
            month = 12;
            --year;
         }
      }
      else
         --month;
      showMonth( month, year);
    }
    else if( key == 81 )
    {
      if( year > 0 ) --year;
      showMonth( month, year);
    }
    else if( key == 73 )
    {
      if( ++year <= 0 ) year = 1;
      showMonth( month, year);
    }
    else if( key == '\r' )
    {
      enterYearMonth( month, year);
      showMonth( month, year);
    }
    else if( key == 27 )
      break;
  }

  return 0;
}


Можно сходить к вечному календарю, провериться...

Это сообщение отредактировал(а) feodorv - 4.5.2013, 23:56


--------------------
Напильник, велосипед, грабли и костыли - основные инструменты программиста...
PM MAIL   Вверх
zeitgeistz
Дата 4.5.2013, 22:04 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Awaiting Authorisation
Сообщений: 36
Регистрация: 23.4.2013

Репутация: нет
Всего: нет



Не угас smile Решил отвлечься просто, погулял.

Я не сильно долго сиплюсплюсю, поясните пожалуйста, что за штуки такие

в 
Код

inline int isLeapYear( int year )
{
  return (year % 4) == 0 && ((year % 100) != 0 || (year % 400) == 0);
}

 что inline слово выполняет, для чего оно и почему без него нельзя?


вот это ещё
Код

for( ;; )


Я повыше уже спрашивал, Вы, наверно, не заметили, что такое 0xe0?


PM   Вверх
feodorv
Дата 4.5.2013, 22:26 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2214
Регистрация: 30.7.2011

Репутация: 12
Всего: 45



Цитата(zeitgeistz @  4.5.2013,  23:04 Найти цитируемый пост)
что inline слово выполняет, для чего оно и почему без него нельзя?

С этим ключевым словом подпрограмма встраивается в код в месте вызова (то есть сколько вызовов, столько раз возникает код данной подпрограммы). Замена #define'а в С (хотя в C тоже можно инлайнить). Без инлайна можно, сильно хуже не будет. Не нравится это ключевое слово - удаляйте...


Цитата(zeitgeistz @  4.5.2013,  23:04 Найти цитируемый пост)
вот это ещё

Это бесконечный цикл, аналог while(1){ } или Вашего do{ }while(1); Выглядит попроще, вот и предпочитаю его...
Цитата

      Синтаксис:     for([начальное-выражение];   
                         [условное-выражение];   
                         [выражение-цикла]) ...

Здесь все внутренние выражения можно опустить, остаются одни точки с запятыми, вот и получается for(;;){ }


Цитата(zeitgeistz @  4.5.2013,  23:04 Найти цитируемый пост)
Я повыше уже спрашивал, Вы, наверно, не заметили, что такое 0xe0?

Это Вы у Microsoft спросите, не меня:
Цитата

The _getch and_getwch functions read a single character from the console without echoing the character. None of these functions can be used to read CTRL+C. When reading a function key or an arrow key, each function must be called twice; the first call returns 0 or 0xE0, and the second call returns the actual key code.

Взято отсюда. Согласно этому описанию и проводится проверка на 0xe0...


--------------------
Напильник, велосипед, грабли и костыли - основные инструменты программиста...
PM MAIL   Вверх
zeitgeistz
Дата 4.5.2013, 22:56 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Awaiting Authorisation
Сообщений: 36
Регистрация: 23.4.2013

Репутация: нет
Всего: нет



А можете подробнее рассказать о формулах в dayOfWeek? Тяжело понимается, особенно первая строка внутри скобок

Код

int dayOfWeek( int month, int year)
{
  int weekDay = 6 + year + (isLeapYear(year) ? DayForwLeap[month-1] : DayForw[month-1]);
  --year;
  weekDay += year / 4 - year / 100 + year / 400;
  return weekDay % 7 + 1;
}

PM   Вверх
feodorv
Дата 4.5.2013, 23:55 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2214
Регистрация: 30.7.2011

Репутация: 12
Всего: 45



Цитата(zeitgeistz @  4.5.2013,  23:56 Найти цитируемый пост)
особенно первая строка внутри скобок

Распишите подробнее:
Код

const int* DayForwUniversal =  DayForw;
if( isLeapYear(year) ) DayForwUniversal = DayForwLeap;
int weekDay = 6 + year + DayForwUniversal[month-1];
...


Что за формула?
Вычисляется число дней, прошедших с 1 января 1-го года нашей эры по 1-е число интересующего нас месяца, при том что известно, что 01.01.0001 - это понедельник (сходите в тот же "вечный календарь").
Чему равно число таких дней? Если бы не было поправок на високосность, то просто (year-1)*365 + (число дней от начала года до начала месяца). 
Потом мы всё равно будем делать %7 (это если, как следует порядочным программистам C/C++, отсчитывать от нуля: 0-понедельник, 1-вторник, ..., 6-воскресенье). Поскольку 365 % 7 = 1, то формула упрощается до безобразия: year-1+yDay (здесь yDay - то самое число дней от начала года до начала интересующего нас месяца, то есть DayForwUniversal[month-1]). (У меня, кстати, неправильно написано year+6 smile ) 
Осталось учесть високосность. Високосным год признаётся, если он без остатка делится на 4, за исключением особых лет, которые делятся на 100, но не делятся на 400 (без остатка). То есть, например, 1600 и 2000 - високосные года, а 1700, 1800, 1900 - не високосные. Сколько же дополнительных високосных дней, случившихся за период с 01.01.0001 по начало текущего года, нужно учесть? Во-первых, високосность текущего года уже учтена, когда определялась переменная DayForwUniversal, следовательно номер текущего года нужно сократить на 1 (например, чтобы для какого-либо месяца 2012 года не учитывать ещё раз високосность этого 2012 года):
Цитата(feodorv @  4.5.2013,  20:58 Найти цитируемый пост)
  --year;

И уже потом добавим число лет, делящихся на 4 без остатка:
Цитата(feodorv @  4.5.2013,  20:58 Найти цитируемый пост)
  weekDay += year / 4

Но из этого числа нужно вычесть года, чьи последние две цифры - нули:
Цитата(feodorv @  4.5.2013,  20:58 Найти цитируемый пост)
  weekDay += year / 4 - year / 100

Однако, делящиеся на 400 нужно оставить, получается полная формула:
Цитата(feodorv @  4.5.2013,  20:58 Найти цитируемый пост)
  weekDay += year / 4 - year / 100 + year / 400;


Ну а потом определяем день недели путём %7 (это в измерении 0-понедельник, 1-вторник, ..., 6-воскресенье). Чтобы перевести это в измерение 1-понедельник, 2-вторник, ..., 7-воскресенье (как у Вас), нужно добавить единицу:
Цитата(feodorv @  4.5.2013,  20:58 Найти цитируемый пост)
  return weekDay % 7 + 1;

Получаем день недели 1-го числа интересующего нас месяца интересующего нас года (из расчёта 1-понедельник, 2-вторник, ..., 7-воскресенье)
Добавлять к weekDay значение понедельника (то есть 0) не обязательно)))


--------------------
Напильник, велосипед, грабли и костыли - основные инструменты программиста...
PM MAIL   Вверх
zeitgeistz
Дата 5.5.2013, 00:19 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Awaiting Authorisation
Сообщений: 36
Регистрация: 23.4.2013

Репутация: нет
Всего: нет



Потрясающе, спасибо большое, как прозрел)

А возможно ли как-то реализовать выделение другим цветом праздничных дней?
PM   Вверх
feodorv
Дата 5.5.2013, 11:23 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2214
Регистрация: 30.7.2011

Репутация: 12
Всего: 45



Цитата(zeitgeistz @  5.5.2013,  01:19 Найти цитируемый пост)
А возможно ли как-то реализовать выделение другим цветом праздничных дней? 

Можно, через SetConsoleTextAttribute, но зачем? Тогда придётся придётся и праздничные дни выделять красным, а в России праздники непостоянны...


--------------------
Напильник, велосипед, грабли и костыли - основные инструменты программиста...
PM MAIL   Вверх
zeitgeistz
Дата 5.5.2013, 13:50 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Awaiting Authorisation
Сообщений: 36
Регистрация: 23.4.2013

Репутация: нет
Всего: нет



Ладно, закончим на этом, спасибо большое за помощь smile
PM   Вверх
Ответ в темуСоздание новой темы Создание опроса
Правила форума "C/C++: Для новичков"
JackYF
bsa

Запрещается!

1. Публиковать ссылки на вскрытые компоненты

2. Обсуждать взлом компонентов и делиться вскрытыми компонентами

  • Действия модераторов можно обсудить здесь
  • С просьбами о написании курсовой, реферата и т.п. обращаться сюда
  • Вопросы по реализации алгоритмов рассматриваются здесь


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, JackYF, bsa.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Для новичков | Следующая тема »


 




[ Время генерации скрипта: 0.1113 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.