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, 22:51
Спасибо огромное, как только не догадался до такого
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, 23:10
isWorkDay(int day, int i) — да «аппендикс» просто, чтобы «развернуть» с комментариями выражение
return  (((0b00100011 >>> (i-day) % 8) & 1)==1);

которое может на начальных уровнях выглядит немного диковато.
Спрашивайте в форуме, на то он и создан.
Joysi
Уровень 41
16 февраля 2016, 14:58
Вариант с циклом (очень не оптимален, просто для примера):
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, 14:38
Для вашего случая лучше решение без циклов, так как
жестко задан постоянный график работы.

Небольшие замечания:
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);
    }