Разминка для мозгов: правильная дата

Разминка для мозгов: правильная дата

Предлагаю очередную простенькую задачку для разминки мозгов.


Необходимо написать функцию, прототип которой выглядит так:

string answer(int x, int y, int z);

В качестве аргументов функция получает три целых числа в диапазоне 1..99.

Функция должна возвращать строку следующего содержания:

  • Дата в формате ДД/ММ/ГГ, если аргументы функции определяют только одну допустимую дату. Например: числа 88, 15, 2 определяют единственную дату «15/02/88».
  • «Ambiguous», если из аргументов функции возможно составить более одной допустимой даты. Например: из чисел 10, 88, 12 можно составить даты 10/12/88 и 12/10/88.
  • «Incorrect», если из аргументы функции невозможно составить ни одной допустимой даты.

Високосные года во внимание не принимать.
Проверку аргументов на принадлежность диапазону 1..99 не делать.
Можно использовать все возможности языка C++ и STL.


Задача может быть решена разными способами. Поэтому, если кто-то уже опубликовал свой вариант, попробуйте найти другое, желательно лучшее, решение. Краткость и эффективность приветствуются.

Наивная реализация (високосный год учитывается):

#include <iostream>

#include <sstream>
#include <iomanip>
#include <string>

#include <algorithm>



bool is_valid_date ( int (&date)[3] )
{
    static const int days_count_from_month[12] = { 31 , 28 , 31 , 30 , 31 , 30 , 31 , 31 , 30 , 31 , 30 , 31 } ;
    int count_days = 0 ;
    bool result = false ;
    if ( date[2] < 13 )
    {
        count_days = days_count_from_month [ date[2] - 1 ] + ( (date[2] == 2) && (date[0] % 4 == 0 ) ) ;
        result = ( date [1] <= count_days ) ;
    }
    //std::cout << "Result for [" << date[0] << "." << date[1] << "." << date[2] << "] " << result << " | count days = " << count_days << std::endl ;
    return result ;
}


std::string answer(int x, int y, int z)
{
    int dateBuffer [ 3 ] = { x , y , z } ;
    int count_valid = 0 ;
    std::sort ( dateBuffer , dateBuffer + 3 ) ;
    std::string resultMessage = "Incorrect" ;
    do
    {
        if ( is_valid_date ( dateBuffer )  )
        {
            if ( ++count_valid > 1 )
            {
                resultMessage = "Ambiguous" ;
                break ;
            }
            std::stringstream ss ;
            ss << std::setw(2) << std::setfill('0') << dateBuffer[1]
                << "." << std::setw(2) << dateBuffer[2]
                << "." << std::setw(2) << dateBuffer[0] ;
            resultMessage = ss.str() ;
        }
    } while ( std::next_permutation( dateBuffer , dateBuffer + 3 ) ) ;
    return resultMessage ;
}


int main()
{
    srand ( time(0) ) ;
    for ( size_t i = 0 ; i < 100 ; ++i )
    {
        int a = rand() % 50 + 1 ; //TODO 100
        int b = rand() % 50 + 1 ; //TODO 100
        int c = rand() % 50 + 1 ; //TODO 100
        std::cout << "Result for [" << a << "." << b << "." << c << "]: " << answer ( a , b , c ) << std::endl ;
    }
}

http://rextester.com/DNTTKS53050

Croessmah, високосность у тебя проверяется неправильно (см. признаки високосности).

Кстати, хорошей разминкой для мозгов было бы написать класс для работы с датами (DateTime).

С возможностью вычитать даты друг из друга (получать разницу), прибавлять с дате определенное количество дней, месяцев и т.п.

count_days = days_count_from_month [ date[2] - 1 ] + ( (date[2] == 2) && (date[0] % 4 == 0 ) ) ;

Посоветовал бы тебе не писать таких конструкций, т.к. они сложны для восприятия (проходится напрягать мозг, чтобы понять, что тут происходит).

Если привести это к нормальной форме, то будет гораздо лучше:

day_count = days_count_from_month[date[2] - 1];
if (date[2] == 2 && date[0] % 4 == 0) {
    // високосный год
    day_count++;
}

осоветовал бы тебе не писать таких конструкций, т.к. они сложны для восприятия (проходится напрягать мозг, чтобы понять, что тут происходит).

Спасибо за совет, конечно, но я в курсе. Это код для форума, а не для нормальной программы.

Croessmah, високосность у тебя проверяется неправильно (см. признаки високосности).

В каком месте? Если делится на 4, то високосный. На 100 и на 400 нет смысла проверять — число от 1 до 99.

С возможностью вычитать даты друг из друга (получать разницу), прибавлять с дате определенное количество дней, месяцев и т.п.

При таком подходе :

Можно использовать все возможности языка C++ и STL.

Лучше вообще time_point или boost::date_time

Что мне нравится в Croessmah, так это хорошее знание STL. Мысль про std::next_permutation мне даже в голову не пришла.

Только во дату ты неправильно форматируешь. По условию задачи сепаратор — прямой слэш, а у тебя — точка.

Только во дату ты неправильно форматируешь. По условию задачи сепаратор — прямой слэш, а у тебя — точка.

Да, косяк ))) Как по мне, так лучше вообще воспользоваться локалью.

А «НЕ-наивную реализацию» покажешь? ;-)

Возможно, но не сегодня. Тыкаю в БП паяльником, так что особо некогда )))

В каком месте? Если делится на 4, то високосный. На 100 и на 400 нет смысла проверять — число от 1 до 99.

Да, кстати, если дата в формате dd/mm/YY — как будет выглядеть 2015 год в этом случае? А 1988?

Лучше вообще time_point или boost::date_time

Тогда смысл задания полностью теряется. Задача как раз самому реализовать подобный функционал. Написание велосипедов — это очень хорошо для обучения.

Да, кстати, если дата в формате dd/mm/YY — как будет выглядеть 2015 год в этом случае? А 1988?

Ну это всё-таки тренировочная задача, а не кусок реального проекта ))

Внимание! Это довольно старый топик, посты в него не попадут в новые, и их никто не увидит. Пишите пост, если хотите просто дополнить топик, а чтобы задать новый вопрос — начните новый.

Ответить

Вы можете использовать разметку markdown для оформления комментариев и постов. Используйте функцию предпросмотра для проверки корректности разметки.

Пожалуйста, оформляйте исходный код в соответствии с правилами разметки. Для того, чтобы вставить код в комментарий, скопируйте его в текстовое поле ниже, после чего выделите то, что скопировали и нажмите кнопку «код» в панели инструментов. Иначе ваш код может принять нечитаемый вид.

Либо производите оформление кода вручную, следующим образом:

``` #include <iostream> using namespace std; int main() { // ... } ```

Предпросмотр сообщения

Ваше сообщение пусто.