Задача про драконьи яйца. Призываем программистов
easy

Задача про драконьи яйца. Призываем программистов

Уровень: начинающий.

Обещаем, что это последний материал про «Игру престолов». Зато это задача, которая решается с помощью программирования!

Фермер решил завести 20 драконов, чтобы продавать яйца по 50 серебряных за штуку. Рептилии (драконы же рептилии?) несут по два яйца в неделю, и каждую неделю все яйца продаются. С этих денег фермер покупает ещё по два дракона в неделю по 300 серебряных, чтобы увеличить свой доход. Но расходы велики: чтобы кормить и содержать питомцев, хозяин каждый день тратит 500 серебряных.

Фермер решил: если прибыли от рептилий так и не будет, через год он продаст их всех одной любительнице драконов, а если будет — продолжит дело. Как вы думаете, продаст он их или нет?

Как будем решать

Можно было бы составить сложную формулу, которая выводит зависимость прибыли от дня года, и начертить график. Там, где график пересёк бы ноль и пошёл вверх, мы бы увидели прибыль. Но формулы — это для математиков, а мы программисты. Мы напишем программу, которая симулирует экономику нашего фермера, перебирая день за днём. Сегодня потратил столько-то, завтра продал яйца и заработал столько-то, послезавтра потратил ещё столько-то… — и будем проверять, когда появится прибыль.

Тот же принцип используют учёные, когда делают симуляции — например, чёрных дыр или Большого взрыва: они задают исходные физические параметры своим объектам и дают компьютеру задание рассчитать каждую секунду их взаимодействия. Вот у нас как про чёрные дыры, только про драконов.

Задачу будем решать на JavaScript, потому что он у вас уже работает в браузере и вы можете спокойно повторить решение прямо сейчас, используя консоль (в меню «Вид» → «Разработчикам» → «Консоль»).

Шаг 1. Знакомство с функцией

Основную математику мы пропишем в функции: она будет заниматься симуляцией экономики фермера. Функция — это мини-программа внутри нашей программы: сначала мы пишем, что она будет делать, а потом вызываем её внутри программы и всё необходимое исполняется. В данном случае нам нужна программа внутри программы, чтобы иметь возможность выйти из неё, когда закончится год.

Чтобы задать функцию, которую мы назовём runDragonSimulator, используем такой код:

function runDragonSimulator() { }

Вначале идёт команда function, которая говорит компьютеру: мы хотим сделать новую функцию, которая будет называться runDragonSimulator. В круглых скобках пишутся параметры функции, оказывающие влияние на её работу. В нашем случае таких параметров нет, функция всегда будет действовать одинаково, поэтому в этих скобках сейчас ничего не указываем. А внутри фигурных скобок {} мы напишем тело функции — код, который выполнится, когда мы вызовем эту функцию.

Почему функция называется именно так — прочитайте в нашей статье о названии функций.

Когда компьютер встретит наименование функции, он поймёт, что нужно выполнить тот кусок кода, который стоит между фигурными скобками. Он его выполнит, а потом снова вернётся к программе — с того же места, где он прервался на функцию.

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

function question() {

     console.log('Валар моргулис');

    // И можно выполнить какие угодно ещё команды, в любом количестве

}

function answer() {

    console.log('Валар дохаэрис');

    // Тут тоже можно выполнить любые дополнительные команды

}

Теперь если мы просто напишем названия этих функций, то компьютер выполнит те команды, которые мы описали в нашей функции:

    question();

    > 'Валар моргулис'

    answer();

    > 'Валар дохаэрис'

У функции есть свойство: её можно прервать в любой момент командой return. Когда компьютер в функции доходит до выполнения команды return, он прекращает осуществлять задачу ровно в этом месте и возвращается в главную программу.

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

Если схематично построить логику нашего решения, оно будет выглядеть так:

  • Считаем дни, сколько прошло всего и с начала месяца.
  • Ежедневно тратим деньги на корм и содержание драконов.
  • Каждую неделю продаём все яйца.
  • На полученные деньги каждую неделю покупаем ещё двух драконов.
  • Если после этого доходы всё ещё меньше расходов — возвращаемся в первый пункт, в противном случае прерываем подсчёты и подводим итоги: пишем, сколько мы заработали и сколько времени на это ушло.

Шаг 2. Установка переменных

Переменные — это ячейки памяти компьютера, где будут храниться нужные нам данные. Нам понадобятся переменные для дохода и расходов, для общего количества дней и для подсчёта каждого седьмого дня, который приносит нам доход.

Переменные в языке JavaScript задаются словами var или let. У них есть разница в видимости, сейчас она нас не волнует, но в будущем о них поговорим. Для этого примера используем var:

// сюда мы будем складывать наш общий доход и расход
var margin, expense;
// переменная поможет нам отследить седьмой день, когда снесутся все драконы и мы продадим все яйца. Пока ничего не началось, это считается нулевым днём.
var day = 0;
// считаем количество дней всего, один год — это 365 дней
var dayZ = 0;

Теперь задаём количество драконов в самом начале и стартовые значения дохода и расхода:

// число драконов на старте — 20
var group = 20;
// сколько яиц нам принесли все драконы за неделю, в самом начале пока — 0
var eggs = 0;
// устанавливаем стартовые цифры дохода и расхода на первый день работы
margin = 0;
expense = 500;

Весь основной код мы поместим в нашу функцию:

function runDragonSimulator() {
   // тут будет наш код
}

Шаг 3. Цикл

Основное, что нам нужно будет делать всё время, — выполнять код до тех пор, пока не сработает наше условие, что доход больше расхода. Для этого используем новый цикл — while:

while ( условие ) { команды }

Смысл такой: пока условие верное, команды выполняются раз за разом. После каждой отработки всех команд цикл возвращается в начало и снова проверяет — выполняется ли до сих пор условие. Если да, снова делаем все команды, если нет — цикл на этом прекращается.

Мы поставим такое условие: пусть всё работает, пока доходы меньше расходов, а мы посмотрим, что настанет раньше — пройдёт один год или мы выйдем в плюс:

while (margin < expense) {
   // тут будет основной код программы
}

Шаг 4. Подсчёты

Началась ежедневная рутина: подсчёт дней, понедельный и общий, и постоянные траты на корм и уход за драконами.

Чтобы увеличить количество прошедших дней на единицу, можно использовать привычную команду day = day + 1. Она берёт старое значение day, прибавляет к нему единицу и результат помещает снова в day. А можно сделать изящнее:

day += 1;

Команда += 1 увеличивает значение нашей переменной на единицу. Если бы мы написали day +=3, то это бы увеличило значение day на 3.

Что у нас происходит каждый день: меняется текущий день недели, возрастает общее количество прошедших дней, тратим 500 серебряных на содержание драконов:

day += 1;

dayZ += 1;

expense += 500;

Теперь надо проверить, вдруг сегодня уже седьмой день, — и тогда мы соберём по два яйца с каждого дракона, продадим их и купим ещё рептилий:

// каждый седьмой день нам приносит доход, это значит:
if (day == 7) {
  // все драконы несут за неделю по два яйца
  eggs += group * 2;
  // берём наш доход и увеличиваем его на прибыль от продажи всех яиц, собранных за неделю
  margin += eggs * 50;
  //каждую неделю покупаем два дракона по 300 серебряных…
  expense += 2 * 300;
  // …это увеличивает общее количество рептилий
  group += 2;
  // все яйца распродали, начинаем сначала
  eggs = 0;
  // начинаем отсчитывать дни заново
  day = 0;
}

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

Шаг 5. Проверки

Теперь надо проверить, вдруг прошёл уже один год и общая сумма наших доходов до сих пор не превысила все наши расходы? Если так, то сообщаем об итогах эксперимента и останавливаем выполнение функции:

// если прошёл год, а проект так и не взлетел (хехех) — останавливаемся и считаем убытки
if ((dayZ == 356) && ((margin - expense) < 0)) {
  // выводим сообщение о доходах и расходах за этот год
  console.log('Драконы за год так и не принеcли вам денег, милорд. Ваши убытки за это время составили ' + (expense - margin) + ' c.');
  // останавливаем функцию и больше ничего не вычисляем
  return;
}

Но что будет, если наш цикл однажды закончится сам? Речь про условие while (margin < expense).

Если однажды это условие не выполнится, это значит, что доходы перестали быть меньше расходов, то есть мы вышли в плюс. Тогда нужно вывести количество дней, сколько у нас ушло на это, а также прибыль, которую мы получили:

console.log('За ' + dayZ + ' дней вы вышли в плюс. Всего вы потратили ' + expense + ' и заработали ' + margin + ' c. Первая прибыль: ' + (margin - expense));

Собираем всё

Все части программы у нас уже есть. Собираем готовый код:

// сюда мы будем складывать наш общий доход и расход
var margin, expense;
// переменная поможет нам отследить седьмой день, когда все драконы снесут яйца
var day = 0;
// считаем количество дней всего, один год — это 365 дней
var dayZ = 0;
// количество драконов, на старте — 20
var group = 20;
// сколько яиц нам принесли все рептилии за неделю, в самом начале пока — 0
var eggs = 0;
// устанавливаем стартовые цифры дохода и расхода на первый день работы
margin = 0;
expense = 500;
// чтобы иметь возможность прекратить подсчёты, когда пройдёт один год, поместим все наши вычисления в функцию
// объявляем функцию с названием runDragonSimulator
function runDragonSimulator() {
  // пока расходы превышают доходы — работаем
  while (margin < expense) {
    // наступил новый день из семи
    day += 1;
    // и сразу считаем общее количество дней
    dayZ += 1;
    // каждый день мы тратим 500 серебряных…
    expense += 500;
    // каждый седьмой день нам приносит доход, это значит:
    if (day == 7) {
      // все драконы несут за неделю по два яйца
      eggs += group * 2;
      // берём наш доход и увеличиваем его на доход от продажи всех яиц, собранных за неделю
      margin += eggs * 50;
      //каждую неделю покупаем два дракона по 300 серебряных…
      expense += 2 * 300;
      // …это увеличивает общее количество рептилий
      group += 2;
      // все яйца распродали, начинаем сначала
      eggs = 0;
      // отсчитываем дни заново
      day = 0;
    }
    // если прошёл год, а проект так и не взлетел — останавливаемся и считаем убытки
    if ((dayZ == 356) && ((margin - expense) < 0)) {
      // выводим сообщение о доходах и расходах за этот год
      console.log('Драконы за год так и не принеcли вам денег, милорд. Ваши убытки за это время составили ' + (expense - margin) + ' c.');
      // останавливаем функцию и больше ничего не вычисляем
      return;
    }
  }
  // если мы всё-таки вышли из цикла, значит доходы превысили расходы — выведем это на экран
  console.log('За ' + dayZ + ' дней вы вышли в плюс. Всего вы потратили ' + expense + ' и заработали ' + margin + ' с. Первая прибыль: ' + (margin - expense));
}
// запускаем функцию с расчётами
runDragonSimulator();

Обратите внимание: сначала мы создали функцию, описали все её ветки и логику. Но когда мы её описываем, она ещё не работает. Мы как бы задали правила игры, но саму игру не запустили. И только на последней строке кода мы говорим runDragonSimulator(); — и вот тогда программа действительно активируется и выполняет всё, как мы её просили.

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

Обложка:

Даня Берковский

Корректор:

Ирина Михеева

Вёрстка:

Маша Климентьева

Получите ИТ-профессию
В «Яндекс Практикуме» можно стать разработчиком, тестировщиком, аналитиком и менеджером цифровых продуктов. Первая часть обучения всегда бесплатная, чтобы попробовать и найти то, что вам по душе. Дальше — программы трудоустройства.
Получите ИТ-профессию Получите ИТ-профессию Получите ИТ-профессию Получите ИТ-профессию
Вам может быть интересно
easy