JavaRush /Java блог /Архив info.javarush /Помогите понять. не цикличные циклы
PaPAlukalos
6 уровень
Санкт-Петербург

Помогите понять. не цикличные циклы

Статья из группы Архив info.javarush
Всем привет. Сейчас завершил 5й уровень. И появился вопрос. Для простоты понимания сформулирую в виде задачки. Вводим дату (пускай будет целое число от 1го до 365) и назовем day. эта day - первый день, когда начинается график работы, скажем на производстве, от которого начинается вот такой отсчет: 2дня работаем, 3 отдыхаем, затем 1 день работаем, 2 отдыхаем и пошло по новой (2 рабочих, 3 отдыха, 1 рабочий, 2 отдыха). И вводим ещё один день (пускай будет i, тоже от 1 до 365). Так надо узнать i - выходной или рабочий? Циклы понятно, как применить при цикличности, а при не стандартных повторениях? есть ли для этого методы? Если есть, то прошу подсказать. А то сам придумал себе задачку и уже 2ой день она покоя мне не дает. Ниже, что удалось придумать... но не работает))) public static boolean positiveWeek(int day, int i) { boolean n = false; day = day + 1; // здесь учитываются первые 2 рабочих дня и false - значит рабочий if (day >= i) return n else{ for (int a = 1; a == i; a++){ // это я цикл сделал (где значения a - от балды взял) :) n = true; day = day + 3; // идут 3 выходных; if (day >= i) break; day = day + 1; // затем 1 рабочий n = false; if (day >= i) break; day = day + 2; // 2 выходных n = true; if (day >= i) break; day = day + 2; // 2 рабочих n = false; if (day >= i) break; } return n; } Вроде логически правильно всё расписал, но всегда возвращает n = false (в самом начале кода). Меняю на true, возвращает true. Также очень буду благодарен, другим отличающимся от моего решениям. Для саморазвития. Спасибо.
Комментарии (4)
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ
PaPAlukalos Уровень 6
16 февраля 2016
Спасибо огромное, как только не догадался до такого
if (currentDay>8) currentDay=1;
if (currentDay==1 || currentDay==2 || currentDay==6) return true;
return false;


И метод с выталкиванием бита — с удовольствием прочитал. Понятно вроде всё, но появился вопрос. по этому коду:
public class Solution {
    public static void main(String[] args) throws IOException {
        System.out.println(isWorkDayVersion2(1, 9));
        System.out.println(isWorkDayVersion2(1, 15));
    }

    public static boolean isWorkDay(int day, int i) {
        // маска режима работы: с конца (младших битов) 1 - работает, 0- отдыхает
        int maskWorkShift= 0b00100011;
        // Так как режимы работы цикличен (с периодичностью 8) - найдем день в очередном цикле (как остаток от деления)
        int s =  (i-day) % 8;
        // Теперь "вытолкнем" вправо из маски для текущего дня бит режима
        // Например, если у нас 6 день, то выталкиваем как  
        //00100011 -> 00010001 -> 00001000 -> 00000100 -> 00000010 -> 00000001
        // И в конце узнаем значние крайнего правого бита ( через битовую операцию AND 1 '& 1')
        int z =  (maskWorkShift >>> s) & 1;
        // Если он 1 (т.е. рабочий - вернем true, иначе - false)
        return (z==1);
    }

    public static boolean isWorkDayVersion2(int day, int i) throws IOException {
        // Проверка начальных данных, ибо если вернуть false - непонятно отдыхает или ошибка.
        if (day<0 || day>365 || i<day || i>365)
            throw new IOException();
        return  (((0b00100011 >>> (i-day) % 8) & 1)==1);
    }
}


Я так понимаю метод isWorkDayVersion2(int day, int i) — это укороченный метод с проверкой isWorkDay(int day, int i)? Т.е. isWorkDay(int day, int i) это — апендикс? :) Просто он в примере применения смущает. Дум
Joysi Уровень 41
16 февраля 2016
Вариант с циклом (очень не оптимален, просто для примера):
public static boolean isWorkDayVersion3(int day, int i) throws IOException {
        // Проверка начальных данных, ибо если вернуть false - непонятно отдыхает или ошибка.
        if (day<0 || day>365 || i<day || i>365)
            throw new IOException();
        // Текущий день
        int currentDay = 1;
        // В цикле будем "проживать" день за днем его 8-дневной цикл
        for (int j = day; j < i+1; j++) {
            currentDay ++;
            if (currentDay>8) currentDay=1;
        }
        // Если 1,2 или 6 день по 8-дневному графику - значит работаем
        if (currentDay==1 || currentDay==2 || currentDay==6) return true;
        // Иначе - гуляем :)
        return false;
    }
}
Joysi Уровень 41
16 февраля 2016
Для вашего случая лучше решение без циклов, так как
жестко задан постоянный график работы.

Небольшие замечания:
1) Функции, возвращающие логическое значение, обычно начинают именовать с is (например isGreen() — является зеленым, isAvailable() — является доступным)
2) Я не знаю, знакома ли Вам двоичная арифметика, если нет — почитайте (например, в Wikipedia).
3) Лучше вначале функции проверять валидность (правильность переданных параметров). И в случае некорректных параметров — отреагировать (например, сгенерировать ошибку — на 9м уровне Вы узнаете подробности).

Вот функция с комментариями:
public static boolean isWorkDay(int day, int i) {
        // маска режима работы: с конца (младших битов) 1 - работает, 0- отдыхает
        int maskWorkShift= 0b00100011;
        // Так как режимы работы цикличен (с периодичностью 8) - найдем день в очередном цикле (как остаток от деления)
        int s =  (i-day) % 8;
        // Теперь "вытолкнем" вправо из маски для текущего дня бит режима
        // Например, если у нас 6 день, то выталкиваем как  
        // 00100011 -> 00010001 -> 00001000 -> 00000100 -> 00000010 -> 00000001
        // И в конце узнаем значение крайнего правого бита ( через битовую операцию AND 1 '& 1')
        int z =  (maskWorkShift >>> s) & 1;
        // Если он 1 (т.е. рабочий - вернем true, иначе - false)
        return (z==1);
    }


Вот она с проверкой валидности и «схлопнутым» вычислением результата:
public static boolean isWorkDayVersion2(int day, int i) throws IOException {
        // Проверка начальных данных, ибо если вернуть false - непонятно отдыхает или ошибка.
        if (day<0 || day>365 || i<day || i>365)
            throw new IOException();
        return  (((0b00100011 >>> (i-day) % 8) & 1)==1);
    }